Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

nadir-route

Right-size Claude Code's subagent spawns. A PreToolUse hook on the Agent tool asks Nadir's free decision API which model the task actually needs, then rewrites model in the spawn's input.

Nadir is a decision engine here, not a gateway. Your prompts and completions go straight from Claude Code to Anthropic on your own auth; Nadir is consulted out of band with the spawn's task text and never sees the request, the response, or a provider key. There is no added latency on the token stream.

claude plugin marketplace add https://getnadir.com/marketplace.json
claude plugin install nadir-route@nadir

No key required. Add one to attribute decisions to your account and get a savings figure on the dashboard (see below).

What it does

Nadir's bucket the hook writes effect
simple haiku your cheapest model
medium sonnet your default working model
complex nothing the spawn keeps the model the session already runs

Three rules, all deliberate:

  • complex is never rewritten. The top tier stays on the model you chose, including which Opus generation. Nadir right-sizes the cheap end; it does not move you off your frontier model.
  • It only writes harness aliases. Agent's model parameter is an enum (haiku, sonnet, opus, fable), and Claude Code converts a schema-invalid hook rewrite into a denied tool call. Aliases also resolve through your own ANTHROPIC_DEFAULT_*_MODEL config, so a routed spawn lands in your family and your generation rather than one this plugin hardcoded.
  • It never moves a spawn up. If the agent already asked for something cheaper than the routed tier, that stands.

Your main thread is never touched, by construction: the hook fires only on spawns.

Measured end to end on Claude Code 2.1.220 — a trivial read bucketed medium and the subagent started on claude-sonnet-5 (from an Opus inherit); a multi-region failover design bucketed complex, the hook emitted nothing, and the subagent ran on claude-opus-5.

Configuration

Set these in ~/.claude/settings.json under env, or export them.

Var Default Meaning
NADIR_ROUTE_DISABLE unset 1 turns the hook off
NADIR_BASELINE_MODEL unset the model your sessions run on, e.g. claude-opus-5. Set this for a savings figure: Claude Code fills tool_input.model only when a spawn names one explicitly, so without it Nadir has no baseline to price against and decisions log unpriced
NADIR_API_KEY unset attributes decisions to your account and surfaces them on the dashboard. Keyless calls store no row at all, by design, so your dashboard stays empty
NADIR_CLAUDE_LADDER {"simple":"haiku","medium":"sonnet"} retune the table above. Map a tier to inherit to leave it alone; {"simple":"inherit","medium":"inherit"} is audit mode — decisions recorded, nothing changed
NADIR_AGENT_POLICY {"subagent":"auto"} keyless raw JSON role policy. Pin a value ({"subagent":"haiku"}) instead of letting the router pick
NADIR_TIMEOUT 5 seconds the decision call may take. Do not lower to 2: a 10-way parallel fan-out measures 1.9–2.3s per call, so a 2s cap loses most decisions in exactly the traffic this is for
NADIR_BUCKET_URL https://api.getnadir.com/v1/bucket endpoint

Requires python3 on PATH for JSON handling. Without it every path exits silently and spawns proceed unrouted.

Fail-open, and how to tell

Every failure path exits 0 with no stdout — disabled, empty prompt, unparseable input, bad policy JSON, network error, timeout, non-200, missing decision field, a model equal to the one already requested, or a rejected key. Claude Code reads that as "no decision" and the spawn proceeds exactly as the agent intended. Only exit code 2 blocks a tool call, and this script cannot produce one.

The cost of that design is that "working" and "doing nothing" look identical, so check explicitly rather than assuming:

echo '{"tool_name":"Agent","tool_input":{"prompt":"rename a variable in one file","description":"rename var","subagent_type":"Explore"}}' \
  | sh ~/.claude/plugins/*/nadir-route/scripts/route-spawn.sh

Expect JSON containing "model":"haiku". Empty output means it is not routing. An invalid NADIR_API_KEY produces exactly the same silence as an unreachable network, so if you are keyed, re-run the same check with NADIR_API_KEY= — if it starts working, your key is being rejected.

Inside a session, Claude Code's PostToolUse tool_response.resolvedModel names the model a subagent actually started on.

Precedence traps

  • CLAUDE_CODE_SUBAGENT_MODEL, if set to anything but inherit, outranks the per-invocation model this hook writes — the hook silently does nothing.
  • The hook does beat a subagent's frontmatter model, including model: inherit.
  • This is a nudge, not a control. Claude Code's Agent permission rules match the agent type, not the model, so there is no local way to enforce a ceiling.

Alternative install

One command, no plugin, same hook — it merges into settings.json, backs it up, and verifies routing is live before it exits:

curl -fsSL https://getnadir.com/install/claude-code.sh | sh

For tiering work that is not a subagent spawn (batch items, "which model should this use", delegate-vs-inline cost), the full skill documents the whole /v1/bucket contract: npx skills add https://getnadir.com

Source

Mirrored from integrations/agent-hooks/claude-code in the Nadir monorepo, which is the source of truth. Issues: https://getnadir.com

About

Auto-route Claude Code subagent spawns to the right model tier via Nadir's routing engine. Install once, every spawn is routed.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages