Excessive File I/O During Sessions (~1.5 writes/second to .claude.json)
Summary
Claude Code performs excessive file I/O operations during normal sessions, writing to .claude.json at an extremely high rate (~1.5 writes/second). A 20-minute session resulted in 1,860 atomic file writes and generated a 2.5 MB debug log with 28,307 lines.
Environment
- Claude Code Version: 2.0.72
- Platform: Linux (WSL2)
- OS Version:
Linux 6.6.87.2-microsoft-standard-WSL2 - Shell: bash
- Working Directory:
~/projects/MyProject/ - Debug Log:
~/.claude/debug/399de4cf-7eca-4e6c-973f-f75dc86448e5.txt
Detailed Description
Observed Behavior
During a normal Claude Code session, the system continuously writes to ~/.claude.json (the main state file). Each write follows this pattern:
[DEBUG] Writing to temp file: ~/.claude.json.tmp.73914.1766019293909
[DEBUG] Preserving file permissions: 100644
[DEBUG] Temp file written successfully, size: 103774 bytes
[DEBUG] Applied original permissions to temp file
[DEBUG] Renaming ~/.claude.json.tmp.73914.1766019293909 to ~/.claude.json
[DEBUG] File written atomically
Session Statistics
Session Duration: 20 minutes 23 seconds (00:34:31 to 00:54:54 UTC)
Total File Writes: 1,860 writes to .claude.json
Write Rate: ~1.5 writes/second (~91 writes/minute)
Debug Log Size: 2.5 MB (28,307 lines)
Average File Size: ~103-104 KB per write
I/O Pattern
File writes occur:
- After every user message
- After every AI response chunk/stream event
- During tool execution
- During permission updates
- During file history snapshots
- During LSP diagnostic checks
- During hook command checks
Example from debug log:
00:40:41 - Write to .claude.json (103,773 bytes)
[2m 21s gap with xclip error]
00:54:53 - Write to .claude.json (103,774 bytes)
00:54:53 - Write to .claude.json (103,774 bytes) [0.035s later]
00:54:53 - Write to .claude.json (103,774 bytes) [0.038s later]
Multiple writes within milliseconds of each other suggest redundant state persistence.
Impact Assessment
Performance Impact
Storage:
- Constant SSD wear from 90+ writes/minute
- Temp file creation/deletion churn
- Debug log bloat (2.5 MB for 20 minutes)
System Resources:
- File system cache pressure
- Atomic write overhead (create temp → write → chmod → rename)
- Debug logging overhead
User Experience:
- Potential session lag/unresponsiveness during I/O spikes
- May contribute to session hangs
Frequency: Always
- Affects all Claude Code sessions
- Rate appears consistent regardless of activity level
- Even idle sessions may write frequently
Data Loss Risk: None
- Frequent writes actually protect against data loss
- Atomic write pattern is safe
- Issue is performance, not correctness
Root Cause Analysis
Potential causes for excessive writes:
-
State Persistence Strategy:
- Claude Code may persist entire session state after every event
- No write coalescing or debouncing
- Every message/tool/event triggers immediate save
-
File History Snapshots:
[DEBUG] FileHistory: Making snapshot for message <UUID> [DEBUG] FileHistory: Added snapshot for <UUID>, tracking N filesCreates snapshots for every message, each triggering a write
-
Hook Command Checks:
[DEBUG] Hooks: Found 0 total hooks in registry [DEBUG] Hooks: checkForNewResponses returning 0 responsesAppears to run after every event, even when no hooks configured
-
Redundant Writes: Multiple writes within milliseconds (same file size) suggest:
- Race conditions between different subsystems
- Lack of debouncing/throttling
- Overlapping save triggers
Reproduction Steps
- Start any Claude Code session:
claude - Have a normal conversation (ask questions, request file operations, etc.)
- Monitor debug log growth:
watch -n 1 'ls -lh ~/.claude/debug/latest' - Count file writes after session:
grep -o "Writing to temp file:.*" ~/.claude/debug/latest | wc -l
Expected Result:
- File writes occur at reasonable intervals (e.g., after message batches, on manual save)
- Debug log grows proportionally to conversation complexity
- Write rate: ~0.1-0.5 writes/second (conservative estimate)
Actual Result:
- File writes occur constantly at ~1.5 writes/second
- Debug log grows to 2.5 MB in 20 minutes
- Write pattern shows redundancy and lack of throttling
Evidence from Debug Log
Write Pattern Sample (Tail of Session)
2025-12-18T00:54:53.909Z [DEBUG] Writing to temp file: ~/.claude.json.tmp.73914.1766019293909
2025-12-18T00:54:53.914Z [DEBUG] File ~/.claude.json written atomically
2025-12-18T00:54:53.947Z [DEBUG] Writing to temp file: ~/.claude.json.tmp.73914.1766019293947
2025-12-18T00:54:53.952Z [DEBUG] File ~/.claude.json written atomically
2025-12-18T00:54:53.985Z [DEBUG] Writing to temp file: ~/.claude.json.tmp.73914.1766019293985
2025-12-18T00:54:53.990Z [DEBUG] File ~/.claude.json written atomically
Three writes within 81 milliseconds (00:54:53.909 to 00:54:53.990), all writing the same data size (103,774 bytes).
Hook Command Check Pattern
[DEBUG] Getting matching hook commands for UserPromptSubmit with query: undefined
[DEBUG] Found 0 hook matchers in settings
[DEBUG] Matched 0 unique hooks for query "no match query" (0 before deduplication)
This pattern repeats hundreds of times despite having zero hooks configured. Each check appears to trigger a file write cycle.
Performance Recommendations
Option 1: Write Debouncing (Recommended)
Implement write debouncing with:
- Minimum interval between writes (e.g., 5 seconds)
- Queue state changes in memory
- Flush on explicit events (user message sent, tool completed)
- Emergency flush on process exit
Option 2: Differential State Updates
Instead of writing full 104 KB state file every time:
- Track delta changes
- Append to journal file
- Periodic compaction to main state file
Option 3: Conditional Writes
Only write state file when:
- Conversation state changes (new message, tool result)
- User explicitly saves or exits
- Critical state changes (permissions, settings)
- Periodic checkpoint (e.g., every 60 seconds)
Skip writes for:
- Hook checks when no hooks configured
- LSP diagnostics when no LSP servers running
- File history snapshots (keep in memory, flush on demand)
Suggested Monitoring
Add metrics to track:
- Write operations per session
- Average time between writes
- Write triggers (which subsystem caused write)
- State file size over time
Make this visible to users:
claude --stats
# File writes: 1860 (1.5/sec avg)
# Session duration: 20m 23s
# State file size: 104 KB
Related Issues
See Also:
- #10505 - "[BUG] Memory leak and runaway write loop in
claude --continuecauses 28GB memory usage"- Extreme version of this issue (infinite loop instead of just frequent writes)
- Same underlying problem (no write debouncing/throttling)
Files for Reference
- Debug Log:
~/.claude/debug/399de4cf-7eca-4e6c-973f-f75dc86448e5.txt(2.5 MB, 28,307 lines) - Session State:
~/.claude.json(~104 KB)
Session ID: 399de4cf-7eca-4e6c-973f-f75dc86448e5