feat(codex): SubagentStart + Pre/PostCompact context surfaces (hook parity)#14
Conversation
Completes native Codex hook parity. fscar init --adapter codex now registers all documented events. These three are context-injection surfaces (no decision in their output schemas, so a scar cannot block them); each emit path matches the surface's generated schema exactly: - SubagentStart: hookSpecificOutput.additionalContext + systemMessage (no decision). - PreCompact/PostCompact: top-level systemMessage only (no hookSpecificOutput, no additionalContext, no decision). run_hook returns exit 0 for all three (no exit-2 decision path), grouped with PermissionRequest in _EXIT_ZERO_EVENTS. Adds HookEventType.SUBAGENT_START / PRE_COMPACT / POST_COMPACT + mappings + WANTED_EVENTS. Output shapes verified against the generated schemas (subagent-start / pre-compact / post-compact .command.output.schema.json). Docs + CHANGELOG. Gate: 193 passed, ruff clean, mypy strict clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4ef7e3755e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if event_type in (HookEventType.PRE_COMPACT, HookEventType.POST_COMPACT): | ||
| # Strictest schema: only continue/stopReason/suppressOutput/ | ||
| # systemMessage — NO hookSpecificOutput, NO additionalContext, NO | ||
| # decision. systemMessage is the only context channel; a scar here | ||
| # cannot block. See pre-compact/post-compact output schemas. | ||
| message = output.system_message or output.additional_context | ||
| return ( | ||
| json.dumps({"systemMessage": message}, ensure_ascii=False) |
There was a problem hiding this comment.
Preserve compaction blocks with continue:false
For PreCompact/PostCompact scars that set block=True (for example, a project scar that wants to stop an auto-compaction until state is saved), this branch drops the block entirely and only emits systemMessage, so Codex proceeds. The Codex hook docs' common output fields include continue, and the PreCompact/PostCompact sections state that returning continue: false stops before/after compaction, so blocking compaction scars need to emit that schema-supported field (with stopReason) rather than being treated as context-only.
Useful? React with 👍 / 👎.
fscar init --adapter codex now registers every documented Codex hook event: the three blocking surfaces (PreToolUse, PermissionRequest, SubagentStop) plus the three context surfaces (SubagentStart, PreCompact, PostCompact), each matched to its generated output schema. Bundles PRs #13 + #14. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
What
Final increment of the Codex hook deepening: the three context-injection surfaces —
SubagentStart,PreCompact,PostCompact. With these,fscar init --adapter codexregisters every documented Codex hook (the three blocking surfaces —PreToolUse,PermissionRequest,SubagentStop— plus these three context surfaces).Schema-driven (the lesson from #13)
None of these has a
decisionin its output schema, so they are context-only — a scar cannot block them. I fetched each generated output schema and matched the emit path exactly:SubagentStart—subagent-start.command.output.schema.json:additionalProperties:false, allowshookSpecificOutput.{hookEventName, additionalContext}+systemMessage, nodecision. → inject viahookSpecificOutput.additionalContext.PreCompact/PostCompact— allow onlycontinue/stopReason/suppressOutput/systemMessage; nohookSpecificOutput, noadditionalContext, nodecision. → context via top-levelsystemMessageonly.A
block=Trueon any of these never leaks adecision/hookSpecificOutputit isn't allowed (covered by tests).How
payload: addHookEventType.SUBAGENT_START/PRE_COMPACT/POST_COMPACT.codex adapter: map each (+ lowercase aliases), add toWANTED_EVENTS(install/doctor/manifest follow), dedicatedemit_outputbranches per schema.run_hook: these joinPermissionRequestin_EXIT_ZERO_EVENTS(exit 0 — no exit-2 decision path).Verification
ruff check fscars cookbook testsclean,mypy fscarsstrict clean.Review focus
SubagentStartallowinghookSpecificOutput.additionalContextwhile compaction forbidshookSpecificOutputentirely).decisionever emitted) andrun_hookreturning exit 0 for them is right.Intended to be cut as v0.8.0 together with
SubagentStop(#13, already on main) = complete Codex native hook coverage. Version not bumped in this PR.🤖 Generated with Claude Code