Choose and route models
Select a model, prefer models for particular tasks, and inspect the decision Orek made.
Orek can choose a model for each turn from your configured providers. A route describes a kind of task, such as simple/lookup or planning/general, and can express model preferences for that task.
Pin a model when you want to choose it yourself. Add route files when you want automatic selection with preferences for different kinds of work.
Need to connect a service first? Start with Providers to choose from the built-in catalog, then follow Quickstart.
Pinning
Start in an open Orek session with a configured provider. Open the model picker:
In Orek · command
/modelChoose a model and press Enter. Ask a project question, then inspect the applied selection:
In Orek · command
/routing/model sets the model for the current session (/model auto returns to automatic routing). To save a default across sessions, run /config set routing.pinned_model <id> or /config set routing.pinned_provider <provider>.
Use Left/Right in /model to adjust reasoning effort. /routing show and /routing status are aliases for /routing.
Pins do not block network access or disable provider fallback. See Local models — disconnected setup.
The rest of this page covers route files, which are advanced configuration.
Route tests run in your shell; /routes is not a TUI command.
Add a route preference
Create a TOML file in your project’s .orek/routes/ directory. For example, .orek/routes/review.toml:
Configuration
[[routes]]
name = "review/audit"
description = "Code review, security auditing, and performance analysis"
sample_queries = [
"Review this implementation for race conditions",
"Audit this controller for security flaws",
"Check the connection pool for performance bottlenecks"
]
tags = ["review", "audit", "security", "performance"]
provider_preference = ["google", "mistral"]
preferred_models = ["mistral/mistral-medium-3-5"]
complexity_bias = "high"
enabled = trueReplace the provider and model preferences with ones you have configured. sample_queries helps Orek match prompts by meaning; tags gives exact words to match.
preferred_models and provider_preference raise a model’s score; they do not exclude other models. To restrict routing to one provider, set routing.pinned_provider.
Check that your route loaded:
In your shell
orek routes list
orek routes test "audit this controller"The list should include review/audit. The test should match its audit tag and show the route’s fields. This tests keyword matching only, not the model Orek would select for a real turn.
Check the actual decision
After a turn, open /routing to see the latest routing decision. Compare the selected model with your intended preference and confirm that its provider is configured.
orek routes test "<your query>" does not match by meaning, estimate complexity, or score models. The preferred_models it prints come from the matching route; they are not a predicted winner. A real turn can match a different route, because matching by meaning runs first when it is available.
For a detailed trace, set up OpenTelemetry export. When you set observe.otlp_endpoint, Orek exports these events with each turn:
| Event | What to inspect |
|---|---|
model_pinned / pin_lookup_failed |
Whether the requested model pin resolved |
route_classified |
Route name, confidence, and matching method |
complexity_assessed |
Estimated task tier and score |
candidates_scored |
Candidate quality, cost, latency, capability, and total scores |
model_selected |
The model and provider Orek applied, and whether they changed |
route_not_matched |
Why a routing decision could not be applied |
model_segment_started |
A model taking over the conversation, at its first request: why (session_start, user, router, fallback or resume), the reasoning method in effect, the provider and model before and after, and why Claude’s earlier thinking stopped being sent, if it did |
provider_request_recorded |
Each request a turn sent: its purpose (always main_turn), the reasoning method, how it ended, the earlier reasoning it resent, passed on from another model, filled with an empty value, or dropped (items and estimated tokens), its latency, and how many resent thinking blocks Anthropic left out, if any |
Pin behavior
If Orek cannot resolve a pinned model or provider for the first turn, it does not start. During a running session, a routing failure keeps the current model and emits route_not_matched. The TUI shows a warning when you can fix the cause.
If a pin stops applying after a provider or catalog change, check the warning, /model list, and your provider configuration. A failed routing decision does not stop the turn.
Where routes come from
Orek loads routes from three layers. Later layers take precedence:
| Layer | Path |
|---|---|
| Built-in | Routes bundled with Orek |
| User | Linux: ~/.config/orek-ai/routes/*.toml; macOS: ~/Library/Application Support/orek-ai/routes/*.toml; Windows: %APPDATA%\orek-ai\config\routes\*.toml |
| Project | <project>/.orek/routes/*.toml |
A route with an existing name replaces that route in full. Omitted fields take their defaults; they do not inherit the earlier route’s values. For example, replacing simple/lookup without a complexity_bias removes the built-in bias.
Within a directory, .toml files load in sorted path order; other files are ignored. With OREK_HOME set, user route files go in <OREK_HOME>/config/routes/.
The [[routes]] schema
Each file contains one or more [[routes]] tables:
| Field | Type | Default | Purpose |
|---|---|---|---|
name |
String | Required | Identifies the route for replacement, keyword matching, and diagnostics |
description |
String | Required | Describes the task; used when matching by meaning |
sample_queries |
Array of strings | [] |
Example prompts added to the description when matching by meaning |
preferred_models |
Array of selectors | [] |
Ordered scoring preference for models |
provider_preference |
String or array of strings | [] |
Ordered scoring preference for providers |
complexity_bias |
simple or low, medium, complex or high, reasoning |
Unset | Adjusts estimated task complexity |
quality_floor |
low, medium, high, frontier |
Unset | Penalizes models below this quality tier |
tags |
Array of strings | [] |
Whole-word terms for keyword matching |
enabled |
Boolean | true |
Excludes the route when false |
Unknown fields are ignored. Tier names are case-insensitive. An unknown complexity_bias or quality_floor value on an enabled route invalidates the file; on a disabled route, these values are not checked.
When a route file is malformed
A TOML syntax error, missing required field, or invalid tier value skips the entire file and logs a warning. Other valid route files still load.
After editing a file, confirm the expected route names and fields in orek routes list. The route count alone cannot show a failed override, because the route it meant to replace is still present.
If a route is missing, check its name, description, enabled value, and TOML syntax. Then look for the file’s parse error in the application log; see local diagnostics for log locations.
The decision pipeline
Without a model pin, routing follows these steps:
- Match the prompt to a route.
- Estimate the task’s complexity.
- Filter and score models from configured providers.
- Select the highest-scoring eligible model.
Steps 2 to 4 run however the route was matched. Routing selects a model; it does not change Plan mode, tool permissions, or approval requirements.
Route classification
Orek tries these methods in order:
- Matching by meaning: compare the prompt with each route’s description and sample queries, using a similarity threshold of
0.5. - Keyword matching: use the first route whose name or tags match the prompt.
- Default route: use the built-in
defaultroute when neither method matches.
Matching by meaning uses the project index’s embeddings and runs only when Orek searches the index before the turn. It is skipped when there is no index, automatic retrieval is off, the prompt uses @!retrieve, or Orek treats the prompt as a short follow-up.
Keyword matching is case-insensitive and checks whole words, in route load order. test matches “write a test,” but not “latest.” A tag such as refactor does not match refactoring; include both when you want both forms:
Configuration
tags = ["refactor", "refactoring"]Multi-word tags match as a whole phrase. Punctuation at a tag’s edge counts: /diff matches “run /diff” but not “/diffing.” Built-in routes have no tags, so keyword matching uses only their names.
The default route uses routing.default_preferred_models when set. Otherwise it combines the preferred_models of routes whose complexity_bias is not simple or low (or of all routes, if that gives none).
What the scorer does with those fields
The scorer considers each model’s quality, price, latency, and capabilities from the catalog. Models from unconfigured providers are never candidates.
A model is excluded when it is hidden in the catalog, is not meant for agent chat, cannot fit the estimated context, or lacks a capability the turn needs. Tools need supports_tools; images need supports_vision. Routes with a tag containing tools or code also need tool support.
Custom [[models]] entries default to supports_tools = false and are skipped on turns with tools unless you set supports_tools = true. If you pick a model without tool support yourself, it runs without tools, and Orek says so once per session.
Eligible models are ranked by combining their quality, cost, latency, and capability scores. The cost estimate uses the price tier for the estimated prompt length; recorded costs use the model that actually served the request and the tokens it reported (see Prompt-length pricing).
| Preference | Scoring effect |
|---|---|
preferred_models |
Boosts models in the order you list them (earlier entries receive a larger boost) |
provider_preference |
Boosts models from your preferred providers in listed order |
quality_floor |
Penalizes models below the specified quality tier (low, medium, high, or frontier) |
Use valid selectors and order your preferred models deliberately. Quality floors and preferences change rankings; they do not exclude models.
Complexity scoring
Orek estimates task complexity (Simple, Medium, Complex, or Reasoning) from your prompt, explicit references, conversation history, and gathered code context. Longer multi-step prompts, planning or refactoring requests, and larger context shift selection toward more capable models.
complexity_bias nudges that estimate down (simple/low) or up (complex/high or reasoning) for a route. It affects which model is selected, not how hard the model thinks; set routing.thinking_effort (or use /effort) for that.
[routing] keys
| Key | Default | Effect |
|---|---|---|
pinned_model |
Unset | Selects a model without route scoring |
pinned_provider |
Unset | Limits automatic routing to one provider’s models |
default_preferred_models |
Unset | Supplies the default route’s model preferences |
thinking_effort |
Unset | auto, none, minimal, low, medium, high, xhigh, or max |
temperature |
Unset | Sent only when set; never sent to Anthropic or to a model that rejects it, and Orek reports this once per model |
cascade_enabled |
false |
Lets the main conversation fall back to another provider after a temporary failure; subagents can fall back independently |
Set routing.pinned_model, routing.pinned_provider, and routing.temperature with orek config set <key> <value> (or /config set in the TUI). Set default_preferred_models, thinking_effort, and cascade_enabled in config.toml, or use /effort for the session’s thinking effort. See Local models before enabling cascade_enabled with local providers.
Orek has no per-request cost cap. Older configurations that still contain budget_per_request or preferred_complexity load normally; those keys are ignored.