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

bash
# Install Codex CLI
npm install -g @openai/codex

# Verify installation
codex --version

Quick Start

python
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.

python
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:

OptionTypeDefaultDescription
commandstr"codex"CLI command (must be on PATH)
argsList[str]["exec", "--skip-git-repo-check"]Default flags passed on every turn
outputstr"text"Output format expected from the CLI
inputstr"arg"Prompt is passed as the final argument
clear_envList[str]["OPENAI_API_KEY"]Env vars stripped before the subprocess runs
timeout_msint300000Subprocess timeout (5 minutes)

Backend CLI Flags

The backend builds the codex command with these flags:

FlagPurpose
execNon-interactive execution mode
--skip-git-repo-checkAllow 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

OptionTypeDefaultDescription
workspacestr“.”Working directory for CLI execution
timeoutint300Timeout in seconds
full_autoboolFalseAllow file modifications
sandboxstr“default”Sandbox mode: “default”, “danger-full-access”
json_outputboolFalseEnable JSON Lines streaming output
output_schemastrNonePath to JSON schema for structured output
output_filestrNonePath to save output

Examples

Basic Execution

python
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:

python
codex = CodexCLIIntegration(
    workspace="/project",
    full_auto=True  # Allow file edits
)

result = await codex.execute("Refactor the utils module")

Sandbox Modes

python
# 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

python
codex = CodexCLIIntegration(
    workspace="/project",
    json_output=True
)

result = await codex.execute("Analyze the codebase")
# Result is parsed from JSON Lines

Structured Output with Schema

python
# 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

python
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

python
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.

python
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

bash
# API Key (for exec mode)
export CODEX_API_KEY=your-key
# or use ChatGPT authentication

CLI Flags Used

The integration uses the following Codex CLI flags:

FlagDescription
execNon-interactive execution mode
--full-autoAllow file modifications
--sandboxSandbox mode selection
--jsonJSON Lines streaming output
--output-schemaStructured output schema
-oOutput file path

JSON Lines Output Format

When json_output=True, the output is a stream of JSON events:

json
{"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

python
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 TimeoutError is now returned as CliBackendResult(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 ... (previously resume was 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_resume is 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

  1. Use full_auto=True only when file modifications are needed
  2. Use structured output for CI/CD pipelines
  3. Set appropriate sandbox mode based on security requirements
  4. Use JSON output for programmatic processing
  5. Set timeouts appropriate for task complexity