[BUG] Claude Desktop (Windows) silently kills run_in_background tasks after 15-min idle — WarmLifecycle taskkills the embedded CLI process tree
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
On Claude Desktop for Windows (build 1.12603.1, bundled Claude Code agent 2.1.170), any task started with run_in_background is silently killed after the session has been idle (tab/window hidden) for ~15 minutes. No error is shown, and the Desktop background-task list still reports the task as running. Only tasks started inside Desktop are affected — the same task started from the standalone CLI (~/.local/bin/claude, v2.1.177) or via OS-level scheduling survives.
Root cause (traced in …\Claude_1.12603.1…\app\resources\app.asar): the Desktop wraps the embedded CLI in a WarmLifecycle manager instantiated with idleTimeoutMs: 900*1e3 (15 min), timeoutOnHidden: true, armOnTurnComplete: "when-hidden". When the session tab is hidden and the idle timer fires, it runs:
onDisconnect → pauseSession → teardownSession(id, "pause") → teardownQuery → query.close()
On Windows, query.close() terminates the spawned claude.exe via taskkill /pid <pid> /T /F. The /T flag kills the entire process tree, so the CLI's run_in_background child processes are force-killed along with it. Re-interacting calls warmSession, which spawns a fresh CLI with a new PID (the PID change confirms this). Because teardownQuery only nulls the async handles (activeWorkflows, pendingGitBashIds, …) without reconciling task state, the background-task list keeps showing running (related: #18390, #59962).
This is a design behavior of Desktop's idle session-recycling, not a transient crash. macOS is likely affected too via the process.kill(-pid, "SIGTERM") branch (process-group kill).
What Should Happen?
Idle session recycling should not silently destroy work the user explicitly backgrounded. Either:
- Don't tear down the CLI process tree while it has live
run_in_backgroundtasks, or - Detach
run_in_backgroundchildren from the CLI process group so they survive aWarmLifecyclepause/re-warm, and/or - At minimum, when the process tree is killed, reconcile background-task state to
failed/killedinstead of leaving it stuck atrunning, and surface a notification to the user.
Error Messages/Logs
No error is produced — the silent kill IS the bug. Relevant Desktop-side evidence:
Analytics/log event emitted on the idle path:
desktop_ccd_session_idle_paused { trigger: "idle_timeout", idle_timeout_ms: 900000, ... }
Decompiled code (app.asar, build 1.12603.1):
new eWA({ idleTimeoutMs: 900*1e3, timeoutOnHidden: true,
onDisconnect: t => this.pauseSession(t),
onWarmUp: t => this.warmSession(t), ... })
scheduleIdleTimeout(e,t){ e.idleTimeoutId = setTimeout(async()=>{
if(this.config.armOnTurnComplete==="when-hidden" && e.isTabVisible) return;
... // → onDisconnect → pauseSession
}, t) }
teardownSession(e,t){ ... if(s.query){ this.teardownQuery(s); if(t==="pause"){ ...emit "paused" } } }
teardownQuery(e){ try{ e.query?.close() }catch{} ; e.activeWorkflows=void 0; e.pendingGitBashIds=void 0; ... }
// Windows process teardown inside query.close():
process.platform==="win32"
? spawn("taskkill",["/pid",String(pid),"/T","/F"],{windowsHide:true})
: process.kill(-pid,"SIGTERM")
Steps to Reproduce
- Open Claude Desktop for Windows (build 1.12603.1), start a Code session in any project.
- Have Claude start a long-running background task, e.g.:
run_in_background a loop that appends a timestamp to a log file every 10s
(PowerShell: while($true){ (Get-Date).ToString('o') | Out-File -Append .\timer.log; Start-Sleep 10 }).
- Note the PID of the spawned
claude.exeand its child shell process in Task Manager. - Switch to another app so the Claude Desktop session tab/window is hidden; leave it idle.
- After ~15 minutes of idle (hidden), observe:
- The background task's child process is gone from Task Manager; the
claude.exePID has changed. timer.logstops growing — no error anywhere.- The Desktop background-task list still shows the task as "running".
Control: run the exact same task from the standalone CLI (claude in a terminal) or via Windows Task Scheduler → it keeps running indefinitely. Only the Desktop-spawned path is affected.
Claude Model
Not sure / Multiple models
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
Claude Desktop 1.12603.1 (Windows); bundled Claude Code agent 2.1.170.
Platform
Anthropic API
Operating System
Windows
Terminal/Shell
Other
Additional Information
_No response_
Showing cached comments. Read the full discussion on GitHub ↗
4 Comments
Found 1 possible duplicate issue:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
This would be nice to get fixed as it is very frustrating.
Happened to me on MacOS CLI
Environment: Claude Code CLI 2.1.205, macOS 26.5.1 (Darwin 25.5.0), plain terminal (not the Desktop app).
I had two
run_in_backgroundtasks running (a Vite dev server and a long-running poller). After being away ~90 min, both were killed with SIGTERM (Terminated: 15). A couple of details from what's described above, in case they're useful:Follow-up on the standalone-CLI case above — and on the root cause.
Same environment as my earlier comment (Claude Code CLI on macOS, plain terminal).
The root issue is the lifecycle-initiated kill resting on a false assumption. The harness reaps
run_in_backgroundtasks after idle because it assumes a lingering process is abandoned and safe to clean up. But the harness has no way to know that. Plenty of background tasks — a dev server, a file watcher, a poller — are supposed to keep running precisely while the user steps away. Treating "idle" as "these processes are garbage" is wrong, and it kills exactly the long-lived tasks people start background jobs for.On top of that, the kill spins up an unprompted, token-burning loop:
Terminated: 15) after idle.killednotification auto-re-invokes the agent — a full turn the user never asked for.Each iteration is a full agent turn, minutes apart, so the prompt cache is cold and the entire context is re-read uncached every time. The user is spending money, while away, on the harness fighting its own reaper.
What would fix it, in order of preference:
killednotification (#45781) so the agent doesn't treat a lifecycle kill as a crash and relaunch into the loop.The through-line: the harness should not terminate work it can't prove is abandoned, and it should never spend the user's tokens on activity the user didn't initiate.