Monitor Daemon
The claude-cleanup monitor subcommand runs cleanup on a schedule so you never have to remember to do it yourself. It’s a thin, detached Node process that wakes up on an interval, runs the same --all cleanup the CLI does, and appends a timestamped line per cycle to a log file.
Subcommands#
| Command | Does |
|---|---|
claude-cleanup monitor start |
Fork a detached daemon. Errors out if one is already running. |
claude-cleanup monitor stop |
Send SIGTERM and wait up to 5s for the PID file to disappear. |
claude-cleanup monitor status |
Print the PID + log-file size, or tell you nothing is running. |
claude-cleanup monitor reset |
stop, then delete the log file. Useful when the log grew unexpectedly. |
start options#
| Flag | Default | Description |
|---|---|---|
--interval <v> |
15m |
How often to run a cleanup cycle |
--age <v> |
2h |
Staleness threshold, same format as the top-level CLI |
--foreground |
false |
Don’t detach — inherit stdio. Alias: --fg |
Example — aggressive settings while debugging:
claude-cleanup monitor start --interval 1m --age 10m --fg
File layout#
The daemon keeps two files next to your Claude config:
| File | Role |
|---|---|
~/.claude/claude-cleanup-monitor.pid |
PID of the running daemon. Removed on SIGTERM / exit. |
~/.claude/claude-cleanup-monitor.log |
Append-only log, one line per cycle. |
Both paths are exported from the package for callers that want to tail/monitor them from elsewhere:
import { MONITOR_PID_FILE, MONITOR_LOG_FILE } from 'claude-cleanup';
Log output looks like:
[2026-04-20T14:15:00.123Z] ═══════════════════════════════════════════════
[2026-04-20T14:15:00.124Z] claude-cleanup monitor started
[2026-04-20T14:15:00.124Z] PID: 12345
[2026-04-20T14:15:00.124Z] Interval: 15m
[2026-04-20T14:15:00.124Z] Age: 2h
[2026-04-20T14:15:00.124Z] ═══════════════════════════════════════════════
[2026-04-20T14:15:00.310Z] [killed] PID 99123 — stale 3h 14m — ~/projects/foo
[2026-04-20T14:15:00.312Z] Cycle complete. Killed 1, skipped 0 dead.
Lifecycle details#
- Detaching.
monitor startspawns the daemon withdetached: trueandstdiopointed at the log file, then callsunref()so your shell can exit without killing it. - PID file discipline. The daemon writes its PID on startup and clears it on
SIGTERMor normal exit. Restart-after-crash works because subsequentstartinvocations useprocess.kill(pid, 0)to check whether the PID file is stale, and clean it up if the process is gone. - Shutdown.
stopsendsSIGTERM, the daemon clears its interval and removes the PID file inside the signal handler, and thenstoppolls the PID file for up to 5 seconds before printing a warning. - No auto-restart. This is deliberately dumb — if the host reboots, you need to start it again. If you want supervision, wire it up with launchd / systemd /
pm2; the daemon emits exit codes and stays on stderr in--fgmode.
Scheduling with launchd / systemd#
If you’d rather let the OS supervise it instead of running it detached, pair monitor start --fg with a launchd agent (macOS) or user-level systemd service (Linux). An outline:
macOS — ~/Library/LaunchAgents/dev.craigory.claude-cleanup.plist:
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/claude-cleanup</string>
<string>monitor</string>
<string>start</string>
<string>--fg</string>
<string>--interval</string>
<string>15m</string>
<string>--age</string>
<string>2h</string>
</array>
<key>RunAtLoad</key><true/>
<key>KeepAlive</key><true/>
Load it with launchctl load ~/Library/LaunchAgents/dev.craigory.claude-cleanup.plist.
Linux — ~/.config/systemd/user/claude-cleanup.service:
[Unit]
Description=claude-cleanup monitor
[Service]
ExecStart=/usr/bin/env claude-cleanup monitor start --fg --interval 15m --age 2h
Restart=on-failure
[Install]
WantedBy=default.target
Enable with systemctl --user enable --now claude-cleanup.
Troubleshooting#
- “Monitor is already running” when you’re sure it isn’t: delete
~/.claude/claude-cleanup-monitor.pidor runclaude-cleanup monitor reset. The daemon cleans this up itself on normal exit, but akill -9will leave it behind. - Log file growing too fast: lower the interval (
--interval 1h), or rotate the file withlogrotatepointing at~/.claude/claude-cleanup-monitor.log.monitor resetis the nuclear option. - Sessions aren’t being killed: run the foreground CLI with the same age threshold —
claude-cleanup --age 2h— and confirm the sessions show up asstalerather thanactive. Remember that “age” is measured from the last line in the JSONL conversation log, not the session-file mtime.