Content
<div align="center">
<img src="rucksack_logo.png" alt="Rucksack — less noise, more context" width="240">
### Your coding agent is drowning in its own tool output — and you're paying for it in lost context.
Every test run, build, linter, and big file read floods your agent's context window with noise that gets re-sent on every turn. Rucksack packs that **noisy coding-agent output** into a short, structure-aware view, **keeps your failure lines visible**, and gives you back the original content the moment you need it.
**Reclaim your context · Faithful recall · Measured savings**
[](https://github.com/MerlijnW70/rucksack/actions/workflows/ci.yml)




[](https://github.com/MerlijnW70/rucksack/releases)
**Jump to:** [Install](#get-it) · [Quickstart](#quickstart) · [Before / after](#before--after) · [Savings](#what-youd-reclaim) · [How it packs](#it-knows-what-to-keep) · [Your stats](#see-what-you-got-back) · [Commands](#everything-you-can-run) · [Limits](#before-you-ask--the-honest-limits)
</div>
> In a reproducible A/B over a realistic mix of noisy tool output, Rucksack gave back **63,795 tokens of context** (82,613 → 18,818, **−77%**) — with **0 expands** needed and every file read compact-first. It's deterministic: run `node bench/ab.js` and you get the same numbers on any clone.
<details>
<summary><b>📖 Full contents</b> — what's in this README (click to expand)</summary>
<br>
- **[What you're losing without it](#what-youre-losing-without-it)** — the hidden cost of noisy tool output, and the four things Rucksack does about it
- **[Get it](#get-it)** — install, restart, and verify with `/rucksack:doctor` + `/rucksack:smoke` in under a minute
- **[Quickstart](#quickstart)** — run your usual commands; watch what your agent ingests shrink
- **[Before / after](#before--after)** — a real `npm test`, shown before and after packing
- **[What you'd reclaim](#what-youd-reclaim)** — the measured A/B result, plus cargo / pytest / npm
- **[It knows what to keep](#it-knows-what-to-keep)** — how it packs each content type (code, markdown, JSON, diffs, logs)
- **[See what you got back](#see-what-you-got-back)** — your savings scoreboard and shareable daily report
- **[Everything you can run](#everything-you-can-run)** — every CLI command and in-session MCP tool
- **[Why did Rucksack skip my command?](#why-did-rucksack-skip-my-command)** — the hook's skip rules, and `explain-hook`
- **[Before you ask — the honest limits](#before-you-ask--the-honest-limits)** — what Rucksack does, and what it doesn't
- **[License](#license)**
</details>
---
## What you're losing without it
You don't burn your context window on your prompts. You burn it on **tool output**. One `npm test`, `cargo build`, or large file read dumps thousands of tokens into the window — and then re-sends them, turn after turn.
You never see a line item for it. You just feel the effects: your agent loses the thread sooner, repeats itself, and needs more hand-holding the longer a session runs. That's context you paid for, spent on noise you'll never read.
Every session you run without Rucksack, that leak keeps running. Here's what closes it:
- 🗜️ **Auto-packs your noisy commands** — npm, cargo, go, pytest, grep, and more — before the output ever reaches the model.
- 📄 **Compact file reads** — `efficient_read` gives you a file's *shape* (signatures, key lines), not the whole wall.
- 🔍 **Compact repo search** — `efficient_grep` returns matches grouped by file with counts, not a 2,000-line dump.
- ↩️ **Faithful recall** — every packed-away chunk gets a handle; `expand(handle)` returns the original content on demand, every meaningful line intact (presentation is normalized — see [the limits](#before-you-ask--the-honest-limits)).
It is **not a summarizer**. No model rewrites your output — packing is deterministic, and your original is one `expand` away.
<p align="center">
<img src="docs/img/how-it-works.svg" alt="Rucksack sits between your tools and your agent: it packs noisy tool output into a compact view plus a recall handle before it reaches your context, and expand(handle) returns the original content on demand." width="100%">
</p>
---
## Get it
You'll need [Node 18+](https://nodejs.org) and the [Claude Code CLI](https://claude.com/claude-code) — nothing else (no Rust, no build step, no services). Then it's three quick steps.
### 1. Install it
Paste these two lines into your terminal:
```sh
claude plugin marketplace add MerlijnW70/rucksack
claude plugin install rucksack@rucksack
```
Rather run a single command? Use the installer for your system instead:
```sh
# macOS / Linux / WSL / Git Bash
curl -fsSL https://raw.githubusercontent.com/MerlijnW70/rucksack/main/install.sh | bash
```
```powershell
# Windows PowerShell
irm https://raw.githubusercontent.com/MerlijnW70/rucksack/main/install.ps1 | iex
```
### 2. Restart Claude Code
That's the whole setup. From your next session, Rucksack starts packing context for you automatically — you don't change how you work.
### 3. Check that it's working
In Claude Code, run these two commands:
```text
/rucksack:doctor → confirms everything is wired up
/rucksack:smoke → proves it works end-to-end ("✓ Rucksack works.")
```
Both come back happy? You're all set. *(Don't see them in the `/` menu yet? Just type* `run rucksack doctor, then smoke` *and Claude runs the same checks.)*
> ℹ️ This installs Rucksack **inside Claude Code**, so it won't add a `rucksack` command to your terminal. Want the `rucksack …` CLI in a shell too? See [Run it from your terminal](#run-it-from-your-terminal-optional).
---
## Quickstart
Installed? Then just **work normally** — Rucksack packs noisy output automatically, no flags or new commands. What changes is what your agent *ingests*:
| You run… | Your agent ingests… | Typical reduction¹ |
|---|---|---:|
| `npm test` (or any test runner) | the head, the **failing lines**, and a recall handle | ~−97% |
| `npm run build` / `webpack` / `vite build` | warnings + errors kept, the repetitive middle packed | ~−95% |
| `grep -rn TODO src` / `rg "error\|warn" .` | matches grouped by file, with counts (path globs work) | ~−95% |
| a JSON / API response | keys + a sample of big arrays | ~−99% |
| open a large file (`efficient_read`) | signatures + structure; bodies on demand | varies |
¹ reductions from the reproducible `node bench/ab.js`. Same idea for `cargo test`, `pytest -v`, `go test` — Rucksack keys off `error · warn · fail · panic`, not the tool.
Need the raw original of anything it packed? Ask Claude to **`expand`** the handle — it comes back faithfully. See your savings anytime with **`rucksack report --today`** (or `mcp__rucksack__report` in-session).
---
## Before / after
One `npm test` normally dumps the **whole** suite into your agent's context — and it gets re-sent on every later turn.
**Before** — what your agent normally eats (~977 tokens):
```text
> rucksack@0.0.1 test
PASS: reduces tokens
PASS: reduction > 50%
PASS: produces a recall handle
PASS: handles empty input
PASS: stable handle for same content
… 50+ more near-identical PASS lines …
FAIL: json: samples the big array (not all 200)
PASS: multiline-sig: full signature kept
=== 58 passed, 1 failed ===
```
**After** — what Rucksack hands the model (~290 tokens, **−70%**):
```text
rucksack: 977 → 290 tok (−70%)
PASS: reduces tokens
PASS: produces a recall handle
FAIL: json: samples the big array (not all 200)
⟨rucksack: elided 60 lines (~746 tok) — expand rk_bad35ce447⟩
=== 58 passed, 1 failed ===
```
Same information your agent needs — your **failure stayed visible** — at a third of the size. Nothing was summarized; those 60 elided lines come back in full with one `expand`.
---
## What you'd reclaim
A reproducible A/B over a realistic mix of ingested tool output — a test run, a build, a stack trace, a repo search, JSON output, logs, and a large file read. It's deterministic, so `node bench/ab.js` prints these exact numbers on any clone:
| Tool output ingested | Without Rucksack | With Rucksack | You save |
|---|---:|---:|---:|
| test suite output | 7,327 | 247 | −97% |
| webpack build output | 6,844 | 374 | −95% |
| stack trace | 1,637 | 413 | −75% |
| repo search (grep) | 8,790 | 429 | −95% |
| JSON API output | 11,377 | 169 | −99% |
| git log | 4,811 | 397 | −92% |
| ANSI-colored log | 9,499 | 193 | −98% |
| large source file read | 32,328 | 16,596 | −49% |
| **Total ingested tool context** | **82,613** | **18,818** | **−77%** |
Every input entered context **compact-first** — **0 expands** needed for this run, **0 full-file reads**. The largest win is on noisy logs/builds (−92% to −99%); a code file compresses less (−49%) because signatures and structure are kept. Reproduce it yourself: `node bench/ab.js` (deterministic — same numbers on any clone).
It's not a Node trick, either — Rucksack keys off language-agnostic signals (`error · warn · fail · panic`), so you get the same win in any stack:
| Your stack | Command | Result | What stays |
|---|---|---|---|
| **cargo** (Rust) | `cargo test` | 47,662 → 12,328 (**−74%**) | build/test signal |
| **pytest** (Python) | `pytest -v` | 1,948 → 490 (**−75%**) | failed assertion + summary |
| **npm** (Node) | `npm test` | **−70% to −83%** | failure lines |
> This measures **ingested tool context for the task** — not your total Claude bill, and not session speed.
---
## It knows what to keep
Rucksack picks a strategy by what it's looking at — it never blindly truncates, so you don't lose the line you needed:
| Content | You keep | Packed away (recall on demand) |
|---|---|---|
| **code** | imports, signatures, doc-comments | function bodies |
| **markdown** | the full heading outline | each section's prose |
| **JSON** | keys + a sample of big arrays | the rest of the structure |
| **diffs** | changed `+/-` lines + hunk headers | unchanged context |
| **logs / tests** | head, tail, and error/warn lines | the repetitive middle |
So you can hand your agent a 14k-token doc and it gets the whole structure for ~1k tokens — and your noisy build log still shows its one real error.
---
## See what you got back
You don't have to take the savings on faith — Rucksack ships its own honest accounting:
```sh
rucksack stats # your all-time scoreboard
rucksack report --today # shareable: net saved today, top sources, repeated expands
```
```text
rucksack report — today (2026-05-25)
NET saved : 124512 tokens (saved 124512 − refetched 0)
repeated expands : 0 (same chunk re-fetched; want 0)
top sources by net saved
cli 65587 · mcp 56449 · grep 2476
```
The model is simple, and it counts the cost of recall against you so the number stays honest:
> **net saved = tokens saved − tokens refetched**
Add `--json` to either command for CI — e.g. `rucksack report --today --json | jq '.net_saved'`.
---
## Everything you can run
**In a session — the default.** Once the plugin is installed, just ask Claude (e.g. *"run rucksack doctor"*) and it calls these tools for you: `efficient_read`, `efficient_grep`, `expand`, `stats`, `report`, `doctor`, `smoke`, `explain_hook`.
Rucksack even tells your agent *how* to use it well — **compact view first, partial expand for exact edits, don't re-expand** — so your savings hold up across a long run. Running an autonomous session? Grab the ready-made [`/goal` run template](docs/goal-template.md).
### Run it from your terminal (optional)
The plugin install runs Rucksack **inside Claude Code** and does not put a `rucksack` command on your PATH. If you also want a terminal CLI, install it from a clone:
```sh
git clone https://github.com/MerlijnW70/rucksack && cd rucksack
npm link # puts `rucksack` on your PATH
```
| Command | What it gives you |
|---|---|
| `rucksack doctor` | A health check (engine, hook, MCP, store, metrics, plugin) |
| `rucksack smoke` | Proof the pipeline works end-to-end (pack → read → expand → stats) |
| `rucksack stats` | Your all-time savings scoreboard |
| `rucksack report --today` | A shareable daily summary: net saved, top sources, repeated expands |
---
## Why did Rucksack skip my command?
The auto-compress hook is deliberately conservative. It looks at the **effective command** — stripping leading env-var assignments (`NODE_ENV=…`) and wrappers (`sudo`, `time`, `npx`, …), and checking each `&&`/`;` segment — and only wraps **plain, noisy commands**, leaving everything else **untouched to preserve your shell's exact semantics**. It skips a command that contains:
- a pipe — `|`
- a redirect — `>`, `<`, `2>&1`
- background execution — `&`
- an existing `rucksack` call
…or whose effective command simply isn't a high-volume tool.
| Command | Wrapped? | Why |
|---|:--:|---|
| `npm run build` | ✅ | on the noisy allowlist |
| `cargo test` | ✅ | on the noisy allowlist |
| `NODE_ENV=production npm run build` | ✅ | env prefix stripped → effective `npm run build` |
| `sudo npm install` · `npx vite build` | ✅ | wrapper stripped → real command matches |
| `cd app && cargo test` | ✅ | a later segment runs an allowlisted command |
| `npm run build 2>&1` | ➖ | redirect — left untouched |
| `npm run build \| tee build.log` | ➖ | pipe — left untouched |
| `npm run build &` | ➖ | background — left untouched |
| `echo "remember to run npm install"` | ➖ | "npm" is only *mentioned*, not the command that runs |
| `echo hello` | ➖ | not on the noisy allowlist |
A skipped command is **not** a failure — it's Rucksack staying out of the way so your shell behaves exactly as written. Not sure about one? Ask it directly:
```sh
rucksack explain-hook 'npm run build 2>&1'
```
```text
Rucksack would NOT wrap this command.
Reason:
contains redirect: 2>&1
Why:
Rucksack avoids wrapping commands with pipes, redirects, or background
operators — they're left untouched to preserve your shell's exact semantics.
Try:
npm run build
```
In a Claude Code session (no CLI on PATH), ask Claude to use the **`explain_hook`** tool instead.
> **Testing the hook?** Run the command **bare** — e.g. `npm install --verbose`, `npx vite build`, `cargo test`, `pytest -vv`. Don't add `2>&1`, `| tee`, or `> out.log`: Rucksack captures stderr itself when it wraps an eligible command, so a redirect only stops it from engaging.
---
## Before you ask — the honest limits
- **Token counts are estimates** — a calibrated character-class model (~5% off Anthropic's official counter), not exact billing tokens.
- **It won't cut your Claude bill by 83%** — the −83% is *ingested tool context for a task*, not total cost, and not session speed.
- **Your savings depend on your output** — large, repetitive output wins big; small or unique output saves little or nothing.
- **It's strongest on noisy coding sessions** — structure detection is heuristic, so it helps less on tiny edits or mostly-prose docs.
- **Recall costs tokens when you use it** — `expand` pulls content back; Rucksack tracks that as `tokens refetched`, so your `net saved` stays honest.
- **Recall is faithful, not byte-identical** — before storing, Rucksack strips terminal color codes, normalizes line endings (CRLF→LF), trims trailing whitespace, and collapses long runs of identical lines (shown as `⟨×N⟩`), so `expand` returns every meaningful line — but not a byte-for-byte copy of colored, CRLF, or duplicated output.
- **It doesn't replace Claude Code** — it sits beside it and packs your context.
---
## License
[MIT](LICENSE) · Built for [Claude Code](https://claude.com/claude-code)
---
<div align="center">
**Stop shipping your context to the void. Pack the noise, keep the signal, recall the original when you need it.**
```sh
claude plugin marketplace add MerlijnW70/rucksack
claude plugin install rucksack@rucksack
```
</div>
Connection Info
You Might Also Like
Train-in-Silence
The first Task-Aware MCP server and automated VRAM calculator for LLM...
stacklit
108,000 lines of code. 4,000 tokens of index. One command makes any repo...
AppClaw
AI-powered mobile automation agent — describe what you want in plain...
pdf-mcp
Production-ready MCP server for PDF processing with intelligent caching....
kotadb
Local-only code intelligence API for AI developer workflows (Bun +...
gemini-api-docs-mcp
A remote HTTP MCP server for searching Google Gemini API documentation.