Documentation
¶
Overview ¶
Package codex implements the agent.Agent interface by shelling out to OpenAI's Codex CLI (`codex` / `@openai/codex`). It reuses the shared prompt templates and helpers from internal/agent/prompt so its planning and review prompts are identical to the claude and opencode providers.
Key differences from the other providers:
- The headless mode is the `codex exec` subcommand (the interactive TUI used by Discuss is `codex` with no subcommand).
- Structured output for Plan and Review is native: an embedded JSON Schema is materialized to a temp file and passed via --output-schema, and the final agent message is written to a file via --output-last-message.
- Auth: Codex reads CODEX_API_KEY (highest precedence). OPENAI_API_KEY is NOT in Codex's main auth path, so childEnv() maps it into CODEX_API_KEY for the child process when CODEX_API_KEY is unset AND no subscription auth.json is present. When auth.json exists the mapping is skipped so the API key does not clobber the subscription.
Index ¶
- type CodexAgent
- func (c *CodexAgent) Discuss(ctx context.Context, opts agent.DiscussOptions) error
- func (c *CodexAgent) Execute(ctx context.Context, task agent.TaskSpec, opts agent.ExecOptions) (*agent.ExecResult, error)
- func (c *CodexAgent) Plan(ctx context.Context, initialPrompt string, opts agent.PlanOptions) (*agent.Plan, error)
- func (c *CodexAgent) Review(ctx context.Context, diff string, opts agent.ReviewOptions) (*agent.ReviewResult, error)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type CodexAgent ¶
type CodexAgent struct {
BinaryPath string // path to `codex` CLI (default: "codex")
Model string // bare model ID, e.g. "gpt-5-codex" (optional)
ReasoningEffort string // "minimal"|"low"|"medium"|"high" (default: "medium")
// Sandbox is the `--sandbox` policy passed to every `codex exec`
// invocation. Empty falls back to "workspace-write" (Codex's default,
// preserved for backward compatibility on hosts where bubblewrap works).
// Set to "danger-full-access" for workers running inside Docker
// containers — Codex's bubblewrap-based sandboxes need an
// unprivileged user namespace which most container hosts (notably
// TrueNAS SCALE Apps) do not grant. The container is already the
// security boundary in that case, so disabling Codex's inner sandbox
// is safe. See internal/config/config.go Agent.CodexSandbox for the
// user-facing config knob.
Sandbox string
}
CodexAgent implements agent.Agent using the Codex CLI.
func NewAgent ¶
func NewAgent(binaryPath, model, reasoningEffort, sandbox string) *CodexAgent
NewAgent creates a new CodexAgent with the given binary path, model, reasoning effort, and sandbox policy. If binaryPath is empty, defaults to "codex". If reasoningEffort is empty, defaults to "medium". If sandbox is empty, defaults to "workspace-write" (Codex's own default).
func (*CodexAgent) Discuss ¶
func (c *CodexAgent) Discuss(ctx context.Context, opts agent.DiscussOptions) error
Discuss launches the Codex interactive TUI (`codex` with no subcommand) with stdio wired through to the user. Codex's TUI has no system-prompt or initial-prompt flag in scope, so there is no clean way to seed the rendered system/initial prompt; this implementation passes stdio through directly and does no output parsing. The system prompt is still required at the API level for parity with the other providers.
func (*CodexAgent) Execute ¶
func (c *CodexAgent) Execute(ctx context.Context, task agent.TaskSpec, opts agent.ExecOptions) (*agent.ExecResult, error)
Execute runs Codex in headless mode (`codex exec`) to complete a task. The task body (or opts.SystemPrompt, if set) is passed as the positional prompt. The final agent message is captured via --output-last-message and returned in ExecResult.Summary; the agent commits as it works in the repo.
If the final message looks suspicious (empty, "Execution error", or very short), Execute retries once after prompt.RetryDelay before returning an error.
Note: Codex has no --max-turns flag; opts.MaxTurns is ignored for this provider (mirroring opencode).
func (*CodexAgent) Plan ¶
func (c *CodexAgent) Plan(ctx context.Context, initialPrompt string, opts agent.PlanOptions) (*agent.Plan, error)
Plan runs Codex to produce a structured plan. It operates in two modes, branching on whether initialPrompt is empty:
Non-empty initialPrompt (headless): like before, the Codex `codex exec` mode is used with native structured output. An embedded JSON Schema is passed via --output-schema and the final JSON message is written via --output-last-message, then parsed with prompt.ReadPlanFile. The rendered planning system prompt and the initialPrompt are folded together into the positional prompt (Codex exec has no --system-prompt flag).
Empty initialPrompt (interactive): mirroring the claude and opencode providers, the user is dropped into a conversational Codex session (the default `codex` invocation, no `exec` subcommand) to refine the brief. Codex's interactive TUI has no --system-prompt or --output-schema flag, so the structured plan is collected out-of-band: the seed prompt instructs the agent to write the final plan JSON to the path in the HERD_PLAN_OUT env var (conforming to the schema at HERD_PLAN_SCHEMA). After the session exits the plan is read back with prompt.ReadPlanFile.
Both modes return the same *agent.Plan struct; only how the plan is collected differs.
func (*CodexAgent) Review ¶
func (c *CodexAgent) Review(ctx context.Context, diff string, opts agent.ReviewOptions) (*agent.ReviewResult, error)
Review runs Codex in headless mode (`codex exec`) to review a diff using native structured output. Because Codex exec has no --system-prompt flag, the review system prompt is folded into the positional message (like opencode). An embedded JSON Schema is passed via --output-schema and the final JSON message is written via --output-last-message.
Returns a structured review result parsed from the agent's JSON output; unparseable output yields ReviewResult{Approved:false, IsUnparseable:true} with a Summary beginning "Failed to parse".