PreToolUse guard: reject unquoted zsh EQUALS and glob tokens in Bash tool commands #562

Open
opened 2026-09-11 20:31:19 +00:00 by jared · 1 comment
Owner

Context

The Bash tool shell is zsh. Two zsh options break agent-written commands: EQUALS expands an unquoted word starting with = as a command lookup, and NOMATCH errors on an unquoted glob with no match. Agents hit this at least four times: three entries in docs/os-sdlc-rebuild/interface-sketches.md, and the responsibility-auditor run of 2026-09-11 ((eval):1: === not found), plus the main session (no matches found: --include=*.rb). Each time the agent re-ran a rephrased command. No root cause or fix was ever recorded. OsSdlc::BashGuard (plugins/os-sdlc/lib/os_sdlc/bash_guard.rb) checks mutation and scope only; it has no shell-syntax check.

Observed

Commands such as echo ===STOP or grep --include=*.rb fail with (eval):1: ... not found or no matches found. Retries waste a turn each time.

Reproduce

echo ===STOP
(eval):1: === not found

Expected

  • Add a deterministic PreToolUse check beside BashGuard that rejects any unquoted token starting with = or containing an unquoted *, ?, or [ outside a quoted span, reusing BashGuard's quoted-span stripping.
  • Rejection message tells the agent to quote the token and names the zsh option (EQUALS or NOMATCH).
  • Unit tests for both cases and for quoted tokens passing.
  • A rubocop cop is not applicable: these are shell strings in tool calls, not Ruby source. A global unsetopt was rejected because it changes the user's interactive shell.

Origin

  • Trigger: Bash tool command failures in zsh with EQUALS/NOMATCH options
  • Improvised this session: Agents re-ran rephrased commands (multiple retries)
  • Chain: Agents hitting this → zsh EQUALS/NOMATCH options → OsSdlc::BashGuard lacks shell-syntax check → DESIGN (ADR-0172 hooks-as-pipes)
  • Root candidate: This ticket
  • Where: plugins/os-sdlc/lib/os_sdlc/bash_guard.rb
  • Session: 3615bdb2-1809-42fc-9997-dc8734583302
  • Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os/3615bdb2-1809-42fc-9997-dc8734583302.jsonl
## Context The Bash tool shell is zsh. Two zsh options break agent-written commands: EQUALS expands an unquoted word starting with `=` as a command lookup, and NOMATCH errors on an unquoted glob with no match. Agents hit this at least four times: three entries in docs/os-sdlc-rebuild/interface-sketches.md, and the responsibility-auditor run of 2026-09-11 (`(eval):1: === not found`), plus the main session (`no matches found: --include=*.rb`). Each time the agent re-ran a rephrased command. No root cause or fix was ever recorded. `OsSdlc::BashGuard` (plugins/os-sdlc/lib/os_sdlc/bash_guard.rb) checks mutation and scope only; it has no shell-syntax check. ## Observed Commands such as `echo ===STOP` or `grep --include=*.rb` fail with `(eval):1: ... not found` or `no matches found`. Retries waste a turn each time. ## Reproduce ``` echo ===STOP ``` ``` (eval):1: === not found ``` ## Expected - Add a deterministic PreToolUse check beside BashGuard that rejects any unquoted token starting with `=` or containing an unquoted `*`, `?`, or `[` outside a quoted span, reusing BashGuard's quoted-span stripping. - Rejection message tells the agent to quote the token and names the zsh option (EQUALS or NOMATCH). - Unit tests for both cases and for quoted tokens passing. - A rubocop cop is not applicable: these are shell strings in tool calls, not Ruby source. A global `unsetopt` was rejected because it changes the user's interactive shell. ## Origin - Trigger: Bash tool command failures in zsh with EQUALS/NOMATCH options - Improvised this session: Agents re-ran rephrased commands (multiple retries) - Chain: Agents hitting this → zsh EQUALS/NOMATCH options → OsSdlc::BashGuard lacks shell-syntax check → DESIGN (ADR-0172 hooks-as-pipes) - Root candidate: This ticket - Where: plugins/os-sdlc/lib/os_sdlc/bash_guard.rb - Session: 3615bdb2-1809-42fc-9997-dc8734583302 - Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os/3615bdb2-1809-42fc-9997-dc8734583302.jsonl
Author
Owner

Checked 2026-09-11 against the recent BashGuard quoting fix (commit 07bb036, tickets #543/#550). That fix stopped the guard from reading quoted data as commands. This ticket is a different mechanism: zsh itself rejects the unquoted token. Reproduced after that fix: zsh -c 'echo ===STOP' prints zsh:1: ==STOP not found, exit 1; the quoted form prints ===STOP. User preference recorded: fix the agent instructions (quote any token that starts with = or contains a glob) before adding a PreToolUse check. Low priority.

Checked 2026-09-11 against the recent BashGuard quoting fix (commit 07bb036, tickets #543/#550). That fix stopped the guard from reading quoted data as commands. This ticket is a different mechanism: zsh itself rejects the unquoted token. Reproduced after that fix: `zsh -c 'echo ===STOP'` prints `zsh:1: ==STOP not found`, exit 1; the quoted form prints ===STOP. User preference recorded: fix the agent instructions (quote any token that starts with = or contains a glob) before adding a PreToolUse check. Low priority.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
jared/cc-os#562
No description provided.