MonoCode version: 0.1.44
OS: macOS 26.6.2
Provider CLI: Claude Code 2.1.270
Correction: my original diagnosis was wrong — cd is not the trigger, and I could not reproduce my own steps. The real trigger is the 5-minute idle park. Original text struck through below, corrected report after it.
What happened (superseded)
Changing the working directory mid-session respawns the harness, and the respawn SIGKILLs the previous process group. Every process the agent had backgrounded dies with it, exit 137, with no error surfaced anywhere.
1. src-tauri/src/harness.rs:750 — the harness child gets process_group(0)
2. src/lib/harness/claude.ts:345 — a cwd change forces a fresh spawn
3. src-tauri/src/harness.rs:143, :332 — installing the new spawn calls terminate(prev.pid)
4. src-tauri/src/harness.rs:865 — that sends kill(-pid, SIGKILL) to the whole group
Backgrounded work is a grandchild in that group, so it is reaped too. nohup does not help; SIGKILL cannot be caught.
Steps to reproduce (superseded)
1. cd /tmp/dir-a 2. sleep 600 & 3. cd /tmp/dir-b 4. Job is gone, exit 137.
Suggested fix (superseded)
src-tauri/src/pty.rs:273 already does the right thing for terminals: setsid() puts each shell in its own session so it outlives the harness.
Corrected report
What happens
registry.ts:137 arms HARNESS_IDLE_PARK_MS (5 min, registry.ts:76) in the finally of every turn. If no new message arrives before it fires, registry.ts:91 calls stopHarnessSession → stopClaudeSession → killChild → terminate(pid) → kill(-pid, SIGKILL) (harness.rs:776). The whole group goes: the CLI process, its in-process subagents, and anything the agent backgrounded.
The timer measures silence, not idleness. A session busy with a background workflow or a long script reads as idle.
Steps to reproduce
- Ask the agent to start background work lasting more than 5 minutes — a background workflow, or a
run_in_background shell loop.
- Let the turn end.
- Send nothing for 5 minutes.
- Everything is gone.
Evidence
- Controlled: two background agents, each ticking every 10 seconds toward 600s. Both stopped right around 300 — 4:50 and 4:40 of real runtime.
- Real, twice: a research workflow lost 4 of 11 agents 5:00.32 after its turn ended; an App Store upload session lost 3 background pollers at 5:00.45, 5:00.22 and 5:00.32 after theirs.
Why it's a bug
Parking an idle session is reasonable — it resumes on the next message. The defect is that nothing checks for work in flight before the kill.
A guard for exactly this already exists: claude.ts:1268 holds the turn open while live.agentTasks is non-empty, which is why foreground work is safe. Backgrounded tasks don't register there, so the turn settles and the timer arms underneath them.
setsid() alone would not fix it. It would save shell-backgrounded jobs, but subagents run inside the CLI process — no child PIDs under it in any of my tests — so parking kills them whatever their process group.
The kill mechanism described in the original report still holds; only the trigger was wrong.
MonoCode version: 0.1.44
OS: macOS 26.6.2
Provider CLI: Claude Code 2.1.270
What happened(superseded)Changing the working directory mid-session respawns the harness, and the respawn SIGKILLs the previous process group. Every process the agent had backgrounded dies with it, exit 137, with no error surfaced anywhere.1.src-tauri/src/harness.rs:750— the harness child getsprocess_group(0)2.src/lib/harness/claude.ts:345— a cwd change forces a fresh spawn3.src-tauri/src/harness.rs:143,:332— installing the new spawn callsterminate(prev.pid)4.src-tauri/src/harness.rs:865— that sendskill(-pid, SIGKILL)to the whole groupBackgrounded work is a grandchild in that group, so it is reaped too.nohupdoes not help; SIGKILL cannot be caught.Steps to reproduce(superseded)1.cd /tmp/dir-a2.sleep 600 &3.cd /tmp/dir-b4. Job is gone, exit 137.Suggested fix(superseded)src-tauri/src/pty.rs:273already does the right thing for terminals:setsid()puts each shell in its own session so it outlives the harness.Corrected report
What happens
registry.ts:137armsHARNESS_IDLE_PARK_MS(5 min,registry.ts:76) in thefinallyof every turn. If no new message arrives before it fires,registry.ts:91callsstopHarnessSession→stopClaudeSession→killChild→terminate(pid)→kill(-pid, SIGKILL)(harness.rs:776). The whole group goes: the CLI process, its in-process subagents, and anything the agent backgrounded.The timer measures silence, not idleness. A session busy with a background workflow or a long script reads as idle.
Steps to reproduce
run_in_backgroundshell loop.Evidence
Why it's a bug
Parking an idle session is reasonable — it resumes on the next message. The defect is that nothing checks for work in flight before the kill.
A guard for exactly this already exists:
claude.ts:1268holds the turn open whilelive.agentTasksis non-empty, which is why foreground work is safe. Backgrounded tasks don't register there, so the turn settles and the timer arms underneath them.setsid()alone would not fix it. It would save shell-backgrounded jobs, but subagents run inside the CLI process — no child PIDs under it in any of my tests — so parking kills them whatever their process group.The kill mechanism described in the original report still holds; only the trigger was wrong.