Skip to content

feat(telemetry): ask a codex tui session for its task - #1058

Merged
blafourcade merged 9 commits into
nextfrom
feat/telemetry-codex-hooks
Oct 20, 2026
Merged

blafourcade merged 9 commits into
nextfrom
feat/telemetry-codex-hooks

Conversation

@blafourcade

Copy link
Copy Markdown
Contributor

🎯 What & why

Codex calls were measured, but no Codex session was ever asked for its task: each hook returned early because its guard accepted only Claude Code's payload. The same three hooks now serve Codex too, and Claude Code behaves exactly as before.

🛠️ How it works

  • Which tool sent the payload. hooks/lib/tool.cjs checks for Claude Code first, using the unchanged isClaudePayload. Otherwise the payload is Codex when it has a session_id and its transcript_path is a Codex session file. The path decides, not CLAUDE_CODE_SESSION_ID, because a Codex started inside Claude Code inherits that variable. The shared fixture section is now hookTool (claude | codex | null).
  • Whether a person can see a block. Codex shows a block's reason only in its TUI, and a hook receives nothing that names the surface. The session file's first line does: the hook reads up to 1 MiB of it. The largest first line measured was 48 KiB. A prompt is held only when all of these hold:
    • the first line is a session_meta with source: cli and originator: codex-tui;
    • the payload has no agent_id;
    • permission_mode is default.
      Anything else lets the prompt through (presence.cjs). A change in Codex can only stop the asking, never block work.
  • The session a declaration binds. aidd telemetry task binds AIDD_TELEMETRY_SESSION_ID, else CLAUDE_CODE_SESSION_ID (declaringSessionOf, runtime/wiring/telemetry.ts). Only the Codex hook sets the first one, to its payload's session_id. A sub-agent's calls carry their root's session, so they take its task.
  • What a Codex block returns. Only {decision, reason}. Codex was never seen to accept suppressOriginalPrompt, so the typed declaration stays visible there; it is still not sent to the model.
  • Session start. For Codex, session-start.cjs does nothing, not even the consent check, because Codex gives a hook no process id. catch-up.cjs ingests for both tools.
  • The merged .codex/hooks.json. It kept only type, command, timeout and statusMessage, so async was lost. Each entry is now kept whole, as the plugin tree (renameCodexHookEvents) already does (flat-hooks-merge.ts). Across plugins/*/hooks/hooks.json the entry keys are only type, command, timeout and async. One existing test pinned a timeout of the wrong type being dropped; it now expects that value to pass through, as it does on the plugin route.

🧪 How to verify

  • node scripts/check-tests-leave-git-alone.js -- node --test 'scripts/__tests__/**/*.test.js', sandboxed: 476 tests pass. The hook rows of the presence rule are in codex presence: a prompt is held when, and only when, every condition holds.
  • cd cli && pnpm test: includes the new end-to-end test asks a Codex TUI session, binds its declaration to that session, and attributes its calls and its sub-agent's.
  • The red runs, the hook mutations done by hand, and every gate's output are in evidence.md.

⚠️ Heads-up

  • Not observed yet; real run pending. The real run with the Codex TUI has not been done: trust the hooks with /hooks, check the TUI holds a prompt, check codex exec never does. The trust and async effects below come from reading the openai/codex source.
  • Trust again after this change. Codex trusts a hook by its entry. A project whose merged .codex/hooks.json gains async gets a changed entry, so Codex asks for that hook to be trusted again. The plugin's own hooks.json is unchanged.
  • Limits, written into the usage contract and the README:
    • Nothing asks until the hooks are trusted.
    • codex exec, the IDE extension, the desktop app and full-access mode are never asked.
    • A TUI thread resumed by codex exec with an auto-review approver would be held with nobody to see why. Not observed.
    • A Codex /clear or fork is asked again.

🔗 Linked issue

None. Follows #1057: Codex is measured, now it is asked for its task.

✅ I certify

  • I DO CERTIFY I READ EACH LINE OF THE PULL REQUEST BECAUSE I AM A SOFTWARE ENGINEER, NOT A AI PUPPY.

🤖 Generated with Claude Code

https://claude.ai/code/session_01TnCgcujM2xi6T6dkmVogVw

blafourcade and others added 9 commits October 19, 2026 12:22
`aidd telemetry task` binds AIDD_TELEMETRY_SESSION_ID, else
CLAUDE_CODE_SESSION_ID. Codex sets no session variable, so its hook
names the session for the command it runs.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TnCgcujM2xi6T6dkmVogVw
The hooks tell a Codex payload from Claude Code's by its session file.
A Codex prompt on an undeclared branch is held only when the file's
first line, read up to 1 MiB, says the TUI made it, no sub-agent sent
it, and approvals are on. A typed declaration binds the payload's
session. Session start does nothing for Codex; the catch-up ingests.
Claude Code behaviour is unchanged.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TnCgcujM2xi6T6dkmVogVw
The merged .codex/hooks.json kept only type, command, timeout and
statusMessage, so the telemetry catch-up lost `async` and would run in
the way of the session start. Each entry is now kept whole, as the
plugin tree already keeps it. An entry merged before changes, so Codex
asks for it to be trusted again.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TnCgcujM2xi6T6dkmVogVw
Usage contract, plugin README, the start and stop texts and the CLI
memory: the Codex TUI is asked once its hooks are trusted, never
`codex exec`, the IDE extension, the desktop app or full access. The
task folder holds the contract, the plan and the evidence.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TnCgcujM2xi6T6dkmVogVw
…read limit

The hook names the payload's session for every declaration, so a stale
exported AIDD_TELEMETRY_SESSION_ID cannot win in Claude Code. The Codex
session-file pattern leaves claude-only.cjs for its own module. A TUI
thread resumed in the IDE extension or desktop app is written down as a
limit, with a real-run step to observe it; the presence row reads
permission_mode exactly default.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TnCgcujM2xi6T6dkmVogVw
A real Codex 0.163.0 TUI with plugins installed runs through the app
server and records source vscode, not cli, so the prompt was never
held. The presence rule drops the source condition: originator
codex-tui, no agent_id and permission_mode default. An object source,
a sub-agent's own file, is still refused.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TnCgcujM2xi6T6dkmVogVw
The real run on Codex 0.163.0 held a TUI prompt, bound its declaration,
never held codex exec, and attributed the calls. The desktop app shows
a hook's block reason, so a TUI thread resumed there is asked visibly.
The README and usage contract say hooks are trusted with /hooks in the
TUI and that the desktop app offers no review of its own. aidd
telemetry on now names the Codex TUI beside Claude Code.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TnCgcujM2xi6T6dkmVogVw
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TnCgcujM2xi6T6dkmVogVw
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TnCgcujM2xi6T6dkmVogVw
@blafourcade
blafourcade marked this pull request as ready for review October 20, 2026 03:42
@blafourcade
blafourcade requested a review from a team as a code owner October 20, 2026 03:42
@blafourcade
blafourcade merged commit c338b19 into next Oct 20, 2026
38 checks passed
@blafourcade
blafourcade deleted the feat/telemetry-codex-hooks branch October 20, 2026 03:42
@blafourcade blafourcade added this to the This week milestone Oct 22, 2026 — with Claude
@aidd-bot aidd-bot Bot mentioned this pull request Oct 26, 2026
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