Repository navigation
feat(telemetry): ask a codex tui session for its task - #1058
Merged
Merged
Conversation
`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
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.
🎯 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
hooks/lib/tool.cjschecks for Claude Code first, using the unchangedisClaudePayload. Otherwise the payload is Codex when it has asession_idand itstranscript_pathis a Codex session file. The path decides, notCLAUDE_CODE_SESSION_ID, because a Codex started inside Claude Code inherits that variable. The shared fixture section is nowhookTool(claude|codex|null).session_metawithsource: cliandoriginator: codex-tui;agent_id;permission_modeisdefault.Anything else lets the prompt through (
presence.cjs). A change in Codex can only stop the asking, never block work.aidd telemetry taskbindsAIDD_TELEMETRY_SESSION_ID, elseCLAUDE_CODE_SESSION_ID(declaringSessionOf,runtime/wiring/telemetry.ts). Only the Codex hook sets the first one, to its payload'ssession_id. A sub-agent's calls carry their root's session, so they take its task.{decision, reason}. Codex was never seen to acceptsuppressOriginalPrompt, so the typed declaration stays visible there; it is still not sent to the model.session-start.cjsdoes nothing, not even the consent check, because Codex gives a hook no process id.catch-up.cjsingests for both tools..codex/hooks.json. It kept only type, command, timeout and statusMessage, soasyncwas lost. Each entry is now kept whole, as the plugin tree (renameCodexHookEvents) already does (flat-hooks-merge.ts). Acrossplugins/*/hooks/hooks.jsonthe entry keys are onlytype,command,timeoutandasync. 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 incodex presence: a prompt is held when, and only when, every condition holds.cd cli && pnpm test: includes the new end-to-end testasks a Codex TUI session, binds its declaration to that session, and attributes its calls and its sub-agent's.evidence.md./hooks, check the TUI holds a prompt, checkcodex execnever does. The trust and async effects below come from reading the openai/codex source..codex/hooks.jsongainsasyncgets a changed entry, so Codex asks for that hook to be trusted again. The plugin's ownhooks.jsonis unchanged.codex exec, the IDE extension, the desktop app and full-access mode are never asked.codex execwith an auto-review approver would be held with nobody to see why. Not observed./clearor fork is asked again.🔗 Linked issue
None. Follows #1057: Codex is measured, now it is asked for its task.
✅ I certify
🤖 Generated with Claude Code
https://claude.ai/code/session_01TnCgcujM2xi6T6dkmVogVw