# Codex CLI Schema

**Source**: [openai/codex](https://github.com/openai/codex)

**Official Schema Location**:
- [`codex-rs/protocol/src/protocol.rs`](https://github.com/openai/codex/blob/main/codex-rs/protocol/src/protocol.rs) - Core protocol types (RolloutLine, RolloutItem, EventMsg, etc.)
- [`codex-rs/protocol/src/models.rs`](https://github.com/openai/codex/blob/main/codex-rs/protocol/src/models.rs) - Response item types (ResponseItem, ContentItem, etc.)

**File Location**: `~/.codex/sessions/YYYY/MM/DD/rollout-{timestamp}-{uuid}.jsonl`

**Format**: JSONL (one JSON object per line)

## Official Schema (from source)

### RolloutLine (wrapper)
```rust
pub struct RolloutLine {
    pub timestamp: String,
    #[serde(flatten)]
    pub item: RolloutItem,
}
```

### RolloutItem (discriminated union)
```rust
#[serde(tag = "type", content = "payload", rename_all = "snake_case")]
pub enum RolloutItem {
    SessionMeta(SessionMetaLine),
    ResponseItem(ResponseItem),
    Compacted(CompactedItem),
    TurnContext(TurnContextItem),
    EventMsg(EventMsg),
}
```

## Session Metadata

**Source**: `protocol.rs:1644-1686`

```rust
pub struct SessionMeta {
    pub id: ThreadId,                           // UUID
    pub forked_from_id: Option<ThreadId>,       // For forked sessions
    pub timestamp: String,
    pub cwd: PathBuf,
    pub originator: String,                     // e.g., "codex_cli_rs"
    pub cli_version: String,                    // e.g., "0.95.0"
    pub source: SessionSource,                  // e.g., "cli", "exec"
    pub model_provider: Option<String>,         // e.g., "openai"
    pub base_instructions: Option<BaseInstructions>,
    pub dynamic_tools: Option<Vec<DynamicToolSpec>>,
}

pub struct SessionMetaLine {
    #[serde(flatten)]
    pub meta: SessionMeta,
    pub git: Option<GitInfo>,
}

pub struct GitInfo {
    pub commit_hash: Option<String>,
    pub branch: Option<String>,
    pub repository_url: Option<String>,
}
```

## Turn Context

**Source**: `protocol.rs:1719-1740`

```rust
pub struct TurnContextItem {
    pub cwd: PathBuf,
    pub approval_policy: AskForApproval,        // "untrusted", "on-failure", "on-request", "never"
    pub sandbox_policy: SandboxPolicy,
    pub model: String,
    pub personality: Option<Personality>,
    pub collaboration_mode: Option<CollaborationMode>,
    pub effort: Option<ReasoningEffortConfig>,
    pub summary: ReasoningSummaryConfig,
    pub user_instructions: Option<String>,
    pub developer_instructions: Option<String>,
    pub final_output_json_schema: Option<Value>,
    pub truncation_policy: Option<TruncationPolicy>,
}

#[serde(tag = "type", rename_all = "kebab-case")]
pub enum SandboxPolicy {
    DangerFullAccess,
    ReadOnly,
    ExternalSandbox { network_access: NetworkAccess },
    WorkspaceWrite {
        writable_roots: Vec<AbsolutePathBuf>,
        network_access: bool,
        exclude_tmpdir_env_var: bool,
        exclude_slash_tmp: bool,
    },
}
```

## Event Messages

**Source**: `protocol.rs:700-882`

```rust
#[serde(tag = "type", rename_all = "snake_case")]
pub enum EventMsg {
    Error(ErrorEvent),
    Warning(WarningEvent),
    ContextCompacted(ContextCompactedEvent),
    ThreadRolledBack(ThreadRolledBackEvent),
    TurnStarted(TurnStartedEvent),
    TurnComplete(TurnCompleteEvent),
    TokenCount(TokenCountEvent),
    AgentMessage(AgentMessageEvent),
    UserMessage(UserMessageEvent),
    AgentMessageDelta(AgentMessageDeltaEvent),
    AgentReasoning(AgentReasoningEvent),
    AgentReasoningDelta(AgentReasoningDeltaEvent),
    AgentReasoningRawContent(AgentReasoningRawContentEvent),
    SessionConfigured(SessionConfiguredEvent),
    ThreadNameUpdated(ThreadNameUpdatedEvent),
    McpStartupUpdate(McpStartupUpdateEvent),
    McpStartupComplete(McpStartupCompleteEvent),
    McpToolCallBegin(McpToolCallBeginEvent),
    McpToolCallEnd(McpToolCallEndEvent),
    WebSearchBegin(WebSearchBeginEvent),
    WebSearchEnd(WebSearchEndEvent),
    ExecCommandBegin(ExecCommandBeginEvent),
    ExecCommandOutputDelta(ExecCommandOutputDeltaEvent),
    ExecCommandEnd(ExecCommandEndEvent),
    ExecApprovalRequest(ExecApprovalRequestEvent),
    RequestUserInput(RequestUserInputEvent),
    PatchApplyBegin(PatchApplyBeginEvent),
    PatchApplyEnd(PatchApplyEndEvent),
    TurnDiff(TurnDiffEvent),
    TurnAborted(TurnAbortedEvent),
    ShutdownComplete,
    // ... many more event types
}
```

### Key Event Types

```rust
pub struct UserMessageEvent {
    pub message: String,
    pub images: Option<Vec<ImageContent>>,
    pub local_images: Vec<ImagePath>,
    pub text_elements: Vec<TextElement>,
}

pub struct AgentMessageEvent {
    pub message: String,
}

pub struct TokenCountEvent {
    pub info: Option<TokenInfo>,
    pub rate_limits: Option<RateLimits>,
}

pub struct TokenInfo {
    pub total_token_usage: TokenUsage,
    pub last_token_usage: TokenUsage,
    pub model_context_window: usize,
}

pub struct TokenUsage {
    pub input_tokens: u64,
    pub cached_input_tokens: u64,
    pub output_tokens: u64,
    pub reasoning_output_tokens: u64,
    pub total_tokens: u64,
}
```

## Response Items

**Source**: `models.rs:82-186`

```rust
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ResponseItem {
    Message {
        id: Option<String>,
        role: String,                           // "developer", "user", "assistant"
        content: Vec<ContentItem>,
        end_turn: Option<bool>,
        phase: Option<MessagePhase>,
    },
    Reasoning {
        id: String,
        summary: Vec<ReasoningSummary>,
        content: Option<Vec<ReasoningContent>>,
        encrypted_content: Option<String>,
    },
    LocalShellCall {
        id: Option<String>,
        call_id: Option<String>,
        status: LocalShellStatus,
        action: LocalShellAction,
    },
    FunctionCall {
        id: Option<String>,
        name: String,
        arguments: String,                      // JSON string
        call_id: String,
    },
    FunctionCallOutput {
        call_id: String,
        output: FunctionCallOutputPayload,
    },
    CustomToolCall { ... },
    CustomToolCallOutput { ... },
    WebSearchCall { ... },
    GhostSnapshot { ghost_commit: GhostCommit },
    Compaction { encrypted_content: String },
}

#[serde(tag = "type", rename_all = "snake_case")]
pub enum ContentItem {
    InputText { text: String },
    InputImage { image_url: String },
    OutputText { text: String },
}
```

## Example Session

```jsonl
{"timestamp": "2026-02-04T11:14:26.090Z", "type": "session_meta", "payload": {"id": "019c285c-569c-7f12-b514-a9ceff5f3f8d", "cli_version": "0.95.0", "cwd": "/project", "originator": "codex_cli_rs", "source": "cli", "model_provider": "openai"}}
{"timestamp": "2026-02-04T11:14:26.091Z", "type": "response_item", "payload": {"type": "message", "role": "developer", "content": [{"type": "input_text", "text": "System prompt..."}]}}
{"timestamp": "2026-02-04T11:14:37.486Z", "type": "event_msg", "payload": {"type": "user_message", "message": "Build a blog app"}}
{"timestamp": "2026-02-04T11:15:24.936Z", "type": "turn_context", "payload": {"model": "gpt-5", "cwd": "/project", "approval_policy": "on-request", "sandbox_policy": {"type": "workspace-write"}}}
{"timestamp": "2026-02-04T11:15:26.900Z", "type": "event_msg", "payload": {"type": "token_count", "info": {"last_token_usage": {"input_tokens": 11214, "output_tokens": 118}}}}
{"timestamp": "2026-02-04T11:15:31.573Z", "type": "response_item", "payload": {"type": "function_call", "name": "shell", "arguments": "{\"command\":[\"bash\",\"-lc\",\"mkdir src\"]}", "call_id": "call_abc123"}}
{"timestamp": "2026-02-04T11:15:31.643Z", "type": "response_item", "payload": {"type": "function_call_output", "call_id": "call_abc123", "output": {"output": "Exit code: 0", "success": true}}}
{"timestamp": "2026-02-04T11:20:35.577Z", "type": "event_msg", "payload": {"type": "agent_message", "message": "I've created the src directory."}}
```

## Schema Comparison: Official vs QC Trace Implementation

### Coverage Status: COMPREHENSIVE

Our v1.py schema (`qc_trace/schemas/codex_cli/v1.py`) now includes **all types** from the official Codex CLI schema:

#### RolloutItem Types (All Covered)
| Official Type | Our Implementation |
|---------------|-------------------|
| `session_meta` | `CodexSessionMeta`, `CodexSessionMetaPayload` |
| `turn_context` | `CodexTurnContext`, `CodexTurnContextPayload` |
| `response_item` | `CodexResponseItem`, `CodexResponsePayload` |
| `compacted` | `CodexCompactedItem`, `CodexCompactedItemPayload` |
| `event_msg` | `CodexEventMsg`, `CodexEventPayload` |

#### All 50+ EventMsg Variants (All Covered)
- Error/Warning: `CodexErrorEventPayload`, `CodexWarningEventPayload`
- Turn lifecycle: `CodexTurnStartedEventPayload`, `CodexTurnCompleteEventPayload`, `CodexTurnAbortedEventPayload`
- Messages: `CodexUserMessageEventPayload`, `CodexAgentMessageEventPayload`, `CodexAgentMessageDeltaEventPayload`
- Reasoning: `CodexAgentReasoningEventPayload`, `CodexAgentReasoningDeltaEventPayload`, `CodexAgentReasoningRawContentEventPayload`
- MCP: `CodexMcpToolCallBeginEventPayload`, `CodexMcpToolCallEndEventPayload`, `CodexMcpStartupUpdateEventPayload`
- Exec: `CodexExecCommandBeginEventPayload`, `CodexExecCommandOutputDeltaEventPayload`, `CodexExecCommandEndEventPayload`
- Patch: `CodexPatchApplyBeginEventPayload`, `CodexPatchApplyEndEventPayload`
- Approval: `CodexExecApprovalRequestEventPayload`, `CodexApplyPatchApprovalRequestEventPayload`
- Web: `CodexWebSearchBeginEventPayload`, `CodexWebSearchEndEventPayload`
- Collab: `CodexCollabAgentSpawnBeginEventPayload`, `CodexCollabAgentInteractionBeginEventPayload`, etc.
- And many more...

#### All ResponseItem Variants (All Covered)
| Official Type | Our Implementation |
|---------------|-------------------|
| `message` | `CodexMessagePayload` |
| `reasoning` | `CodexReasoningPayload` |
| `function_call` | `CodexFunctionCallPayload` |
| `function_call_output` | `CodexFunctionCallOutputPayload` |
| `local_shell_call` | `CodexLocalShellCallPayload` |
| `custom_tool_call` | `CodexCustomToolCallPayload` |
| `custom_tool_call_output` | `CodexCustomToolCallOutputPayload` |
| `web_search_call` | `CodexWebSearchCallPayload` |
| `ghost_snapshot` | `CodexGhostSnapshotPayload` |
| `compaction` | `CodexCompactionPayload` |

#### Supporting Types (All Covered)
- Token: `CodexTokenUsage`, `CodexTokenUsageInfo`, `CodexRateLimitSnapshot`, `CodexRateLimitWindow`, `CodexCreditsSnapshot`
- Content: `CodexContentItem`, `CodexInputText`, `CodexInputImage`, `CodexOutputText`
- Sandbox: `CodexSandboxPolicyWorkspaceWrite`, `CodexSandboxPolicyReadOnly`, etc.
- Config: `CodexCollaborationMode`, `CodexTruncationPolicy`, `CodexGitInfo`

## Schema Version

- **Version**: v1 (frozen 2026-02-04)
- **CLI Version**: 0.95.0+
- **Official Source Commit**: Check [codex-rs/protocol](https://github.com/openai/codex/tree/main/codex-rs/protocol)

## System Prompt Assembly

Codex CLI assembles its system prompt locally from multiple sources before sending to the OpenAI API. The prompt uses XML-style tags as section delimiters for the model to parse.

### Message Structure Sent to API

| Message Role | Contents |
|-------------|----------|
| **System** | Base prompt from [`codex-rs/core/prompt.md`](https://github.com/openai/codex/blob/main/codex-rs/core/prompt.md) (baked into binary via `include_str!`) |
| **Developer** | `AGENTS.md` content + developer instructions (`--config developer_instructions`) |
| **User** | `<environment_context>` + `<INSTRUCTIONS>` + `<permissions instructions>` + actual user prompt |

### XML Tags in Messages

These tags appear in `response_item` messages with `role: "developer"` or `role: "user"` content. They are **not a formal spec** — just delimiters the model uses to parse structured sections.

| Tag | Source | Description |
|-----|--------|-------------|
| `<INSTRUCTIONS>` | `AGENTS.md` file(s) | Repo-level instructions, similar to Claude Code's `CLAUDE.md`. Nested files take precedence. |
| `<environment_context>` | Runtime | Dynamically injected: `<cwd>`, `<shell>`, codex config settings |
| `<permissions instructions>` | Approval policy | Generated from the user's selected approval mode (`suggest`, `auto-edit`, `full-auto`) |
| `<repository_context>` | Git state | Current git diff, status, branch info |
| `<file_contents>` | File reads | Contents of files read during the session |
| `<exec_command>` / `<command>` | Shell execution | Commands executed and their context |
| `<approval_policy>` | Config | The sandbox/approval policy in effect |
| `<context>` / `<output>` | Tool results | Tool execution context and output |
| `<cwd>` | Runtime | Current working directory (nested inside `environment_context`) |
| `<shell>` | Runtime | User's shell (nested inside `environment_context`) |

### Approval Policies

The `<permissions instructions>` content varies based on the selected policy:

| Policy | CLI Flag | Behavior |
|--------|----------|----------|
| `suggest` | Default | Must approve all file edits and commands |
| `auto-edit` | `--auto-edit` | File edits auto-approved, commands need approval |
| `full-auto` | `--full-auto` | Everything auto-approved within sandbox constraints |

### AGENTS.md

- Located at repo root and/or any directory from CWD up to root
- More deeply nested files take **higher precedence**
- Direct user/developer instructions override all `AGENTS.md` content
- Can also be overridden entirely via `--config experimental_instructions_file="/path/to/prompt.md"`

### References

- [Base prompt source](https://github.com/openai/codex/blob/main/codex-rs/core/prompt.md)
- [AGENTS.md guide](https://developers.openai.com/codex/guides/agents-md/)
- [Configuration reference](https://developers.openai.com/codex/config-reference/)
- [CLI features](https://developers.openai.com/codex/cli/features/)

## Notes

- Sessions are organized by date: `~/.codex/sessions/YYYY/MM/DD/`
- Session ID is a UUID embedded in the filename
- Token count `info` can be `null` at session start before any API calls
- Reasoning content is typically encrypted (`encrypted_content` field)
- Function call arguments are JSON strings that need parsing
- Official schema uses Rust with serde for serialization
