[FEATURE] Built-in token optimization: read caching, test output filtering, large file blocking

Resolved 💬 3 comments Opened Apr 16, 2026 by soonswan-study Closed May 25, 2026

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:

  1. 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.
  1. Verbose test output: Running pytest or jest produces 200+ lines of output (progress dots, warnings, capture logs, fixture setup), but Claude only needs the session start, failures, and summary to make decisions.
  1. Unbounded log output: Commands like cat app.log or docker logs dump entire files into the context when the last 100 lines would suffice.
  1. 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:

!Session Lifecycle

Read Cache Flow:

!Read Cache Flow

Test Output Filter:

!Test Output Filter

Large File Protection:

!Large File Protection

Priority

Medium - Would be very helpful

Feature Category

Performance and speed

Use Case Example

Example scenario:

  1. I'm working on a Django backend with 50+ files
  2. I ask Claude to fix a bug in services/payment.py (400 lines)
  3. Claude reads the file, edits it, then reads it again to verify — that's 800 lines of tokens for one read of identical content
  4. I then ask Claude to run tests: pytest tests/test_payment.py -v which outputs 150 lines, but only 8 lines matter (collected count + 1 failure + summary)
  5. With read caching, the second read is blocked (0 tokens). With test filtering, 150 lines become 8 lines
  6. Over a 30-minute session with multiple files and test runs, this compounds to significant token savings

Additional Context

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗