Skip to content

[FEAT] codex gets a plugin, and the protocol did not have to move - #71

Merged
gradyzhuo merged 1 commit into
mainfrom
feat/codex-plugin
Sep 24, 2026
Merged

gradyzhuo merged 1 commit into
mainfrom
feat/codex-plugin

Conversation

@gradyzhuo

Copy link
Copy Markdown
Member

The result worth reporting is a negative one: AIToolKit needed no change at
all.
No new method, no widened type, no special case. Nine tests, green on the
first run.

The protocol was designed while looking at claude, so "a third party could
implement this" rested on one example — the one the design was fitted to. This is
the second.

Why codex is the useful second case

Because it is unlike claude:

claude codex
Credentials platform keychain one file
Identity source a JSON field a JWT claim
Special mode — API key: a login with no user

That last one has no claude analogue. It reports as plan: "api key" with a nil
email — calling it absent would hide an account that works, and inventing an
email would be worse.

The part that tests for overfitting

listIdentities and showIdentity read the same file here, and that is not
an argument against having both.

Claude has a cheap source and a costly one, which is why the split exists. Codex
has one source, answers both the same way, and pays nothing for a distinction
it does not need
. A protocol that forced the cheap/costly split on every tool
would have been fitted to claude in exactly the way this change set out to test.

Shipped, deliberately not switched on

Added to every install path — three tarballs, two debs, the install script — but
not added to pluginProvidedTools.

That switch makes codex's identity depend on a binary being present, and the
binary has to reach machines first. It is the same sequence claude went through
(v3.5.4 shipped it; the switch came after), and that sequence was right: doing
both at once would break codex for anyone who had not yet upgraded.

Duplication, pinned not trusted

The host still reads codex's auth.json for Account.refreshInfo, so two
readers of one format exist until that call site moves. There is a parity test
asserting the plugin and the host agree about the same directory, the same as
claude's.

Verification

730 tests pass. Also driven by hand against the real binary over the real
protocol, covering all three shapes:

capabilities: ['tool/describe', 'tool/listIdentities', 'tool/showIdentity']

listIdentities → [ {"email":"real@example.com","plan":"pro"},
                   {"email":null,"plan":"api key"},
                   null ]

The gap stays in place, which is what keeps every later row paired with the right
directory.

🤖 Generated with Claude Code

The protocol was designed while looking at claude, so "a third party could
implement this" rested on one example — the one the design was fitted to. This
is the second, and the result worth reporting is that AIToolKit needed no change
at all: no new method, no widened type, no special case.

Codex earns its place as the second case by being unlike claude. Its credentials
are one file rather than a platform keychain. Its identity comes out of a JWT
claim rather than a JSON field. And it has an API-key mode with no user at all,
which claude has no analogue for — a real login carrying no email. That reports
as plan "api key" with a nil email, because calling it absent would hide an
account that works and inventing an email would be worse.

listIdentities and showIdentity read the same file here, and that is not an
argument against having both. Claude has a cheap source and a costly one; codex
has one source and answers both the same way, paying nothing for a distinction
it does not need. A protocol that forced the cheap/costly split on every tool
would have been fitted to claude in exactly the way this change is testing for.

Shipped in every install path — three tarballs, two debs, the install script —
but deliberately NOT added to pluginProvidedTools yet. That switch makes codex's
identity depend on a binary being present, and the binary has to reach machines
first. It is the same sequence claude went through (3.5.4 shipped it, the switch
came after), and that sequence was right.

The host still reads codex's auth.json for Account.refreshInfo, so two readers
of one format exist until that call site moves. Pinned by a parity test rather
than trusted, the same as claude's.
@gradyzhuo
gradyzhuo merged commit a14892a into main Sep 24, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant