Documentation
Last updated
1 · Generate a manifest
ContextPruner only ever sees file paths and byte sizes — never contents. Any of these commands produces a manifest you can paste into the workspace:
# Linux (GNU find) — paths + byte sizes
find . -type f -not -path './.git/*' -printf '%P\t%s\n'# macOS (BSD stat) — paths + byte sizes
find . -type f -not -path './.git/*' -exec stat -f '%N%t%z' {} +# Any git repo — tracked paths only (sizes unknown)
git ls-files --stage2 · Run the free triage
Paste the output into the workspace on the home page. The engine classifies every file as KEEP, PRUNE, or SUMMARIZE, computes what the junk costs you — metered API dollars, or plan capacity reclaimed for your code if you pay via a subscription — and generates five config files — AGENTS.md (the cross-agent standard), CLAUDE.md, GEMINI.md, .cursor/rules/contextpruner.mdc, and .github/copilot-instructions.md — ready to copy into your repo. It also generates four enforcedfiles the agents' own harnesses apply — covered in section 4. Everything runs in your browser; no network request is ever made with your manifest.
3 · Lint a config you already have
Already have an AGENTS.md or CLAUDE.md? Lint checks it against your actual file tree and grades it, so a config written months ago doesn't quietly stop matching your repo. Lint and the generator share one engine, so a clean lint means your config matches what a fresh generation would produce today. It flags four things:
- Missing— junk in your tree that no rule skips yet, with what it's costing you.
- Dead — a rule that matches nothing, usually a path that moved or got deleted.
- Drift — a rule in one config but missing from another, so your agents disagree.
- Conflict — two rules that contradict each other.
In your browser — free
On the home page, switch the workspace to Lint, paste your existing config and your file tree, and you get the graded report plus one-click fixes you can review and copy back. Like the triage, it runs entirely in your browser — nothing is uploaded.
Run the lint CLI on your machine (Pro)
The contextpruner CLI runs the same check from your terminal. The engine runs on your machine — your file tree never leaves it; only your API key is sent, to confirm an active subscription.
- Subscribe on the account page, then click Create key and copy it — it is shown only once. One subscription covers everything: the same key works for the lint CLI and the config automation below, so if you already have a key, reuse it and skip to the next step.
- Give the CLI your key by exporting it in your shell:
# add to ~/.zshrc or ~/.bashrc to keep it set export CONTEXTPRUNER_API_KEY=cp_live_... - From your repo root, run the lint. With no arguments it auto-detects your
AGENTS.md,CLAUDE.md, and the rest; add--fixto rewrite the managed block in place:npx contextpruner lint # grade every config against your tree npx contextpruner lint --fix # rewrite the managed block to fix the issues
There's nothing to install first — npx fetches the published contextpruner package on demand. Exit codes make it CI-friendly: 0 when the config is clean, 1 when it finds issues, 2 on a usage or auth error.
Fail CI when a config drifts (Pro)
- Download the ready-made workflow into your repo:
mkdir -p .github/workflows curl -fsSL https://contextpruner.app/install/contextpruner-lint.yml \ -o .github/workflows/contextpruner-lint.yml - Add your key as a repo secret: on GitHub, open Settings → Secrets and variables → Actions → New repository secret. Name it
CONTEXTPRUNER_API_KEYand paste the key. If you already added it for the sync Action, reuse that one. - Commit and push the workflow. From now on, every push and pull request lints your configs and fails the check when one drifts from your tree.
4 · Make it enforced
The markdown configs above are advisory: the model reads them and usually complies, but nothing stops it from opening a lockfile anyway. Some agents also support files their own harness enforces — the tool layer blocks the read before the model ever sees the bytes. The workspace generates both kinds side by side, in two labeled tab rows.
.cursorignore— Cursor blocks indexing and Agent access to matching paths..geminiignore— Gemini CLI excludes matching paths from its tools..codeiumignore— Windsurf (now Devin Desktop) blocks matching paths. Newer builds also read.windsurfignoreand.devinignore; the.codeiumignorewe generate stays honored..claude/settings.json— Claude Codepermissions.denyrules block reads at the tool layer: Read, Grep, Glob, and recognized shell commands.
The enforced set is deliberately narrower than the advisory Ignore list: secrets (.env*, with placeholder variants like .env.example re-allowed), dependency, build, and cache directories, and binary media. Lockfiles, fixtures, and logs stay advisory-only on purpose — sometimes an agent legitimately needs to read a lockfile to debug a resolution, and a hard block would get in the way. Copy the files from the workspace and commit them like any other config — or let the Pro automation below write and refresh all nine files on every push.
The honest caveats
- Best-effort, not a guarantee. Cursor's own docs call ignore enforcement best-effort, and on every agent a terminal command or MCP server can still reach a blocked file. Enforcement raises the floor; it doesn't seal the room.
- Claude Code specifics. The deny rules ship in project settings, so they apply to everyone who clones the repo — and they're in force even before anyone accepts the workspace-trust prompt, because trust gates extra permissions, not these blocks. Deny rules can't be negated, so
.env.example-style placeholder files stay blocked in Claude Code even though the three ignore files re-allow them. They hold placeholders, so nothing is lost — but the denial is visible. - Need an exception? Pin the file to Keep in the triage list — that removes the covering rule from all four enforced files (the advisory list still names the rest of the junk). If you use the automation, declare it instead: commit a
.contextprunerfile with lines likekeep: vendor/sdk/docs/**, and every sync (and the lint CLI) drops any enforced rule covering those paths — even untracked ones like docs insidenode_modules/. Or add your own lines below the generated block: gitignore is last-match-wins, but note a file inside an ignored directory can't be re-allowed with a bare!path— you need to re-allow the directory itself. - Copilot and Codex. GitHub Copilot's content exclusion lives in server-side repo/org settings, not a file we can generate — configure it on GitHub. OpenAI Codex has no working enforcement file yet, so the advisory
AGENTS.mdis the lever there.
5 · Filter search junk (Pro)
The enforced files above hard-block pointedreads of secrets and dependency directories. But a broad search — grep across the repo, a glob for every config file — still dredges junk into the results: lockfiles, minified bundles, snapshots, fixtures, logs. That's the middle tier the enforced set leaves advisory on purpose, because a hard block would also stop the agent when it legitimately needs one of those files. The runtime filter handles it differently: it drops junk paths from search results before they reach the model, while a request for one named file always passes through untouched. It runs on your machine, needs the same cp_live_ key as the lint CLI, and — like everything paid — sends only your key, never your files.
One command installs both delivery paths, because different agents search differently:
export CONTEXTPRUNER_API_KEY=cp_live_... # same key as lint
contextpruner serveShell shims — the cross-agent floor
serve writes shims for rg, grep, find, and ls into ~/.contextpruner/bin, then prints the line to put on the front of your PATH:
# prepend the shim dir — put this in ~/.zshrc or ~/.bashrc
export PATH="$HOME/.contextpruner/bin:$PATH"Prefer one line? This installer runs serve for you — via npxif the CLI isn't installed globally — and appends the PATHline to your shell profile, only if it isn't there already:
export CONTEXTPRUNER_API_KEY=cp_live_... # same key as lint
curl -fsSL https://contextpruner.app/install/contextpruner-serve.sh \
-o contextpruner-serve.sh && sh contextpruner-serve.sh && rm -f contextpruner-serve.shEach shim runs the real tool and pipes its output through ContextPruner, dropping junk paths from broad fan-out results. Any agent that shells out to these tools gets the filter with zero per-agent setup. Every filtered result ends with a footer of what it hid — showing 40 of 210 matches; 170 pruned as junk — and when a search actually pruned something, a savings note goes to stderr so your tokens-per-turn win is visible while stdout stays clean. cat gets a passthrough shim: reading a named file is a pointed read and is never filtered.
MCP tools — for agents that bypass the shims
Some agents don't shell out — Claude Code runs its own bundled ripgrep, which never touches your PATH. For those, servewrites (or merges into) each agent's MCP config so it can spawn ContextPruner's filtered-search server, exposing contextpruner_search, contextpruner_glob, and contextpruner_list — the same junk-pruning, with a all: trueargument to see everything. Claude Code's project .mcp.json is always written; Cursor, Gemini CLI, and Windsurf are written only when that agent is set up in the repo, so serve never litters a config for an agent you don't use. Restart the agent afterward.
Steer the agent toward the filtered tools
Adding a tool isn't enough — the agent has to prefer it over its built-in search. So serve also marks the repo's .contextpruner file with a prefer-tools directive. Commit it. The committed marker is what tells the config automation to add a “Prefer these tools” section to your generated AGENTS.md, CLAUDE.md, and the rest, steering agents toward the filtered search. Because it's a committed signal rather than local detection, the automation reads the same value on your machine and in CI, so the section never appears in one place and vanishes in another.
The honest caveats
- Nothing is hidden silently. Every filtered result names its count, and there's always an escape hatch: set
CONTEXTPRUNER_ALL=1for the shims, or passall: trueto an MCP tool, to run one search unfiltered. - It filters, it never blocks. The runtime filter only prunes broad search results. A pointed read of a named file — including a lockfile you actually need to debug — always goes through. Hard blocking is the enforced set's job (see the Enforce section above); this layer is the softer companion to it.
- macOS and Linux for now. The shims are POSIX
sh; Windows isn't supported yet. The MCP tools work anywhere the agent runs. - Opt-in usage counts. The first time you run
serve— and only in an interactive terminal — it asks once whether to share two aggregate numbers, how many files the filter assessed and how many bytes of junk it kept out of context, to display on the site. It stays off unless you say yes, it never asks in a non-interactive shell, and nothing else is ever sent — no paths, no file contents. The filter itself runs entirely on your machine.
6 · Automate it (Pro)
The $9/month tier keeps your config files current automatically — your repo changes every day, and this is the piece that means you never re-paste. Your machine sends only file paths and byte sizes, our API returns the config text, and your own runner commits it. We never hold repo credentials. Syncs are metered into your account's usage dashboard, so you can see what the last one cut and how many have run. There are two installers; both replace only the span between the <!-- contextpruner:begin --> markers, so your own instructions and your Exceptions section survive every regeneration. And when nothing changed except the generation timestamp, both skip the commit entirely.
Pick one of the three below — they're alternatives, not steps. The GitHub Action runs in CI on every push, with nothing to install locally and coverage for your whole team. The pre-commit hook runs on your machine on every commit. The raw API is for wiring it into your own script. You only need one.
Set up the GitHub Action (syncs on every push)
- Subscribe on the account page, then click Create key. Copy the key right away — it is shown only once. The same key powers the lint CLI too, so if you already made one, reuse it. You can hold two keys at a time, so you can also create a new one before you revoke the old one.
- In your repo, download the workflow file:
mkdir -p .github/workflows curl -fsSL https://contextpruner.app/install/contextpruner.yml \ -o .github/workflows/contextpruner.yml - Add the key to your repo's secrets: on GitHub, open Settings → Secrets and variables → Actions → New repository secret. Name it
CONTEXTPRUNER_API_KEYand paste the key as the value. - Commit and push the workflow file. From now on, every push regenerates all nine config files — the five advisory configs and the four enforced ones — and the workflow commits any changes using its own GITHUB_TOKEN. In an existing
.claude/settings.jsononly the sentinel-marked deny span is touched; a file that can't be parsed is skipped, never overwritten. Enforcement exceptions survive every regeneration: declare them in a committed.contextprunerfile (see the Enforce section above).
Set up the pre-commit hook (configs join each commit)
- Get an API key the same way: subscribe on the account page, click Create key, copy it.
- From your repo root, install the hook:
curl -fsSL https://contextpruner.app/install/contextpruner-hook.sh \ -o .git/hooks/pre-commit && chmod +x .git/hooks/pre-commit - Give the hook your key — either export it in your shell profile or store it next to the hook (inside
.git/, so it can never be committed):# option A — shell profile (~/.zshrc or ~/.bashrc) export CONTEXTPRUNER_API_KEY=cp_live_... # option B — per-repo file the hook reads automatically mkdir -p .git/contextpruner echo 'CONTEXTPRUNER_API_KEY=cp_live_...' > .git/contextpruner/env - Commit as usual. Updated config files are added to each commit automatically. If you are offline or anything fails, the hook skips quietly and never blocks your commit.
Note: step 2 overwrites an existing .git/hooks/pre-commit. If you already have one (or use a hook manager like lefthook or pre-commit), save the script elsewhere and call it from your existing hook instead.
Or call the API directly
Any script can do what the installers do — the request is one curl:
# paths + byte sizes only — file contents never leave your machine
curl -sS https://contextpruner.app/api/prune \
-H "Authorization: Bearer $CONTEXTPRUNER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"version": 1,
"source": "api",
"files": [
{"path": "src/app/page.tsx", "sizeInBytes": 4812},
{"path": "pnpm-lock.yaml", "sizeInBytes": 912640}
]
}'7 · The math, defended
The savings counter makes claims; this section defends them. Every question below is one a skeptical reader should ask — and the answer holds up to a hand check.
Are you saying my codebase is junk?
No. The counter says so first: “all N code files kept.” Everything you wrote is classified KEEP. What gets pruned is installed machinery: node_modules/, build output, lockfiles, caches — files your package manager and build tools generate. On a typical JavaScript project that machinery outweighs your source a thousand to one by bytes, which is why the percentage looks dramatic. The percentage measures bytes removed from your agent's view, not the worth of your code.
I can’t find these junk files in my GitHub repo. Where are they?
They're on your disk, not in your repo. Dependency and build directories are gitignored, so GitHub has never seen them — a repo with 89 tracked files can sit in a working directory with 25,000+ files on disk. But coding agents don't read GitHub: they read the working directory, where those files are real. A find-style manifest captures that on-disk reality; a git ls-filesmanifest captures only the repo. Both are honest answers to different questions — “what's in my repo?” versus “what's on the disk my agent actually reads?”
My plan costs $200/mo. How can junk “cost $500/mo”?
The two numbers are in different currencies. Waste is priced at API list rates — the only universal unit — while a subscription is a bulk discount: vendors sell plan users usage worth far more than the sticker price if it were metered. So junk worth $500/mo at list prices can genuinely flow through a $200/mo plan. What junk actually costs a subscriber is capacity: junk tokens burn your rolling usage limits exactly like useful tokens do, so you hit the wall sooner and get less real work per session. That's also why the headline can never exceed your plan price — no matter how large the leak, all you ever had at stake is what you pay.
Where does the “5% context slice” come from?
It's a stated modeling assumption, not a measurement. It's printed in the formula under the counter so you can judge it. Modern agents don't resend your repository every prompt; they pull localized slices via search indexes, and many respect .gitignore when indexing. Junk leaks in around those defenses: stack traces pointing into node_modules, lockfiles read while debugging versions, build output opened during troubleshooting, tools that don't honor ignore files. We model that leak as ~5% of each prompt's context payload.
Is “50 prompts/day” my number?
Only if you want it to be. 50 prompts/day is our stated baseline for a developer working with an agent full-time (50 prompts across a working day, 20 working days a month), not a measurement of you — so we made it a slider. Drag the prompts/day dial under the counter and the monthly figure recomputes to your volume; the math is linear, so 100 prompts a day doubles it and a 10-prompt-a-day side project divides it by five. Both of our assumptions — the prompt volume and the 5% slice — are printed in the formula under the counter, and prompts/day is now yours to set.
Why does per-prompt waste stop at 50K tokens?
Because a prompt can't be bigger than the model's context window. Per-prompt junk clamps to 5% of the window — min(junk, window) × 5%. On a 1M-token model that's 50K tokens; on a 200K model, 10K. Without this clamp, a large enough manifest would claim more junk per prompt than any model can physically hold, and every dollar figure built on it would be fiction. When your junk alone overflows the window, the counter tells you so.
Cloud agents clone fresh from GitHub — doesn’t that avoid the junk?
The clone starts clean, but the working environment doesn't stay that way. The first thing a cloud agent does with your project is install dependencies — regenerating the same tens of thousands of junk files inside its sandbox. The one protection that follows your code everywhere is a committed instruction file: because AGENTS.md, CLAUDE.md, and the rest live in the repo, every clone carries them, and they're in force before the install ever runs.
Are the dollar figures guarantees?
No. They're estimates, and deliberately conservative ones. Every step is bounded or understated: per-prompt waste is capped by the model's context window, the monthly headline is capped by what you actually pay, token and percentage figures are truncated so they never overstate, per-prompt costs truncate to a tenth of a cent, monthly dollars are shown to the cent, and the plan multiple truncates too — junk worth 2.59× your plan displays as 2.5×. The full formula is printed under the counter, and every number on the screen can be recomputed by hand from the numbers next to it. If you find one that can't, that's a bug — report it.
What if a generated rule is wrong for my repo?
It will happen: ContextPruner only sees paths and byte sizes, and only you know which junk-shaped files are load-bearing in your repo: test fixtures your suite depends on, a spec document the skim-all-markdown rule would catch, vendored docs an existing instruction file orders read in full. (We hit this ourselves — our own BLUEPRINT.md is exactly the kind of file the skim rule mis-handles.) There are two remedies. For a specific file, click its verdict in the triage list — the pin cycles PRUNE → KEEP → SKIM, the rules and the savings math recompute instantly, and pinned verdicts are written into the generated rules as taking precedence. For anything broader, every generated file ends with an “Exceptions (yours — edit freely)” section, outside the marked block, for overrides in your own words. The GitHub Action and pre-commit hook rewrite only the marked block, leaving your Exceptions and any pre-existing instructions above the block untouched. If you re-paste a regenerated file by hand, replace only the marked block and keep your own Exceptions section. On any conflict, your own instructions win.
Does my file list leave my browser?
No. The free triage runs 100% client-side — no network request is ever made with your manifest. And the manifest itself contains only file paths and byte sizes; your file contents are never read by anything, anywhere.
Sources & assumptions
Every figure in the counter is either sourced or ours — here is which is which:
- Model prices & context windows — sourced, machine-checked. Pulled from the LiteLLM community pricing dataset, validated weekly by an automated job that fails loudly if any model we list drifts from the dataset.
- Subscription plan prices — sourced, checked July 2026. The “you pay via” caps come from each vendor's pricing page: Anthropic, OpenAI, Google, xAI. Vendors change tiers constantly, so treat them as indicative and the linked pages as the source of truth. DeepSeek offers no consumer subscription, so it shows API pricing only.
- 1 byte ≈ 0.25 tokens — industry rule of thumb. The widely published ~4-characters-per-token approximation for English text and code; slightly conservative for code, which tends to tokenize denser.
- Ours alone — stated assumptions, no external source. 50 prompts/day × 20 working days, and the 5% context slice. Both are visible in the printed formula, not hidden facts — and prompts/day is a slider you set to your own volume — see the FAQ entries above for how to judge and rescale them.