What a router is supposed to fix
Send the easy work to something cheap and fast, the hard work to something strong, and stop paying frontier prices for a rename. That part is well understood.
Open source · AGPL-3.0 · .NET · Windows
They pick a model using a rule someone wrote down once, and never find out whether it was the right call. They’re as good on day ninety as they were on day one. That’s not stability, that’s a ceiling.
Arc Router is a local proxy. Point your existing coding agent at it, send
"model": "auto", and each task goes to the model that has actually earned
that kind of work. Then
the answer gets graded, and the result changes what happens next
time.
Pre-release v1.0.0 · Windows 10 1809+ · x64 · not code-signed yet
> TotallyHotArcRouter --sync-benchmark-data
benchmark_id_results ..... 9,999 tasks x 8 models
benchmark_ood_results .... 176 tasks x 8 models
benchmark_models ......... 8 models, USD pricing
verified ................. ok
# routing a request
task ....... refactor: extract service layer
class ...... design · mid difficulty
vote ....... 4 of 5 voters, llm_router abstained
routed ..... backend-3 est. $0.004
score ...... blank until graded
01 The problem
Coding agents send a stream of wildly uneven work to a single model. Renaming a variable and redesigning a module both arrive as “a request”, and both get billed at frontier prices.
Send the easy work to something cheap and fast, the hard work to something strong, and stop paying frontier prices for a rename. That part is well understood.
Check afterwards. Most routers decide before an answer exists, never grade what came back, and so never learn that the cheap model got good at your codebase.
02 How it works
Two of these you would expect from any router. The third is the one that makes the difference, and it happens after you already have your answer.
Every request is read for what kind of work it is, how hard it looks and what it’s written in — plus a fingerprint of what it means, so two descriptions of the same problem land in the same place even when they share no words.
That read is provisional, and treated that way. Nothing downstream takes it as settled.
The router weighs what it already knows — how models have scored on this kind of work, on jobs like this one, on your codebase specifically — and routes accordingly. Anything that doesn’t recognise the job is set aside rather than forced into a low-confidence answer.
This is where most routers stop. The decision is made, the request is served, and nothing that happens next will change what it does tomorrow.
You get your answer immediately; the grading happens afterwards, so nothing ever waits on it. Every response is scored on whether it was any good, never on what it cost. And it learns from the work you were already doing — so it gets better at what your team actually builds, rather than at a benchmark somebody else ran.
This is step three, and it is the entire product.
A job comes in, and the router sizes it up.
heuristic classifier → dimension · difficulty · language
It works out what the job means, so “fix this null crash” and “this throws NullReferenceException” land in the same place — even though they share almost no words.
task embedding, on a stopwatch — the request proceeds without one rather than making you wait
Five helpers each read the notebook a different way and vote on who should do the job. Any of them is allowed to say “I don’t know.”
dim_best · memory_kNN · cluster_best · logreg · llm_router → weighted sum, argmax. Abstention is a designed answer, not a failure
If you always pick your favourite, you never find out the cheap helper got good. So a fixed 1 in 20 jobs goes to someone else on purpose — and it records those odds, so the trial can’t skew what it learns.
ε-exploration; propensity (1−ε)+ε/K logged per request so the statistics can be de-biased
It writes down what happened straight away — but leaves the grade blank, because nobody has marked the work yet. You never wait for the marking.
transcript row written at serve time, score column null. Grading runs off the hot path
A parser and a judge grade the answer, their two opinions become one score, and the blank gets filled in. Then it checks whether it actually beat its old self.
two graders joined into exactly one score → RouterMemory + EmbeddingMemory → scored against a frozen baseline, leave-one-out
The router does not get to grade its own work.
That is the whole design, and it is why the numbers can be trusted: the router logs the odds it had of making each pick, and grades itself against a frozen baseline that was never shown the answer. Read the full walkthrough →
03 Why it's different
Two of the rows below are the ones that matter. They are the questions where the honest answer for most of the field is simply “no”.
In plain terms: most routers guess who should do a job and never find out whether they guessed right. Arc Router grades the answer, sometimes tries someone new on purpose, and keeps a report card against its old self — so “it got better” is something it can prove instead of something it says.
| Capability | Typical router today | Arc Router |
|---|---|---|
| Picks by 1 ,2 ,3 | A strategy you configure — weighted shuffle, lowest latency, lowest cost, least busy — or one learned classifier over the prompt. | Five independent voters hold a weighted election, and any of them may abstain. |
| Where the learning lives 4 ,5 | A hosted meta-model, trained centrally on evaluation data. | Your machine — a local SQLite tally of your own traffic. |
| Checks the answer? 5 | No. The decision is scored before an answer exists. | Yes. Every response is graded by a parser and a rubric judge, joined into exactly one score. |
| Tries new models? 5 | Exploits what it already believes. | About 1 in 20 requests explore on purpose — and it records the odds, so the statistics stay honest. |
| Can it prove it helped? 5 | A dashboard of spend. | Scored against a frozen baseline, computed leave-one-out. |
| Task categories 3 | Fixed, hand-written. | Re-clustered from your own history — spherical k-means, k swept 6 to 24. |
| Runs where 5 | A hosted API. | Your machine. AGPL-3.0, source published. |
Vendor claims verified 2026-09-07 against the documentation linked above.
04 The evidence
Two independent graders score every response, and neither one looks at price. Their opinions are joined into exactly one score before anything is written down.
Code in the response is parsed, never run. C# goes through Roslyn and JavaScript through Acornima — real parsers, real verdicts. Python and shell get a bracket-balance heuristic, which is flagged as non-authoritative and weighted at half, because a bracket count is not a compiler’s opinion.
Four analyzers look for the specific way a weaker model fails: placeholders, truncation, diagnostics, and runaway complexity. A stub parses perfectly — catching that is the most valuable check of the four.
Parsing is not the same as being right, and perfect nonsense compiles fine. So the response also goes to a judge model with a rubric written for that task type.
It returns a digit from 1 to 5 — and then the interesting part: rather than trust the digit it happened to sample, the router reads the token probabilities and takes a probability-weighted mean. A judge torn between 3 and 4 scores 3.5, not a coin flip.
Worth being precise, because it is a real design decision. The live vote is
cost-blind. dim_best, memory_kNN and
cluster_best all rank purely on quality score; none of them looks at price.
Cost appears in exactly two places, both of them accounting rather than selection: the
reward function used by the offline harness, and the live report card against the frozen
baseline. The router
chases quality, then measures whether that was worth the money.
Arc Router evaluates against CodeRouterBench, a task-by-model benchmark published by Zhou et al. alongside arXiv:2606.22902. The dataset is their work, released on Hugging Face under the MIT license, and this project consumes it as an external dependency.
05 In your critical path
The .NET implementation ships the plumbing a router needs once it sits between your agents and your providers.
Point an existing coding agent at the router and it routes what already flows through your tooling, with no client rewrite.
Router functions are exposed as MCP tools, including sync_benchmark_data, so agents can drive it directly.
Per-request token accounting reconciled against provider-reported usage, charted in the dashboard.
Every response reports the model you asked for, the model that served it, and why they differ.
Provider keys are handled through a dedicated secrets-at-rest design rather than left in plain configuration.
Benchmark tables sync on demand into a local SQLite file. Nothing about your traffic leaves the machine to make a routing call.
06 What it doesn't know
A system that grades itself should be candid about what it cannot yet prove.
This list is maintained in the repository, not written for this page. Read it at source →
07 Get it
The 1.0.0 installer, what Windows will say about it, and how to verify the download.
Get Arc Router →A short path from empty folder to a running router with benchmark data loaded.
Bootstrap guide →Guided walkthroughs of setup, proxy routing, telemetry, and the MCP endpoint.
Watch the walkthroughs →The handbook plus every design document for the router, the GUI, and the data layer.
Read the docs →The routing approach and the CodeRouterBench dataset are the work of Zhou et al. (arXiv:2606.22902). The quality-scoring judge implements G-Eval, by Liu et al. (arXiv:2303.16634). If you use either, cite their papers — the repository carries the BibTeX.