Summary
needle stop --all exits non-zero and prints an error naming still-running PIDs whether or not the workers actually stopped. The message, the exit code, and the PIDs it lists are all unreliable — only an external pgrep after a short delay reveals the true state.
Observed nine times over two days on the same machine: three genuine orphans requiring a manual kill, six workers that had already exited by the time pgrep ran five seconds later. The output was indistinguishable in both cases.
Environment
needle 0.6.0
bead-rs 0.2.4
Ubuntu 22.04.5 LTS on WSL2 (Windows 11)
Python 3.10.12, pytest 6.2.5, tmux
Workspace: git repo with a remote, bead-rs backend bound via `needle bead-backend-bind`
Reproduction
needle run --agent claude --identifier alpha
# let it claim and complete a bead
needle stop --all; echo "exit=$?"
sleep 5
pgrep -af "needle run" || echo clean
Actual output (worker had in fact exited)
Error: 1 needle process(es) still running after kill attempt for session 'needle-claude-alpha':
PID 11469: /home/aperna/.local/bin/needle run --agent claude --count 1 --identifier alpha
no server running on /tmp/tmux-1000/default
Error: needle-claude-alpha - kill attempt reported success but 1 process(es) still running
clean
The tmux session is already gone (no server running), the error names PID 11469, and pgrep five seconds later finds nothing. When the worker genuinely is orphaned, the output is identical.
Worse with multiple workers
With --count 3, each session's stop attempt lists all three PIDs, so the error repeats three times — nine false-alarm lines, zero actual orphans:
Error: 3 needle process(es) still running after kill attempt for session 'needle-claude-alpha':
PID 12568: ... --identifier alpha
PID 12611: ... --identifier bravo
PID 12721: ... --identifier charlie
can't find session: needle-claude-alpha
Error: needle-claude-alpha - kill attempt reported success but 3 process(es) still running
[... repeated for bravo and charlie ...]
clean
The per-session error appears to enumerate the global process list rather than that session's own processes.
Impact
Not merely cosmetic. On 2026-08-30 a worker survived needle stop --all. Because the error looks identical to the harmless case, it was assumed stopped. It continued running after the session ended, completed a bead, wrote a file, and pushed a commit unattended. Work was done that nobody was watching, and nothing in the audit trail indicates the operator believed the system was halted.
For anyone considering unattended or scheduled runs, "did it actually stop" is a question the command currently cannot answer.
Suggested fix
- Poll for process exit for a few seconds before deciding the stop failed, so a graceful shutdown in progress is not reported as a failure.
- Scope each session's error to that session's own PIDs.
- Exit 0 when no processes remain; reserve non-zero for genuine orphans.
- If a definitive answer is not possible, say so rather than asserting failure — e.g. "shutdown signalled; verify with
pgrep -af 'needle run'".
Current workaround
needle stop --all; sleep 5; pgrep -af "needle run" || echo clean
# only if pgrep itself reports a PID:
kill <that PID>; sleep 5; pgrep -af "needle run" || echo clean
Never kill the PID named in the error — it may already be dead, and the number could have been recycled.
Summary
needle stop --allexits non-zero and prints an error naming still-running PIDs whether or not the workers actually stopped. The message, the exit code, and the PIDs it lists are all unreliable — only an externalpgrepafter a short delay reveals the true state.Observed nine times over two days on the same machine: three genuine orphans requiring a manual kill, six workers that had already exited by the time
pgrepran five seconds later. The output was indistinguishable in both cases.Environment
Reproduction
Actual output (worker had in fact exited)
The tmux session is already gone (
no server running), the error names PID 11469, andpgrepfive seconds later finds nothing. When the worker genuinely is orphaned, the output is identical.Worse with multiple workers
With
--count 3, each session's stop attempt lists all three PIDs, so the error repeats three times — nine false-alarm lines, zero actual orphans:The per-session error appears to enumerate the global process list rather than that session's own processes.
Impact
Not merely cosmetic. On 2026-08-30 a worker survived
needle stop --all. Because the error looks identical to the harmless case, it was assumed stopped. It continued running after the session ended, completed a bead, wrote a file, and pushed a commit unattended. Work was done that nobody was watching, and nothing in the audit trail indicates the operator believed the system was halted.For anyone considering unattended or scheduled runs, "did it actually stop" is a question the command currently cannot answer.
Suggested fix
pgrep -af 'needle run'".Current workaround
Never kill the PID named in the error — it may already be dead, and the number could have been recycled.