Routing rules
When a request asks for the model auto, Prism looks at the request, then walks your rules from top to bottom. The first rule whose conditions all match decides the model. This page explains how Prism sees a request and how to write rules.
Manual or automatic
model in the request | What happens |
|---|---|
A model id or alias, such as claude-sonnet | Manual: that model answers, with its failover chain |
auto, or left empty | Automatic: your rules choose |
An unknown model name returns a 404 error that lists the names Prism knows.
How Prism sees a request
Before the rules run, Prism builds a profile of the request with fast text checks. It does not call a model to do this.
| Profile field | How it is worked out |
|---|---|
task | vision if the request has images; else security for words like "vulnerability", "exploit", "pentest" or "threat model"; else docs for "readme", "documentation", "changelog" and similar; else code if a programming language is detected or words like "implement", "refactor", "debug" or "unit test" appear; else general |
language | From the language name on a code block (for example python), from phrases like "in Rust" or "Go function", or from typical code in the message |
vision | true if any message has an image |
| Estimated tokens | The length of all message text divided by four |
Check any prompt's profile with prism explain "your prompt".
Write a rule
Each rule has an if with one or more conditions and a then with a model:
routing:
default: claude-sonnet
rules:
- if: {language: python}
then: qwen-coder
- if: {task: security}
then: claude-sonnet
- if: {task: vision}
then: claude-sonnet
- if: {offline: true}
then: local:any
- if: {budget_exceeded: true}
then: local:any
- if: {task: code}
then: qwen-coder- All conditions in one
ifmust match. - A condition you leave out matches anything. An empty
if: {}matches every request, which is useful as a last catch-all rule. - Order matters: put the most specific rules first.
- If no rule matches,
routing.defaultanswers. If there is no default either, the request fails.
Conditions
| Condition | Matches when |
|---|---|
task | The task is code, security, docs, vision or general |
language | The detected language, for example python, go, rust, javascript, typescript |
vision | true: the request has images; false: it has none |
offline | true while Prism runs in offline mode |
budget_exceeded | true once this month's spend has reached budget.monthly_usd |
min_context_tokens | The estimated request size is at least this many tokens |
task and language ignore upper and lower case.
Targets
then takes any model id or alias, or one of these:
| Target | Picks |
|---|---|
local:any | The first model of a provider marked local: true |
local:<capability> | The first local model with that capability, for example local:code |
Prism checks every target when it starts. A rule that names an unknown model stops the gateway with an error naming the rule, so typos are caught at once.
Test your rules
Edit
prism.yaml.Run
prism explainwith a few typical prompts:bashprism explain "Audit this nginx config for vulnerabilities" prism explain "Refactor this function"Read the
reasonfield. It names the rule that matched, for examplerule 2 matched (task=security). Rules are numbered from 1.Restart
prism serveso the running gateway uses the new rules.
To see what a model name resolves to, including its failover chain, use -m:
prism explain -m claude-sonnet "hello"The dashboard's Routing page shows the rules the running gateway loaded, and the Playground has an Explain route button.
Offline mode
Start the gateway with --offline, or set offline: true at the top level of prism.yaml, to use local providers only:
prism serve --offlineIn offline mode the offline: true condition matches, and cloud models are removed from every chain. A request that no local model can serve fails with offline mode: no local provider can serve this request.
Size limits
If a model has a context_window and the estimated request is larger, Prism leaves that model out of the chain. Add a rule with min_context_tokens to send long requests to a model with a big context window:
- if: {min_context_tokens: 100000}
then: gpt-5