Other harnesses
The hook protocol of Claude Code (JSON on stdin, JSON on stdout, a deny or a block in the output) became the convention across coding agents, and every harness below has most of the events the plugin needs. The logic in src/lib/ assumes no harness; only the shims in src/hooks/ and the hooks.json wiring are Claude Code’s. adapters/README.md records the contract an adapter has to meet and the per-harness constraints.
What works where
Section titled “What works where”Only the Claude Code adapter exists. The table says what each harness’s documented hook surface can carry for the current design. I checked it against the vendor docs on 2026-10-27; “untested” means the docs neither confirm nor deny it. Three rows need no hooks at all, because they are Vale and a CLI: the commit gate, /init and /doctor, and the config-adjusted reminder text.
| Feature | Claude Code | Codex | Cursor | Copilot CLI | Gemini CLI | OpenCode | AGENTS.md only |
|---|---|---|---|---|---|---|---|
| Rules at context start: startup, resume, clear, compaction | yes | yes¹ | partial — sessionStart injects, no source, nothing after compaction² |
partial — sessionStart has a source, nothing after compaction³ |
partial — SessionStart has a source, PreCompress is notification-only |
partial — a system-prompt transform keeps the rules on every request⁴ | partial — static file |
| Rules injected into subagents | yes | yes⁵ | no — subagentStart can deny, not inject |
yes — subagentStart additionalContext |
no — no subagent events | untested | no |
| Rules plus the violation report on the next prompt | yes | yes — UserPromptSubmit additionalContext |
no — beforeSubmitPrompt can block, not inject |
partial — config hooks cannot inject on the prompt event; userPromptTransformed rewrites the model-facing prompt⁶ |
yes — BeforeAgent additionalContext |
partial⁴ | no |
| Reply check: read the final reply, block for a rewrite | yes | yes — Stop carries last_assistant_message |
partial — afterAgentResponse reads the text; only stop can push a follow-up turn |
partial — agentStop blocks but hands over a transcript path, not the text |
yes — AfterAgent has prompt_response and a deny that retries |
partial — session.idle is an event; the reply comes through the client, and nothing blocks |
no |
| File check after a write, facts into context | yes | partial — PostToolUse injects, but edits arrive as apply_patch patches to parse⁷ |
yes — postToolUse additional_context |
yes — postToolUse additionalContext; tool names differ |
yes — AfterTool additionalContext |
yes — tool.execute.after appends to the tool output |
no |
| Stop gate for files in block mode | yes | yes — Stop with stop_hook_active |
partial — stop followup_message |
yes — agentStop decision: block |
yes — AfterAgent deny |
no — nothing blocks at idle | no |
Publish gate before gh, MCP, and the artifact page: deny with the text in hand |
yes | partial — PreToolUse denies; ask is parsed but not supported, so unresolved values need publish.unresolved set |
yes — beforeShellExecution and beforeMCPExecution allow, deny, or ask |
yes — preToolUse denies or asks; fail-closed on a hook crash |
partial — BeforeTool denies; no ask |
partial — tool.execute.before throws to block; permission.ask sets allow or deny |
no |
| Confirmation prompt before a policy-file edit | yes | no — no ask; deny or allow | no — preToolUse denies only |
yes | no — deny only | partial — permission.ask |
no |
Commands: init, doctor, allow, rules, remind, restate |
yes | yes — skills | yes — skills | yes — skills | partial — TOML commands | partial — command files | no |
restate capture of the rejected reply |
yes | untested — needs the prompt hook to read Codex’s transcript | no — no prompt-time hook output | untested — transcript format | yes — BeforeAgent receives the prompt; the reply needs Gemini’s history |
untested | no |
Commit gate, /init, /doctor, config-adjusted reminder text |
yes | yes | yes | yes | yes | yes | commit gate only |
- Codex
SessionStartcarriessourcewithstartup,resume,clear,compact, andfork, and acceptsadditionalContext. - Cursor’s
preCompactis observational andsessionStarthas no source field, so the rules cannot be re-injected after compaction from a hook. - Copilot’s
preCompactprocesses no output. - OpenCode’s
experimental.chat.system.transformappends to the system prompt. Rules present on every request covers startup, compaction, and the post-violation prompt at once, at the cost of the report riding a system prompt instead of a user turn. - Codex documents
additionalContextonSubagentStart. - Copilot’s
userPromptSubmittedoutput is dropped for config-file hooks; only SDK hooks modify the prompt.userPromptTransformedreturnsmodifiedTransformedPrompt, which replaces what the model receives, so an adapter could append the rules there. Unverified. - Codex delivers edits as patch strings in
tool_input.command. The adapter parses out added lines before linting, whichedit-ranges.jsdoes not do today.
Sacrifices by harness: Cursor and Copilot lose the prompt-time re-injection, so the report has to ride the next context start or a tool result. Codex and Gemini lose the confirmation prompt on policy files and fall back to deny or allow. OpenCode has no gate at the end of a turn, so block mode for files and replies does not exist there.