Sweeper: prune old session JSONL files in $CLAUDE_CONFIG_DIR/projects/ #131

Closed
opened 2026-04-20 11:34:08 +00:00 by claude-desktop · 0 comments
Collaborator

User story

As the operator, I want the sweeper to delete old session-history JSONL files under ~/.config/claude-hooks/agent-env/<agent>/projects/<cwd>/<uuid>.jsonl so that disk usage for per-agent session state stays bounded over time.

Context

PR #125 landed the rw bind that makes Claude Code actually persist session history on disk. Every dispatch now writes a JSONL file. The files are never deleted — per-agent disk usage will grow linearly with dispatch count.

The sweeper (src/sweeper.ts) already handles cache-clone pruning, stale worktrees, and expired sessions. This story extends it with a pass that deletes session JSONLs whose mtime is older than N days.

Acceptance criteria

Sweeper pass

  • New helper in src/sweeper.ts (or a new src/sweeper-sessions.ts if cleaner) that walks every agent's projects/ bind-source dir and deletes *.jsonl files older than the TTL.
  • TTL defaults to 30 days — matches the /stats default window, so everything visible on the stats tab is still resumable.
  • TTL overridable via config/agents.json top-level session_history_ttl_days: N. Absent → default.
  • The sweep runs in the existing runSweep entry point (same as storage pass), so both the periodic 6 h timer and the POST /sweep dashboard button trigger it.
  • Returns a count in the runSweep result shape so the POST /sweep response surfaces it (e.g. { sessions_pruned: N }).

Safety

  • Never delete a JSONL whose session id appears in the live sessions.json store (~/.local/state/claude-hooks/sessions.json). Read it once up front; skip any file whose basename UUID matches a stored id, regardless of age.
  • Iterates per-agent dirs from listResolvedAgents() — skips agents with container.enabled: false.
  • Best-effort: a failure on one file (permission denied, etc.) logs + continues; doesn't abort the sweep.

Tests

  • src/sweeper.test.ts extension: seed a temp projects/<cwd>/<uuid>.jsonl tree with a mix of fresh + expired + sessions-json-referenced files; assert only the expired, non-referenced ones are deleted.
  • Test the session_history_ttl_days override resolves from config.
  • Test empty projects dir → zero deletions, no error.

Docs

  • CLAUDE.md Sweeper row updated to mention session-history pruning.

Out of scope

  • Per-agent or per-type TTL overrides.
  • Compressing old JSONLs instead of deleting — delete only.
  • Backfilling a last_accessed timestamp instead of mtimemtime is good enough (Claude CLI appends to the file on every turn, bumping mtime).

References

  • src/sweeper.ts — existing sweep pass.
  • src/sessions.ts — session-store to read for the "don't-delete live ids" guard.
  • Bind layout: ~/.config/claude-hooks/agent-env/<agent>/projects/<encoded-cwd>/<uuid>.jsonl.

Dependencies

  • Blocked by: nothing (#125 merged).
  • Blocks: nothing.
  • Branch off: main.
## User story As the **operator**, I want the sweeper to delete old session-history JSONL files under `~/.config/claude-hooks/agent-env/<agent>/projects/<cwd>/<uuid>.jsonl` so that disk usage for per-agent session state stays bounded over time. ## Context PR #125 landed the rw bind that makes Claude Code actually persist session history on disk. Every dispatch now writes a JSONL file. The files are never deleted — per-agent disk usage will grow linearly with dispatch count. The sweeper (`src/sweeper.ts`) already handles cache-clone pruning, stale worktrees, and expired sessions. This story extends it with a pass that deletes session JSONLs whose `mtime` is older than N days. ## Acceptance criteria ### Sweeper pass - [ ] New helper in `src/sweeper.ts` (or a new `src/sweeper-sessions.ts` if cleaner) that walks every agent's `projects/` bind-source dir and deletes `*.jsonl` files older than the TTL. - [ ] TTL defaults to **30 days** — matches the `/stats` default window, so everything visible on the stats tab is still resumable. - [ ] TTL overridable via `config/agents.json` top-level `session_history_ttl_days: N`. Absent → default. - [ ] The sweep runs in the existing `runSweep` entry point (same as storage pass), so both the periodic 6 h timer and the `POST /sweep` dashboard button trigger it. - [ ] Returns a count in the `runSweep` result shape so the `POST /sweep` response surfaces it (e.g. `{ sessions_pruned: N }`). ### Safety - [ ] **Never** delete a JSONL whose session id appears in the live `sessions.json` store (`~/.local/state/claude-hooks/sessions.json`). Read it once up front; skip any file whose basename UUID matches a stored id, regardless of age. - [ ] Iterates per-agent dirs from `listResolvedAgents()` — skips agents with `container.enabled: false`. - [ ] Best-effort: a failure on one file (permission denied, etc.) logs + continues; doesn't abort the sweep. ### Tests - [ ] `src/sweeper.test.ts` extension: seed a temp `projects/<cwd>/<uuid>.jsonl` tree with a mix of fresh + expired + sessions-json-referenced files; assert only the expired, non-referenced ones are deleted. - [ ] Test the `session_history_ttl_days` override resolves from config. - [ ] Test empty projects dir → zero deletions, no error. ### Docs - [ ] `CLAUDE.md` Sweeper row updated to mention session-history pruning. ## Out of scope - Per-agent or per-type TTL overrides. - Compressing old JSONLs instead of deleting — delete only. - Backfilling a `last_accessed` timestamp instead of `mtime` — `mtime` is good enough (Claude CLI `append`s to the file on every turn, bumping `mtime`). ## References - `src/sweeper.ts` — existing sweep pass. - `src/sessions.ts` — session-store to read for the "don't-delete live ids" guard. - Bind layout: `~/.config/claude-hooks/agent-env/<agent>/projects/<encoded-cwd>/<uuid>.jsonl`. ## Dependencies - **Blocked by:** nothing (#125 merged). - **Blocks:** nothing. - **Branch off:** `main`.
claude-desktop removed their assignment 2026-04-20 11:39:06 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
charles/claude-hooks#131
No description provided.