Repository navigation
feat: Codex CLI hooks; fix the budget watchdog and plugin-only tool names (0.53.0) - #69
Merged
Merged
Conversation
…ames (0.53.0)
Codex grew Claude Code's lifecycle-hook protocol, so the handlers port
unchanged: `install-hook --client=codex` writes ~/.codex/hooks.json (or the
project's) wiring the shell rules, session start and prompt submit. Codex has
no file-read tool, and apply_patch/spawn_agent carry payloads our edit gate
and router would misread, so those stay out.
Claude Code 2.1.271 moved a subagent's report into a SubagentHandback tool
call. The response-budget watchdog was measuring the text stub left beside it
— 4 tokens for a 5 KB report — so no tp-* agent could exceed its budget. It
reads the handback message now. Transcript output_tokens also stopped being
usable (199 for a 117k-token run, because the usage-carrying records are the
classifier's), so task events take the larger of that sum and the reply size.
Hook advice named mcp__token-pilot__* everywhere, which does not exist on a
plugin-only install; the prefix is resolved at runtime now, and bless-agents
writes both spellings.
Also: `git log --oneline -1` no longer denies itself inside a compound
command, hook commands quote ${CLAUDE_PLUGIN_ROOT}, the README client matrix
stops promising hooks for clients we never wrote hooks for, dead Codex env
detection removed, and tp-run can reach WebFetch/WebSearch.
The preamble injected into all 25 tp-* agents told them to call mcp__token-pilot__smart_read. On a plugin install that tool is named mcp__plugin_token-pilot_token-pilot__smart_read, so the instruction every agent reads first pointed at something that does not exist there. The text is baked at build time, so the namespace is dropped entirely — the agent's own tools list already carries both spellings, and Claude Code resolves a bare MCP name since 2.1.271. Also documents uninstall-hook --client=codex in the CLI help.
Verified live: Codex 0.156 fires the installed PreToolUse hook and blocks `cat big.ts` with our message — which then told it to use Read(path, offset, limit). Codex has no Read tool; the line now says where that suggestion applies, and the head/tail advice beside it already works everywhere.
Measured on Codex 0.156: every session reported "SessionStart Failed"; replacing our reply with a minimal one completed, so Codex validates hookSpecificOutput and rejects the Claude Code extension `watchPaths`. The Codex installer now passes --client=codex and the hook leaves Claude-only keys out for it. Re-verified live afterwards: SessionStart, UserPromptSubmit, PreToolUse and PostToolUse all complete, and a blocked `cat` still returns our message.
…ote nothing The recursive-search rule matched its pattern anywhere in the command line, so a commit message or a heredoc that mentioned the flag was blocked as if it had been invoked — the same false positive v0.30.4 fixed for git log. It surfaced by blocking this release's own commit. The invocation must now start the command or follow a separator. Denied shell commands also left no telemetry: only the Read hook wrote events, so shell interceptions were invisible — and on Codex, where the model reads through the shell, that is nearly every interception. They now write a bash_denied diagnostic, awaited so the hook process cannot exit first.
…live watchdog check
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Claude Code moved to 2.1.281 and Codex CLI to 0.156 since the last release. Two
of our guarantees had gone quiet in the meantime, and Codex grew a hook system
that happens to be ours.
Added — Codex CLI runs token-pilot's hooks
Codex reads lifecycle hooks from
~/.codex/hooks.jsonor<repo>/.codex/hooks.json, in the same{matcher, hooks: [{type, command}]}shape, and blocks a call through
hookSpecificOutput.permissionDecisionorexit 2 — the shapes our handlers already emit
(docs). So they are reused
unchanged:
Wired:
PreToolUseandPostToolUseonBash,SessionStart,UserPromptSubmit. Codex has no file-read tool — the model reads through theshell, which the bash rules already intercept.
apply_patchandspawn_agentstay out: their payloads are not Claude Code's
EditandAgent, and thosehandlers would be reasoning about fields that are not there. Codex will not run
a hook definition it has not been shown, so the installer says to run
/hooks.Verified end to end against Codex 0.156, not only in unit tests:
cat big.tscomes back blocked with our message, and all four wired events complete. The
last part needed a fix —
SessionStartfailed on every start until the replystopped carrying
watchPaths, a Claude Code extension Codex rejects, so theinstaller now tells the hook which client it serves.
Fixed — the response-budget watchdog was measuring a stub
Claude Code 2.1.271 moved a subagent's report into a
SubagentHandbacktoolcall. Measured on a real run in this repo: the handback message was 5129
characters while the last text block beside it was 17 — so the watchdog scored
a full report at 4 tokens and no
tp-*agent could ever exceed its declaredbudget. The reply now comes from the handback message, with the last text turn
kept as the fallback for older builds.
The same transcript stopped carrying a usable output total: summing
usage.output_tokensacross a run that cost 117k tokens returns 199, becausethe records carrying usage are the server-side classifier's. Task events take
the larger of that sum and the reply size.
Fixed — hook advice named a tool plugin-only users do not have
Every deny message pointed at
mcp__token-pilot__smart_readand friends, whichon a plugin install are named
mcp__plugin_token-pilot_token-pilot__*. With MCPdefinitions loaded on demand the model cannot even find the real tool from the
name it was handed. 0.52.0 fixed this for agent frontmatter and missed the
messages; they resolve the prefix at runtime now, and
bless-agentswrites bothspellings.
Fixed — smaller things
git log --oneline -1denied itself inside a compound command: the-<N>bound only counted when a space or end-of-string followed it.
${CLAUDE_PLUGIN_ROOT}; unquoted they break on a pluginpath containing a space.
Cline and Antigravity. We have never written hooks for them.
installation.mdrepeated the claim and said "22 MCP tools" where there are 25.
OPENAI_CODEX/CODEX_MODE; neither string existsin the 0.156 binary.
tp-runcan reachWebFetch/WebSearch— the router matches on wordingalone and would send "read the changelog" to an agent with no way to open a
page.
omitClaudeMdis documented as of 2.1.271; the reference says so.Verified
18 new tests — every one pinning a defect was red before its fix — and one
removed along with the Codex env branch it covered. Full suite 1484/1484,
tsc --noEmitclean, build clean. The Codex hook file is asserted for what itcontains and for what it leaves out.