Codex provider
Why this one matters most
Section titled “Why this one matters most”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.
What is known
Section titled “What is known”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 asessionId. This is exactly the kind of differenceSpawnOptionsexists 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,apiKeyandserviceTier. Claude’s adapter takes none of these. Where they belong — inSpawnOptions, 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.
What is not known
Section titled “What is not known”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
typediscriminator — which would letEventParserwork unchanged — or something that needs translating inparseLine. - Its permission or sandbox vocabulary, and whether every member of
PermissionModecan be spelled in it. - Whether it exposes
mcpandauthsubcommands, and in what shape. - Whether it reports its own mode back, which is what
reportedMode()depends on.
What attaching it is expected to change
Section titled “What attaching it is expected to change”The porting order is fixed, and step three is the point of the exercise:
- Port the adapter accurately, matching the CLI’s real behaviour.
- Note every place the existing contract had to be worked around — especially in
Auth/andMcp/, and anywherePermissionModedid not fit. - Extract the common shape from the two implementations.
- 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.
Where to go next
Section titled “Where to go next”- Writing a provider — the seven steps, ending in extracting the contract.
- Abstract provider — why the base class is still small.
- Roadmap — where this sits in the order of work.