ContextPruner

Documentation

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 --stage

2 · 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. Everything runs in your browser; no network request is ever made with your manifest.

3 · Automate it (Pro)

The $9/month tier keeps your config files current automatically. 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. 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.

Set up the GitHub Action (syncs on every push)

  1. Subscribe on the account page, then click Create key. Copy the key right away — it is shown only once. You can hold two keys at a time, so you can create a new one before you revoke the old one.
  2. In your repo, download the workflow file:
    mkdir -p .github/workflows
    curl -fsSL https://contextpruner.vercel.app/install/contextpruner.yml \
      -o .github/workflows/contextpruner.yml
  3. Add the key to your repo's secrets: on GitHub, open Settings → Secrets and variables → Actions → New repository secret. Name it CONTEXTPRUNER_API_KEY and paste the key as the value.
  4. Commit and push the workflow file. From now on, every push regenerates the five config files, and the workflow commits any changes using its own GITHUB_TOKEN.

Set up the pre-commit hook (configs join each commit)

  1. Get an API key the same way: subscribe on the account page, click Create key, copy it.
  2. From your repo root, install the hook:
    curl -fsSL https://contextpruner.vercel.app/install/contextpruner-hook.sh \
      -o .git/hooks/pre-commit && chmod +x .git/hooks/pre-commit
  3. 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
  4. 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.vercel.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}
    ]
  }'

4 · 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?

Probably not. It's 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. The math is linear, so treat it as a dial: if you're closer to 100 prompts a day, double the monthly figure; a 10-prompt-a-day side project, divide by five. Both of our assumptions — the prompt volume and the 5% slice — are printed in the formula under the counter, precisely so you can re-run the math with your own numbers.

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: