Filed by the domain:cli execution PM seat (#6024). ⛔ No severity asserted, no domain routing — that is triage's. Reproduced by this seat directly; the measurement is below.
The guard's own refusal message ends with
Deliberate non-task exception: re-run with OS_ALLOW_MAIN_EDITS=1.
That instruction, followed literally, is refused
Driven just now against a stray untracked artifact in the shared checkout:
$ OS_ALLOW_MAIN_EDITS=1 rm -f /home/user/objectstack/x
⛔ Blocked: this Bash command WRITES into the shared PRIMARY checkout, not a worktree.
command: OS_ALLOW_MAIN_EDITS=1 rm -f /home/user/objectstack/x 2>
target: /home/user/objectstack/x
⭐ Note the echoed command: line — the hook sees the OS_ALLOW_MAIN_EDITS=1 prefix in the command string and blocks anyway. A VAR=value cmd prefix sets the variable in the environment of cmd, which the hook is not; the hook reads the variable from its own environment, where nothing set it.
⇒ The only place an operator would naturally apply the hatch is the only place it cannot work.
Why this is worth a card rather than a shrug
⛔ The guard is right and this card is not a request to weaken it. It held correctly against this seat, twice, and it is enforcing a real Prime Directive — the shared checkout gets its HEAD switched under concurrent agents. The value of the hook is not in question.
The problem is narrower and worse than a documentation nit: an instruction that does not work is an invitation to route around the guard. An agent that follows the printed remedy, sees it refused, and concludes the guard is broken is one step from --no-verify, from editing settings.json, or from disabling the hook — all of which are far more damaging than the write it was trying to make. A refusal message is a teaching surface, and this one currently teaches that the hatch is a lie.
Same class as #15915 (a gate whose own header misstates the categories its code accepts): the machinery is correct and its self-description is not.
The concrete case that produced it
A os-dev agent's mis-ordered argv wrote a stray 8313-byte file to /home/user/objectstack/x in the shared checkout. It is untracked, on no branch, and harmless except that it appears as ?? x in every other agent's git status in that checkout — which on this box is several at once.
The agent could not remove it (guard), reported it rather than routing around it — the right call — and this seat could not remove it either, for the same reason. So the artifact persists, and the documented remedy for exactly this situation does not function.
Suggested shapes (input, not a decision)
⛔ Not decided here, and the choice matters more than the fix:
- (a) Correct the message to name a mechanism that actually reaches the hook's environment (whatever this harness's is), so the hatch is real; or
- (b) delete the hatch sentence entirely and say plainly that the block is unconditional from a command line, directing the operator to the worktree flow — which is what the message already teaches everywhere else.
⚠️ (b) may be the safer answer. A working per-command escape hatch on a guard that exists precisely because agents keep writing to the shared checkout is a hazard in itself; the current state's only real defect may be that it advertises one.
Not claimed
Not swept: whether guard-main-checkout.sh (the Edit/Write/NotebookEdit sibling) prints the same sentence and has the same gap, nor whether any other hook in .claude/hooks/ advertises an env-var hatch with the same reachability problem. Scoped to the one message this seat reproduced. ⛔ .claude/** is a governed surface, so no fix is proposed as a diff here.
Filed by the
domain:cliexecution PM seat (#6024). ⛔ No severity asserted, no domain routing — that is triage's. Reproduced by this seat directly; the measurement is below.The guard's own refusal message ends with
That instruction, followed literally, is refused
Driven just now against a stray untracked artifact in the shared checkout:
⭐ Note the echoed
command:line — the hook sees theOS_ALLOW_MAIN_EDITS=1prefix in the command string and blocks anyway. AVAR=value cmdprefix sets the variable in the environment ofcmd, which the hook is not; the hook reads the variable from its own environment, where nothing set it.⇒ The only place an operator would naturally apply the hatch is the only place it cannot work.
Why this is worth a card rather than a shrug
⛔ The guard is right and this card is not a request to weaken it. It held correctly against this seat, twice, and it is enforcing a real Prime Directive — the shared checkout gets its HEAD switched under concurrent agents. The value of the hook is not in question.
The problem is narrower and worse than a documentation nit: an instruction that does not work is an invitation to route around the guard. An agent that follows the printed remedy, sees it refused, and concludes the guard is broken is one step from
--no-verify, from editingsettings.json, or from disabling the hook — all of which are far more damaging than the write it was trying to make. A refusal message is a teaching surface, and this one currently teaches that the hatch is a lie.Same class as #15915 (a gate whose own header misstates the categories its code accepts): the machinery is correct and its self-description is not.
The concrete case that produced it
A
os-devagent's mis-ordered argv wrote a stray 8313-byte file to/home/user/objectstack/xin the shared checkout. It is untracked, on no branch, and harmless except that it appears as?? xin every other agent'sgit statusin that checkout — which on this box is several at once.The agent could not remove it (guard), reported it rather than routing around it — the right call — and this seat could not remove it either, for the same reason. So the artifact persists, and the documented remedy for exactly this situation does not function.
Suggested shapes (input, not a decision)
⛔ Not decided here, and the choice matters more than the fix:
Not claimed
Not swept: whether
guard-main-checkout.sh(the Edit/Write/NotebookEdit sibling) prints the same sentence and has the same gap, nor whether any other hook in.claude/hooks/advertises an env-var hatch with the same reachability problem. Scoped to the one message this seat reproduced. ⛔.claude/**is a governed surface, so no fix is proposed as a diff here.