Agent backend injection (Claude / Codex toggle)
Status: design + Phase 1 (in progress) · Branch:feat/agent-backend-injection
Motivation
The panel orchestrator is hard-wired to the Claude Agent SDK (@anthropic-ai/claude-agent-sdk) in src/orchestrator/panel-agent.ts. We want
the agent backend to be dependency-injected so the same panel/orchestrator can
run on a different provider — starting with OpenAI Codex — selected by a toggle.
Design goals:
- No extra user install. The backend ships as an optional npm dependency
(exactly like
@anthropic-ai/claude-agent-sdktoday). Codex is@openai/codex. - One port, many adapters. The orchestrator depends on a provider-neutral
AgentBackendinterface; each provider is an adapter. Capability flags let the panel degrade gracefully when a backend can’t do something. - Generalizes. The same contract is the “OpenAI ↔ Claude DI schema” and the path to future backends.
How each provider is driven (“clink” points)
- Claude —
query({ prompt: AsyncIterable<SDKUserMessage>, options }): a persistent streaming session (channel-in),Query.interrupt(),forkSession+resumeSessionAt,supportedModels(). Subscription auth (claude.ai OAuth, no key). - Codex — the
codex app-serverJSON-RPC protocol over stdio (this is how our ownopenai-codexplugin drives it — seeplugins/openai-codex/.../scripts/lib/app-server.mjs,CodexAppServerClient), notcodex execstring-scraping. Methods:thread/start,thread/resume,turn/start,turn/interrupt, streaming notifications (turn/started, item deltas,turn/completed),config/read,account/read. ChatGPT login auth (subscription, no key).codex exec --jsonis the simpler one-shot fallback.
Capability matrix
Two real adjustments: conversation-rollback is capability-gated off for Codex, and
the panel
panel_* tools must be reachable as a standalone MCP server (the one
shared refactor) since Codex can’t host in-process SDK tools.
The port (provider-neutral)
PanelAgent keeps the orchestration (queue, turn-gate, bridge
push, rewind-anchor tracking, self-restart) and delegates the provider-specific
bits (SDK call, option building, message→event normalization, interrupt, models,
session/fork) to an injected AgentBackend.
Phased plan
- Seam (zero behavior change). Add
agent-backend.ts(port + events + capabilities) and wrap today’s Claude path asClaudeBackend. Orchestrator depends on the port. Build + 577 tests + 9/9 harness stay green. - Codex adapter.
CodexBackendovercodex app-server(@openai/codexas an optional dep), interrupt viaturn/interrupt, models viaconfig/read, conversation-rollback gated off. - Toggle.
PANEL_AGENT_BACKEND=claude|codex(env/config) + panel selector; capability flags drive panel UI (e.g. hide conversation-rollback for Codex). - Shared MCP refactor. Expose
panel_*as a standalone MCP server so non-Claude backends can use the live-graph tools. - Generalize. Document the canonical schema as the provider DI contract.
Open questions
- Codex mid-thread fork: confirm whether the app-server can resume a thread truncated to a turn (would re-enable conversation-rollback for Codex).
- Whether to vendor a minimal app-server client or depend on
@openai/codex’s. - Panel-tools MCP server transport (stdio vs loopback HTTP) for the Codex backend.