[BUG] --print mode hangs indefinitely when team agents (in_process_teammate) are used
Description
When using --print (non-interactive) mode with team agents (TeamCreate + Agent with team_name), the session hangs indefinitely after the lead agent finishes its work. The lead's do-while loop in the print mode controller treats in_process_teammate tasks as blocking background tasks that must complete before exiting, but team agents persist across turns (their status stays "running"), so the loop never terminates.
Steps to Reproduce
claude --print "Create a team with 2 agents, have them each send a broadcast, then shut them all down"
Or programmatically:
claude --print --output-format stream-json \
"Spawn a team of 2 agents, have a quick standup, then gracefully shutdown all teammates"
Expected Behavior
After all team agents are shut down (via shutdown_request → shutdown_response with approve: true), the --print session should exit cleanly.
Actual Behavior
The session hangs forever. Even after all teammates have shut down and their tasks are marked complete, the do-while loop continues spinning because it checks for any task with status === "running" — and in_process_teammate tasks remain in the running state throughout their lifecycle.
Root Cause
In the print mode controller (ITz / print.ts logic in bundled cli.js), the do-while exit condition checks:
// npm version (minified):
Kv8(K1).some((D1) => lP(D1))
// native binary (less minified):
function AER(T) {
for (let R of Object.values(T.tasks))
if (R.type === "in_process_teammate" && R.status === "running")
return true;
return false;
}
This returns true for any running in_process_teammate, which keeps the outer do-while loop spinning. The loop was designed for short-lived background tasks (bash, subagents) that naturally complete, but team agents are long-lived — they stay "running" across wake/idle cycles and only terminate on explicit shutdown.
Suggested Fix
Exclude in_process_teammate tasks from the do-while active-task check:
// Before:
tasks.some((task) => isActive(task))
// After:
tasks.some((task) => isActive(task) && task.type !== "in_process_teammate")
Team agent lifecycle is already managed by the shutdown protocol (shutdown_request → shutdown_response). The do-while loop should only block on tasks that are expected to naturally complete (bash commands, subagents).
Workaround
Patch the npm-distributed cli.js (plain-text JS) to add the in_process_teammate exclusion. This is not possible with the native Bun binary — same-length byte replacement causes the binary to hang on startup due to integrity checks. Details in the patch script below.
<details>
<summary>Patch script (for npm version only)</summary>
CLI_JS="$(npm root -g)/@anthropic-ai/claude-code/cli.js"
cp "$CLI_JS" "$CLI_JS.bak"
node -e "
const fs = require('fs');
let src = fs.readFileSync('$CLI_JS', 'utf8');
// Exclude in_process_teammate from do-while active-task check
const old1 = 'Kv8(K1).some((D1)=>lP(D1))';
const new1 = 'Kv8(K1).some((D1)=>lP(D1)&&D1.type!==\"in_process_teammate\")';
if (src.includes(old1)) {
src = src.replace(old1, new1);
fs.writeFileSync('$CLI_JS', src);
console.log('Patched successfully');
}
"
Note: The minified variable names (Kv8, lP, D1) are version-specific. This patch was tested against v2.1.63.
</details>
Environment
- Claude Code version: 2.1.63
- OS: macOS Darwin 25.2.0 (Apple Silicon)
- Installation: Both native binary (
~/.local/share/claude/versions/2.1.63) and npm (@anthropic-ai/claude-code@2.1.63) - Mode:
--print(non-interactive)
Additional Context
- The native Bun binary has the same JS logic with different (less minified) variable names, but cannot be patched — even same-length byte replacement causes the binary to fail integrity checks and hang on startup.
- Related issue: #26426 (inbox polling in non-interactive mode — different code path, same feature area)
- Two additional improvements were applied alongside the main fix:
- Poll timeout: 60s safety net to force exit if shutdown stalls
- Reset the shutdown-injected flag between turns to allow retry
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗