Pipeline agents cannot submit handoffs in a worktree-isolated session: the guard refuses the subagent-stop heredoc #819

Closed
opened 2026-09-28 22:07:59 +00:00 by jared · 3 comments
Owner

Problem

Agent charters tell each pipeline agent to submit its handoff with a heredoc piped into os-sdlc-subagent-stop. When the orchestrating session is isolated in a worktree (EnterWorktree, or a session started inside one), the Claude Code worktree guard refuses that command. Agents with a Write tool can write the payload to a file and redirect it. Agents without a Write tool (test-reviewer, behavior-verifier, suite-check, contract-auditor) cannot submit at all. The dispatch stays open and returns no next_step.

Observed

Implementation 71 (#814), 2026-09-28. Dispatch 707 (change-auditor) was refused 3 times, the last with a minimal heredoc and an empty items list:

This session is isolated in the worktree ..., but this command runs os-sdlc-subagent-stop with a value computed at runtime ... inside a construct too complex to verify ... Refusing to run it

Dispatch 710 (test-reviewer) has no Write tool, so it could not create the payload file. The orchestrator submitted 7 of 10 handoffs by hand. It copied the YAML from the agent's final output into a JSON file and ran os-sdlc-subagent-stop --target os-sdlc < file. A plain redirect passes the guard. Session b505a812 (#808, implementation 67) hit the same guard and used a scratchpad submit-handoff.rb.

Reproduce

/os-sdlc:implement <ticket>   # from a session isolated in a worktree

Origin

  • Trigger: /os-sdlc:implement 814 in a worktree-isolated session
  • Improvised this session: agents returned YAML in a fenced block; an orchestrator script built the payload file and redirected it into os-sdlc-subagent-stop
  • Chain: handoff not recorded <- guard refuses a heredoc with a runtime value <- charters prescribe heredoc submission and read-only agents have no other channel <- DESIGN (agent charter submission contract) and UPSTREAM-TOOL (Claude Code worktree guard)
  • Root candidate: this ticket
  • Where: plugins/os-sdlc/agents/*.md submission section; plugins/os-sdlc/bin/os-sdlc-subagent-stop
  • Session: 47a537c2-08a1-4d3c-9688-75df56dfdd3d
  • Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os--claude-worktrees-ticket-808/47a537c2-08a1-4d3c-9688-75df56dfdd3d.jsonl
  • Related: #814, #527

VERDICT: CREATE
REASON: This is an observed failure that a second session (b505a812, #808) also hit. The guard is an upstream tool, not something this session caused. Read-only agents cannot submit handoffs at all, so dispatches stay open. The charters' heredoc submission contract is the DESIGN cause, and the chain does not end in IMPROVISATION.

## Problem Agent charters tell each pipeline agent to submit its handoff with a heredoc piped into `os-sdlc-subagent-stop`. When the orchestrating session is isolated in a worktree (EnterWorktree, or a session started inside one), the Claude Code worktree guard refuses that command. Agents with a Write tool can write the payload to a file and redirect it. Agents without a Write tool (test-reviewer, behavior-verifier, suite-check, contract-auditor) cannot submit at all. The dispatch stays open and returns no `next_step`. ## Observed Implementation 71 (#814), 2026-09-28. Dispatch 707 (change-auditor) was refused 3 times, the last with a minimal heredoc and an empty items list: ``` This session is isolated in the worktree ..., but this command runs os-sdlc-subagent-stop with a value computed at runtime ... inside a construct too complex to verify ... Refusing to run it ``` Dispatch 710 (test-reviewer) has no Write tool, so it could not create the payload file. The orchestrator submitted 7 of 10 handoffs by hand. It copied the YAML from the agent's final output into a JSON file and ran `os-sdlc-subagent-stop --target os-sdlc < file`. A plain redirect passes the guard. Session b505a812 (#808, implementation 67) hit the same guard and used a scratchpad `submit-handoff.rb`. ## Reproduce ``` /os-sdlc:implement <ticket> # from a session isolated in a worktree ``` ## Origin - Trigger: /os-sdlc:implement 814 in a worktree-isolated session - Improvised this session: agents returned YAML in a fenced block; an orchestrator script built the payload file and redirected it into os-sdlc-subagent-stop - Chain: handoff not recorded <- guard refuses a heredoc with a runtime value <- charters prescribe heredoc submission and read-only agents have no other channel <- DESIGN (agent charter submission contract) and UPSTREAM-TOOL (Claude Code worktree guard) - Root candidate: this ticket - Where: plugins/os-sdlc/agents/*.md submission section; plugins/os-sdlc/bin/os-sdlc-subagent-stop - Session: 47a537c2-08a1-4d3c-9688-75df56dfdd3d - Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os--claude-worktrees-ticket-808/47a537c2-08a1-4d3c-9688-75df56dfdd3d.jsonl - Related: #814, #527 VERDICT: CREATE REASON: This is an observed failure that a second session (b505a812, #808) also hit. The guard is an upstream tool, not something this session caused. Read-only agents cannot submit handoffs at all, so dispatches stay open. The charters' heredoc submission contract is the DESIGN cause, and the chain does not end in IMPROVISATION.
Author
Owner

Resolution

Done: os-sdlc-subagent-stop accepts the handoff as --json '' (one simple command, no heredoc, no pipe, no file). All ten charters use it; apostrophes are written as ' in JSON. Stdin stays for the SubagentStop hook. Root cause: the Claude Code worktree guard refuses any non-simple Bash command, and #706 had only moved the heredoc from a file write into the stop command.

Evidence: main 3764b363 + c5328d62 (merged ed3b8295). cli_subagent_stop_test 22 runs 0 failures incl. --json success and invalid-JSON cases; probes exit 3 missing_dispatch_id as designed; no charter contains <<'JSON'. Full suite 1328 runs, 0 failures.

Follow-ups: none

Needs review: Live check: in a session that entered a worktree with EnterWorktree, run one pipeline dispatch and confirm the harness guard accepts os-sdlc-subagent-stop --json ''. This session was not worktree-isolated, so the guard never ran.

## Resolution **Done:** os-sdlc-subagent-stop accepts the handoff as --json '<payload>' (one simple command, no heredoc, no pipe, no file). All ten charters use it; apostrophes are written as ' in JSON. Stdin stays for the SubagentStop hook. Root cause: the Claude Code worktree guard refuses any non-simple Bash command, and #706 had only moved the heredoc from a file write into the stop command. **Evidence:** main 3764b363 + c5328d62 (merged ed3b8295). cli_subagent_stop_test 22 runs 0 failures incl. --json success and invalid-JSON cases; probes exit 3 missing_dispatch_id as designed; no charter contains <<'JSON'. Full suite 1328 runs, 0 failures. **Follow-ups:** none Needs review: Live check: in a session that entered a worktree with EnterWorktree, run one pipeline dispatch and confirm the harness guard accepts os-sdlc-subagent-stop --json '<payload>'. This session was not worktree-isolated, so the guard never ran.
jared referenced this issue from a commit 2026-09-29 16:46:31 +00:00
Author
Owner

Live run evidence, 2026-09-29: /os-sdlc:implement 827 (implementation 78) ran from a worktree-isolated session (EnterWorktree on .claude/worktrees/ticket-827). All 8 dispatches (775-782) submitted their own handoffs and returned next_step, including the read-only agents test-reviewer (778), behavior-verifier (780), suite-check (781) and contract-auditor (782). The orchestrator submitted zero handoffs by hand. The worktree guard refused no subagent-stop call. Result: implementation_complete in 6 min 8 s, 0 retries.

Live run evidence, 2026-09-29: /os-sdlc:implement 827 (implementation 78) ran from a worktree-isolated session (EnterWorktree on .claude/worktrees/ticket-827). All 8 dispatches (775-782) submitted their own handoffs and returned next_step, including the read-only agents test-reviewer (778), behavior-verifier (780), suite-check (781) and contract-auditor (782). The orchestrator submitted zero handoffs by hand. The worktree guard refused no subagent-stop call. Result: implementation_complete in 6 min 8 s, 0 retries.
Author
Owner

Resolution

Done: The needs-review live check passed. In a worktree-isolated session, every pipeline agent submitted its handoff with os-sdlc-subagent-stop --json and the worktree guard accepted it.

Evidence: Live run 2026-09-29 (comment 13:05): /os-sdlc:implement 827, implementation 78, EnterWorktree on .claude/worktrees/ticket-827. Dispatches 775-782 all self-submitted and returned next_step, including read-only test-reviewer 778, behavior-verifier 780, suite-check 781, contract-auditor 782. Zero guard refusals, zero hand submissions; implementation_complete, 0 retries. Code: main 3764b363 + c5328d62 (merged ed3b8295).

Follow-ups: none

## Resolution **Done:** The needs-review live check passed. In a worktree-isolated session, every pipeline agent submitted its handoff with os-sdlc-subagent-stop --json and the worktree guard accepted it. **Evidence:** Live run 2026-09-29 (comment 13:05): /os-sdlc:implement 827, implementation 78, EnterWorktree on .claude/worktrees/ticket-827. Dispatches 775-782 all self-submitted and returned next_step, including read-only test-reviewer 778, behavior-verifier 780, suite-check 781, contract-auditor 782. Zero guard refusals, zero hand submissions; implementation_complete, 0 retries. Code: main 3764b363 + c5328d62 (merged ed3b8295). **Follow-ups:** none
jared closed this issue 2026-09-30 11:22:30 +00:00
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#819
No description provided.