feat: Codex CLI plugin as a 4th delivery format - #46
Conversation
Repo-root .codex-plugin/plugin.json and .agents/plugins/marketplace.json
install the same shell-hook capture pipeline Claude Code uses - no
TypeScript port needed, since Codex's plugin-root hooks.json turns out
to be schema-identical to Claude Code's (confirmed against the bundled
figma@openai-curated plugin). Install: `codex plugin marketplace add
dynamic/throughline` -> `codex plugin add throughline@throughline`.
All 5 hooks verified end-to-end against a real installed plugin cache
with CLAUDE_PLUGIN_ROOT unset: piped synthetic Claude-Code-shaped JSON
at each script directly (session-prompt, session-capture,
session-precompact, session-flush, session-onboard) and confirmed the
buffer file got the right redacted/timestamped lines, the compaction
and session-ended markers landed, and onboard's version-tagged context
block rendered correctly - the _lib.sh sourcing fallback
(${CLAUDE_PLUGIN_ROOT:-$DIR/..}) needed zero changes.
Along the way: hooks/session-precompact.sh was missing its executable
bit (unlike its four siblings) - a real, pre-existing bug that broke
this hook on Claude Code too, since exec'ing a non-executable file's
path fails at the OS level before the script's own logic runs. Fixed.
Also added `license: MIT` to all 4 SKILL.md frontmatters (matches
.claude-plugin/plugin.json; gh skill publish --dry-run now passes clean).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J73antfNfrGEBa5fHHcAew
/review-pr surfaced a real problem with the original approach: I'd only verified the hook SCRIPTS work correctly with CLAUDE_PLUGIN_ROOT unset (ran each directly with synthetic JSON), not that Codex actually FIRES them - the reviewer independently tried and could not get any hook to fire under real `codex exec` either. There's also a plausible double-registration risk: Codex's hook discovery warns when it finds both a file and a directory representation at the same plugin-root layer, which this repo's hooks.json + hooks/ (Claude Code's own convention) would trigger - and session-capture.sh has no idempotency guard, so a double-registration would silently double-log every action. One claimed fix turned out to be wrong too: the reviewer's "critical" finding said plugin.json needs a `hooks` field pointing at hooks.json. Tested directly - Codex's own validate_plugin.py (0.149.0) rejects a `hooks` key outright, contradicting the reference doc that suggested it (which also separately states hooks are unsupported - the doc is internally contradictory and shouldn't be trusted over a live test). Applying the same discipline from the sibling assistant-skills PR (drop what can't be verified rather than ship a guess with a plausible corruption risk): removed hooks.json. Codex delivery is now skills-only - the 4 skills (handoff/onboard/consolidate/consolidate-memory) install and load correctly (re-verified end-to-end after this change), automatic capture is not wired. Filed #47 with both reviewers' findings for when this can actually be tested against a firing hook. README/CHANGELOG corrected to state what's actually verified instead of what was assumed to work. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01J73antfNfrGEBa5fHHcAew
/review-pr summaryRan code-reviewer against the diff. Genuinely important findings this time - one led to a real scope change. The critical finding, tested and confirmed wrong: the reviewer flagged that The two findings that mattered, both real:
Fix (26eb42b): removed Confirmed correct, no changes needed: 🤖 Generated with Claude Code |
…gation Extends CI (.github/workflows/ci.yml) and local-ci (.local-ci.json) manifest validation to cover .codex-plugin/plugin.json and .agents/plugins/marketplace.json, which shipped with zero validation since PR #46. Adds a version-agreement check between the two independently hand-maintained plugin.json version strings. Closes issue #47 (Codex automatic-capture hooks) with a full empirical investigation via a live probe hook under real `codex exec`. Decision: not wiring hooks - discovery is solved and double-registration is ruled out for the recommended pattern, but hooks require an interactive trust grant with no verified non-interactive path, so wiring it now would look automatic while silently not firing for most real usage. Skills-only framing stands, now backed by evidence instead of an inconclusive prior attempt. /review-pr found no blocking issues; fixed one sub-threshold divergence between the local-ci and CI forms of the version-agreement check (missing-file edge case) and filed #49 for a pre-existing, unrelated local-ci/CI parity gap it surfaced.
Summary
.codex-plugin/plugin.json+.agents/plugins/marketplace.jsonat repo root socodex plugin marketplace add dynamic/throughlineinstalls natively, alongside the existing Claude Code plugin and OpenCode plugin.hooks.jsonmirrorshooks/hooks.json, but with./hooks/<script>.shcommands instead of${CLAUDE_PLUGIN_ROOT}/hooks/<script>.sh- Codex has noCLAUDE_PLUGIN_ROOTequivalent, and the existinghooks/_lib.shfallback (${CLAUDE_PLUGIN_ROOT:-$DIR/..}) already handles that, so no script changes were needed.license: MITadded to all 4 SKILL.md frontmatters (matches.claude-plugin/plugin.json; clears the onlygh skill publish --dry-runwarning).hooks/session-precompact.shwas missing its executable bit (unlike its four siblings) - this silently broke the hook on Claude Code too, not just the new Codex path.Test plan
python3 validate_plugin.py(Codex's own validator) passescodex plugin marketplace add/plugin list/plugin add throughline@throughline- full round-trip against this branch, confirmed a real copy landed in the plugin cache includinghooks/with executable bits intactCLAUDE_PLUGIN_ROOTunset - piped synthetic Claude-Code-shaped JSON at each and confirmed correct buffer output: prompt line, tool-call line, compaction-boundary marker, session-ended marker, and the version-tagged onboard context block all rendered correctlygh skill publish --dry-run- clean, zero warnings/local-ci- 167/167 shell tests pass, shellcheck cleanFiled a follow-up issue for docs/promo: #45
Co-Authored-By: Claude Sonnet 5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01J73antfNfrGEBa5fHHcAew