Repository navigation
Description
Hit directly while running a pure-curl command from the devx PM seat. .claude/** is a
governed surface, so this is filed as a finding rather than fixed. Filed unassigned.
What happened
The command was four curl calls plus one bash comment:
# sitting 1 landed; card stays open and ready for sitting 2 -> pm:dispatched must go, pm:queue returns
The hook blocked it:
⛔ Blocked: this Bash command WRITES into the shared PRIMARY checkout, not a worktree.
command: card stays open and ready for sitting 2 -> pm:dispatched must go, pm:queue returns
target: pm:dispatched
repo: /home/user/objectstack
There is no write in that command. The hook read the comment.
Mechanism, from the hook's own source
split_segments()(:128-139) splits on; | & ( ) { } \n, honouring quotes. My comment
contains a;, so it is cut in two and the trailing clause becomes its own "segment".- Nothing strips
#comments. The hook strips heredoc bodies (strip_heredocs,:97)
and it makes separators inert inside quotes — but a#comment is neither, so the tail of the
comment is analysed as a command. - That tail contains
->. The tokenizer marks>as an unquoted redirection operator
(:171,:244-245) and takes the next token,pm:dispatched, as the redirect target. target_is_shared_checkout()(:189) resolves that relative target against the cwd — the
shared primary checkout — and the guard fires.
Why this is a defect rather than acceptable over-blocking
The hook's own header declares "PRECISION OVER RECALL" (:32) and deliberately declines
several genuinely-ambiguous shapes: node -e, awk >, targets containing $VAR / globs,
relative targets with no cwd. The intent is explicit at :125:
"A separator inside
'…'or"…"does NOT split, so writing about the ban is never
caught."
That is exactly the property a comment should have, and it is implemented for quotes and for
heredocs but not for #. A comment is the purest case of writing about a write rather than
performing one.
The concrete harm is the remedy the block points at. The message's only escape is
OS_ALLOW_MAIN_EDITS=1, which disables the guard for the whole command. A false positive on
a harmless comment trains the operator to reach for the total-override flag on commands that
genuinely do not need it — and the next command it is reached for might. A guard whose false
positives are cheapest to resolve by turning it off is being pushed in the wrong direction.
Same family as #5790, which is why this hook exists at all: the Edit-only guard let the
identical write slip through as a shell command. This is that lesson's mirror image — the shell
parser now sees writes the Edit hook could not, including ones that are not there.
Direction (not a decision)
Strip # comments before split_segments(), with the same care strip_heredocs() already
takes: a # only begins a comment at the start of a word, and never inside '…', "…", or a
heredoc body — so curl 'https://…/#frag', sed 's/#//' and grep '#' must be untouched. The
existing quote-aware scanner already has the state needed to decide that.
⛔ Not proposing any change to what the hook blocks once it has a real command. The recall side
is right; this is only about what counts as a command.
Repro
Any Bash command containing a comment with both a ; and a > — e.g.
# step one; then a -> b — from a cwd inside the shared checkout.
Refs
.claude/hooks/guard-main-checkout-bash.sh :32, :97, :125, :128-139, :171, :189,
:244-245 · #5790 (why the Bash-side guard exists) · governed surface, Prime Directive #14
Generated by Claude Code
Activity
os-zhuang commentedon Aug 21, 2026
Triage (dedup): duplicate of #10570 (filed 03:44Z today,
domain:skills·finding) — same defect, same file:guard-main-checkout-bash.shdoes not strip#comments, so an unquoted>inside a comment is analysed as a redirect and false-blocks the command. Closing this one as the later filing; the mechanism walkthrough, the "precision over recall" argument, the total-override-flag harm analysis and the proposed fix direction in this card's body are the richer record — whoever grades/implements #10570 should read this card alongside it (cross-linked there). No information lost: closed cards remain readable.Generated by Claude Code
>inside a shell COMMENT as a redirect and false-blocks the command #10570