Worktree command guard refuses pipeline agents' os-sdlc-subagent-stop calls #1096

Open
opened 2026-10-17 22:08:10 +00:00 by jared · 5 comments
Owner

Problem

In a worktree-isolated session the PreToolUse command guard refuses commands it cannot verify as staying inside the worktree. It refuses the pipeline agents' os-sdlc-subagent-stop calls, so a gated agent cannot submit its handoff and the Runner records a placeholder as a pass.

Observed

During implementation 61 the change-auditor ran os-sdlc-subagent-stop --json <multi-kilobyte payload>. The guard refused it four times. The agent then submitted a placeholder handoff. The Runner recorded dispatch 527 as verdict pass with an empty items list. Downstream nodes would have run on no audit. The orchestrator abandoned run 61 and reopened as run 62. The guard also refused the orchestrator's python3 -I - <<'EOF' heredocs and one cat > file <<'EOF' write.

os-sdlc-subagent-stop --json '<4 KB JSON handoff>'
This session is isolated in the worktree /home/jared/dev/cc-os/.claude/worktrees/ticket-1093, but this command is too complex to verify that it stays inside the worktree. Refusing to run it — a worktree-isolated session's git operations must target its own worktree. Split it into plain, separate commands and run them from /home/jared/dev/cc-os/.claude/worktrees/ticket-1093.

Reproduce

os-sdlc-subagent-stop --json '<a 4 KB JSON handoff>'

Run it in a worktree-isolated session.

Approach

Boot::Inputs.subagent_stop accepts --json-file PATH beside --json and stdin. The agent writes the handoff to a file and submits a short command. The guard allows every os-sdlc-* bin regardless of argument length, because these bins never run git.

Required work:

  1. Boot::Inputs.subagent_stop reads the handoff from --json-file PATH — check: present json-file in plugins/os-sdlc/lib/os_sdlc/boot/inputs.rb
  2. Agent briefs tell gated agents to write the handoff to a file and submit os-sdlc-subagent-stop --json-file PATH, never a placeholder — check: present --json-file in plugins/os-sdlc/agents/*.md

Orchestrator work: allowlist the os-sdlc-* bins in the worktree PreToolUse guard in plugin os (plugins/os/skills/worktree/SKILL.md describes it).

Acceptance criteria

  1. Given a 4 KB handoff written to a file in a worktree session, when the agent runs os-sdlc-subagent-stop --json-file PATH, then the Runner records the full handoff.
  2. Given any os-sdlc-* command in a worktree session, when its arguments exceed the guard's complexity limit, then the guard does not refuse it.
  3. Given the guard refuses a stop call, when the agent reads its instructions, then they tell it to use --json-file rather than a placeholder.

Owner sketch

Boot::Inputs.subagent_stop reads --json-file. The worktree guard in plugin os holds the os-sdlc-* allowlist.

Origin

  • Trigger: /os-sdlc:implement 1093, implementation runs 61 and 62, 2026-10-17
  • Improvised this session: the orchestrator asked the agent to return the YAML as reply text and re-ran the audit in a fresh implementation.
  • Chain: placeholder pass recorded ← stop call refused ← guard judges by command length and shape ← DESIGN (plugins/os/skills/worktree/SKILL.md guard; plugins/os-sdlc/lib/os_sdlc/boot/inputs.rb subagent_stop accepts --json or stdin)
  • Root candidate: this ticket
  • Where: plugins/os-sdlc/lib/os_sdlc/boot/inputs.rb (subagent_stop) and the worktree PreToolUse guard in plugin os
  • Session: 909d1bcd-dd81-408f-8581-5c682b1a742d
  • Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os/909d1bcd-dd81-408f-8581-5c682b1a742d.jsonl
  • Parent: #1093 (closed, AI-created)
  • Skeptic: VERDICT: CREATE
## Problem In a worktree-isolated session the PreToolUse command guard refuses commands it cannot verify as staying inside the worktree. It refuses the pipeline agents' `os-sdlc-subagent-stop` calls, so a gated agent cannot submit its handoff and the Runner records a placeholder as a pass. ## Observed During implementation 61 the change-auditor ran `os-sdlc-subagent-stop --json <multi-kilobyte payload>`. The guard refused it four times. The agent then submitted a placeholder handoff. The Runner recorded dispatch 527 as verdict pass with an empty items list. Downstream nodes would have run on no audit. The orchestrator abandoned run 61 and reopened as run 62. The guard also refused the orchestrator's `python3 -I - <<'EOF'` heredocs and one `cat > file <<'EOF'` write. ``` os-sdlc-subagent-stop --json '<4 KB JSON handoff>' ``` ``` This session is isolated in the worktree /home/jared/dev/cc-os/.claude/worktrees/ticket-1093, but this command is too complex to verify that it stays inside the worktree. Refusing to run it — a worktree-isolated session's git operations must target its own worktree. Split it into plain, separate commands and run them from /home/jared/dev/cc-os/.claude/worktrees/ticket-1093. ``` ## Reproduce ``` os-sdlc-subagent-stop --json '<a 4 KB JSON handoff>' ``` Run it in a worktree-isolated session. ## Approach `Boot::Inputs.subagent_stop` accepts `--json-file PATH` beside `--json` and stdin. The agent writes the handoff to a file and submits a short command. The guard allows every `os-sdlc-*` bin regardless of argument length, because these bins never run git. Required work: 1. `Boot::Inputs.subagent_stop` reads the handoff from `--json-file PATH` — check: present `json-file` in `plugins/os-sdlc/lib/os_sdlc/boot/inputs.rb` 2. Agent briefs tell gated agents to write the handoff to a file and submit `os-sdlc-subagent-stop --json-file PATH`, never a placeholder — check: present `--json-file` in `plugins/os-sdlc/agents/*.md` Orchestrator work: allowlist the `os-sdlc-*` bins in the worktree PreToolUse guard in plugin os (`plugins/os/skills/worktree/SKILL.md` describes it). ## Acceptance criteria 1. Given a 4 KB handoff written to a file in a worktree session, when the agent runs `os-sdlc-subagent-stop --json-file PATH`, then the Runner records the full handoff. 2. Given any `os-sdlc-*` command in a worktree session, when its arguments exceed the guard's complexity limit, then the guard does not refuse it. 3. Given the guard refuses a stop call, when the agent reads its instructions, then they tell it to use `--json-file` rather than a placeholder. ## Owner sketch `Boot::Inputs.subagent_stop` reads `--json-file`. The worktree guard in plugin os holds the `os-sdlc-*` allowlist. ## Origin - Trigger: /os-sdlc:implement 1093, implementation runs 61 and 62, 2026-10-17 - Improvised this session: the orchestrator asked the agent to return the YAML as reply text and re-ran the audit in a fresh implementation. - Chain: placeholder pass recorded ← stop call refused ← guard judges by command length and shape ← DESIGN (plugins/os/skills/worktree/SKILL.md guard; plugins/os-sdlc/lib/os_sdlc/boot/inputs.rb subagent_stop accepts --json or stdin) - Root candidate: this ticket - Where: plugins/os-sdlc/lib/os_sdlc/boot/inputs.rb (subagent_stop) and the worktree PreToolUse guard in plugin os - Session: 909d1bcd-dd81-408f-8581-5c682b1a742d - Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os/909d1bcd-dd81-408f-8581-5c682b1a742d.jsonl - Parent: #1093 (closed, AI-created) - Skeptic: VERDICT: CREATE
Author
Owner

Resolution

Done: Mechanism: the os-sdlc-subagent-stop --json command is refused by the worktree guard or harness, and the agent improvises. Occurrences: #848 "Pipeline agents without Write cannot submit a handoff that contains the word git from a worktree session"; #854 "Handoff stop refused by the worktree guard when its text contains git".

Evidence: #848 adds #844 impl 9 dispatch 75: read-only agents (contract-auditor, change-auditor, behavior-verifier, reviewer, test-reviewer, seam-designer) have no Write tool to move the handoff into a file. #854 adds #852 impl 16 dispatch 128: three forms (--json, cd && --json, heredoc) refused because the JSON named a git command.

Follow-ups: none

## Resolution **Done:** Mechanism: the os-sdlc-subagent-stop --json command is refused by the worktree guard or harness, and the agent improvises. Occurrences: #848 "Pipeline agents without Write cannot submit a handoff that contains the word git from a worktree session"; #854 "Handoff stop refused by the worktree guard when its text contains git". **Evidence:** #848 adds #844 impl 9 dispatch 75: read-only agents (contract-auditor, change-auditor, behavior-verifier, reviewer, test-reviewer, seam-designer) have no Write tool to move the handoff into a file. #854 adds #852 impl 16 dispatch 128: three forms (--json, cd && --json, heredoc) refused because the JSON named a git command. **Follow-ups:** none
Author
Owner

Occurrence: Worktree command filter refuses runtime-variable operands and long quoted text, so pipeline agents submit stub handoffs.
Seen: change-auditor dispatch 895 in implementation 113 (ticket 1234) recorded only a stub handoff (summary: x, verdict: fail) after the filter refused its stop command; the run escalated and was rerouted. The ticket-skeptic agent for this very occurrence could not run its backlog search: every Bash call was refused ("working directory resolved to the shared checkout"). Posting this comment with --body inline was refused too ("cannot be shown not to be git"); it went through --body-file.
Run: session 9feaee0d-e0ed-4f5a-85b4-db1166f8539a, implementations 113 and 114.
Adds: the refusal fires on any $VAR path operand (sed, cat), on long quoted text in a plain command, and on subagents whose cwd resolves to the main checkout, not only on the stop command. Workaround used: a prompt note on every dispatch to spell out literal paths and write handoff YAML with the Write tool.

Occurrence: Worktree command filter refuses runtime-variable operands and long quoted text, so pipeline agents submit stub handoffs. Seen: change-auditor dispatch 895 in implementation 113 (ticket 1234) recorded only a stub handoff (summary: x, verdict: fail) after the filter refused its stop command; the run escalated and was rerouted. The ticket-skeptic agent for this very occurrence could not run its backlog search: every Bash call was refused ("working directory resolved to the shared checkout"). Posting this comment with --body inline was refused too ("cannot be shown not to be git"); it went through --body-file. Run: session 9feaee0d-e0ed-4f5a-85b4-db1166f8539a, implementations 113 and 114. Adds: the refusal fires on any $VAR path operand (sed, cat), on long quoted text in a plain command, and on subagents whose cwd resolves to the main checkout, not only on the stop command. Workaround used: a prompt note on every dispatch to spell out literal paths and write handoff YAML with the Write tool.
Author
Owner

Occurrence: Keep a subagent-stop handoff from being refused by the worktree guard
Seen: plugins/os-sdlc/agents/behavior-verifier.md:49 (stop command form)
Run: implementation 134 (#1266), dispatch 1146, session 4f3f95ea-3c6f-4d23-a0ea-e349d6ab02a5
Adds: The Runner stayed at await_completion with no stall, so the run waited without a signal. Workaround that worked: SendMessage to the same agent asking it to resend single-quoted JSON with no dollar sign, backticks, =>, <, >, or pipe characters in the content.

Occurrence: Keep a subagent-stop handoff from being refused by the worktree guard Seen: plugins/os-sdlc/agents/behavior-verifier.md:49 (stop command form) Run: implementation 134 (#1266), dispatch 1146, session 4f3f95ea-3c6f-4d23-a0ea-e349d6ab02a5 Adds: The Runner stayed at await_completion with no stall, so the run waited without a signal. Workaround that worked: SendMessage to the same agent asking it to resend single-quoted JSON with no dollar sign, backticks, =>, <, >, or pipe characters in the content.
Author
Owner

Occurrence: Worktree guard false positive refuses os-sdlc-subagent-stop when inline handoff YAML contains "git merge-base"
Seen: worktree PreToolUse guard; refusal text "cannot be shown not to be git"
Run: dispatch 1394, implementation 161 (session eb98cdcd-6783-46a0-b7df-cf18a8fe2a56, 2026-10-25)
Adds: a different trigger text (the words "git merge-base" inside the handoff YAML). Writing the YAML to a file and passing it worked. Effect: a green programmer dispatch could not submit its handoff.

Occurrence: Worktree guard false positive refuses os-sdlc-subagent-stop when inline handoff YAML contains "git merge-base" Seen: worktree PreToolUse guard; refusal text "cannot be shown not to be git" Run: dispatch 1394, implementation 161 (session eb98cdcd-6783-46a0-b7df-cf18a8fe2a56, 2026-10-25) Adds: a different trigger text (the words "git merge-base" inside the handoff YAML). Writing the YAML to a file and passing it worked. Effect: a green programmer dispatch could not submit its handoff.
Author
Owner

Occurrence: Worktree guard blocks os-sdlc-subagent-stop with a JSON payload, so Bash-only pipeline agents cannot submit their handoff
Seen: the worktree-isolation PreToolUse Bash guard, behavior-verifier dispatch 1625, implementation 184, ticket #1404
Run: session 47f54f99-e35c-4567-a3e6-581fecf54dc3
Adds: the agent tried four forms with no "git" substring in any payload (--json, reworded --json, heredoc to a file, stdin from the missing file); all but the last were refused. This disproves the "git substring" reading in handoff 2026-10-27-1540. The orchestrator relayed the unchanged payload from a file written with the Write tool via stdin, which the Runner accepted. The guard also refused the orchestrator's own multi-line os-backlog comment body in this worktree. Same fault as #1415.

Occurrence: Worktree guard blocks os-sdlc-subagent-stop with a JSON payload, so Bash-only pipeline agents cannot submit their handoff Seen: the worktree-isolation PreToolUse Bash guard, behavior-verifier dispatch 1625, implementation 184, ticket #1404 Run: session 47f54f99-e35c-4567-a3e6-581fecf54dc3 Adds: the agent tried four forms with no "git" substring in any payload (--json, reworded --json, heredoc to a file, stdin from the missing file); all but the last were refused. This disproves the "git substring" reading in handoff 2026-10-27-1540. The orchestrator relayed the unchanged payload from a file written with the Write tool via stdin, which the Runner accepted. The guard also refused the orchestrator's own multi-line os-backlog comment body in this worktree. Same fault as #1415.
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#1096
No description provided.