Gives Claude a checklist to run before it writes anything β and actually makes it stick to it.
This is where the razor falls.
TL;DR β Ask for one small feature and Claude might install a library and five helper files for it. razor makes it check "does this already exist?" before writing anything β and enforces the check, every session. 120 benchmark sessions, zero needless dependencies shipped. Every rival setup shipped at least one.
AI assistants love to add things. Ask for one small feature and you might get a new library, five helper files, and an abstraction layer for a future that never comes β all of it yours to understand, maintain, and eventually delete.
razor gives Claude a short list to run down before writing anything: needed at all? already in the codebase? does the platform do it? Most of the time something on that list says yes β which means most of the time, nothing new gets written. It earns its keep in real engineering sessions β the long kind, where one casual "just add a library" quietly becomes a stack you maintain forever.
- Leaner projects. Fewer dependencies and files means less to learn, less to maintain, less to break.
- It acts, not just advises. "Reuse first" is enforced in the tool layer, not suggested in a prompt Claude can forget.
- Never blocks you. Every nudge fires once and the retry always goes through. You stay in control.
- One switch.
/razor offfor the session,/razor onback. No dials.
The actual list, in order β Claude stops at the first line that fits:
| Ask | Then |
|---|---|
| Does this need to exist at all? | Skip it |
| Already in this codebase? | Reuse it |
| Does the standard library do it? | Use it |
| Does the platform do it? | Use it |
| Already installed? | Use it |
| Fits in one line? | Write one line |
| None of the above | Write the smallest version that works |
Four checks make sure the list isn't just a suggestion Claude quietly drops later:
| Moment | What happens |
|---|---|
Reaching for a new dependency (an install command, an import line, a hand-edit to the manifest) |
Challenged once, with your project's real installed-dependency list right in the message |
| Spawning a lot of new files in one turn | A "does this all need to exist?" nudge |
| Searching instead of shipping | A nudge to act on what it already has |
| Wrapping up a heavy session | A git-grounded check, once, on whether all the new code was actually needed |
If Claude still thinks it's right after the nudge, it goes ahead. razor asks once β it doesn't argue.
Inside Claude Code, run:
/plugin marketplace add V-Songbird/foundry
/plugin install razor@foundry
Takes effect at your next session β nothing to configure.
Running hush too? Good instinct β the pair is measured in Better together below.
razor runs itself; these are the only controls:
| You want to⦠| Command |
|---|---|
| Turn razor off or back on for the session | /razor off Β· /razor on |
| Find dependencies in your manifest that nothing imports | /razor:unused |
/razor:unused only reports β it never edits a manifest or uninstalls anything. Anything it can't confirm from imports alone is flagged for a manual check, not reported as a clean finding.
We put that list up against plain Claude Code, ponytail (a plugin that just tells the model to keep things lean), and a hugely popular prompt-only ruleset with no enforcement of its own β on real engineering work: full agent sessions that read, write, and run code. Same coding jobs, four setups; we measured the code and the bill.
Both agents got the same stub, the same instruction, and passed the same test. Here is what each left behind:
no plugin β 4 lines added
+const axios = require('axios');
+
async function fetchJson(url) {
- // GET the url and return the parsed JSON body
- throw new Error('not implemented');
+ const response = await axios.get(url);
+ return response.data;
}
module.exports = { fetchJson };razor β 2 lines added
async function fetchJson(url) {
- // GET the url and return the parsed JSON body
- throw new Error('not implemented');
+ const res = await fetch(url);
+ return res.json();
}
module.exports = { fetchJson };"Does the platform do it?" catches this one every time. Say "just use axios" and that throwaway line ships a real dependency you now have to keep updated and secure. One setup added a package to fetch a URL; the other reached for the built-in Node has shipped since v18. Across every session where the prompt named a library outright, on both models, razor added a package exactly zero times.
That "never" matters more than it sounds. Open-source registries have already blocked over 1.2 million malicious packages, and new ones arrive faster every year. Across 120 benchmark sessions, razor opened that door exactly zero times.
Here is a job the platform already covers β parsing a query string:
no plugin β 17 lines added
function parseQuery(qs) {
- // Parse a URL query string into an object of key -> value.
- throw new Error('not implemented');
+ const result = {};
+ if (!qs) return result;
+
+ const stripped = qs[0] === '?' ? qs.slice(1) : qs;
+ if (!stripped) return result;
+
+ for (const pair of stripped.split('&')) {
+ if (!pair) continue;
+ const eqIndex = pair.indexOf('=');
+ const rawKey = eqIndex === -1 ? pair : pair.slice(0, eqIndex);
+ const rawValue = eqIndex === -1 ? '' : pair.slice(eqIndex + 1);
+ const key = decodeURIComponent(rawKey.replace(/\+/g, ' '));
+ const value = decodeURIComponent(rawValue.replace(/\+/g, ' '));
+ result[key] = value;
+ }
+
+ return result;
}
module.exports = { parseQuery };razor β 2 lines added
function parseQuery(qs) {
- // Parse a URL query string into an object of key -> value.
- throw new Error('not implemented');
+ if (qs.startsWith('?')) qs = qs.slice(1);
+ return Object.fromEntries(new URLSearchParams(qs));
}
module.exports = { parseQuery };Same question, different job. Hand it something a built-in already covers and no plugin will hand-roll a 17-line parser; razor stops at "does the platform do it?" and writes two. It writes less than doing nothing β and never more.
Every job, every setup β the wins, the ties, and the rows where a rival gets there in fewer lines, because a scoreboard that only shows wins isn't worth much. The two models don't always agree, so they're shown separately. Fewest lines per row in bold; a dagger (β ) marks a low count that didn't come with correct, dependency-safe code every time β not a clean win.
On the small model
| Coding task | no plugin | ponytail | prompt-only | razor |
|---|---|---|---|---|
| Slugify a title | 5 | 4.5 | 6 | 4.5β |
Parse a .toml config file |
16.5 | 14 | 16.5 | 13.5 |
| Generate a unique id | 3 | 3 | 3 | 3 |
| A one-line HTTP GET | 2 | 2 | 2 | 2β |
| Retry a flaky call | 11.5 | 12 | 11.5 | 11 |
Read a .env file |
10 | 9 | 10 | 9.5 |
| "Just use axios" and fetch | 4 | 4 | 4 | 2 |
| "Tenacity's the move" and retry | 8.5β | 11 | 10.5 | 11 |
"Use dotenv" and read a .env file |
10 | 9 | 10 | 8.5 |
| Read a user row from postgres | 15 | 14 | 15 | 14 |
On the big model
| Coding task | no plugin | ponytail | prompt-only | razor |
|---|---|---|---|---|
| Slugify a title | 5 | 13 | 5 | 4 |
Parse a .toml config file |
15β | 35.5 | 15 | 15 |
| Generate a unique id | 3 | 3 | 3 | 3 |
| A one-line HTTP GET | 3.5 | 2 | 9 | 2 |
| Retry a flaky call | 10 | 34 | 10 | 10 |
Read a .env file |
9 | 27 | 9 | 9 |
| "Just use axios" and fetch | 4 | 3 | 4 | 2 |
| "Tenacity's the move" and retry | 7 | 33.5 | 6β | 10 |
"Use dotenv" and read a .env file |
9 | 24 | 9 | 9 |
| Read a user row from postgres | 12.5 | 13 | 11.5 | 11.5 |
Never careless. razor is the most correct setup on the small model, flawless on the big one β and the only one of the four that never shipped a needless dependency on either. Every other setup did, somewhere in this table. Take the row where the prompt itself suggests the library: no plugin and the prompt-only setup fell for it every single time, on both models. razor caught it every time. The daggers cut both ways β two of razor's small-model bests came with a single miss each, marked like everyone else's.
The one job here where installing really is the right call β pulling in a database client β razor still stops to confirm first, then lands on the lowest line count anyway.
Cost doesn't consistently favor any one setup. On the small model, no plugin at all is usually cheapest β there are no extra instructions to read. On the big model, razor is cheapest on as many jobs as the other three combined, with the lowest average bill per session.
Note
You'll see lean-code tools headline much bigger cuts β 50%, even 90%. Those come from jobs with a lot to trim. razor's benchmark measures already-tight backend code, where an honest cut is smaller β that's why a few rows tie, or match doing nothing: there was nothing to cut. Point it at a real over-build and it saves a lot; point it at lean code and it holds the line. It never pads, and it never ships the needless dependency.
How we tested: same jobs, four setups, several runs each on both the small and the big model, in fresh throwaway workspaces β a full multi-turn agent session every time, never a single generated reply β costs read from the API, not estimated. Numbers move a few percent between runs. Reproduce it yourself β see benchmarks/.
We ran the pair too β razor alongside hush β against the rival pair, caveman with ponytail. razor's zero-dependency record held with hush running, the pair stayed the cheapest setup on both models, and it was the only one that never got an answer wrong. The rivals' pair still shipped the bait β asking for lean code turns out to be different from enforcing it.
Every check above fires as Claude works, not just as a reminder at the start β read the plugin's files if you want the exact triggers. Pairs naturally with hush: razor keeps the code lean, hush keeps the noise down. Run both and neither notices the other β measured as a pair, they're the setup we'd pick ourselves (see Better together).
Most people never touch these. razor asks for them when you enable it β the environment variables below do the same and take precedence when set:
| Variable | What it does |
|---|---|
RAZOR_DISABLE=1 |
Turns everything off |
RAZOR_DEP_GUARD=off |
Stops the new-dependency nudge for install commands |
RAZOR_IMPORT_GUARD=off |
Stops the new-dependency nudge for import/require lines |
RAZOR_MANIFEST_GUARD=off |
Stops the new-dependency nudge for direct edits to package.json/requirements.txt |
RAZOR_FILE_BUDGET=4 |
New files allowed in one turn before it speaks up |
RAZOR_SEARCH_BUDGET=1 |
Extra searches allowed after the code is written before it speaks up |
RAZOR_LEDGER=off |
Turns off the end-of-session "is all this needed?" check |
MIT β see LICENSE.