Skip to content

Hygiene

xsyetopz edited this page Oct 22, 2026 · 1 revision

Session Hygiene

This page tells what the hygiene slice of the core plugin claudetto does at the start of a session and after each edit. A user reads it to learn which files and folders claudetto removes. A contributor reads it before an edit of slices/hygiene/.

The Cleanup at Session Start

The session.start hook starts the cleanup and does not wait for it, so it does not block the start of the session. The cleanup is one sh script. It removes only what it can show is not in use. It finds the age of a folder from its modification time. A session is live when a file in ~/.claude/sessions (or $CLAUDE_CONFIG_DIR/sessions) names its id, or when it is the current session.

What Where Rule
Leftover probe folders fswatch-probe-* in <CLAUDE_CODE_TMPDIR or /tmp>/claude-<uid> Older than PROBE_MAX_AGE_MIN (60 minutes). A bug of Claude Code leaves them (anthropics/claude-code#104170)
Session folders claude-<uid>/*/<uuid> in the same folder Older than cleanupPeriodDays (30 days when the setting is not set), and not live
Gate logs and other session files <tmp>/claudetto/*/<uuid>.* The same rule as session folders
Worktrees <project>/.claude/worktrees/* See below

The probe sweep has a timeout of SWEEP_TIMEOUT_MS (60,000 ms).

Worktrees

A worktree goes with git worktree remove only when all of these are true:

  • No session file has its cwd in the worktree.
  • It is older than the age.
  • It is a git worktree.
  • It is clean, with no changed, untracked, or git-ignored file, because git worktree remove deletes the git-ignored files, such as .env. The files in a folder that a tool makes again do not count: node_modules, .venv, __pycache__, dist, build, target, .next, and coverage.
  • It has no commit that is not on another branch or a remote.

Otherwise the cleanup keeps it and names the reason: live, young, not a worktree, dirty, unmerged, or not removed.

The Messages

The hook writes what it did to the log of the interface, which the model does not read:

  • CLEANED gives the counts of the removed folders, bytes, files, worktrees, and probe folders.
  • WORKTREES_KEPT names each kept worktree with its reason.
  • UNKNOWN_KEPT counts the entries of the claude-<uid> folder that no rule names. The cleanup keeps them.

The Edit Ledger

Claude cannot know that a file changed after its last edit when the user or a tool changed it. The slice keeps a ledger for this.

  1. After each Edit or Write, the classic.PostToolUse hook stores the path, a hash of the file (FNV-1a, 64 bits), and the agent that edited it (main, or the agent type). The ledger lives in the plugin state. A write that lost a race to another write runs again, at most LEDGER_WRITE_TRIES (5) times. The ledger holds at most LEDGER_MAX_FILES (200) files, and the oldest entry goes first.
  2. At each prompt, the classic.UserPromptSubmit hook hashes the files of the ledger again. For a file that changed after the last edit, it adds one line to the context: The user or a tool changed `<path>` after the last edit of `<agent>`. It marks the file as told, so it says the line once for each change.
  3. When no file changed, the hook adds nothing, so the cost is 0 tokens.

Two limits of the ledger:

  • A subagent gets no line at its own next turn.
  • An edit by a Bash command shows as a change by "the user or a tool".

Related Pages

Clone this wiki locally