Scheduled-task cron fires leak Claude Code processes + API session state
Summary
Each cron-triggered scheduled-task fire spawns a new Claude Code process that never exits after the task completes. Over hours these accumulate, holding local RAM and active Anthropic API session state that bills against the account. On 10 May 2026 I discovered 78 orphan processes consuming 5.6 GB of RAM on a single laptop, accumulated over a few hours of normal scheduled-task operation. Account-level token usage continued to drain ~2% even after the local cleanup was visible — suggesting server-side sessions remain billed.
Reproduction
- Create a scheduled task via the
mcp__scheduled-tasks__create_scheduled_taskMCP with a frequent cron (e.g.*/5 * * * *) - Let it run for an hour without quitting Claude Code
- Inspect:
``bash`
ps -eo pid,etime,command | grep 'claude.app/Contents/MacOS/claude' | grep -v -- '--resume'
claude
You will see many orphan processes, paired by start time (parent + child), with no --resume` flag. Each is the residue of one cron fire.
Observed pattern
- Each fire produces a pair of processes (parent + child) holding ~70 MB RAM
- Process count grows linearly with
(cron_frequency × time_since_quit) - API session state appears to remain active on the server side (visible in account usage)
- Killing the orphan PIDs locally reclaims memory but cannot recover the already-billed tokens
Expected behaviour
A scheduled-task fire should: spawn process → run task → exit cleanly, releasing both the local process and the server-side API session.
Impact
- 78 orphan processes / 5.6 GB RAM on one laptop
- ~150 MB of accumulated JSONL session files written to disk in a single day
- Visible 2%+ account token drain continuing after user reported the issue
- iMessage plugin reuses one session ID indefinitely — accumulated to 40 MB over 10 days, replayed in full on every incoming text
Workaround in place
I built a Bash sweeper that kills orphan processes (no --resume flag, age >10 min) and runs 3×/day via another scheduled task. Happy to share the script. This is patching a real bug — please prioritise the upstream fix.
Suggested fix
The scheduled-task runner should:
- Wait for the spawned Claude process to exit after task completion
- If the process hasn't exited within N seconds of task completion, SIGTERM it
- Confirm server-side that the API session is closed
Environment
- macOS Sonoma 14.x, Apple Silicon
- Claude Code 2.1.128
- ~30 scheduled tasks defined; ~6 active
- Plugins: telegram, imessage, oh-my-claudecode, chrome-devtools-mcp, and others
permission-mode: bypassPermissionsset globally
Related
Separate-but-related: the iMessage plugin (~/.claude/plugins/cache/claude-plugins-official/imessage/0.1.0) reuses one session ID indefinitely. Over 10 days that session accumulated to 40 MB and was replayed in full on every incoming text. Worth auditing other long-running plugin servers (telegram, etc.) for the same pattern.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗