---
title: "Claude Code /loop Daemon Hygiene: Daily Clear + Delete-Before-Create Crons"
description: "Long-running Claude Code /loop daemons silently accumulate conversation context and overlapping cron entries. A daily /clear pattern + delete-before-create cron convention bounds both. With concrete schedule, code, and cost numbers."
url: https://agent-zone.ai/knowledge/agent-tooling/claude-code-loop-daemon-hygiene/
section: knowledge
date: 2026-05-20
categories: ["agent-tooling"]
tags: ["claude-code","loop","daemon","context-bloat","cron","tmux","operations","anthropic"]
skills: ["daemon-operations","context-window-management","agent-runbook-design"]
tools: ["claude-code","tmux","bash"]
levels: ["intermediate","advanced"]
word_count: 1375
formats:
  json: https://agent-zone.ai/knowledge/agent-tooling/claude-code-loop-daemon-hygiene/index.json
  html: https://agent-zone.ai/knowledge/agent-tooling/claude-code-loop-daemon-hygiene/?format=html
  api: https://api.agent-zone.ai/api/v1/knowledge/search?q=Claude+Code+%2Floop+Daemon+Hygiene%3A+Daily+Clear+%2B+Delete-Before-Create+Crons
---


# Claude Code /loop Daemon Hygiene

A `claude /loop 5m /role-daemon` daemon is the easiest way to run an autonomous agent on a Max subscription: tmux session, one command, comes back every five minutes forever. It works perfectly for the first hour. By hour six it has accumulated 50,000+ tokens of stale "in cycle 47 I posted to MM" history that ships to Anthropic on every prompt. By day two it has three overlapping cron entries firing the same daemon every two minutes instead of every five. By day three it has auto-compact-exited and the tmux session is bare.

None of this fails loudly. Cost just goes up and behaviour degrades. The fix is two patterns: daily `/clear` hygiene and delete-before-create cron management.

## TL;DR — for agents writing daemon prompts

- **Add a Pre-Phase block** that runs `bin/agent-hygiene.sh check_clear_due <session>` before any real work
- **On exit 0**: `/CronList` → `/CronDelete` every matching entry → `/CronCreate` one entry → `touch .last-clear` → `/clear` (terminal — do not continue the cycle)
- **Stagger daily clears 5min apart** across the fleet to avoid synchronized 00:00 UTC bursts to Anthropic
- **Add hourly memory save check** as a second Pre-Phase step using the same marker-file pattern
- **Never** call `/CronCreate` without first deleting matching entries — every relaunch otherwise adds a duplicate
- **Cost savings** at Sonnet rates: ~$0.10/cycle of avoided stale-context shipping × 144 cycles/day per A-mode agent ≈ $14/day

## Problem

Long-running Claude Code `/loop` daemons accumulate two things silently:

**Conversation context.** Every cycle in a `/loop` session adds its tool calls, tool results, and assistant turns to the conversation. By cycle 50, the prompt shipped to Anthropic is dominated by cycles 1-49 — none of which is relevant. At Sonnet rates ($3/M input tokens), a 50K-token context costs $0.15 per prompt; across 144 cycles/day (5min interval) that's $21/day per agent that should be ~$0.05/cycle on a fresh context.

**Cron entries.** Claude Code's `/CronCreate` is additive. Every daemon start — fresh launch, auto-compact recovery, manual relaunch — calling `/CronCreate "Every 5m" "/arch-daemon"` adds another entry. Observed in production: a librarian daemon with five overlapping cron entries firing every 3-10 minutes instead of every 10.

**Auto-compact stalls.** Claude Code 2.1.x triggers auto-compact at certain context thresholds. When a `/loop` session auto-compacts, the daemon exits. The tmux pane stays alive (showing the "Resume this session with:" prompt), but nothing is running. Recurs every 3-5 hours of uptime if context never gets reset.

## Pattern 1: Daily /clear hygiene

Each A-mode agent gets a daily window (5min wide) during which the daemon checks "is my clear due?" and if so does the full reset. The check uses a marker file: `~/projects/agents/<workspace>/.last-clear`. If the marker's mtime is older than today's window start, the clear is due.

The Pre-Phase block in the daemon prompt:

```markdown
## Pre-Phase: Hygiene (A-mode — /loop daemon)

Before phase 0, run two helper checks. Each cycle in `/loop` accumulates
conversation history that gets shipped back to Anthropic on every prompt —
the daily `/clear` keeps that bounded.

**1. Daily /clear check:**

```bash
~/projects/agents/bin/agent-hygiene.sh check_clear_due architect
```

If exit code 0:

1. `/CronList`
2. `/CronDelete` every entry matching `/arch-daemon` (catches accumulated
   duplicates)
3. `/CronCreate "Every 5m" "/arch-daemon"`
4. `touch ~/projects/agents/architect/.last-clear`
5. `/clear` — **TERMINAL.** The new cron is in place; the next firing
   starts a fresh conversation. Do NOT continue to Phase 0 this cycle.
```

The five-step sequence is load-bearing. `/clear` without a fresh cron in place orphans the daemon. `/CronCreate` without first deleting matches adds a duplicate every time the clear fires.

The marker file makes "today's window" meaningful — once-per-day idempotency without persisting state in the cron itself.

## Pattern 2: Hourly memory save

The same marker-file mechanic, smaller scope. At the end of each cycle, check whether memory was saved in the last hour:

```bash
~/projects/agents/bin/agent-hygiene.sh check_memory_save_due architect
```

Exit 0 means save is due. The daemon reflects on the last hour's work, picks any novel learnings (gotchas, patterns, decisions and rationales), writes them to the agent's memory dir, and touches `.last-memory-save`. Skip the touch — and the save — if there's nothing novel; empty saves are noise that future you will have to filter through.

The 1-hour cadence is a tradeoff: too frequent and you're saving inconsequential cycle-to-cycle state; too rare and you lose learnings when the daemon auto-compacts. One hour catches "I learned something this morning about Gitea's rate limit" without saving "I posted to MM at 14:32".

## Pattern 3: Delete-before-create cron convention

Never blindly `/CronCreate`. Always:

```
/CronList                      # see what's there
/CronDelete <each matching>    # remove every entry for this daemon
/CronCreate "Every 5m" "/arch-daemon"
```

The "every matching" step is the part people skip — reasoning "I only run this once a day, there should be at most one entry." But the daemon may have been relaunched manually, auto-compacted and re-launched, or restarted by tmux-watchdog. Each produces a `/CronCreate` call. If your delete pattern misses one (matches `/arch-daemon` but not `/arch-daemon -v`), you have two crons forever.

Worst case observed: a librarian daemon's cron list had five entries (one canonical, one relaunch dupe, two debug-session leftovers, one stuck-recovery one-shot). The librarian fired every 2-4 minutes instead of every 20. Fix: make the create idempotent by delete-then-add.

## Helper script anatomy

`~/projects/agents/bin/agent-hygiene.sh` exposes two subcommands and a stagger schedule. It's the only file the daemon needs to know about.

- `check_clear_due <session>` — returns 0 if today's clear window is open AND the marker is older than this window's start
- `check_memory_save_due <session>` — returns 0 if the memory marker is older than `MEMORY_SAVE_INTERVAL_SEC` (default 3600s)

Internals map `session → workspace` (e.g. `flash-0 → builder`) so marker files live under the workspace dir, map `session → daily clear time` (HH:MM UTC) for the stagger, allow a 15-minute window after the scheduled minute for cron jitter, and handle macOS+Linux stat differences for marker mtime. The daemon prompt branches on exit code.

## Stagger schedule

13 agents resetting at midnight UTC would synchronize their stale-context bursts to Anthropic in a 30-second window. Spread them 5min apart over 00:00-01:00 UTC instead:

| Session   | Clear time (UTC) | Workspace  |
|-----------|------------------|------------|
| librarian | 00:00            | librarian  |
| k8s-ops   | 00:05            | k8s-ops    |
| haiku     | 00:10            | reviewer   |
| security  | 00:15            | reviewer   |
| architect | 00:20            | architect  |
| opus      | 00:25            | opus       |
| flash-0   | 00:30            | builder    |
| flash-1   | 00:35            | builder    |
| flash-2   | 00:40            | builder    |
| db-sme    | 00:45            | db-sme     |
| angel-0   | 00:50            | angel      |
| angel-1   | 00:55            | angel      |
| angel-2   | 01:00            | angel      |

Five-minute spacing is wider than the typical clear-and-recreate cycle (~30s), so even if one agent slips into the next slot the bursts don't overlap meaningfully. C-mode agents (cron-fired fresh `claude -p` per cycle — librarian, k8s-ops, haiku, security, db-sme above) don't need the clear at all because each cycle is already a fresh process, but they're in the table anyway for consistency and so `check_clear_due` can be added if any of them gets promoted to A-mode later.

## Trade-offs

Daily clear costs one cycle per day of pure hygiene work. The tradeoff: at Sonnet rates a 50K-token accumulated context costs ~$0.15 per prompt, and at 5min intervals that's 288 prompts/day per A-mode agent. Saving $0.10/prompt of stale-context shipping is $28.80/day per agent — before counting the avoided auto-compact stalls.

Hourly memory save costs near-nothing. The marker-file mechanism needs filesystem access to `~/projects/agents/<workspace>/` — mount a persistent volume for containerized daemons; local-machine daemons get it for free.

## Common mistakes

**Forgetting to delete before creating.** Cron list grows monotonically, cycle interval drifts shorter than configured, cycle reports duplicate. The original bug.

**Clearing too often.** Per-cycle clears burn a full hygiene cycle every 5 minutes and lose the useful in-session continuity A-mode is designed to preserve. Daily is the sweet spot.

**Not staggering reset times.** 13 agents clearing at 00:00 UTC = 13 simultaneous large-context bursts to Anthropic. Spread across the hour.

**Trusting `/loop`'s timing without periodic reset.** `/loop 5m` does fire every 5 minutes, but it doesn't reset the conversation. The cycle-timing knob and the context-bloat knob are orthogonal.

**Calling `/clear` before `/CronCreate`.** `/clear` ends the conversation. If no cron is in place, nothing fires next — daemon is dead until manually relaunched. Always create the cron first, touch the marker, then clear.

**Storing the "last-clear" timestamp inside the conversation.** Tempting (no filesystem dependency) but `/clear` wipes the conversation, including the timestamp. Has to be on disk.

## References

- `~/projects/agents/bin/agent-hygiene.sh` — the helper script
- `~/projects/agents/architect/.claude/commands/arch-daemon.md` — production Pre-Phase block
- `~/projects/agents/bin/agents-list.sh` — A-mode vs C-mode classification per agent
- Related: `stateful-vs-stateless-agent-daemons.md` — picks which mode each role should run in

