How the Auto-Cleanup Hook Detects Stale Files in claude-code-harness
The auto-cleanup hook handles stale file detection by comparing line counts against configurable thresholds after write operations, emitting JSON warnings for oversized Plans.md, session-log.md, or CLAUDE.md files, but it never performs removal—actual deletion of temporary artifacts is delegated to separate session-end hooks.
The auto-cleanup hook in claude-code-harness provides proactive file size management without destructive actions. Integrated via the PostToolUse event, this hook analyzes files immediately after they are written or edited, comparing line counts against environment-defined limits. Unlike traditional cleanup mechanisms, it detects "stale" or oversized files through threshold comparisons and archive-section analysis while delegating actual removal to separate session-end hooks.
How the Hook Triggers on PostToolUse Events
The auto-cleanup mechanism activates through the PostToolUse event registration in hooks/hooks.json. According to the claude-code-harness source code, the hook executes after the Write, Edit, or Task matchers complete their operations. Immediately following a file modification, the harness binary at bin/harness routes execution to the auto-cleanup implementation, passing a JSON payload via standard input.
Parsing JSON Input and Normalizing Paths
When invoked, the hook reads the JSON payload from STDIN to extract critical fields: tool_input.file_path (or tool_response.filePath) and the current working directory (cwd). In scripts/auto-cleanup-hook.sh, the script first attempts to parse this data using jq, but falls back to a Python one-liner if jq is unavailable (lines 47-50).
Path normalization occurs next. If the file path begins with the $cwd/ prefix, the hook strips this segment to create a deterministic, project-relative path. This normalization ensures consistent threshold checking regardless of absolute path variations across different execution environments.
Threshold-Based Stale File Detection
The auto-cleanup hook implements size-based staleness detection using configurable line-count thresholds. Default limits are defined at lines 52-56 of scripts/auto-cleanup-hook.sh and mirrored in the Go implementation:
PLANS_MAX_LINES: 200 linesSESSION_LOG_MAX_LINES: 500 linesCLAUDE_MD_MAX_LINES: 100 lines
The hook uses wc -l to count lines in the target file, then dispatches to file-specific check functions. In go/internal/hookhandler/auto_cleanup_hook.go, the checkFile function (lines 12-25) routes to specialized validators: checkPlans for Plans.md, checkSessionLog for session-log.md, and checkClaudeMd for CLAUDE.md.
Individual File Validation Logic
Plans.md checks occur in the checkPlans function (lines 29-65). If the file exceeds 200 lines, the hook assembles a warning recommending archival via /maintenance.
session-log.md validation happens in checkSessionLog (lines 68-79), triggering when the file surpasses 500 lines with suggestions to split content by month.
CLAUDE.md monitoring in checkClaudeMd (lines 82-93) warns at 100 lines, suggesting migration to .claude/rules/ or a dedicated docs directory.
Archive Section Detection and SSOT Synchronization
For Plans.md specifically, the hook performs deep content analysis beyond simple line counting. The implementation scans for archive markers including 📦 アーカイブ, ## アーカイブ, or the string "Archive" (lines 68-88 in the shell script).
When the hook detects an archive section, it locates the repository root using git rev-parse and checks for the existence of .claude/state/.ssot-synced-this-session. If this flag file is missing, the hook appends an urgent secondary warning recommending /memory sync execution before any cleanup occurs. This prevents data loss by ensuring significant decisions and learning patterns are persisted to the SSOT (decisions.md/patterns.md) before users archive active content.
Go vs Shell Implementation
The claude-code-harness provides dual implementations of identical logic. The compiled Go binary contains the AutoCleanupHandler function in go/internal/hookhandler/auto_cleanup_hook.go, while the shell script at scripts/auto-cleanup-hook.sh serves as a fallback.
Both versions parse JSON input identically (Go lines 49-78), resolve thresholds from environment variables with hard-coded defaults, execute the same file-type dispatch logic, and output identical JSON structures via writeCleanupOutput (Go lines 45-66). Users can invoke the hook directly via the binary:
echo '{"tool_name":"Write","tool_input":{"file_path":"CLAUDE.md"},"cwd":"/repo"}' \
| ./bin/harness PostToolUse
JSON Output and SystemMessage Integration
Rather than deleting files, the auto-cleanup hook generates JSON output containing warning messages. When thresholds are exceeded, the hook constructs a response where hookSpecificOutput.additionalContext contains the concatenated warning strings (shell script lines 112-115).
For example, an oversized CLAUDE.md produces:
{
"hookSpecificOutput": {
"hookEventName": "PostToolUse",
"additionalContext": "⚠️ CLAUDE.md が 150 行です。.claude/rules/ への分割、または docs/ に移動して @docs/filename.md で参照することを検討してください。"
}
}
The harness injects this text directly into the systemMessage displayed to the user. If no warnings trigger, the hook exits silently with code 0, producing no output.
Summary
- The auto-cleanup hook triggers on
PostToolUseevents forWrite,Edit, andTaskoperations via configuration inhooks/hooks.json. - It detects "stale" (oversized) files by comparing line counts against thresholds: 200 lines for Plans.md, 500 lines for session-log.md, and 100 lines for CLAUDE.md.
- For Plans.md, the hook analyzes content for archive markers and verifies SSOT synchronization via
.claude/state/.ssot-synced-this-sessionbefore permitting cleanup recommendations. - The hook never deletes files; it only emits JSON warnings through
additionalContextthat the harness displays as system messages. - Dual implementations exist in
go/internal/hookhandler/auto_cleanup_hook.go(Go) andscripts/auto-cleanup-hook.sh(shell), with identical logic but different execution contexts.
Frequently Asked Questions
Does the auto-cleanup hook delete files automatically?
No. The auto-cleanup hook in claude-code-harness does not delete or remove any files. According to the source code in both scripts/auto-cleanup-hook.sh and go/internal/hookhandler/auto_cleanup_hook.go, the hook only detects oversized files and emits warning messages suggesting manual actions like /maintenance or /memory sync. Actual removal of temporary artifacts is handled by separate hooks such as WorktreeRemove or SessionEnd.
How does the hook determine if Plans.md needs archiving?
The hook checks if Plans.md exceeds 200 lines (configurable via PLANS_MAX_LINES). Additionally, it scans for archive section markers including 📦 アーカイブ, ## アーカイブ, or "Archive". When these markers exist, the hook verifies the SSOT sync flag at .claude/state/.ssot-synced-this-session. If the flag is missing, it warns the user to run /memory sync before archiving to prevent losing important decisions.
What are the default file size thresholds?
Default thresholds are hard-coded in scripts/auto-cleanup-hook.sh lines 52-56 and mirrored in the Go implementation:
- Plans.md: 200 lines (
PLANS_MAX_LINES) - session-log.md: 500 lines (
SESSION_LOG_MAX_LINES) - CLAUDE.md: 100 lines (
CLAUDE_MD_MAX_LINES)
These values can be overridden by setting the corresponding environment variables before invoking the harness.
Can I use the auto-cleanup hook without the Go binary?
Yes. The repository includes a shell script implementation at scripts/auto-cleanup-hook.sh that executes when the compiled Go binary is unavailable. The script provides identical functionality, parsing JSON from STDIN (with a Python fallback if jq is missing), normalizing paths, checking thresholds, and outputting warnings in the same JSON format as the Go version's writeCleanupOutput function.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →