Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

32 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Reducer

Query-aware context compression for Claude Code, without the toolchain.

Reducer shrinks the context Claude Code sends to the model — prior conversation turns and large tool outputs — down to the parts that are actually relevant to what you're currently asking, before they cost you tokens. It's pure JavaScript: no Rust, no Python, no ONNX runtime, no model download. The default scoring mode makes zero network calls.

Tagline: token savings without the toolchain.

Why this exists

Two real projects already do context compression for coding agents: SuperCompress and Headroom. Headroom in particular is excellent and far more feature-complete than this project — reversible compression, cross-agent memory, a trained ML model, 15+ agent integrations. Reducer doesn't try to out-feature it.

The wedge is install friction. Headroom's own README documents Rust toolchain fallbacks, an ONNX runtime download, Python version pinning, and corporate SSL-proxy workarounds. That's real overhead for people who just want fewer tokens. Reducer's entire install is one npm install plus one setup command — no compiled dependency, anywhere, ever. Exact commands below.

Install

Published on npm as reducer-cloud — not as reducer (that name was already taken by an unrelated package before this project started). The CLI command itself is still the short reducer, once installed.

npm install -g reducer-cloud
reducer setup

Prefer not to install globally? npx works too, but you have to name the actual published package — npx reducer ... would silently run someone else's package:

npx reducer-cloud setup

reducer setup finds your Claude Code settings file, backs it up, and registers Reducer's UserPromptSubmit and PostToolUse hooks. It never prompts, merges into your existing settings rather than overwriting them, and writes nothing beyond that one JSON file plus a timestamped backup next to it.

Hooks take effect the next time you start a Claude Code session (a running session won't pick them up until it's restarted, or until Claude Code's own settings file watcher reloads them — see the docs for your version).

Undo at any time:

reducer restore

This surgically removes only Reducer's hook entries — anything else you changed in that settings file since installing is left alone.

From source

For contributing, or if you're reading this before v0.1.0 is live on npm:

git clone https://github.com/rafipopz98/cloud.reduce.git
cd cloud.reduce
npm install
npx reducer setup

(npx reducer resolves correctly here because it's finding this checkout's own bin/reducer.js locally — the naming caveat above only applies to fetching from the public registry.)

Quick start

reducer setup          # register the hooks (user-wide by default)
# start a new Claude Code session, use it normally
reducer stats           # see tokens saved and latency so far
reducer restore         # undo, any time

Scope options, on both setup and restore:

reducer setup --project     # this project's .claude/settings.json only
reducer setup --dry-run     # preview the change without writing
reducer setup --config=PATH # patch an explicit settings file

Commands

Command What it does
reducer setup Registers the Claude Code hooks (backs up first)
reducer restore Removes them again
reducer stats Prints local usage totals: tokens saved, latency, event count
reducer bench Benchmarks compress() latency on your machine

How it works

Two hooks, both calling the compression engine directly in-process — no proxy, no local server, no network hop:

  • UserPromptSubmit fires before Claude sees your new prompt. It can't rewrite the prompt itself (that's a Claude Code hook API constraint, not a Reducer limitation), so it compresses the prior conversation against your new prompt and writes a relevance-ranked digest to ~/.reducer/inbox/latest.md, pointing Claude at it via additionalContext.
  • PostToolUse fires after a tool call succeeds and can rewrite what Claude sees, via updatedToolOutput. This is where most of the real savings come from — large Read/Bash/Grep outputs get compressed in place before they ever reach the model.

Compression itself: split the text into chunks (sentences, code blocks, and JSON blocks kept intact — never split mid-structure), score each chunk's relevance to your query, then greedily keep the highest-scoring chunks within a token budget.

Heuristic mode (default) scores by keyword overlap with your query, recency, and a role/recency floor for system prompts and the last few turns — zero API calls, zero cost. Embedding mode is opt-in (mode: "embedding" plus an API key) for higher-quality scoring when you want it; it's never required.

Real numbers

Everything below is measured on this project's own test data, not borrowed from either reference project's marketing.

Reduction

~59% average token reduction, measured across 8 real local Claude Code session transcripts on the development machine (test/compress.test.js, heuristic mode) — individual runs ranged 58.5%–59.8%, tightly clustered. A separate set of 4 hand-written synthetic fixtures ranged wider (39%–63%, mean ~54%), which is expected — they're much smaller inputs where a handful of tokens shifts the percentage a lot.

That ~59% figure held up on real production tool-output data, not just conversation text. During PostToolUse hook integration, two live cases were captured and independently reproduced and verified against this project's actual live session data:

  • A grep-style Bash output (21 file matches for userId: string, 712 tokens) queried against a real question about why that field wasn't ObjectId61.2% reduction, with the actually-relevant matches surviving in the output.
  • An Edit-tool response containing a full TypeScript model file → 60.0% reduction.

(Those two cases initially compressed to 0 kept tokens — a real bug where a single indivisible chunk larger than the token budget got dropped entirely instead of truncated. Fixed in src/chunk.js and src/select.js; see git history for the full writeup.)

Latency

Measured with reducer bench — heuristic mode, 200 timed iterations per size tier after 20 discarded warmup runs, real prose from this repo's own plan.md/docs/research-notes.md as input:

Input size Median p95 Max
~160 tokens 0.24ms 0.27ms 2.67ms
~2,200 tokens 3.06ms 3.47ms 3.80ms
~14,000 tokens 20.14ms 54.96ms 152.26ms

Single-digit milliseconds for typical tool outputs, low-double-digit milliseconds even at ~14k tokens (roughly a full 40-turn conversation window). The large-input tail (p95/max) is real, not smoothed over — likely GC pressure under 200 back-to-back large-string tokenization passes in a tight loop; a single real invocation from a hook won't see that pattern. Reproduce with reducer bench on your own machine.

Install time vs. Headroom

Measured on the development machine:

Step Time
npm install (cold cache, clean-machine simulation) 8.5s
npm install (warm cache) 1.2s
reducer setup (node bin/reducer.js setup, from source) 0.34s
Total, cold start → hooks registered ~8.8s

This is a timing comparison, not a compression-quality comparison — Headroom is the more feature-complete engine. The fair comparison is install friction: Headroom's own README documents a Rust toolchain fallback path, an ONNX runtime download, Python version pinning across 3.10–3.13, and corporate-SSL-proxy workarounds as part of getting it running. Reducer's install is npm install + one command, entirely pure JavaScript, and was not separately timed against a live Headroom install on this machine — the claim being made is the absence of those extra steps, documented in Headroom's own README, not a stopwatch comparison of two installs run side by side.

Modes

const { compress } = require('reducer-cloud'); // or require('./src/compress') from source

const result = await compress({
  context: [{ role: 'user', content: '...' }],  // string or array of turns
  query: 'what the user is currently asking',
  targetTokens: 2000,
  mode: 'heuristic',   // default — no network, no API key needed
});

Embedding mode:

await compress({
  context,
  query,
  targetTokens: 2000,
  mode: 'embedding',
  apiKey: process.env.REDUCER_EMBEDDINGS_API_KEY,  // or set the env var directly
});

HTTP API (optional)

For hosted/non-hook use:

node src/server.js
curl -X POST http://localhost:3000/compress \
  -H "Content-Type: application/json" \
  -d '{"context":[{"role":"user","content":"..."}],"query":"...","targetTokens":2000}'

Status

Pre-release. Working end to end (hooks fire in real Claude Code sessions, verified live — not just simulated). Package metadata, LICENSE, and the files allowlist are publish-ready; v0.1.0 is not yet live on npm.

License

MIT — see LICENSE.

About

Same answers, fewer tokens, save $ with simple npx install.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages