jev-harness-router
One batched call picks model tier, tools, skill and effort for each turn.
# jev-harness-router
**One fast call decides how an agent turn should run — then runs it.**
Before a harness spends a second on the real work, it has to answer four questions about
the turn in front of it. This asks all four in a single [Jev](https://docs.typesafe.ai/)
call, in about 350 ms, behind a deadline it is not allowed to miss.
| decision | how it is asked |
| --- | --- |
| **model tier** | not asked — derived in code from how hard the turn is and how much it touches |
| **effort budget** | same, from the same `Score` |
| **tools** | one `Noul` per tool, plus the tail of a ranking `Choice` |
| **skill** | one `Choice` over the catalogue, gated by four request-shape `Noul`s |
```ts
import { createRouter, defineCatalog } from "jev-harness-router";
const catalog = defineCatalog({
models: [ // cheapest first — the order is the ladder
{ tier: "fast", id: "claude-haiku-4-5", label: "Haiku", use: "Lookups, one-file edits." },
{ tier: "deep", id: "claude-opus-5", label: "Opus", use: "Design, cross-cutting work." },
],
tools: {
Read: { description: "Open a file the user named.", risk: "read" },
Bash: { description: "Run a shell command.", risk: "execute" },
},
skills: {
debug: { description: "Work backwards from an error to its root cause." },
},
});
const router = createRouter({ catalog });
await router.prewarm(); // once, at startup
const route = await router.route({ message: "arreglá el bug de auth en el login" });
route.tier; // "fast" | "deep" — your names, not ours
route.model; // "claude-opus-5"
route.effort; // "low" | "medium" | "high" | "xhigh"
route.tools; // ("Read" | "Bash")[]
route.skill; // "debug" | null
route.source; // "jev