Your Claude Code routine left 618 sessions behind. Mine deletes them while I sleep.
One line from a Show HN thread has been living in my head: "Claude Code's
scheduled tasks (routines) leaves a session behind on every run and in the
desktop app you can only delete them one at a time. We had 618 open sessions
in just one routine."
An hourly routine makes 700+ sessions a month. They pile up in the routine's
Runs list, eat disk, and slow the app down when it loads them — and the only
official way to remove them is clicking delete 618 times.
So I built the other shape of the fix: not a skill you drive by hand, but a
zero-dependency CLI that runs unattended on a schedule and prunes the pile by
policy.
routine-sweeper — pip install routine-sweeper
(GitHub,
PyPI)
routine-sweeper status # paths, is the app running, counts
routine-sweeper scan # list routine runs and their status
routine-sweeper sweep # print the deletion plan (changes nothing)
routine-sweeper sweep --yes # apply it
How it finds routine runs
Every session is an append-only JSONL transcript under
~/.claude/projects/<project>/<session-id>.jsonl. A routine-started session
opens with a kickoff message of the form:
<scheduled-task name="my-routine" file="...">
The sweeper streams each transcript once: the kickoff identifies the routine,
and any later human-typed message marks the run "engaged". Deletion removes
the transcript, its sidecar directory, and its entry in the
~/.claude/sessions/ live registry.
The safety policy (this is the whole design)
- Only routine runs are ever candidates. Ordinary sessions are invisible to the planner, no matter how aggressive the flags.
-
Runs you replied in are protected. Tool results, skill loads, and
harness-injected entries don't count — only something a person typed.
--include-engagedopts in explicitly. - Live sessions and runs active in the last 15 minutes are never touched.
- Whitelist routine names, session ids, or fnmatch patterns.
-
Dry-run preview by default.
sweepprints the plan and deletes nothing until--yes.
The one thing you must know
The desktop app keeps its Runs list in memory. Delete a run's files while
the app is running and the app can write its in-memory record back to disk —
the run comes back as a "Session not found on disk" ghost. So sweep --yes
refuses while the app is running. Schedule it when the app is closed:
# every night at 3:05am, keep 10 newest runs per routine
5 3 * * * routine-sweeper sweep --yes >> ~/.claude/sweeper.log 2>&1
When the app is closed its in-memory list is rebuilt from disk on next
launch, so swept runs stay gone. If you want instant deletion while the app
is open, that's a different tool: naw103's
claude-routine-cleanup
skill deletes through the app's own session tool with per-batch approval
cards. Ours is for the pile never growing back.
Also in the neighborhood: sdlc-skills' config-gc — a skill that garbage
collects Claude Code config bloat with a strict "never delete
autonomously, every candidate gets [y/n/skip]" rule. Different domain,
opposite posture: routine-sweeper is designed for unattended scheduled runs,
with protection expressed as policy instead of per-item prompts.
Honest limitations
The transcript format is internal and undocumented — detection rests on the
kickoff marker as observed today, and if a future Claude Code release changes
it, the tool does nothing rather than guess. Deletion is permanent; there is
no trash. And Claude Code's own cleanupPeriodDays (default 30) already
prunes old history by age — the sweeper is for the runs you want gone sooner,
or deliberately kept longer.
Stdlib only, everything local, MIT licensed. 17 fixture-based tests, all
green. If your routines have been quietly stacking up sessions for months —
this is the cron job.
Top comments (0)