[FEATURE] Built-in token optimization: read caching, test output filtering, large file blocking
Preflight Checklist
- [x] I have searched existing requests and this feature hasn't been requested yet
- [x] This is a single feature request (not multiple features)
Problem Statement
Claude Code consumes tokens every time it reads a file, runs a test, or checks logs. In a typical coding session, I observed several wasteful patterns:
- Redundant file reads: The same file gets read 3-5 times per session (before edit, after edit, during review, when referencing). Each re-read consumes tokens for identical content that Claude already has in context.
- Verbose test output: Running
pytestorjestproduces 200+ lines of output (progress dots, warnings, capture logs, fixture setup), but Claude only needs the session start, failures, and summary to make decisions.
- Unbounded log output: Commands like
cat app.logordocker logsdump entire files into the context when the last 100 lines would suffice.
- Large file consumption: Files with 1000+ lines get read in full even when Claude only needs a specific section, consuming massive amounts of tokens unnecessarily.
These patterns compound in longer sessions and lead to faster context exhaustion and higher token costs.
Proposed Solution
I built a set of 6 hook scripts that solve these problems using Claude Code's existing hook system. The hooks work transparently without changing how the user interacts with Claude Code:
Read caching (pre-read.sh + post-file-cache.sh):
- First read: passes through normally, caches a snapshot
- Re-read (unchanged): blocked entirely with "File unchanged" message
- Re-read (after edit): returns only the unified diff, not the full file
Test output filtering (pre-bash.sh + pre-bash.helper.filter.sh):
- Detects test commands (pytest, jest, vitest, Django test)
- Pipes output through an awk filter that extracts only: session start, collected count, failures, errors, and final summary
- 200+ lines become ~8 lines
Log output limiting (pre-bash.sh):
- Detects log commands without existing truncation (cat *.log, docker logs, journalctl)
- Automatically appends
| tail -100
Large file blocking (pre-read.sh):
- Files over 1000 lines are blocked unless offset/limit is specified
- Forces targeted reads instead of full-file consumption
Compaction awareness (post-compact.sh + session-start.sh):
- Clears read cache after context compaction (since Claude loses detailed file content)
- Cleans up stale caches older than 7 days
I'd love to see some form of these optimizations built into Claude Code natively, or at minimum, included as an official example/recipe in the docs.
Alternative Solutions
I'm currently using these hooks via a standalone repository with a one-command installer:
Repository: https://github.com/soonswan-study/claude-code-thrifty**
The installer symlinks hooks to ~/.claude/hooks/ and merges config into ~/.claude/settings.json. It works well but requires manual installation and jq as a dependency.
Session Lifecycle:
Read Cache Flow:
Test Output Filter:
Large File Protection:
Priority
Medium - Would be very helpful
Feature Category
Performance and speed
Use Case Example
Example scenario:
- I'm working on a Django backend with 50+ files
- I ask Claude to fix a bug in
services/payment.py(400 lines) - Claude reads the file, edits it, then reads it again to verify — that's 800 lines of tokens for one read of identical content
- I then ask Claude to run tests:
pytest tests/test_payment.py -vwhich outputs 150 lines, but only 8 lines matter (collected count + 1 failure + summary) - With read caching, the second read is blocked (0 tokens). With test filtering, 150 lines become 8 lines
- Over a 30-minute session with multiple files and test runs, this compounds to significant token savings
Additional Context
- Repository with full implementation: https://github.com/soonswan-study/claude-code-thrifty
- Detailed per-hook documentation: https://github.com/soonswan-study/claude-code-thrifty/blob/main/docs/HOOKS.md
- Requirements:
jqfor JSON parsing,bash4.0+ - The hooks are session-scoped (each session gets its own cache directory), so parallel sessions don't interfere
- All hooks are non-invasive: partial reads (offset/limit), binary files, and first reads always pass through unchanged
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗