Skip to content

agent/codex

View on pkg.go.dev

import "github.com/thesimonho/warden/agent/codex"

Package codex implements the agent.StatusProvider and agent.SessionParser interfaces for OpenAI Codex CLI. It parses session JSONL files written by Codex at ~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl.

Unlike Claude Code, Codex has no separate config file with cost data. All cost information comes from token-based estimation via the JSONL parser.

func EstimateCost(model string, tokens agent.TokenUsage) float64

EstimateCost computes an estimated cost in USD from cumulative token usage. Codex has no actual-cost source, so this is always the primary cost. Returns 0 for unknown models.

ActionPayload is the nested action payload for local_shell_call and web_search_call items. Both use the “action” JSON key with different fields.

type ActionPayload struct {
Command []string `json:"command,omitempty"` // local_shell_call
Query string `json:"query,omitempty"` // web_search_call
}

CompactedItem is the payload for top-level “compacted” entries.

type CompactedItem struct {
Message string `json:"message,omitempty"`
}

Credits holds subscription credit information.

type Credits struct {
HasCredits bool `json:"has_credits"`
Unlimited bool `json:"unlimited"`
Balance float64 `json:"balance"`
}

EventMsg is the payload for “event_msg” entries. The Type field distinguishes token counts, user messages, task lifecycle, etc.

type EventMsg struct {
Type string `json:"type"`
TurnID string `json:"turn_id,omitempty"`
Message string `json:"message,omitempty"`
Reason string `json:"reason,omitempty"`
// Token count fields (type == "token_count").
Info *TokenCountInfo `json:"info,omitempty"`
RateLimits *RateLimits `json:"rate_limits,omitempty"`
// Command approval fields (app-server only — never persisted in limited mode).
ServerName string `json:"server_name,omitempty"`
// Exec command fields (type == "exec_command_end").
// Available in extended mode for agent commands; also persisted in limited
// mode for user shell commands (source == "user_shell").
CallID string `json:"call_id,omitempty"`
ExitCode *int `json:"exit_code,omitempty"`
Status string `json:"status,omitempty"`
Source string `json:"source,omitempty"`
Command []string `json:"command,omitempty"`
Stdout string `json:"stdout,omitempty"`
Stderr string `json:"stderr,omitempty"`
AggregatedOutput string `json:"aggregated_output,omitempty"`
// MCP tool call fields (type == "mcp_tool_call_end", extended mode only).
ToolName string `json:"tool_name,omitempty"`
McpServerName string `json:"mcp_server_name,omitempty"`
// Patch apply fields (type == "patch_apply_end", extended mode only).
FilePath string `json:"file_path,omitempty"`
// ThreadRolledBack fields (type == "thread_rolled_back").
NumTurns int `json:"num_turns,omitempty"`
}

GitInfo holds git repository data from session metadata.

type GitInfo struct {
CommitHash string `json:"commit_hash"`
Branch string `json:"branch"`
RepositoryURL string `json:"repository_url"`
}

Parser implements agent.SessionParser for Codex CLI session JSONL files. Token counts in Codex are cumulative (total_token_usage), so the parser forwards them directly without accumulating.

Codex’s rollout persistence policy filters which events land in JSONL. In limited mode (CLI default), begin events (exec_command_begin, mcp_tool_call_begin, patch_apply_begin), approval/permission requests, elicitation requests, and stream errors are never persisted. Tool use is captured via response_item entries (always persisted). Error details from end events (exec_command_end, etc.) require extended persistence mode, only available via `codex app-server` (ThreadStartParams.persist_extended_history). See docs/developer/events_codex.md for the full persistence policy.

type Parser struct {
// contains filtered or unexported fields
}

func NewParser() *Parser

NewParser creates a new Codex JSONL parser.

func (p *Parser) FindSessionFiles(homeDir string, project agent.ProjectInfo) []string

FindSessionFiles discovers active Codex session files for a project by reading shell_snapshots. Codex creates a shell snapshot file per active session at ~/.codex/shell_snapshots/<session_id>.<timestamp>.sh. Each snapshot contains exported env vars including WARDEN_PROJECT_ID, which we use to filter to the correct project. The session ID from the filename is then used to glob for the matching JSONL file across date directories.

func (p *Parser) ParseLine(line []byte) []agent.ParsedEvent

ParseLine parses a single JSONL line into zero or more ParsedEvents.

func (p *Parser) SessionDir(homeDir string, _ agent.ProjectInfo) string

SessionDir returns the host-side directory containing Codex session JSONL files. Codex stores all sessions under ~/.codex/sessions/ in date-based subdirectories. Unlike Claude (one directory per project), Codex uses a flat date hierarchy.

Provider implements agent.StatusProvider for Codex CLI. Codex has no config file equivalent to .claude.json, so ExtractStatus returns an empty map. Cost comes from JSONL parsing via EstimateCost.

type Provider struct{}

func NewProvider() *Provider

NewProvider creates a new Codex status provider.

func (p *Provider) ConfigFilePath() string

ConfigFilePath returns an empty path — Codex has no global config file equivalent to Claude’s .claude.json.

func (p *Provider) ExtractStatus(_ []byte) map[string]*agent.Status

ExtractStatus returns an empty map — Codex doesn’t write per-project status to a config file. Cost data comes from JSONL token events.

func (p *Provider) Name() string

Name returns the agent identifier.

func (p *Provider) NewSessionParser() agent.SessionParser

NewSessionParser creates a stateful JSONL parser for Codex sessions.

func (p *Provider) ProcessName() string

ProcessName returns the CLI binary name for pgrep detection.

RateLimits holds rate limit and subscription information.

type RateLimits struct {
LimitID string `json:"limit_id"`
Credits *Credits `json:"credits,omitempty"`
PlanType string `json:"plan_type"`
}

ResponseItem is the payload for “response_item” entries. The Type field distinguishes function calls, messages, and reasoning.

type ResponseItem struct {
Type string `json:"type"`
Role string `json:"role,omitempty"`
Name string `json:"name,omitempty"`
CallID string `json:"call_id,omitempty"`
Arguments string `json:"arguments,omitempty"`
Output string `json:"output,omitempty"`
Status string `json:"status,omitempty"`
Content json.RawMessage `json:"content,omitempty"`
// Action holds nested data for local_shell_call and web_search_call items.
Action *ActionPayload `json:"action,omitempty"`
// CustomToolCall fields (type == "custom_tool_call").
Input string `json:"input,omitempty"`
}

RolloutItem is the top-level structure of every JSONL line. The Type field determines which payload structure is used.

type RolloutItem struct {
Timestamp string `json:"timestamp"`
Type string `json:"type"`
Payload json.RawMessage `json:"payload"`
}

SessionMeta is the payload for “session_meta” entries. Contains session identity, working directory, and git info.

type SessionMeta struct {
ID string `json:"id"`
Timestamp string `json:"timestamp"`
CWD string `json:"cwd"`
CLIVersion string `json:"cli_version"`
ModelProvider string `json:"model_provider"`
Git *GitInfo `json:"git,omitempty"`
}

TokenCountInfo holds cumulative and per-turn token usage.

type TokenCountInfo struct {
TotalTokenUsage TokenUsageDetail `json:"total_token_usage"`
LastTokenUsage TokenUsageDetail `json:"last_token_usage"`
}

TokenUsageDetail holds token consumption counters for Codex.

type TokenUsageDetail struct {
InputTokens int64 `json:"input_tokens"`
CachedInputTokens int64 `json:"cached_input_tokens"`
OutputTokens int64 `json:"output_tokens"`
ReasoningOutputTokens int64 `json:"reasoning_output_tokens"`
TotalTokens int64 `json:"total_tokens"`
}

TurnContext is the payload for “turn_context” entries. Contains model, approval policy, and sandbox configuration per turn.

type TurnContext struct {
TurnID string `json:"turn_id"`
CWD string `json:"cwd"`
Model string `json:"model"`
ApprovalPolicy string `json:"approval_policy"`
}

Generated by gomarkdoc