Skip to main content

Models & providers

Model Routing

Routing decides which model handles each request. Bodega ships sensible defaults (a chat classifier and Smart Auto for code mode), but unlike other IDEs the routing logic is yours: write ordered rules that send requests wherever you want, by mode, ask type, agent step, file path, message size, or what you've already spent today. Everything lives in Settings → AI Behavior → Routing, and every routed request tells you which rule decided it.

How a request picks its model

Evaluation order, top to bottom - first decision wins:

  1. Your explicit picks - a model pinned in the composer dropdown, a fixed tier on the chat pill (Fast/Smart/Code instead of Auto), a custom agent's pinned model, or Cloud Boost driving a request. Explicit intent always outranks rules.
  2. Project rules - routing rules shipped in the project's .bodega/config.json, if any.
  3. Your rules - the ordered list in the Routing section, first match wins.
  4. Built-in heuristics - the chat classifier (per message) and Smart Auto (per code-mode step), both visible as toggleable default rules in the same section.
  5. Model slots - the matched tier resolves through your Fast/Smart/Code model slots from Settings → Models.

Hard guards always apply afterwards: air-gap, VRAM and single-active-model limits, and spend caps clamp whatever routing decides. A rule can point at a cloud model; it can never bypass a cap to reach one.

Write your first rule

  1. Open Settings → AI Behavior → Routing and click + Add rule.
  2. Name it - the name is what shows up when the rule fires.
  3. Pick conditions (leave everything empty for a catch-all): mode (chat/code), chat ask type (what the classifier saw: fast/smart/code), code step type (read/write/plan/verify), a file path glob (**/auth/**, **/*.test.ts), message size bounds in tokens, or cloud spend today in dollars.
  4. Pick the action: route to a model slot (fast/smart/code) or an exact model, and optionally stay local.
  5. Save. The backend validates every rule before anything persists - a typo'd condition is rejected with a reason, never silently ignored.

Rules are an ordered list: drag priority with the arrows, toggle rules off without deleting them, and export/import the whole list as JSON to share or back up.

Starter recipes

Four one-click starting points, added as normal rules you can edit:

  • Keep it free - everything stays on local models, zero cloud spend.
  • Cloud for reasoning only - plan and verify steps get your smart model; reads ride the fast local one.
  • Private paths stay local - auth code and .env files never leave the machine.
  • $10/day budget brake - past $10 of cloud spend today, everything routes to the fast local model.

OR/NOT conditions (advanced)

Rule conditions are AND by default: every condition you set must hold. Two combinators cover the rest, authored in the per-rule JSON editor (the Edit as JSON button in the rule form):

  • anyOf - an array of condition groups; the rule matches when ANY group holds. Example: match auth code or env files: "anyOf": [{ "pathGlob": "**/auth/**" }, { "pathGlob": "**/.env*" }].
  • not - a condition group that must NOT hold. Example: every code step except reads: "not": { "iteration": ["read"] }.

Groups are one level deep (no anyOf inside anyOf) and use the same conditions as the form. One subtlety worth knowing: not matches when its condition is absent - not: { iteration: ["read"] } also fires on chat messages, because a chat message isn't a read step.

Teach the classifier your vocabulary

The chat classifier decides whether a message is a quick ask, a reasoning task, or a coding task. Classifier patterns let you extend it: a case-insensitive regex plus a tier, checked before the built-in tables. "Anything mentioning kubernetes or terraform is a code ask" is one row: kubernetes|terraform → code.

Patterns are validated when you save - patterns that could hang a send (nested quantifiers like (a+)+, backreferences) are rejected outright with the reason. Your rules still run after a pattern picks the tier, so a pattern changes WHAT the message counts as, and rules decide where it goes.

Per-project rules

A repo can ship routing rules in .bodega/config.json under llm.routing_rules - same schema as your own rules. They evaluate ABOVE your rules, so a team can encode "auth code stays local" once for everyone who opens the project.

Transparency is non-negotiable here: project rules show read-only at the top of the Routing section whenever the open project defines any, and a routed-by line from one always says project rule - a repo can never route your requests invisibly. Project rules pass through the same guards as everything else; they cannot bypass air-gap or spend caps.

See every decision: the chip, the dry run

  • The Auto pill hint - while you type in chat with rules configured, the pill previews which rule would catch the message (→ Tests go local). Hover for the full routed-by line.
  • Try it - the dry-run box at the bottom of the Routing section runs any hypothetical message through the REAL chain (overrides, project rules, your rules, slots) and reports the model, the tier, and exactly which rule decided - without sending anything. It uses your open project, so project rules show up too.
  • Code mode - each iteration that a rule routes emits a routing_rule_applied entry in the Debug panel log with the rule name and the model it picked.

If a rule says stay local while your active provider is cloud, the routed-by line says local-only could not be enforced rather than pretending it was. Honest beats quiet.

How rules interact with Smart Auto and the pill

  • The Auto pill must be on Auto for chat rules to run - picking Fast/Smart/Code on the pill is an explicit per-message choice, and rules respect it. Same for a pinned model in the dropdown: pins survive until you pick Default again.
  • Smart Auto (code mode, per step: reads fast, writes code, plan/verify smart) still runs when no rule matches an iteration. Rules out-vote it; they don't replace it. Both built-ins render as toggleable default rules in the Routing section - turning one off writes the same setting the old switch did.
  • Rules never touch QEL verification model choice, and image generation requests bypass rules entirely (a catch-all text rule can't hijack the image model).

This page mirrors the in-app docs hub for app version 1.0.0-beta.29.1. Found something unclear or out of date? Tell us on Discord. New here? Download the free beta and follow along.