Skip to content

Codex provider

AbstractAdapter is deliberately small, and it stays that way until a second adapter exists. A contract drawn from a single implementation is a guess; the shape worth committing to is the one that survives a second.

Codex is the strongest candidate for that second implementation, because the differences it presents are already visible from the outside — which makes it useful pressure rather than a guess about pressure.

The survey of the largest competing JetBrains plugin recorded the parameters each of its CLI channels takes, and Claude and Codex diverge immediately:

Channel Parameters its send takes
Claude sessionId, disableThinking, agentPrompt
Codex threadId, baseUrl, apiKey, serviceTier

Two things follow from that row, and they are the whole of what is established:

  • Codex identifies a conversation by a threadId, not a sessionId. This is exactly the kind of difference SpawnOptions exists to absorb — a caller who has to know that one CLI calls this a session and another calls it a thread is not being offered an abstraction.
  • Codex accepts baseUrl, apiKey and serviceTier. Claude’s adapter takes none of these. Where they belong — in SpawnOptions, in the environment, or somewhere that does not exist yet — is undecided.

The same survey found the command lists differ too: seven commands for Claude against three for Codex.

Nothing else about the codex CLI has been verified against the real binary. Specifically, the following are not yet investigated:

  • Which flags make it a controllable two-way stream, and whether it has an equivalent of --input-format stream-json.
  • Whether its output is NDJSON with a type discriminator — which would let EventParser work unchanged — or something that needs translating in parseLine.
  • Its permission or sandbox vocabulary, and whether every member of PermissionMode can be spelled in it.
  • Whether it exposes mcp and auth subcommands, and in what shape.
  • Whether it reports its own mode back, which is what reportedMode() depends on.

The porting order is fixed, and step three is the point of the exercise:

  1. Port the adapter accurately, matching the CLI’s real behaviour.
  2. Note every place the existing contract had to be worked around — especially in Auth/ and Mcp/, and anywhere PermissionMode did not fit.
  3. Extract the common shape from the two implementations.
  4. Only then widen AbstractAdapter.

command.auth and command.mcp are the first place pressure is expected to land. They are currently Claude-shaped: they run claude auth status --json and claude mcp list and parse what those print. They are constructed with the provider’s name, so they will run against another CLI — and produce nothing useful if it spells its subcommands differently.

That is a finding to raise, not a thing to work around. Forking the parser or special-casing a provider name inside it would hide the evidence about where the abstraction boundary really belongs.

Command is the part that should need the least changing. It speaks in intent — a message, a model, a permission mode — and none of those words are Claude’s. If porting Codex forces a change there, that is the most interesting finding of the whole exercise and worth writing down.