Phase 2 — Codex Adapter
Goal
Add the second backend (codex) using the abstraction phase 1 established. The main value of this phase is not the Codex backend itself — it's that two backends prove the abstraction works. Surface every place where Codex's CLI surface doesn't fit cleanly into the phase-1 contracts.
Preconditions
Phase 1 shipped: the AgentAdapter Protocol, AgentEvent union, runner.py, tools/base.py, Tier-0 sandbox, technical-user auth all exist and are exercised by the Claude Code adapter.
Deliverables
adapters/codex.pyimplementingAgentAdapterfor the OpenAI Codex CLI.tools/codex.py— a thin subclass ofExternalAgentToolwithbackend = "codex".- Registry entry for
codex. - Config example for Codex in the plugin's docs / sample
codumentor.yaml. - Unit tests parallel to the Claude Code tests.
- If
AgentAdapterProtocol orAgentEventunion must change to accommodate Codex, the changes must be strictly backward-compatible (additive fields only; no renames; no removed kinds) and called out in the handoff.
New files
src/codumentor/plugins/external_agent/adapters/codex.py
src/codumentor/plugins/external_agent/tools/codex.py
tests/test_external_agent_adapter_codex.py
tests/fixtures/external_agent/codex_stream_*.jsonl (or .txt if non-stream)
Touched: registry.py (one new entry), plugin.py (instantiate the Codex tool when configured).
Implementation steps
- Determine Codex's actual CLI surface. Run
codex --helpand the help for any subcommands (likelycodex execfor non-interactive). Document the exact flags you chose in your handoff. As of the design date, Codex's streaming JSON support was less mature than Claude Code's; if stream-json is not viable, fall back toparse_oneshotand emit a singlecompletedevent after the process exits.
- Auth. OpenAI Codex authenticates with
OPENAI_API_KEY(or similar — confirm). The Codex CLI may also have its own login state directory; for phase 2 we useOPENAI_API_KEYvia technical-user auth only. Per-user HOME is phase 6.
- Session resume. If Codex supports a resume mechanism, wire it up in
build_argvandextract_session_id. If it does not, setsupports_resume = Falseand document the consequence: a follow-up call tocodex(query=..., subagent_id=X)will start a fresh Codex session each time but the Codumentor-side conversation history remains. This is acceptable for phase 2.
- Event mapping. Map Codex's output to the eight
AgentEventkinds. Anything that doesn't fit one of the existing kinds is dropped silently — do not invent new kinds without orchestrator approval (a new kind is a contract change and must surface).
- Tests. Same shape as phase 1's tests — fixture-driven, no real binary required.
Acceptance criteria
make testpasses.- Manual probe with the real
codexCLI installed:codex(query="hello")returns a response wrapped in the envelope; transcript card renders. - If Codex does not support streaming, the card still appears (in a "pending → completed" two-state form) and the test asserts the single
completedevent is emitted.
Out of scope
- OpenCode / Gemini — phase 4.
- BYO API key for Codex — phase 3.
- Adapter abstraction overhaul. If you find Codex requires substantial changes to
AgentAdapter, halt and surface to the orchestrator. The orchestrator decides whether to redesign or to absorb the asymmetry in the Codex adapter alone.
Handoff
Fill out the template from §7 of the index. Be explicit in "Contracts established/changed" about:
- The exact Codex argv invocation.
- Whether
supports_resumeandsupports_stream_jsonare true or false for Codex. - Any additive Protocol or union changes (with exact diff).
- Any
AgentEventpayload fields that Codex needed which Claude Code did not produce (these may be optional fields that Claude Code's adapter should later be updated to emit too — flag in "Open questions").