Context
PR #46 shipped Codex CLI as a delivery format for throughline's 4 skills (handoff,
onboard, consolidate, consolidate-memory) via .codex-plugin/plugin.json +
.agents/plugins/marketplace.json. That half is verified: codex plugin marketplace add / plugin add throughline@throughline install correctly and skills load.
Automatic capture (the 5 hooks) was deliberately left out, for two reasons found
during /review-pr on that PR:
-
Unverified firing. I ran each hook script directly (piped synthetic
Claude-Code-shaped JSON at session-prompt.sh etc. with CLAUDE_PLUGIN_ROOT
unset) and confirmed the scripts' own logic works correctly outside
CLAUDE_PLUGIN_ROOT. But that only proves the shell logic is portable - it does
not prove Codex actually invokes these hooks at all, with what cwd, or with
what env vars set. The reviewer independently tried to get a hook to fire under
real codex exec (with hooks declared various ways, --enable hooks --enable plugin_hooks, absolute command paths, a user-level $CODEX_HOME/hooks.json)
and could not get any hook to fire either. Hook execution under Codex is
unverified in both directions as of this issue.
-
A plausible double-registration risk. Codex's own hook-discovery code carries
a diagnostic: loading hooks from both <path> and <path>/; prefer a single representation for this layer. throughline's plugin root has both a file
(whatever hooks.json would live there) and a directory (hooks/, which contains
its own hooks.json for Claude Code's convention). If Codex's discovery treats
these as two representations of the same layer, every hook could register twice
- and
session-capture.sh has no idempotency guard on capture lines (only
session-precompact.sh and session-flush.sh guard their stamps), so a
double-registration would silently double-log every captured action.
Separately worth checking: whether Codex actually sets CLAUDE_PLUGIN_ROOT (or a
PLUGIN_ROOT/CLAUDE_PLUGIN_ROOT pair) for hook-invoked processes - if so, the
existing hooks/hooks.json (unmodified, same one Claude Code uses) might just
work if pointed at directly, with no second config file and no drift risk at all.
Also worth checking: whether Codex's manifest hooks field is real -
validate_plugin.py (Codex 0.149.0) empirically rejects a hooks key in
plugin.json even though the plugin-json-spec.md reference doc both shows it in
an example ("hooks": "./hooks.json") and separately states the opposite
("Validation rejects unsupported manifest fields such as hooks"). That
reference doc is internally contradictory on this point and needs resolving
empirically, not by reading it again.
What to do
Needs a real Codex session where a hook can actually be observed firing (or not) -
not another static read of the manifest spec. Once that's possible:
Until this is resolved, Codex users get the 4 skills on-demand but not automatic
session capture - document that clearly in the README's Codex section rather than
implying parity with the Claude Code / OpenCode delivery formats.
Context
PR #46 shipped Codex CLI as a delivery format for throughline's 4 skills (
handoff,onboard,consolidate,consolidate-memory) via.codex-plugin/plugin.json+.agents/plugins/marketplace.json. That half is verified:codex plugin marketplace add/plugin add throughline@throughlineinstall correctly and skills load.Automatic capture (the 5 hooks) was deliberately left out, for two reasons found
during
/review-pron that PR:Unverified firing. I ran each hook script directly (piped synthetic
Claude-Code-shaped JSON at
session-prompt.shetc. withCLAUDE_PLUGIN_ROOTunset) and confirmed the scripts' own logic works correctly outside
CLAUDE_PLUGIN_ROOT. But that only proves the shell logic is portable - it doesnot prove Codex actually invokes these hooks at all, with what cwd, or with
what env vars set. The reviewer independently tried to get a hook to fire under
real
codex exec(withhooksdeclared various ways,--enable hooks --enable plugin_hooks, absolute command paths, a user-level$CODEX_HOME/hooks.json)and could not get any hook to fire either. Hook execution under Codex is
unverified in both directions as of this issue.
A plausible double-registration risk. Codex's own hook-discovery code carries
a diagnostic:
loading hooks from both <path> and <path>/; prefer a single representation for this layer. throughline's plugin root has both a file(whatever hooks.json would live there) and a directory (
hooks/, which containsits own
hooks.jsonfor Claude Code's convention). If Codex's discovery treatsthese as two representations of the same layer, every hook could register twice
session-capture.shhas no idempotency guard on capture lines (onlysession-precompact.shandsession-flush.shguard their stamps), so adouble-registration would silently double-log every captured action.
Separately worth checking: whether Codex actually sets
CLAUDE_PLUGIN_ROOT(or aPLUGIN_ROOT/CLAUDE_PLUGIN_ROOTpair) for hook-invoked processes - if so, theexisting
hooks/hooks.json(unmodified, same one Claude Code uses) might justwork if pointed at directly, with no second config file and no drift risk at all.
Also worth checking: whether Codex's manifest
hooksfield is real -validate_plugin.py(Codex 0.149.0) empirically rejects ahookskey inplugin.jsoneven though the plugin-json-spec.md reference doc both shows it inan example (
"hooks": "./hooks.json") and separately states the opposite("Validation rejects unsupported manifest fields such as
hooks"). Thatreference doc is internally contradictory on this point and needs resolving
empirically, not by reading it again.
What to do
Needs a real Codex session where a hook can actually be observed firing (or not) -
not another static read of the manifest spec. Once that's possible:
CLAUDE_PLUGIN_ROOTfor hook processes at allhooks.jsonis discovered by convention, orwhether the manifest needs some declaration - and if so, what actually gets
accepted (
validate_plugin.pysayshooksthe field is rejected; empiricallytest whether hooks fire anyway via convention-based discovery)
reusing the existing
hooks/hooks.jsondirectly ifCLAUDE_PLUGIN_ROOTisset by Codex (zero drift risk), or add idempotency to
session-capture.shfirst if a duplicate-file approach is unavoidable
.local-ci.jsoncheck keeping any new hook config in sync withhooks/hooks.jsonif a second file ends up being necessaryUntil this is resolved, Codex users get the 4 skills on-demand but not automatic
session capture - document that clearly in the README's Codex section rather than
implying parity with the Claude Code / OpenCode delivery formats.