Short, plain replies from your coding agent. Answer first, no filler, every fact kept, powered by versa
| output tokens than Vanilla Claude 10 developer questions |
blind votes for clearcut against Vanilla Claude |
output tokens than caveman same questions |
blind votes for clearcut against caveman |
Example · Install · The rules · Benchmark · Commands · How it works · Privacy
Coding agents explain too much: greetings, recaps, "it's worth noting", closing offers. clearcut is a set of writing rules plus hooks that keep them active in every session. Heavily inspired by caveman and unslop.
"What's the point of using a debouncer on a search input?", asked on Claude Opus 5.5:
Same question: 55% fewer tokens than Vanilla Claude, 36% fewer than caveman.
| Vanilla Claude · 469 tokens | caveman · 330 tokens | clearcut · 210 tokens |
|---|---|---|
|
|
|
The Vanilla Claude reply
A debouncer holds off the search until the user stops typing for a short time, usually 200–500 ms. Without one, typing "laptop" fires six searches (
l,la,lap, ...). With one, it fires a single search forlaptop.Why it helps:
Less load on the backend. Far fewer API calls or database queries. That cuts server cost, avoids hitting rate limits, and matters a lot for paid APIs or slow full-text search.
No out-of-order results. When requests fire on every keystroke, they can come back in a different order than they were sent. If the response for
laparrives after the one forlaptop, the UI shows stale results. Debouncing makes this much less likely. It doesn't remove the problem entirely, so you still want request cancellation, such asAbortController.Smoother UI. Results don't flicker or re-render on every keystroke, and the main thread isn't busy with work the user is about to throw away. This applies even to client-side filtering of large lists.
Fewer useless searches. Results for half-typed words like
lapare rarely what the user wants, so you skip work nobody will look at.Tradeoffs:
- Added delay. Results arrive a little later. Too long a delay (over about 500 ms) makes the UI feel slow. Too short a delay barely saves any requests.
- Debounce vs. throttle. Debounce waits for a pause in typing. Throttle runs at most once per interval, even while the user is still typing. Throttle fits better when you want live updates during continuous typing.
- Pair it with other measures. Common companions are a minimum query length (e.g. 2+ characters), caching repeated queries, and cancelling in-flight requests when a new one starts.
Minimal example:
function debounce(fn, ms) { let t; return (...args) => { clearTimeout(t); t = setTimeout(() => fn(...args), ms); }; } input.addEventListener('input', debounce(e => search(e.target.value), 300));
The caveman reply
A debouncer cuts the work done per keystroke. Without one, typing "react hooks" fires 11 searches, one per character. With one, it fires one search after the user pauses typing (often 200–500 ms).
Benefits:
- Fewer requests. Less load on your API or server, and lower cost when the API bills per call or has rate limits.
- No stale results. Fewer requests in flight means fewer race conditions. Without it, a slow response for "rea" can arrive after "react" and overwrite the newer results.
- Smoother UI. No flicker from results re-rendering on every keystroke, and less work on the main thread for expensive client-side filtering.
- More useful queries. Partial input like "r" or "re" returns noise anyway.
Tradeoff: the user waits a little before results appear. Tune the delay. Too short gives little benefit. Too long makes the search feel slow.
Related: throttle runs at most once per interval while the user is still typing, so results update during typing. Debounce waits until typing stops. For search-as-you-type, debounce is the usual choice. Also cancel in-flight requests with
AbortController, because debounce alone does not stop the race above.function debounce(fn, ms) { let t; return (...args) => { clearTimeout(t); t = setTimeout(() => fn(...args), ms); }; } input.addEventListener('input', debounce(e => search(e.target.value), 300));
The clearcut reply
A debouncer delays the search until the user stops typing for a short time, typically 200 to 500 ms. You then send one request per pause instead of one per keystroke.
Typing "react hooks" without one fires 11 searches. With one, it usually fires 1 or 2.
What you gain:
- Fewer requests: less load on the server and fewer hits against API rate limits or costs.
- Fewer out-of-order results: with fewer requests in flight, a slow response for "rea" is less likely to arrive after the one for "react" and overwrite it. You still need request cancellation or a sequence check to rule this out.
- Less wasted work on the client: the results list re-renders less often and flickers less.
The cost is a short delay before results appear. Keep the delay short so the search still feels responsive. If the search is local and cheap, such as filtering a small in-memory list, you often don't need a debouncer at all.
Requirements: Node 22 or newer on PATH for the Claude Code hooks, and Python 3.10 or newer for the Codex, pi, and vibe adapters.
/plugin marketplace add versa-training/clearcut
/plugin install clearcut@clearcut
Restart Claude Code. clearcut is on from the first message of every session, subagents included.
git clone https://github.com/versa-training/clearcut.git
python3 clearcut/adapters/install.py| Agent | How clearcut loads | One-time step |
|---|---|---|
| Codex | SessionStart hook in ~/.codex/hooks.json |
Start codex, run /hooks, and trust the clearcut hook |
| pi | Extension in ~/.pi/agent/extensions/ that adds the rules to every run |
None |
| vibe | Prompt file ~/.vibe/prompts/clearcut.md, selected by system_prompt_id |
Rerun python3 clearcut/adapters/vibe/sync.py after a vibe update |
All three read the rules from the cloned repository, so git pull updates them. python3 clearcut/adapters/install.py --remove undoes the install.
Plain English, cut to what the reader needs. Every reply follows the same rules.
| Rule | What it means |
|---|---|
| Answer first | The answer, then the reason, then the next step. No greeting, no "let me", no recap, no closing offer |
| No AI phrases | No "delve", "seamless", "It's not X, it's Y", "Let's dive in", no em dashes |
| Short, whole sentences | At most 20 words, active voice, plain words: "use", not "utilize". Articles stay |
| Meaning never dropped | not, never, no, and only always stay. Numbers, units, code, paths, and errors stay exact |
| Structure that scans | Tables only for rows of the same kind. One topic per section |
| Ordered by what you do next | Outcome, details, evidence, open decisions. Long replies end with a tl;dr |
| Knows when to stop | Security warnings, irreversible actions, and anything saved outside the chat get full, careful prose |
The complete rules: skills/clearcut/SKILL.md.
We asked Claude Opus 5.5 ten everyday developer questions, from React re-renders to queues vs topics, once with each instruction below. The counts are Claude Code's own; reasoning tokens are included in the output tokens.
| Instruction | Output tokens | Reasoning tokens | Fewer output tokens than Vanilla Claude | Cost of 10 calls |
|---|---|---|---|---|
| Vanilla Claude | 10,571 | 143 | $0.326 | |
| "Answer concisely." | 6,870 | 86 | 35% | $0.244 |
| caveman | 6,863 | 146 | 35% | $0.247 |
| clearcut | 5,410 | 374 | 49% | $0.221 |
A blind judge (Claude Sonnet 5.5) compared clearcut's reply with each other reply for the same question and picked the one that is easier to read while still complete and correct. Each pair was judged twice, with the order swapped:
| clearcut against | clearcut preferred | Other preferred |
|---|---|---|
| Vanilla Claude | 17 | 3 |
| "Answer concisely." | 18 | 2 |
| caveman | 10 | 10 |
Method, every run, and how to reproduce it: docs/benchmarks.md.
| Command | What it does |
|---|---|
/clearcut |
Default level: plain English, short sentences |
/clearcut terse |
Also drops articles and allows fragments |
/clearcut status |
Shows the current level |
stop clearcut or normal mode |
Off for this session |
Set CLEARCUT_DEFAULT_MODE to clearcut, terse, or off to choose how new Claude Code sessions start. Levels switch in Claude Code; Codex, pi, and vibe always run the default level.
| Hook | Script | What it does |
|---|---|---|
SessionStart |
hooks/clearcut-activate.js |
Loads the rules and records the session's level |
SubagentStart |
hooks/clearcut-activate.js --subagent |
Gives subagents the same rules |
UserPromptSubmit |
hooks/clearcut-mode-tracker.js |
Switches levels on request and adds a short reminder every turn, so the style holds in long sessions |
The level is stored per session in ~/.claude/clearcut/. For a statusline badge, call hooks/clearcut-statusline.sh from your statusline command; it prints [clearcut] or [clearcut:terse].
clearcut runs entirely on your machine. It makes no network calls and collects no telemetry.
- The Claude Code hooks write one small level file per session under the Claude config dir (
~/.claude/clearcut/) and delete level files older than 7 days. adapters/install.pywrites~/.codex/hooks.json, a symlink in~/.pi/agent/extensions/, and~/.vibe/prompts/clearcut.md, and edits~/.vibe/config.toml.--removeundoes each.
npm testSee CONTRIBUTING.md to change a rule and CHANGELOG.md for releases.
clearcut adapts writing rules from caveman (Apache-2.0) and unslop (MIT). No source code is copied; see NOTICE.
clearcut is from the team behind versa.training. Looking for a tool to help your team master difficult conversations? Check out versa.training.