examples/hooks: demonstrate compound-command pre-flight with deny-and-steer in the bash validator example#76289
Open
ss251 wants to merge 2 commits into
Open
Conversation
…ator hook Extend the PreToolUse bash validator example to detect compound command shapes (chaining, pipes, command substitution, find -exec, xargs, compose redirects) and deny with construct-specific guidance steering the model to split into separate Bash calls, using the hook's existing stderr + exit 2 contract. Quoted strings and heredoc bodies are excluded from scanning; an opt-in allowlist permits read-only pipe filters. Adds dependency-free unittest coverage. Mitigates the silent headless auto-deny UX tracked in anthropics#31523 from the user side. AI-assisted (Codex gpt-5.6-terra worker, Claude-supervised). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01J8NGaAFCBE4HLGLojEwvvy
…ing caveat Address cross-provider review: N>, N>>, >&, &>, and N>&M no longer trigger the compose-redirect rule (ls 2>/dev/null and make 2>&1 pass; steer text for plain file redirects stays coherent alongside fd dups); unquoted newlines outside heredoc bodies now count as chaining; add a naive-lexing honesty caveat and note the intentional grep-pipe behavior change. Locks all cases in with 5 new tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01J8NGaAFCBE4HLGLojEwvvy
This was referenced Jul 10, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Extends
examples/hooks/bash_command_validator_example.pyto demonstrate compound-command pre-flighting: the hook detects command chaining (;,&&,||, unquoted newlines), pipelines (with an opt-in allowlist for read-only filters likehead/wc), active command substitution,find -exec,xargs, and plain-file compose redirects — and denies with construct-specific guidance steering Claude to split the operation into separate Bash calls, using the hook's existing stderr + exit-2 contract.Motivation
Claude Code's permission analyzer can reject compound Bash commands; interactive sessions get a prompt, but headless/unattended sessions can drop the denied action silently (#31523 tracks that UX). A user-side PreToolUse hook can pre-empt this deterministically: catch the compound shape before the analyzer sees it and steer the model to equivalent single commands. This pattern comes from field use — in our own session transcripts we counted 50+ silent denials that this pre-flight would have converted into actionable steers. The existing example only style-lints
grep/find, so it was the natural home to demonstrate the pattern.This example does not change or claim to fix the CLI's analyzer.
What changed
find -exec,xargs,>/>>/teefile composition.git commit -m "fix: a && b",awk '{print $1;}') pass; heredoc bodies are not scanned; backslash-newline continuations pass; file-descriptor redirects (2>/dev/null,2>&1,&>,N>>,exec 3>&1) are excluded so everyday single commands are never denied.git add -Aandgit commit -m xas two separate Bash calls.").grepis now caught by the pipe rule rather than exempted) is noted in a comment.&detection) and users should tune the rules.unittestcases exercising the real hook via subprocess (test_bash_command_validator_example.py).Validation
python3 -m py_compileclean on both files; 20/20 tests green.ls 2>/dev/null→ exit 0;make 2>&1→ exit 0;git add -A && git commit -m x→ exit 2 with split guidance;python3 script.py > out.log 2>&1→ exit 2 with steer naming onlyout.log; newline-separated command pair → exit 2; heredoc containinga && b→ exit 0.AI-assisted: implemented by a Codex (gpt-5.6-terra) worker agent, adversarially reviewed by a fresh-context Claude Opus verifier (initial REJECT drove the fd-redirect and newline fixes above), human-supervised. We run this hook pattern daily on our own machines.