Skip to content

About

Cut Claude Code token usage 80-95% on big-file reads. Deterministic, ~1ms, zero egress — no second LLM.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

4 Commits

Folders and files

Repository files navigation

context-broker

A Halley project

Cut Claude Code's token bill on big-file reads by 80–95% — with zero fidelity loss, zero latency, and zero data egress.

When Claude reads a 2,000-line file to answer one question, you pay for 2,000 lines. Spotify's Portal/shunt attacks this by routing reads through a cheaper LLM that summarizes the file — which works, but costs 10–30 seconds per read, ships your source to a second model vendor, and returns lossy summaries (their own writeup admits the worker missed a thread-safety bug).

context-broker takes a different bet: most of what Claude needs from a big file is its structure, and structure can be extracted deterministically. No second model. Nothing leaves your machine. ~1 millisecond.

Portal / shunt context-broker
Mechanism second LLM summarizes structural extraction — no model
Latency 10–30 s per delegation ~1 ms per interception
Fidelity lossy summary verbatim source lines, real line numbers
Data egress code sent to a second vendor zero
Read → edit re-read the whole file to edit skeleton keeps line numbers → ranged read of just the slice
Savings ~90 % on bulk reads 80–95 % per intercepted file

How it works

A PreToolUse hook intercepts Claude Code's Read tool:

  1. File ≤ 350 lines, binary, image/PDF/notebook, or a ranged read (offset/limit) → passes through untouched.
  2. Otherwise the full read is denied — but the denial contains the answer: the file's exact skeleton (imports, signatures, types, doc comments — verbatim source lines with real line numbers). Claude gets the structure instantly and expands only the bodies it needs via ranged reads, which always pass through.
  3. Any error, anywhere → fail open. The hook can never break Read.

Because the skeleton keeps real line numbers, the read→edit path Portal can't handle just works: Claude sees the structure, ranged-reads the 30 lines it wants to change, edits them. No double read.

The interception message teaches the expand/bypass mechanics at exactly the moment they're needed — zero standing prompt-context tax.

 42│export interface Post {
   │ ⋯ 16 lines (43-58)
 59│/** Metadata only — what the bundle gets. */
 60│export type PostMeta = Omit<Post, 'body' | 'html'>;
 61│
 62│export function readPosts(dir: string): Post[] {
   │ ⋯ 65 lines (63-127)

Install

As a Claude Code plugin (recommended)

/plugin marketplace add halleylabs/context-broker
/plugin install context-broker@context-broker

That's it. The hook is wired automatically. On first session start the plugin compiles the native binary in the background (needs any C++17 compiler); until then — or if no compiler exists — it runs on the bundled Python implementation, which behaves identically at ~25 ms instead of ~1 ms.

Manual

git clone https://github.com/halleylabs/context-broker && cd context-broker
make && ./test.sh

Then add to .claude/settings.json (project) or ~/.claude/settings.json (global):

{"hooks": {"PreToolUse": [{"matcher": "Read", "hooks": [
  {"type": "command",
   "command": "/path/to/context-broker/cb hook 2>/dev/null || python3 /path/to/context-broker/cb.py hook",
   "timeout": 10}
]}]}}

CLI

The same binary is a standalone tool:

cb skeleton <file>          # exact structural view, line-numbered
cb read <file> <start> <n>  # exact ranged slice
cb fold < build.log         # compress noisy logs: dedupe, keep failures + stack frames
cb bench <repo>             # measure would-be savings across a repo (no model calls)
cb stats                    # cumulative tokens saved (~/.cache/context-broker/ledger.jsonl)
cb hook                     # PreToolUse handler (stdin JSON → decision JSON)

cb bench on a repo before installing tells you exactly what you'd save — measured, not estimated.

Tuning

Env var Default Meaning
CB_MIN_LINES 350 files at or under this pass through
CB_MAX_SKEL_LINES / CB_MAX_SKEL_BYTES 220 / 10000 skeleton budget
CB_FOLD_CAP 300 fold output line budget
CB_DISABLE=1 — kill switch

Set them in the env block of your Claude Code settings, or in your shell profile.

Real-world benchmark

cb bench on a production Python monorepo (506k LOC including its .venv), one command, no model calls:

409 files over 350 lines · 3,832,475 → 455,840 tokens (89% saved) · scanned in 296ms

Two things this run shows beyond the headline:

  • Hand-written code never triggered the hook. Every project-authored source file was under the 350-line threshold — the only project file intercepted was uv.lock. The interceptor is invisible until Claude wanders somewhere expensive.
  • The savings land exactly where full reads are pure waste — dependencies, lockfiles, and generated artifacts, the files agents dip into when chasing library behavior:
File Full read Skeleton Saved
ruff.cyclonedx.json (SBOM) 102,448 tok 91 tok 100%
uv.lock 76,397 tok 2,520 tok 97%
fastapi/routing.py 63,908 tok 2,080 tok 97%
anthropic/.../messages.py 33,327 tok 1,726 tok 95%

The SDK skeleton keeps every create / stream / count_tokens signature — sync and async — with real line numbers, which is precisely what an agent needs when checking call shapes. A session that pokes into site-packages a handful of times goes from ~150k tokens of full reads to ~8k of exact structure.

Performance

Hand-rolled matchers, no regex on the hot path, single ~200 KB dependency-free binary:

  • skeletonize an 800-line file: ~1 ms
  • skeletonize a 28,000-line vendored bundle: ~8 ms
  • bench an entire repo: ~3 ms
  • allow-path overhead added to every Read: <1 ms

Languages with real structural awareness: TypeScript/JavaScript/TSX, Python, Go, Rust, Java/Kotlin/Swift/Scala/C#, C/C++/Obj-C, Ruby, PHP, CSS/SCSS, shell, SQL, Markdown, YAML/TOML, JSON — plus an indent-based generic fallback for everything else.

Design notes

  • Exact text only. Every emitted line is verbatim from disk with its real line number. A skeleton can be stale-read or incomplete, but it can never be wrong — there is no summarizer to hallucinate a signature.
  • The denial is the answer. Blocking a tool call normally costs a re-planning round trip. Here the skeleton rides inside the denial reason, so interception is strictly cheaper than the read it replaced.
  • Fail open, always. Unreadable file, binary content, malformed hook input, any exception: the original Read proceeds. ./test.sh covers every path.
  • cb.py is the executable spec. The C++ and Python implementations produce byte-identical output (verified by test.sh; the one divergence is that oversized skeletons truncate at a line boundary in C++ vs mid-line in Python).

Limitations

  • Skeletons are structure, not behavior — for deep-logic questions Claude should (and will) pull full bodies via ranged reads.
  • macOS/Linux. Windows: the Python fallback should work under Git Bash; untested.
  • Token counts use a chars/4 estimate for the ledger; real savings depend on your tokenizer.

License

MIT

About

Cut Claude Code token usage 80-95% on big-file reads. Deterministic, ~1ms, zero egress — no second LLM.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages