Skip to content

About

Per-turn model routing for the Pi coding agent: a small judge picks the cheap or the strong tier for each message, with multi-model failover, task-level orchestration, and an optional decision-model judge (Jev) that answers with a calibrated probability instead of prose.

Topics

Resources

Contributing

Stars

13 stars

Watchers

0 watching

Forks

Repository files navigation

pi-shift-router hero — routine turns stay on the cheap tier; a judge moment upgrades the work that matters to the strong tier, which plans and delegates to fast engineers

pi-shift-router

Stop paying flagship prices for routine turns — and stop handing your hardest turns to a cheap model.

npm Downloads License Pi Agent Decision models Node deps size CI Stars

[English] | 简体中文

🌐 Project site | ⚙️ How it works | 🚀 Why now | 🧭 Decision models: a judge that answers with a number | ⚖️ vs. the alternatives | ❓ FAQ | 🔧 Configuration | 🩺 Troubleshooting

You pay for two tiers of intelligence and can only use one of them per turn.

Every message you send is a bet: is this task hard enough to deserve the expensive model? Bet high and you burn flagship money renaming a variable. Bet low and you get a shallow fix for an architecture problem. So most people pick one model, set it forever, and eat both losses.

This extension removes the bet. A small judge reads each message and picks a tier; that tier then runs the whole turn — thinking, tool calls, edits. You configure two chains, and the expensive one is spent only where it changes the outcome. It runs as a pi-coding-agent extension — no separate server, no per-call setup. extension: no server, no per-call setup.

🦾 [deepseek-v4.1-flash] → fix the failing test
🧭 judging…
🧠 [claude-fable-5]              ← "design the auth flow" → upgraded instantly
⚠️ deepseek-v4.1-flash 429 → switching to glm-5.3-flash — retry in 1m
🦾 [glm-5.3-flash]                    ← same-tier failover

For genuinely large tasks, picking a model is not enough: the Smart tier turns into a CTO that plans the work, delegates implementation to Fast subagents, reviews the results and iterates. That is task-level orchestration, and it is on by default for complex work.

Orchestration needs pi-subagents (pi install npm:pi-subagents). Without it the router works normally — complex tasks just run on the Smart tier directly, with no delegation.

The judge itself comes in three modes, and the third is a different kind of model: a decision model that returns a probability instead of prose. Nothing to parse, about $0.0001 per turn, off by default and labelled Beta — the honest case for it is here.

  • Upgrades happen immediately; downgrades wait for two consecutive fast turns.
  • Each tier is a fallback chain with exponential-backoff cooldown, so a 429 does not end your session.
  • One config file. Until you pick models, it does nothing.
pi install npm:pi-shift-router   # then: /router config → /router status

Why now

Three things changed recently, and together they turned per-turn routing from a clever hack into a sensible default.

1. Providers split their own families, and the price gap within a family is big.

Family Cheapest tier Strongest tier Spread
OpenAI GPT-5.6 Luna $0.20/M GPT-5.6 Sol $5 → GPT-6 Astra $10 50×
Anthropic Haiku 4.5 $1 Opus $5 → Fable 5 $10 10×
Google Gemini Flash-Lite $0.10 Flash $0.75 → 3.1 Pro $2 20×
GLM 5.3-Flash $0.15 GLM-5.3 $1.40 9×
MiMo $0.14 $1.31 9×
DeepSeek V4.1 Flash $0.30 V4 Pro $1.32 4×

Prices are input $/M, from pi's bundled catalog (41 providers, 1443 priced models) — open /model and check them. The cheap tier is often enough: one independent comparison found MiMo-V2.6-Flash beating the Pro tier on a benchmark while costing a third as much.

2. The choice itself got too big to make by hand.

OpenRouter alone lists 380 priced models, spanning 1579× from Mistral Nemo ($0.019) to GPT-5.5 Pro ($30). Add Cloudflare AI Gateway (51), Vercel (236), opencode (70), Ollama's cloud models, and flat-rate pools like OpenCode Go's 28 models for $10/month, where switching costs nothing extra.

3. Judging became a model class of its own.

Classifying a turn used to mean calling a frontier model and parsing JSON out of its prose. In September 2026 TypeSafe shipped Jev, a System One model: send it a state and typed questions, get typed answers with probabilities, and no generated sentence. The category has since grown past one vendor — OpenAI's Decisions API, Cloudflare's Clef, Perplexity's Decider — and pi ships the transport for all of them. Using a classification model for a classification is both cheaper and less fragile — details, and the catches.


vs. the alternatives

What it does well What it doesn't
OpenRouter Auto Router Zero-config, market-driven model choice, cost_tier knob. Great for a raw API. It optimizes for quality, not your bill — OpenRouter's own docs say routing to an expensive model "is working as designed". You don't set the tiers, see the verdict, or control the failure mode.
Cloudflare AI Gateway Dynamic Routing Versioned routing flows with quotas and fallbacks, at the gateway. You author the graph per gateway, and it sees requests, not tasks — no notion of "this turn is architecture work".
A single strong model Never picks wrong. You pay flagship rates for fix the typo, forever.
Doing it by hand Free. Until the first time you forget to switch back — which is the whole problem.

The difference in one sentence: this routes on the shape of the task, inside your agent, between two chains you define — and you can see every verdict in /router status.


How it works

One cheap call per turn. The fast-tier model (usually your cheapest) reads your message and marks it fast (routine) or smart (worth the good model), with a confidence between 0 and 1. That is the only classification in the system; the chosen tier then runs the whole turn.

Why the default leans toward spending. A wrong switch costs very different amounts depending on which way it goes. Upgrading a simple task wastes the price difference once. Keeping a hard task on the cheap model costs a redo, plus the smart model anyway, plus your time. So the router should not split 50/50:

Run smart when the chance this turn needs it is at least θ. Default θ ≈ 0.33.

Confidence is that chance. A smart verdict at confidence 0.9 means 90% likely needed; a fast verdict at 0.9 means 10%, so a very confident fast is the strongest signal to stay cheap. A verdict below minConfidence (0.5) is ignored and the router stays where it is.

Judge says confidence chance smart is needed result
smart 0.9 0.90 🧠 smart
smart 0.2 0.20 🦾 fast — the call was weak
fast 0.9 0.10 🦾 fast
fast 0.6 0.40 🧠 smart — "probably simple" is not simple enough
any < 0.5 — hold: stay put rather than guess

Where 0.33 comes from: the price difference between tiers cancels out of the comparison, so the only thing that matters is how badly a fumble hurts relative to that difference (reworkPenalty, default 3 — a fumble costs about 3× the price gap, so a one-in-three chance of needing the good model justifies it). /router sport raises the penalty to 5 and makes routing eager (θ = 0.2); /router eco lowers it to 2 and makes it conservative (θ = 0.5).

Two things keep it from bouncing. Upgrades happen immediately; downgrades need two consecutive fast turns. And when both tiers share a provider, the router raises the bar and refuses to downgrade while the prompt cache is still warm, because switching mid-session makes the next model re-read the whole conversation at full price.

The verdict has to be machine-readable, so OpenAI-compatible endpoints get response_format: json_object (the API rejects non-JSON) and Anthropic gets a { prefill to force JSON. The status bar shows 🧭 judging… while it runs. If the call fails, the router holds the current tier rather than guessing.

Three judge modes (v1.7.0). Reuse the Fast tier chain (default, no extra config), a dedicated Judge LLM chain you edit like a tier, or a decision model — see decision models.

When a provider goes down

429 / 402 / 5xx / quota / token-plan exhausted / Codex usage limit / account balance empty? pi retries first (3× provider, 3× agent); if it still fails, the router takes over:

  1. The failing model enters exponential-backoff cooldown — 5xx starts at 1m (1m → 4m → 16m → 1h → 4h… capped at 6h), while a failover-worthy 4xx (429 rate limit / 402 Insufficient Balance / quota) skips the first two tiers and starts at 16m, because client-side limits (rate window or account balance) usually outlive server blips.
  2. setModel switches immediately to the next healthy model in the same tier — never across tiers.
  3. pi's pending retry lands on the fallback — same-turn failover.
  4. Later turns skip cooled models; a 2xx response clears the cooldown; a session restart resets everything.

The judge shares the same cooldown map (it walks the full fast-tier chain before giving up). Manual override (/route-force) always bypasses cooldowns; auth/config errors (400/401) never trigger failover.


Decision models as the judge (Beta)

The judge answers one question per turn: is this hard? Most routers ask an LLM and then parse JSON out of the reply. A decision model is a different kind of model — hand it typed questions and it hands back the option plus a probability:

// what comes back (System One shape; the OpenAI Decisions shape is normalized to this)
{ "model": "jev-1.14.0",
  "answers": {
    "tier":        { "choice": "fast", "probabilities": { "fast": 0.99, "smart": 0.01 } },
    "orchestrate": { "noul": 0.13 } } }

That response is everything the router needs. It compares 0.99 against θ and moves on, so there is no JSON mode and no parse step, which removes the whole "the judge failed because a model added a comma" category. A missing field means no verdict and the router holds. The same call also answers the orchestration question, so a complex turn needs one judgment rather than two.

It is cheap for the same reason: a verdict costs input tokens only — at TypeSafe's $0.25–0.42 per million input tokens that is about $0.0001 per turn, with output free.

pi already speaks this protocol

You do not need a custom models.json entry any more. Since pi 1.4.0, pi ships the transport and a catalog of decision models, and this router judges through pi's classifier layer — so pi resolves the key, attributes the request, retries it and prices the call:

Provider Models
TypeSafe jev-latest, jev-1.13, jev-1.14
OpenAI gpt-6-luna (the Decisions API)
Cloudflare clef, clef-flash, clef-omni
Perplexity pplx-decider-v1.2, pplx-decider-flash
Microsoft · Liquid · Upstage microsoft-decision-1 · d1 · solar-decide
Gateways OpenRouter (30 models), Vercel AI Gateway (14), OpenCode, Azure OpenAI

/router config → 🧭 Judge → 🧮 Decision model (Beta) lists what your install can actually reach, authenticated entries first. Nothing is probed over the network when the menu opens.

A hand-configured api: "typesafe-decisions" endpoint in models.json still works. That path is deprecated — it is the router's own protocol code, kept for older pi hosts and custom endpoints, and it will be removed once the native path has displaced it. Using it logs a deprecation line.

The catch

Decision models are public beta, and the honest version of that is:

  • They can be slow. We measure 1.4–6.6 s per verdict against api.typesafe.ai (median ~5 s), and a 5× smaller prompt does not help — that is provider capacity, not the integration. OpenAI's Decisions API answers in the hundreds of milliseconds in external benchmarks, which is one reason the picker is not tied to one vendor.
  • The evidence is mixed. A September 2026 independent evaluation found decision models behind the per-task best LLM on 14 of 15 annotation tasks, and October 2026 benchmarks show the ranking changing with the task — including between decision models themselves.
  • So it is opt-in. /router config → 🧭 Judge lists both LLM options first and the decision mode third, labelled Beta. Upgrading does not change your default.

Setting it up

  1. Authenticate a provider that serves a decision model — /login typesafe, /login openai, or an OpenRouter key you already have.
  2. /router config → 🧭 Judge → 🧮 Decision model (Beta) → pick the model.
  3. Save. There is no network probe at save time; the wizard raises judgeTimeout when your value would cut decision calls off, because the 5 s default does.

If the decision model stops answering, the router steps down to your LLM judge rather than stalling, and to plain routing if that fails too. It never shows up in the Fast/Smart pickers: pi cannot stream that protocol as a chat model.


Task-level orchestration (v1.0.0)

Routing normally decides which model runs a turn. When the judge says smart and orchestration is in auto mode (the default), the Smart tier also takes over how the turn runs: it plans the work, delegates implementation to Fast subagents, reviews each result, and iterates until the work is clean, then does a final acceptance pass. A fast verdict never triggers any of this — those turns stay on the plain router.

How an orchestrated turn runs

  1. Enter. Judge says smart → the router switches the main agent to the Smart model and injects an orchestrator instruction (your role, delegation rules, hard caps). The status bar shows live telemetry throughout: [🧠 deepseek] • 42 tok/s while the CTO plans (the wand 🪄 appears only once workers are actually spawned), then 🪄 Done(2)/Total(3) • ~30 tok/s while Fast workers run.
  2. Plan. The Smart agent decomposes the task into phases, each with acceptance criteria.
  3. Delegate. For each phase it spawns a Fast subagent via the subagent tool — agent: "worker", context: "fresh", model pinned from your Fast tier — with a self-contained task contract (goal, constraints, acceptance criteria, files to touch).
  4. Review. It reads each worker's result against the phase's acceptance criteria. Failed phases go back to a worker with concrete feedback — or the Smart agent takes over the phase itself after N failures.
  5. Accept. It finishes with a short CTO summary and a final acceptance pass.

Why workers get a fresh context

Workers run with context: "fresh", inheriting no session history: the task string is all they get, so it has to be a precise contract (goal, constraints, acceptance criteria, out-of-scope). That keeps each worker small and cheap — measured ~$0.004 for a narrow task against ~$0.06 for an inherited 176k-token fork — and avoids the anchoring that makes a forked agent defend a plan it did not write.

Hard caps

Two numbers are enforced by the plugin, not by the prompt:

  • orchestration.maxRounds (default 3) — max delegate→review rounds per task.
  • orchestration.escalationThreshold (default 2) — after N worker failures on a phase, the Smart agent takes over that phase itself.

The loop stops when either the Smart agent says done or a cap is hit.

Acceptance audit

Review is the Smart agent's own judgment, so the plugin adds a second opinion at the end of any orchestrated turn that actually delegated (spawned ≥ 1, checked at agent_end). A turn the CTO did itself (spawned = 0) skips the audit entirely — no warnings, just a (self-executed) marker in /router status.

  1. Deterministic checks (free): every spawned worker reported back (done == spawned), the final message carries a CTO summary (the output-contract markers), and whether the run ended at a hard cap.
  2. LLM audit (on by default, one small fast-tier call): the auditor prompt reads the original user goal (captured when orchestration entered), the CTO summary, and the worker results, and checks three dimensions:
    • Grounding — the acceptance claim is backed by actual results (no "done" without review, no ignored worker failures, no contradictions).
    • Goal alignment — the delivered work actually addresses the user's request (no scope drift, core ask answered).
    • Delivered quality — worker outputs are complete, not placeholders/ TODOs passed off as done, no empty results, no "could not finish".

An audit finding never blocks the finished turn: it flags (console.warn plus a toast), and /router status shows Last audit for the most recent run. Turn it off with orchestration.audit.enabled (default true). This is the one part of the loop that does not trust the CTO's own review.

When it doesn't engage

  • Simple tasks (fast verdict) — plain routing, always. Orchestration is never forced on routine work.
  • pi-subagents not installed — complex tasks run on the Smart tier directly, exactly as before. No crash, no deadlock.
  • Orchestration set to off (/router orchestrate off) — plain two-tier routing only.

When it pays off / when it doesn't

Worth it when

  • Your session is long and mixed: dozens of routine turns with the occasional consequential one. Routine stays on the cheap tier, the important work upgrades automatically — no manual model switching.
  • You want a sticky deep mode: planning sessions stay on the strong tier, then drop back once you're editing files.
  • You worry about provider rate limits. With 2–3 models per tier, 429/5xx fail over automatically within the tier.

Not worth it when

  • Your session is uniformly easy or uniformly hard. Every classification is then pure overhead — roughly 200ms–2s plus a few thousand tokens per turn.
  • You never configure the tiers. Both start empty and the router is a no-op.
  • You don't trust the fast-tier model's judgment. The classification is only as good as the model you give it; when it's wrong, it conservatively stays put.

Quick start

Prerequisites: Node.js ≥ 24, pi-agent ≥ 0.80, a provider account (API key in pi-agent's auth.json), and one model for each tier.

1. Install

pi install npm:pi-shift-router

Local checkout: pi install <path-to-repo>. From git: pi install git:github.com/green-dalii/pi-shift-router. Installation registers the extension in ~/.pi/agent/settings.json and loads it on the next pi launch.

1.5. (Recommended) Enable orchestration

pi install npm:pi-subagents   # Smart CTO → Fast subagent delegation

Orchestration is on by default (auto mode); this installs the subagent machinery it delegates to. Without it, the router still works — plain two-tier routing only.

2. Configure

/router config

Pick a model for the Fast tier and one for the Smart tier — several per tier also works and forms a fallback chain. Save to user or project scope; when both exist, project wins. The picker shows the same configured/auth'd models pi's /model shows (since v1.6.0 — reads pi's own ModelRegistry, not a re-derived local catalog).

The wizard also exposes 🔒 Cache-aware routing — on by default when your Fast and Smart tiers share a provider (e.g. both Anthropic). It protects your prompt cache: the effective smart bar θ is divided by sameFamilyPenalty (fewer downgrades) and mid-session downgrades are suppressed while the cache is warm, so routing to a cheaper model never costs more than staying put. Toggle it there, or via the config file (routing.cacheAware.enabled).

3. Verify

/router status

A themed dashboard opens (q / Esc closes): your live tier and model, context-window and cache-hit gauges, last routing decision, session savings (plus worker spend when orchestrating), both chains with cooldowns inlined, and a plain-language "how routing decides" section. Your next message triggers the first classification.


Commands

Command What it does
/router status Open the status dashboard (TUI): live model, last decision, money, chains, health, config layer
/router on / /router off Enable / disable routing
/router config Launch the TUI configuration wizard
/router quiet Toggle inline toast notifications
/router verbose Toggle verbose logging
/router eco|default|sport Gear-shift economics presets (persisted): eco → R=2 (θ=0.5, cheaper — only clearly-needed turns run smart), default → R=3 (θ≈0.33), sport → R=5 (θ=0.2, eager — any real chance of needing Smart escalates). Top-level words so pi tab-completes them; /router status shows the current gear in plain language
/router orchestrate auto Task-level orchestration (default): complex tasks → Smart CTO delegates to Fast subagents; simple tasks stay on the plain router
/router orchestrate off Disable orchestration — plain two-tier routing only
/route-force <tier> Pin a tier for the next turn
/route-force <provider>/<model> Pin a specific model for the next turn
/route-force auto Clear manual override

Native model picks vs router authority (strict takeover). The router owns model selection while enabled (SPEC §2.4): on every turn before_agent_start guarantees the active model is the routed tier's best available model. Using pi's own switcher (/model, Ctrl+P) runs for the current turn, then the next routing point re-asserts the tier chain. To take full manual control run /router off (status bar shows ⛔); /route-force pins a tier/model for the session.

/router status also reports cost telemetry — per-tier spend and how much routing saves you:

Money · this session
  saved   $2.742 of $3.210  (85%)  vs all-smart: opencode-go/deepseek-v4.1-flash
  spent   $0.465  fast ▓░░░░░░░░░ 10% · smart ▓▓▓▓▓▓▓▓░░ 90%
  orchestration  $0.0689  (5 workers)

The orchestration row appears only when delegated workers actually spent something this task — each worker's usage.cost.total lands in a bounded per-worker ledger (last 20) and accumulates into the task total, so delegation cost is never hidden inside the main-agent figures.

The baseline asks: what would this session have cost if every turn ran on your configured Smart-tier model (priority 1) — i.e. no router? The difference is your savings. If pricing is missing (fully-local session with no models-store.json pricing), it shows baseline: unavailable instead of a made-up number.

Other pi routers

pi-shift-router (this) @tenchi4u/pi-bifrost pi-smart-router
How it decides One LLM prompt you can read in src/prompts/judge.md (or a decision model) 7-step rules plus history heuristics 12-step local pipeline, no LLM
Tiers 2 (fast / smart) 4 (quick / general / writing / frontier) 3, including a local one via LM Studio / Ollama
Complex tasks Smart tier orchestrates: plans, delegates to Fast workers, reviews Per-turn routing only One helper call on the strong model
Cost Dollars saved per session, measured against an all-smart baseline Saves subscription quota rather than dollars Cost estimate from a formula, not your bill
Provider failure Same-tier fallback with cooldown (1m → 6h), shared with the judge Circuit breaker, may switch tiers Circuit breaker, within tier only
Prompt cache Raises the downgrade bar and holds while the cache is warm Keeps its own cache Also protects the cache, different math
Weight 0 dependencies, ~409 KB 0 dependencies, 2.5 MB Needs a local DB and model, 2.5 MB plus downloads

All three are real choices; the differences are in how much machinery sits between your message and the model.


FAQ

Does the judge add latency or cost?

A classification is a few thousand tokens billed at the fast tier's price (your cheapest), typically 200ms–2s round-trip; the status bar shows 🧭 judging… while it runs. Against the cost of a missed upgrade, it's usually noise.

Can tiers mix providers?

Yes. Each tier is an ordered list of {provider, model, priority} — combine freely.

Will it downgrade Smart too early?

Downgrades need two consecutive decisive fast decisions (economics.downgradeMemory, default 2) plus the cache-aware idle gate — a single routine turn never drops you, and a hold (confidence < minConfidence) or any smart decision resets the streak. Tune economics.reworkPenalty (default 3, θ ≈ 0.33): raise it to 5 for cheaper routing, lower it to 2 to stay on Smart longer. Upgrades are always immediate on a decisive smart decision.

How do I set up a decision model as the judge?

Three steps:

  1. Authenticate a provider that serves one. TypeSafe (/login typesafe), OpenAI (/login openai), or any OpenRouter key you already have; Cloudflare Workers AI, Azure OpenAI and Vercel AI Gateway work too if you already use them for chat. Store the key the way you store any other provider credential — pi resolves it.
  2. Pick it in the wizard. /router config → 🧭 Judge → 🧮 Decision model (Beta). The list comes from pi's own classifier catalog (TypeSafe Jev, OpenAI gpt-6-luna, Cloudflare Clef, Perplexity Decider, and more), so there is no models.json entry to write and no base URL to get right.
  3. Save. There is no network probe at save time; the wizard raises judgeTimeout when your value would cut decision calls off, because the 5 s default does.

On a pi older than the classifier layer, or for a custom endpoint, you can still register "api": "typesafe-decisions" by hand in models.json. That path is deprecated and logs a notice.

Can I just ask pi to set it up for me?

Yes. Send pi something like:

Set pi-shift-router's judge to a decision model through pi's own classifier catalog. Check which providers I am authenticated with, pick a decision model from that set, and configure 🧭 Judge → 🧮 Decision model (Beta) — no models.json edit needed. Tell me what you picked and why.

…or, in Chinese:

把 pi-shift-router 的判定器设成决策模型,走 pi 自带的 classifier 目录。先看我已经登录了哪些 Provider,再从里面挑一个决策模型,配到 /router config → 🧭 Judge → 🧮 决策模型(Beta),不要改 models.json。告诉我你选了什么、为什么。

Why doesn't a decision model show up in my Judge menu?

The wizard lists what pi's classifier catalog exposes and what your credentials can reach. Check in order:

  • pi version. The native path needs pi 1.4.0 or newer (pi --version). Older hosts fall back to hand-configured typesafe-decisions endpoints.
  • Authentication. /login typesafe or /login openai, or an OpenRouter key; a model whose provider has no credentials is listed but marked unavailable.
  • The provider serves a classifier at all. Anthropic, Google and DeepSeek do not ship a decision endpoint — for those, keep the LLM judge; there is nothing to configure.

A hand-configured entry is only listed when it is marked api: "typesafe-decisions"; openai-completions will not appear.

How is this different from OpenRouter's Auto Router?

Auto Router picks from the whole market and optimizes for quality — its own docs note that an expensive pick "is working as designed". This router picks between two chains you defined, inside your agent, on the task shape of the turn. You set the tiers, you see every verdict in /router status, and the failure modes (429/402 failover, cooldown) are yours to configure. They compose: point a tier at an OpenRouter model if you like.

What if the judge picks the wrong tier?

Upgrades are instant, downgrades need two consecutive fast verdicts, and a low-confidence verdict is ignored entirely (window.minConfidence) rather than acted on. If the judge itself fails, the router holds its current tier instead of guessing — and if your judge configuration became unusable (retired model, removed key), it falls back to the LLM judge and says so. /router status shows the recent verdict window, so you can see whether the threshold matches your work.

Do I need multiple providers?

No. Two chains from one provider already pay off — every family spans 4–50× in price, and cache-aware routing keeps same-provider switches from paying full price for a repeated prompt. Multiple providers add failover: when one returns 429 or Insufficient Balance, the next in the chain takes the turn.

Can I disable it without uninstalling?

/router off disables it and /router on re-enables it; the switch persists in the config file.

What triggers orchestration?

Only a smart verdict on a complex task — with orchestration in auto mode (default). Simple tasks (fast) never orchestrate; they stay on the plain router. See Task-level orchestration.

Does orchestration cost more?

The Smart tier plans and reviews; the Fast tier implements — workers run fresh-context, so each is small and cheap (~$0.004 for a narrow task vs ~$0.06 for an inherited 176k-token fork). The judge still costs its normal single classification call. If a task turns out simple, the orchestration machinery never engages.

How do I know a turn orchestrated?

/router verbose prints 🪄 orchestrating when the orchestrator instruction is injected. /router status shows Orchestration: 🪄 auto (idle) normally, (active) during an orchestrated run, or ✗ (off) when disabled.


Reference


See also

  • dsh-shift-router — a sister project: the same two-tier routing architecture (LLM Judge, multi-model fallback chains, exponential-backoff failover, task-level orchestration) adapted for the DeepSeek Harness instead of pi-coding-agent. Uses dsh plugin to install; lives in the cordis.patch.yml profile layer. By the same author.
  • obsidian-llm-wiki — an Obsidian plugin that turns your notes into a connected, queryable knowledge base. The Karpathy LLM Wiki idea, built into the editor where you already write. Graph retrieval works without embeddings; ten interface languages; works with every LLM provider. Local-first, no backend, GDPR-friendly. By the same author.

Acknowledgements

Author & License — pi-shift-router by green-dalii, licensed under MIT © 2026.

About

Per-turn model routing for the Pi coding agent: a small judge picks the cheap or the strong tier for each message, with multi-model failover, task-level orchestration, and an optional decision-model judge (Jev) that answers with a calibrated probability instead of prose.

Topics

Resources

Contributing

Stars

13 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages