Skip to content

fix(hook): pass the post-tool entry when the installed discipline predates it - #785

Merged
orieg merged 2 commits into
mainfrom
claude/objective-rhodes-38d596
Oct 16, 2026
Merged

orieg merged 2 commits into
mainfrom
claude/objective-rhodes-38d596

Conversation

@orieg

@orieg orieg commented Oct 16, 2026

Copy link
Copy Markdown
Owner

Closes #784

What

The post-tool entry discipline hook install writes (since v0.22.0) now checks the installed release first: discipline hook run --help 2>/dev/null | grep -q post-tool || { echo '<notice>' >&2; exit 0; }. A release before v0.22.0 does not list post-tool in its help, so the entry prints one line on stderr and exits 0 instead of running --event post-tool.

Why

A release before v0.22.0 rejects --event post-tool with a clap usage error and exit 2. Claude Code treats exit 2 from a PostToolUse hook as a blocking error, so every shell call in a repository with v0.22.0 hook files reported "PostToolUse:Bash hook blocking error" on a machine with discipline 0.20.0 on PATH. The post-tool witness never blocks by design, so skipping it changes no verdict.

The pre-tool, check and session-start entries are unchanged and keep failing closed. The OpenCode plugin is unchanged: it already ignores the witness's exit code (READ). A v0.22.0 hook file without the check is still recognised as generated, so --upgrade rewrites it. A file with the check in front of any other entry is not recognised as generated. .claude/settings.json, .agents/hooks.json and .github/hooks/discipline.json are regenerated with hook install --observe --upgrade. The ledger row is | unreleased | (bug fix).

Evidence

  • RUN: the regenerated .claude/settings.json post-tool command, run through sh with discipline 0.20.0 on PATH, prints discipline on PATH predates v0.22.0 (no --event post-tool); the post-tool hook did not run (...) and exits 0. With this branch's binary on PATH it exits 0 with no notice.
  • RUN: new e2e test the_post_tool_entry_passes_with_a_release_that_predates_it (tests/test_agent_hooks.rs). It covers Claude Code, Codex, Qwen Code, Copilot CLI and agy and runs each installed post-tool entry with a fake older discipline on PATH.
    • The entry exits 0, stderr is exactly the notice, and the fake never receives --event post-tool.
    • Control: without the check, the same fake exits 2.
    • A fake that lists post-tool gets the witness call.
    • This release's hook run --help lists post-tool.
  • RUN, mutation: replacing grep -q post-tool with an always-matching grep -q possible makes that e2e test fail. The mutant was restored.
  • RUN, mutation: accepting the check in front of any entry in json_command makes the new unit test the_post_tool_release_probe_is_read_on_the_witness_only fail. The mutant was restored.
  • RUN: cargo fmt --check, cargo clippy --all-targets -- -D warnings and cargo test --no-fail-fast all passed before the merge from main. After merging main, cargo test --test test_agent_hooks --test test_docs passes.

allow-agent-instructions: .claude/settings.json the post-tool entry skips with a notice when the installed discipline predates v0.22.0
allow-agent-instructions: .agents/hooks.json the post-tool entry skips with a notice when the installed discipline predates v0.22.0
allow-agent-instructions: .github/hooks/discipline.json the post-tool entry skips with a notice when the installed discipline predates v0.22.0

orieg added 2 commits October 16, 2026 13:22
…dates it

A release before v0.22.0 rejects `hook run --event post-tool` with a clap
usage error and exit 2. Claude Code reports exit 2 from a PostToolUse hook
as a blocking error, so every shell call in a repository whose hook files
come from v0.22.0 failed on a machine with an older discipline on PATH
(seen live with Homebrew discipline 0.20.0).

The generated post-tool entry now first runs `discipline hook run --help`
and, when it does not list `post-tool`, says so in one line on stderr and
exits 0. The witness never blocks by design, so this changes no verdict.
The pre-tool, check and session-start entries are unchanged. The OpenCode
plugin already ignores the witness's exit code and is unchanged.

A v0.22.0 file without the probe is still read as a release's (so
`--upgrade` rewrites it); the probe in front of any other entry is not.
The repository's hook files are regenerated with `hook install --observe
--upgrade`.

Signed-off-by: Nicolas Brousse <nicolas@brousse.info>
…es-38d596

Signed-off-by: Nicolas Brousse <nicolas@brousse.info>

# Conflicts:
#	docs/ROADMAP.md
@orieg
orieg enabled auto-merge (squash) October 16, 2026 20:48
@orieg
orieg merged commit cc790e6 into main Oct 16, 2026
25 checks passed
@orieg
orieg deleted the claude/objective-rhodes-38d596 branch October 16, 2026 21:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Post-tool hook entry fails on a discipline older than v0.22.0

1 participant