Skip to content

Codex support: implementation contract ​

This document records the implementation added to PR #450 for the operator's A1–A7 and B1–B4 findings on issue #449. It supersedes the brainstorm's proposed per-session CODEX_HOME and resume-by-recency approach. Codex keeps the operator's normal home, authentication, settings and sandbox policy.

FindingResult
A1: resume identityPut a unique conversation marker in the initial user prompt. Match the rollout's marker and exact working directory, then bind the native UUID in the registry. Resume only that UUID; missing, ambiguous or mismatched rollouts refuse resume.
A2: stop gateInstall a native Stop command that returns Codex's JSON continuation protocol, including the existing bounded retry cap. Preserve unrelated hooks and explicit operator choices.
A3: instructionsPreserve existing AGENTS.md or AGENTS.override.md and maintain an identified block pointing to the bundled skill, command procedures and graph verbs. Native plugins also expose the shared skill.
A4: harness traceLocate the identified native rollout and normalize text, tool calls, tool results, reasoning summaries and compaction for the existing transcript API and UI. Retain original event payloads.
A5: MCP delegationUse the selected adapter's actual binary and one-shot arguments, never its interactive launch arguments (codex exec rejects TUI-only flags such as -a). Unknown harnesses block instead of running Claude. Extract Codex's final JSON agent message.
A6: critic output and accountingRun codex exec --json; extract the final completed agent message and latest usage record. Account for cached input without counting it twice. Do not invent dollar costs.
A7: distributionAdd the Codex installer component, native plugin manifest and hook definitions. Bundle shared instructions, command procedures and hooks in both wheels and source distributions.
B1: required labelsKeep the ALL-of semantics established by decision-381. Emit poll.item_filtered with the missing labels and repository-qualified work item when this gate excludes an item.
B2: retired argumentsMigrate routing.harnessArgs into harnesses[].args of already-declared harnesses, including current-version configs. Never declare a harness (that would offer it). Preserve explicit modern arguments, report conflicts, drop a malformed block and leave a repeat migration unchanged.
B3: default fallbackLog and emit session.default_harness_bypassed when a declared default cannot host the session. Include the declared and effective harness and reason.
B4: stale connectionRetry a disconnected GraphQL read once. Never replay mutations or semantic API failures.

Architecture ​

Codex 0.160.0's interactive CLI does not accept a preassigned conversation ID. Rollout discovery validates UUIDs, explicit absolute working-directory metadata and filesystem containment. A launch marker may resolve only one conversation. The loop does not copy authentication into a separate home or select the most recent conversation. A live endpoint binds its native ID on subsequent delivery; transcript reads and respawns can also resolve the marker before that binding.

The daemon installs its Stop hook in the operator's Codex home so the definition is shared across worktrees. Project installation uses .codex/hooks.json; user installation respects CODEX_HOME. Codex requires the operator to review and trust a new non-managed hook definition through /hooks. The loop reports that step and does not bypass Codex's hook trust policy. Disabling routing.harnessPlugins.enabled disables automatic instruction and hook setup; workspace trust preparation has its own independent switch.

The current native plugin surface is documented by OpenAI's plugin documentation. Stop continuation and hook trust follow OpenAI's hook documentation. Custom prompt copies are optional in the issue comment; shared procedures are available through the installed skill and managed instruction block instead.

PR review follow-up ​

The PR #450 review found ten issues; the tracked-instructions follow-up is now resolved using Codex's native global instruction source:

  • The managed AGENTS.md block is kept out of git in work-item checkouts via info/exclude (shared helper the_loop.gitexclude, also used for the spec tree). When the effective project instructions file is tracked, its bytes are preserved and the managed block is installed in $CODEX_HOME/AGENTS.md (or its existing AGENTS.override.md). Codex loads global instructions before project instructions; a read-only probe with codex-cli 0.160.0 confirmed both sources. Explicit project-scope installation still writes into the requested project.
  • mcp-call no longer appends interactive launch args to codex exec.
  • A linked worktree's main root goes through is_too_broad() before it is trusted.
  • One codex_home() (stripped, ~ expanded) serves trust, hooks, rollouts and install.
  • The Stop gate is matched by script and argument, so a stale path is replaced.
  • Rollout lookups cache identified rollouts and per-file metadata.
  • Bypassed-default and filtered-item diagnostics are reported once, not per event.
  • requirements.md, testing-plan.md and tasks.md were recorded (in review).

Testing strategy ​

The fresh smoke run exposed a start-control bug: the dispatcher correctly deferred spawning at phase selection, but the CLI interpreted the absent session as a failure and cleared the start request. Deferred deliveries now carry a settled parked-at-human-start-gate outcome in the existing bounded deduper. The CLI reads that outcome after draining dispatch and returns waiting with success, preserving the request. Actual spawn failures still clear it. This adds no second outcome cache or alternative spawn path.

Regression tests cover exact conversation recovery after an unrelated chat, ambiguous markers, mismatched directories, unsafe IDs, escaping symlinks, native trace normalization, JSONL critic output and usage, native Stop results, MCP adapter selection, installer behavior, argument migration, default fallback, label diagnostics and read-only connection retries.

The bundled instructions include both the operating skill and its required sibling writing skill, including each skill's references.

Build verification must include a wheel built from the checkout and a wheel rebuilt from an extracted source distribution, with the shared resources present in each. Static checks include Ruff, Pyright, configuration validation, version lockstep and Markdown lint. Local execution evidence and environmental limits are recorded in evidence/codex-verification.md.

Security design ​

Rollout lookup validates native UUIDs, requires explicit absolute directory metadata and matching launch identity, and checks containment in the Codex session store before reading. Missing or ambiguous identity refuses resume. R2's negative tests cover malformed metadata, unrelated conversations and symlink escapes.

Instruction preparation preserves operator text, refuses malformed blocks and escaping symlinks, and checks file changes before replacing content. Spawn setup leaves tracked project instructions unchanged and prepares the native global source instead. Trust preparation refuses / and the home directory, including linked-worktree roots. Hook setup preserves unrelated definitions and reports the native trust step; it does not bypass sandbox or approval policy. R3's preservation, containment, concurrency and broad-root tests enforce these boundaries.

The dispatcher still validates authorized GitHub actors and human gate answers. The new start settlement only preserves a request already accepted by the CLI; it does not answer the gate. Its success and real-failure integration scenarios prove both lifecycle paths. Unknown harnesses block, one-shot arguments use argv lists and only disconnected read requests are retried. No new dependencies or credential storage are introduced by the completion fixes.

Released under the MIT License.