Skip to content

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 requestWhat happens
A model id or alias, such as claude-sonnetManual: that model answers, with its failover chain
auto, or left emptyAutomatic: 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 fieldHow it is worked out
taskvision 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
languageFrom 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
visiontrue if any message has an image
Estimated tokensThe 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:

yaml
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 if must 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.default answers. If there is no default either, the request fails.

Conditions ​

ConditionMatches when
taskThe task is code, security, docs, vision or general
languageThe detected language, for example python, go, rust, javascript, typescript
visiontrue: the request has images; false: it has none
offlinetrue while Prism runs in offline mode
budget_exceededtrue once this month's spend has reached budget.monthly_usd
min_context_tokensThe 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:

TargetPicks
local:anyThe 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 ​

  1. Edit prism.yaml.

  2. Run prism explain with a few typical prompts:

    bash
    prism explain "Audit this nginx config for vulnerabilities"
    prism explain "Refactor this function"
  3. Read the reason field. It names the rule that matched, for example rule 2 matched (task=security). Rules are numbered from 1.

  4. Restart prism serve so the running gateway uses the new rules.

To see what a model name resolves to, including its failover chain, use -m:

bash
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:

bash
prism serve --offline

In 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:

yaml
- if: {min_context_tokens: 100000}
  then: gpt-5

Next steps ​