Codex CLI Integration
Integrate OpenAI's Codex CLI for non-interactive code execution
Codex CLI Integration
PraisonAI provides integration with OpenAI’s Codex CLI for non-interactive code execution, file modifications, and structured output.
Installation
# Install Codex CLI
npm install -g @openai/codex
# Verify installation
codex --versionQuick Start
from praisonai.integrations import CodexCLIIntegration
# Create integration
codex = CodexCLIIntegration(
workspace="/path/to/project",
full_auto=True
)
# Execute a coding task
result = await codex.execute("Fix the authentication bug")
print(result)Use as Agent Backend
Delegate an Agent’s LLM turns to codex exec instead of the OpenAI API — uses your ChatGPT subscription.
from praisonaiagents import Agent
agent = Agent(name="assistant", cli_backend="codex-cli")
agent.start("Hello")Backend Configuration
The codex-cli backend ships with this default configuration:
| Option | Type | Default | Description |
|---|---|---|---|
command | str | "codex" | CLI command (must be on PATH) |
args | List[str] | ["exec", "--skip-git-repo-check"] | Default flags passed on every turn |
output | str | "text" | Output format expected from the CLI |
input | str | "arg" | Prompt is passed as the final argument |
clear_env | List[str] | ["OPENAI_API_KEY"] | Env vars stripped before the subprocess runs |
timeout_ms | int | 300000 | Subprocess timeout (5 minutes) |
Backend CLI Flags
The backend builds the codex command with these flags:
| Flag | Purpose |
|---|---|
exec | Non-interactive execution mode |
--skip-git-repo-check | Allow non-git workspaces |
-C <cwd> | Working directory |
-c instructions="..." | System prompt injection |
--image <path> | Attach image(s) |
resume <session_id> | Session resume (only when session.is_resume) |
Configuration Options
| Option | Type | Default | Description |
|---|---|---|---|
workspace | str | “.” | Working directory for CLI execution |
timeout | int | 300 | Timeout in seconds |
full_auto | bool | False | Allow file modifications |
sandbox | str | “default” | Sandbox mode: “default”, “danger-full-access” |
json_output | bool | False | Enable JSON Lines streaming output |
output_schema | str | None | Path to JSON schema for structured output |
output_file | str | None | Path to save output |
Examples
Basic Execution
from praisonai.integrations import CodexCLIIntegration
codex = CodexCLIIntegration(workspace="/project")
result = await codex.execute("Explain the main.py file")
print(result)Full Auto Mode
Enable file modifications:
codex = CodexCLIIntegration(
workspace="/project",
full_auto=True # Allow file edits
)
result = await codex.execute("Refactor the utils module")Sandbox Modes
# Default sandbox (restricted)
codex = CodexCLIIntegration(
workspace="/project",
sandbox="default"
)
# Full access (for network operations)
codex = CodexCLIIntegration(
workspace="/project",
sandbox="danger-full-access"
)JSON Streaming Output
codex = CodexCLIIntegration(
workspace="/project",
json_output=True
)
result = await codex.execute("Analyze the codebase")
# Result is parsed from JSON LinesStructured Output with Schema
# Create a schema file
schema = {
"type": "object",
"properties": {
"summary": {"type": "string"},
"issues": {
"type": "array",
"items": {"type": "string"}
},
"recommendations": {
"type": "array",
"items": {"type": "string"}
}
}
}
# Save schema
import json
with open("schema.json", "w") as f:
json.dump(schema, f)
# Use with Codex
codex = CodexCLIIntegration(
workspace="/project",
output_schema="schema.json"
)
result = await codex.execute_with_schema(
"Analyze code quality",
schema_path="schema.json"
)
print(result)
# {'summary': '...', 'issues': [...], 'recommendations': [...]}Streaming Output
codex = CodexCLIIntegration(
workspace="/project",
json_output=True
)
async for event in codex.stream("Add comprehensive tests"):
event_type = event.get("type")
if event_type == "thread.started":
print("Task started")
elif event_type == "item.completed":
item = event.get("item", {})
if item.get("type") == "agent_message":
print(f"Agent: {item.get('text')}")
elif event_type == "turn.completed":
print("Task completed")As Agent Tool
from praisonai import Agent
from praisonai.integrations import CodexCLIIntegration
codex = CodexCLIIntegration(
workspace="/project",
full_auto=True
)
# Create tool
tool = codex.as_tool()
# Use with agent
agent = Agent(
name="Code Fixer",
role="Bug Fixer",
goal="Find and fix bugs in code",
tools=[tool]
)
result = agent.start("Fix all bugs in the authentication module")As a native async agent tool
Preferred when the agent runs on agent.astart(...) (or any async entrypoint) — the tool is awaited directly on the running loop with no thread hop.
from praisonaiagents import Agent
from praisonai.integrations import CodexCLIIntegration
codex = CodexCLIIntegration(workspace="/project", full_auto=True)
agent = Agent(
name="Code Fixer",
role="Bug Fixer",
goal="Find and fix bugs in code",
tools=[codex.as_async_tool()], # registers as `codex_atool`
)
await agent.astart("Fix all bugs in the authentication module")as_async_tool() was added in PraisonAI PR #4022; as_tool() still works and is now also safe to call from inside an async agent runtime.
Environment Variables
# API Key (for exec mode)
export CODEX_API_KEY=your-key
# or use ChatGPT authenticationCLI Flags Used
The integration uses the following Codex CLI flags:
| Flag | Description |
|---|---|
exec | Non-interactive execution mode |
--full-auto | Allow file modifications |
--sandbox | Sandbox mode selection |
--json | JSON Lines streaming output |
--output-schema | Structured output schema |
-o | Output file path |
JSON Lines Output Format
When json_output=True, the output is a stream of JSON events:
{"type":"thread.started","thread_id":"abc123"}
{"type":"item.completed","item":{"type":"agent_message","text":"Analyzing..."}}
{"type":"item.completed","item":{"type":"tool_use","name":"read_file"}}
{"type":"turn.completed"}Error Handling
from praisonai.integrations import CodexCLIIntegration
codex = CodexCLIIntegration(timeout=120)
try:
result = await codex.execute("Complex refactoring")
except TimeoutError:
print("Task timed out")
except Exception as e:
print(f"Error: {e}")Robustness (PR #4111)
- A subprocess
TimeoutErroris now returned asCliBackendResult(error=...)instead of escaping as an exception. - On
CalledProcessError, the CLI’s actual stderr diagnostic is surfaced (previously only the exit status was shown). - The system-prompt argument is JSON-escaped for TOML basic-string compatibility — prompts containing quotes/newlines no longer break.
- The resume shape is now
codex exec resume <id> --skip-git-repo-check ...(previouslyresumewas misplaced after--skip-git-repo-check, which failed). -m(model) and-C(cwd) are threaded through, so scheduled runs can pin a model and run in a workspace.CliSessionBinding.is_resumeis now set on the second turn of a session, so the resume branch runs instead of re-sending the system prompt every turn.
Best Practices
- Use full_auto=True only when file modifications are needed
- Use structured output for CI/CD pipelines
- Set appropriate sandbox mode based on security requirements
- Use JSON output for programmatic processing
- Set timeouts appropriate for task complexity