Your best model shouldn't do every job.
Downshift gives your coding agent the right model for each subagent, shorter output from clean commands, and, if you turn it on, only the code a change touches. No extra AI call to decide.
- up to~53%fewer tokens per task in real use, routing and compactor combined (KiroCrew, 2026-10-21). Routing alone: ~24% in a four-arm Claude Code trial (46 runs, one operator, 2026-10-21).
- 0extra AI calls to decide
- about1 in 10spawns left unrouted on purpose, as a control group
Right model, shorter output, less to read.
RoutingCompleted on Claude Code
Right model per subagent
Mechanical subagent work goes to a smaller model; risky or unclear work keeps yours. A local hook decides, with no extra AI call.
downshift try$ downshift try "rename userId to accountId…" assumed current: claude-opus-5-5… → small: opus → haiku why: trivial task, no risk, confident
Real CLI output, 2026-10-21. Long lines trimmed. CompactorOn by default
Shorter clean output
Passing test runs and clean builds reach the context in a line or two. Errors, stack traces and failing exits stay untouched.
downshift compact$ go test ./internal/... Go test: PASS (3 packages ok) under … ok execwrap ok telemetry ok classify [downshift compact: compacted 205 to 119 bytes]
Real CLI output, 2026-10-21. Long lines trimmed. DCIOpt-in
Less to read
When you ask for a change, the agent gets only the code it touches. Opt-in; measured for size and speed, not for answer quality.
downshift dci$ downshift dci impact HashSessionID Target: HashSessionID Target Type: Symbol Callers/Deps: 31 - cmd/downshift/cmd_test.go:TestHook…
Real CLI output, 2026-10-21. Long lines trimmed.
Who it is for
Downshift acts when your agent delegates a task. What you gain depends on how you pay.
Your agent delegates
With Claude Code, each subagent can get a model sized for the job; Codex and Cursor are functional; OpenCode is beta. No subagents, nothing to switch.
You pay per token
Mechanical work on a smaller model costs less per token.
downshift reportshows tokens per completed task, routed against control.You are on a plan (Pro, Max, Team)
There is no per-token bill. Downshift shows how many tokens ran on a smaller model. What that does to your plan limit is still being measured.
Not for: picking your main model, or deciding whether to delegate.
Where a coding agent spends more than it needs to.
Three leaks. Downshift is one Go binary, no daemon, and acts on each.
Subagents inherit your most expensive model
Renaming a variable gets the same model as an architecture review.
Fix
A local hook scores the task and rewrites the model only when it is confident. In doubt, your model stays.
Status
Completed on Claude Code
Routine output fills the context
A passing test run or a clean
git statusdrops dozens of repeated lines into the context.Fix
downshift compactshortens the clean run. Errors, stack traces and failing output stay byte for byte.Status
Implemented, on by default
The agent reads more code than the change needs
To change one symbol it opens whole files and hunts for callers.
Fix
DCI packs only the affected symbols, under a byte cap.
Status
Opt-in. Measured for latency and bytes.
Completed: seen working end to end. Implemented: code, tests and at least one real observation. Opt-in: off until you turn it on. Reports show tokens and coverage, not dollars.
- 1
Right model per subagent
Completed on Claude CodeRewrites only the subagent's model, never your main session.
QualifierAbout 53% fewer tokens per completed task in real use, routing and compactor combined (KiroCrew, 2026-10-21, 6 control tasks — directional).
- 2
Compactor
On by defaultWraps
git,go testand the other test and build tools listed in the docs; keeps the exit code.QualifierOnly a plain allowlisted command is rewritten; of the git commands, only
git statusshrinks, the rest pass through unchanged; automatic rewrite is Claude Code only. - 3
Code intelligence, DCI
Opt-inGives the agent only the code a change touches.
QualifierBytes and latency measured; answer quality not measured.
Several harnesses, honest levels
One install sets up Claude Code, Codex and Cursor hooks; OpenCode is beta.
QualifierCodex and Cursor are functional, OpenCode is beta.
Guardrails Implemented
Auth, payments, crypto and private data are never downshifted.
QualifierDetection is pattern based, English and Portuguese; false-positive rate on real traffic is not measured.
See and compare Implemented
Switched, held or only observed, with the reason, plus routed against control.
QualifierChild token usage is observed on Claude Code only; the report needs 20 completed tasks per group.
See Downshift in action
Pick a task to see the decision, or type your own to build the command and run it in your terminal.
Real decisions from the CLI on 2026-10-19, assuming claude-opus-5-5 as the current model. ~75% and ~50% are the price gap of one model swap at list price, not a saving on a session. This page builds the command; it does not run the classifier.
Rewritten
Stays on frontier
Original model kept
- Task
- rename the userId variable to accountId
- Tier
- small
- mid
- frontier
- Model move
- opus → haiku
- Price gap
- ~75%, price gap of one model swap (est., list price), not a session saving
- Outcome
- Rewritten
- Why
- trivial task, no risk, confident
Guardrail
not rewritten: held by a guardrail
The classifier was not confident or the task touches a risk area, so the task runs on the model it asked for.
Your command
downshift try '<your task>'Type a task to fill in the command.
Some characters were removed so the command pastes safely in bash, zsh, fish and PowerShell.
This page does not run the classifier. It only builds the command. The real decision runs locally in the CLI, on your machine. Up to 200 characters.
Clean output, smaller context.
Passing test runs and clean builds reach your agent in a line or two. Errors, stack traces, diffs and any failing exit stay exactly as they were.
Compactor is on by default. It runs routine commands through downshift compact, which keeps the exit code and shortens only output it can tell is clean. It wraps every git subcommand and the listed test and build tools (go, pytest, vitest, jest, tsc, cargo, playwright, cypress, phpunit, gradle, maven, flutter, dart, next build). Of the git commands, only git status shrinks; the rest pass through byte for byte.
Automatic rewrite works on Claude Code. In other harnesses your agent runs downshift compact -- <command> directly. This is not the /compact command: it never summarises your conversation.
On the synthetic test corpus (248 files), the 26 that compact shrink by 82.3% in bytes, the best clean ones by 91 to 97%. Across all 248, including failures built to stay raw, the cut is 23.7%. Bytes, not tokens, and not your command mix.
Turn it off with "exec": false in the config or DOWNSHIFT_EXEC=0.
Before and after, real runs
| Run | Before | After | Cut |
|---|---|---|---|
| Full suite | 4,466 | 2,331 | −47.8% |
| Package 1 | 752 | 317 | −57.8% |
| Package 2 | 619 | 238 | −61.5% |
| Package 3 | 471 | 174 | −63.1% |
| Package 4 | 278 | 142 | −48.9% |
Single runs, 2026-10-21, bytes.
Send the code a change touches, not the whole repo.
Ask for a change and the agent starts with the callers and symbols it can reach, packed under a byte cap, instead of opening whole files.
Run 1: downshift dci impact Route
Opt-in (downshift dci enable). It finds the impact radius of a symbol and packs only the affected code. Go by AST; TypeScript, JavaScript, Python, Rust, PHP, Java and C# by pattern.
Benchmark: cold index 295 ms, warm p95 5.64 ms, packs 568 to 2,801 bytes.
Measured so far: size and latency. Not measured: whether answers get better. Read it as a way to send less, not proof of better answers.
Read the DCI docsHow a spawn gets its model.
Eight steps, all code in the repository. Your agent spawns a subagent; a local hook scores the task; guardrails check it; the hook rewrites the model or leaves it alone; telemetry records counts and timings.
Harness
The agent spawns a subagent
Agent / TaskThe main agent delegates through its spawn tool: Agent or Task, spawn_agent, invoke_subagent. Downshift sees nothing until the harness fires its pre-tool hook.
Downshift
The hook starts
runHookAdapterrunHookAdapter reads the payload from stdin, capped at 1 MiB with a 2 s read timeout, sets a 1.5 s budget, and turns any panic into an unchanged spawn.
Downshift
The adapter reads the payload
internal/adaptersThe harness adapter reads the task text, the model the child would run on and the session. It declares what the harness can do and holds no policy.
Downshift
The task is classified
internal/classifyWeighted signals in English and Portuguese give TRIVIAL, SIMPLE, MEDIUM or COMPLEX, which maps to a tier: small, mid or frontier. A prompt with no signal defaults to mid and abstains.
Downshift
The semantic step can only raise
internal/fuseAn in-process word-hash step may lift a hesitant class. It never lowers a tier, never boosts a prompt with no signal and never creates COMPLEX on its own.
Downshift
Floors and guardrails check
selfcheck.go R1-R9The risk floor, guardrails R1 to R9 and the project floor in .downshift/policy.json run next. The session model list and the quota gate decide what can be written. Any hit means: keep the model.
Downshift
Rewrite or hold
updatedInputIf it is confident and safe, the hook returns updatedInput with only the model changed, plus reasoning_effort where the harness takes it. Otherwise the spawn goes through as asked. About 1 in 10 spawns is left unrouted on purpose, as the control group.
Harness, then Downshift
The subagent runs and is recorded
events.jsonlThe harness runs the child on the written model, or ignores the rewrite, which Downshift cannot control. Downshift then appends counts, hashes, timings and, on Claude Code, priced tokens to events.jsonl. No prompt text.
What never happens
- No AI call to pick a model.
- No prompt, task text or file path stored.
- No rewrite when unsure.
- No downshift of complex tasks or of auth, payments or secrets.
- No blocked spawn because of an error: a bad payload, panic or timeout leaves the spawn unchanged.
- About 1 in 10 spawns is left unrouted on purpose, as the control group.
Nine layers, each with its status.
Status is what the repository shows today, not what is planned. Implemented does not mean validated on every harness.
Right model, less noise
ClassificationScores the task text into TRIVIAL, SIMPLE, MEDIUM or COMPLEX, with no LLM call.Implemented
- internal/classify: weighted signals in English and Portuguese
- language guard
- internal/fuse: hash semantic boost, raise-only
On blind test sets, tier accuracy is 40 to 53%, and most misses are abstentions that keep your model.
Model catalog and sessionKnows which models exist in your session, their tier, list price and whether one is explicit-only.Implemented
- internal/catalog: tiers, list prices, aliases, explicit_only
- session models from hook lists, session-models.json, discovery, or inferred from the current model on Claude Code
Prices are a dated snapshot, so savings are list-price estimates.
Routing hook per harnessRuns the same decision in every harness and writes the rewrite in that harness's own format.Implemented
- one shared runner, runHookAdapter
- adapters: claudecode, cursor, codex, opencode, antigravity, kirocrew
Claude Code is completed, Codex and Cursor are functional, OpenCode is beta, Antigravity is experimental, KiroCrew is functional.
Shell output compaction (downshift compact)git and the listed test and build tools. Keeps the exit code and compacts only what is unambiguously clean.On by default
- shell exec wrapper; automatic rewrite on Claude Code only
- "exec": false or DOWNSHIFT_EXEC=0 turns it off
- downshift context compress, for pipes
Understand code
Code intelligence (DCI)Finds the impact radius of a symbol and packs only the affected code under a byte cap.Opt-in
- downshift dci impact and dci inspect
- Go AST, plus TypeScript/JavaScript, Python, Rust, PHP, Java and C# by pattern
- BM25 ranking, 3500-byte default budget
Stay in control
GuardrailsHolds any change the evidence does not support and keeps the model you asked for.Implemented
- R1 to R9 (R3 retired) in selfcheck.go
- risk floors: secret, authz, crypto, payment, vuln, pii, destructive, concurrency, prompt injection
- project tier floor in .downshift/policy.json, which only raises
- quota and credit gate
The quota gate is implemented but not validated on every harness.
Rules it always follows
- Local classification. Each task is scored on your machine with signals and a model catalog. No LLM call. Prompts are evaluated in memory and never stored.
- Fail-open. Any error or missing capability leaves the spawn untouched. Downshift only changes the model and effort fields.
- Doubt keeps your model. Unsure? The spawn keeps the model it asked for. Doubt never spends money, and a cheaper pick without confidence is held.
- Risk floors. Payments, auth and secrets are protected. Migrating a payment webhook stayed on opus. Rotating production secrets kept its original model.
Telemetry, control group and reportsRecords what happened and compares routed spawns with an unrouted control.Implemented
- events.jsonl: counts, hashes, timings
- downshift stats, session and watch: switched, held or observed per spawn
- downshift report: tokens per completed task, routed against control
- 10% control group (DOWNSHIFT_CONTROL_SHARE)
Two controlled runs so far, both on mechanical tasks (2026-10-15 and 2026-10-21). report needs 20 completed tasks per group and compares tokens per completed task; child token usage is currently recorded on Claude Code only. stats and report print no dollar amounts.
Mods in Claude CodeMake the work visible: a progress bar with each subagent's Downshift state, a panel of subagents, a file tree and a dock to reopen them.Implemented
- savvy-progress
- filetree
- downshift-dock
- downshift-theme, optional
savvy-progress and filetree are vendored third-party mods; downshift-dock is original and tested only against a mock engine. None holds routing logic. setup installs them, but not the theme.
Real numbers. No marketing math.
KiroCrew real use + Claude Code four-arm trial, 2026-10-21. Two harnesses, independent evidence.
- ~53%fewer tokens per completed task, routing and compactor, real useKiroCrew harness2026-10-216 control tasksOne session. Control group is thin; treat as directional, not definitive.
- ~24%fewer tokens per accepted run, routing only, four-arm trialClaude Code46 runsone operator2026-10-2116% per run; 95% interval +2.1% to +46.7%. Routing only; Compactor savings are additional. State isolation bugs found in battery — number may change.
- 12 of 12accepted in both routed arms (C and D)
- 82.3%fewer bytes on the 26 of 248 corpus files that compactsynthetic fixtures23.7% across all 248your mix will differ
- about1 in 10spawns left unrouted as a control group
Tokens per accepted run, four arms
- A Opus fixed2.25M10 of 11 accepted
- B opusplan2.00M10 of 11 accepted, no routing
- C opusplan + routing1.52M12 of 12 accepted
- D routing + Compactor1.46M12 of 12 accepted
Tokens = input + output + cache read + cache write, all models. Bar length relative to arm A.
Fewer tokens per accepted run, arm against arm
- Routing (B−C)24.1%interval +2.1% to +46.7%. Per run, before charging failures: 16.5%, +0.6% to +29.7%. Includes the cost of one failed run in the opusplan arm (named constants, 2 of 3 accepted).
- Routing + Compactor (B−D)26.8%interval +4.4% to +48.3%
- Compactor alone (C−D)3.5%interval −14.8% to +19.4%, includes zero: not measurable in this part. The agents chained commands with “;”, which Compactor did not wrap until PR #424 (merged 2026-10-21).
- Opus fixed against everything on (A−D)34.8%interval +19.1% to +52.5%
- opusplan alone (A−B)11.0%interval −28.9% to +39.0%, includes zero
solid: interval excludes zero. hatched: interval includes zero.
Earlier trial (2026-10-15, list price)
Up to about 12% cheaper per run on the mechanical batch. One trial, one operator, three runs per cell, list price, Claude Code, 2026-10-15. 12 of 12 checks passed in both arms; checks verify structure, not quality.
Saving per task, routed against control
- Rename~33%all five subagents downshifted
- Named constants~14%
- Doc comments~10%the interval includes zero
- Mirrored testsnoisenothing downshifted in 2 of 3 runs
solid: saving. hatched: interval includes zero, or noise.
List-price estimate. Bar length is relative to the largest saving.
What we have not shown
- A saving on your plan limit. Still being measured.
- Any saving from everyday use. Two controlled runs on mechanical tasks so far; nothing attributable.
- Compactor's own effect on tokens in a run. Not measurable in part 1.
- Routing on natural fixes that run tests. That is part 2.
- That DCI gives better answers. We measured size and latency only.
- Compaction on your own commands. The 82.3% is a synthetic corpus, in bytes.
- That the model is honored in every harness. See the table below.
- A false-positive rate for risk detection on real traffic.
Part 1 of 2: mechanical tasks. Part 2 (natural fixes that run tests) is next.
Read the four-arm write-upRead the A/B reportSee the corpus results
One router, six harnesses, honest levels.
The levels are what was observed, not what is planned. A rewrite emitted proves the hook answered; only the last column says whether the subagent ran on that model.
What each harness does with the rewrite
| Harness | Level | Model rewrite | Subagent used the model | Compactor |
|---|---|---|---|---|
| Claude Code | Completed | Emitted | Observed, 2026-10-06 | Automatic rewrite; or run downshift compact -- <command> |
| Codex | Functional | Emitted | Inferred from the next spawn, not observed | Run the command directly |
| Cursor | Functional | Emitted | Unconfirmed; discarded on Free and legacy Pro | Run the command directly |
| OpenCode | Beta | Adapter ready; plugin in development | Not observed yet | Run the command directly |
| Antigravity | Experimental | Emitted via an undocumented field | Observed once, desktop 2.21.1 | Run the command directly |
| KiroCrew | Functional | Block and retry (policy mode); no in-place rewrite | Not recorded (block and retry path) | Run downshift compact -- <command> |
Compactor works in KiroCrew by calling the command directly (steering): 223 calls recorded on 2026-10-21. Compactor is a plain shell command, so it works in any harness. Only Claude Code rewrites it in automatically. Each harness routes its own models. Verified routing is Claude Code only; the others sit at the levels in the table. OpenRouter models are discovery only and are never routed.
hook PreToolUse rewrite updatedInput.model keeps every sibling field doubt original model kept
hook PreToolUse rewrite model, reasoning effort keeps every sibling field doubt original model kept
hook preToolUse rewrite updated_input.model keeps every sibling field doubt original model kept
PreToolUse on Agent and Task rewrites updatedInput.model. Rewrite observed on 2026-10-06.
PreToolUse on spawn_agent rewrites model and reasoning effort. Honor inferred, not observed.
preToolUse on Task rewrites updated_input.model. Honor unconfirmed on the build tested.
Install, preview, then write.
Setup shows the diff for every harness it finds before it writes anything, saves a timestamped backup, and --undo restores it.
curl -fsSL https://raw.githubusercontent.com/tiagovilasboas/downshift/main/install.sh | shDownload the binary for your platform.
downshift setup --dry-runPrint the diff. Writes nothing.
downshift setup --yesWrite the hooks, with a backup. (Run
downshift setupto be asked first.)downshift doctorCheck the binary, the hooks, state and scores.
downshift try "rename the userId variable"See the tier it would pick, and why.
downshift setup --undoRestore the latest backup.
Binaries for macOS and Linux (amd64, arm64) and Windows (amd64). On Claude Code, setup also sets the main session to opusplan and plan mode, unless you pass --no-session-policy. It shows a diff first.
Open source, Apache-2.0.
Built in the open by Tiago Vilas Boas. The most useful contribution is a misrouted prompt: run downshift try with it, compare the tier with what you expected, and open an issue with both.
Sponsorship funds maintenance, benchmarks and the model catalog.
SponsorFrequently asked questions
Is Compactor the same as /compact?
No. /compact summarises your conversation. Compactor shortens the clean output of commands such as go test and git status, keeps the exit code, and leaves errors and failures exactly as they were.
Does it save my plan limit?
We do not know yet. Downshift shows how many tokens ran on a smaller model; the effect on a plan limit is still being measured.
What is sent anywhere?
Downshift stores no prompts or task text, only counts, hashes and timings, locally. Routing makes no network call. Your harness still sends the subagent's work to your model provider, as before. A detached refresh of public model scores sends no prompt and can be turned off with DOWNSHIFT_SCORES=off.
Will it route to the wrong model?
It rewrites only when it is confident and no guardrail objects; in doubt your model stays, and complex tasks or tasks touching auth, payments or secrets never go down. Run downshift session --why to see any decision, and report a misroute as an issue.
How do I undo it?
downshift setup --undo restores the latest backup of your harness config. Pause one session with downshift session --pause, or stop all rewriting with DOWNSHIFT_NO_ROUTE=1.
Which coding agents does it support?
Claude Code is completed. Codex and Cursor are functional, OpenCode is beta, Antigravity is experimental, KiroCrew is functional. The table above shows what was observed for each.
Is DCI safe to turn on?
It is opt-in and off until you enable it. We measured its size and speed, not whether answers improve, so try it on a branch and compare.
Where is the dashboard?
The web dashboard was removed on 2026-10-20. Use downshift report, downshift stats and downshift session, which show tokens and coverage in the terminal.
Does it call an AI to pick a model? Do I need another key?
No to both. Routing is local, from scored signals and a model catalog, with no extra model call and no key.
How much does it save?
In real use with routing and compactor combined, about 53% fewer tokens per completed task (KiroCrew harness, 2026-10-21, 6 control tasks — directional, not definitive). Routing alone: about 24% fewer tokens per accepted run in a four-arm Claude Code trial (46 runs, one operator, 2026-10-21; 16% per run, interval +2.1% to +46.7%). Compactor savings are on top of routing. Estimates are not invoices.
Is Downshift related to the React downshift library?
No. The React downshift library builds accessible autocomplete and dropdown components. This project is an unrelated Go tool that routes AI coding agent subagents to right-sized models.
Is it free?
Yes. Apache-2.0, a single Go binary, no daemon.
What changes on my machine?
Setup merges hooks into your harness config files, such as Claude Code's settings.json, and saves a timestamped backup first. A project can add an optional .downshift/policy.json tier floor. Nothing runs as a daemon.
Does it slow down a subagent spawn?
It adds one local process call, with no network and no LLM. In one traced run the binary exited in 30 ms. The hard limits are 2 s to read the payload and 1.5 s of hook budget, and an overrun or error leaves the spawn unchanged. On Claude Code it may also wait up to 400 ms for the parent transcript, to learn the current model. That is one trace, not a benchmark.