# How Model Roles and Routing (default, smol, slow, plan) Are Configured in Oh-My-Pi

> Learn how Oh-My-Pi configures model roles and routing with aliases and priority chains. Understand default, smol, slow, and plan configurations for your LLM models. Optimize your setup now.

- Repository: [Can Bölük/oh-my-pi](https://github.com/can1357/oh-my-pi)
- Tags: internals
- Published: 2026-05-21

---

**Oh-My-Pi uses a role-based routing system where abstract roles like "smol," "slow," and "plan" are mapped to concrete LLM models through user-defined aliases and priority chains, resolved at runtime by the model-resolver module.**

The `omp` CLI in the `can1357/oh-my-pi` repository implements a sophisticated **model roles and routing** architecture that decouples task requirements from specific provider implementations. This design allows you to configure speed tiers and reasoning levels centrally, ensuring lightweight tasks use fast models while complex reasoning flows through capable alternatives.

## What Are Model Roles?

Model roles are named slots that represent different capability or speed requirements. According to [`packages/coding-agent/src/config/model-registry.ts`](https://github.com/can1357/oh-my-pi/blob/main/packages/coding-agent/src/config/model-registry.ts) (line 81), the system recognizes eight predefined role identifiers:

- `default`
- `smol` (fast, lightweight)
- `slow` (capable, reasoning-heavy)
- `vision` (multimodal)
- `plan` (architecture/design)
- `designer` (UI/UX generation)
- `commit` (commit message generation)
- `task` (general task execution)

Each role is stored as a key in the `modelRoles` record defined in [`packages/coding-agent/src/config/settings-schema.ts`](https://github.com/can1357/oh-my-pi/blob/main/packages/coding-agent/src/config/settings-schema.ts) (lines 317–323), where the value is a model pattern string that may include an optional thinking-level suffix (e.g., `:high` or `:xhigh`).

## The Model Routing Pipeline

When `omp` needs to resolve a model for a specific task, it executes a four-stage pipeline defined in [`packages/coding-agent/src/config/model-resolver.ts`](https://github.com/can1357/oh-my-pi/blob/main/packages/coding-agent/src/config/model-resolver.ts):

### 1. Role Lookup and Alias Expansion

The system first retrieves the configured pattern for the requested role. If you specify an alias like `pi/smol`, the `expandRoleAlias` function (lines 15–30 in [`model-resolver.ts`](https://github.com/can1357/oh-my-pi/blob/main/model-resolver.ts)) expands this to the actual model pattern stored in your settings.

### 2. Pattern Parsing

The `resolveModelRoleValue` function (lines 601–640) parses the model string, extracting the base identifier and any thinking-level selectors (e.g., `anthropic/claude-sonnet-4:xhigh`). This produces a `ResolvedModelRoleValue` object containing the target model and metadata.

### 3. Priority Chain Resolution

For the `smol` and `slow` roles, the system consults [`packages/coding-agent/src/priority.json`](https://github.com/can1357/oh-my-pi/blob/main/packages/coding-agent/src/priority.json). This file contains ordered arrays listing preferred model identifiers for each speed tier. For example, the `smol` array might list `"cerebras/zai-glm-4.7"` as the first preference, ensuring the fastest available model is selected.

### 4. Concrete Model Selection

Finally, `resolveModelFromString` → `parseModelPattern` → `parseModelPatternWithContext` (lines 730–773) performs fuzzy matching against the available model catalog. If multiple roles are specified (e.g., `["smol","default","slow"]`), `resolveRoleSelection` (lines 998–1015) walks the ordered list and returns the first resolvable model.

## Configuring Roles via CLI

You can override role assignments directly from the command line. The CLI parser in [`packages/coding-agent/src/cli/args.ts`](https://github.com/can1357/oh-my-pi/blob/main/packages/coding-agent/src/cli/args.ts) (lines 28–33) handles flags that write to the `modelRoles` record:

```bash

# Assign a fast model to the "smol" role for quick tasks

omp --smol anthropic/claude-haiku-4-5

# Set a high-capability model for the "slow" role

omp --slow gpt-5.4

# Configure the "plan" role with explicit thinking level

omp --plan anthropic/claude-sonnet-4-5:xhigh

```

These flags update the runtime settings, which persist according to your configuration storage preference.

## Programmatic Configuration

For embedded usage or plugins, modify role bindings through the Settings API:

```typescript
import { Settings } from "@oh-my-pi/pi-coding-agent/config";

const settings = Settings.getInstance();

// Use an alias with explicit thinking level
settings.setModelRole("smol", "pi/smol:high");

// Configure the planner role
settings.setModelRole("plan", "anthropic/claude-sonnet-4-5:xhigh");

```

The `setModelRole` method writes directly into the `modelRoles` record, which is then referenced during the resolution pipeline.

## Internal Resolution API

Extensions and internal utilities can resolve models explicitly using the resolver module:

```typescript
import { resolveModelRoleValue, findSmolModel } from "@oh-my-pi/pi-coding-agent/config/model-resolver";
import { Settings } from "@oh-my-my-pi/pi-coding-agent/config";

const settings = Settings.getInstance();
const availableModels = modelRegistry.getAvailable();

// Full resolution with context
const roleValue = settings.getModelRole("slow");
const resolved = resolveModelRoleValue(roleValue, availableModels, { settings });

if (resolved.model) {
  console.log(`Provider: ${resolved.model.provider}`);
  console.log(`Thinking level: ${resolved.thinkingLevel ?? "default"}`);
}

// Fast helper for title generation (findSmolModel, lines 1325-1362)
const quickModel = await findSmolModel(modelRegistry, settings.getModelRole("smol"));
const title = await generateTitle(quickModel, diffContent);

```

The `findSlowModel` helper (lines 1460–1480) provides similar functionality for deep-reasoning tasks, selecting the most capable available model from the slow priority chain.

## Default Cycle Order

When cycling through models via the UI button, `omp` uses the `DEFAULT_CYCLE_ORDER` defined in [`packages/coding-agent/src/config/settings-schema.ts`](https://github.com/can1357/oh-my-pi/blob/main/packages/coding-agent/src/config/settings-schema.ts) (lines 890–894):

```typescript
["smol", "default", "slow"]

```

This order also serves as the fallback chain when a specific role is undefined in user settings. If no role matches, the system defaults to the first enabled model with a valid API key.

## Summary

- **Model roles** (`default`, `smol`, `slow`, `plan`, etc.) are abstract identifiers defined in [`model-registry.ts`](https://github.com/can1357/oh-my-pi/blob/main/model-registry.ts) and stored in the `modelRoles` settings record.
- **Routing** occurs through the [`model-resolver.ts`](https://github.com/can1357/oh-my-pi/blob/main/model-resolver.ts) pipeline: role lookup → alias expansion → pattern parsing → priority chain resolution.
- **Priority chains** for `smol` and `slow` roles are configured in [`priority.json`](https://github.com/can1357/oh-my-pi/blob/main/priority.json), ensuring appropriate model selection based on speed or capability requirements.
- **CLI flags** (`--smol`, `--slow`, `--plan`) and the Settings API allow runtime configuration of role-to-model mappings.
- **Fallback behavior** follows the `DEFAULT_CYCLE_ORDER` (`smol` → `default` → `slow`) when roles are unspecified.

## Frequently Asked Questions

### What is the difference between the "smol" and "slow" model roles?

The **smol** role targets fast, low-latency models suitable for quick tasks like title generation or lightweight completions, while the **slow** role targets high-capability models optimized for deep reasoning and complex planning tasks. According to [`priority.json`](https://github.com/can1357/oh-my-pi/blob/main/priority.json), each maintains a separate ordered list of preferred providers and model identifiers.

### How do I set a default model if a specific role is not configured?

If a role entry is missing from the `modelRoles` record, the system falls back to the `DEFAULT_CYCLE_ORDER` (defined in [`settings-schema.ts`](https://github.com/can1357/oh-my-pi/blob/main/settings-schema.ts) lines 890–894), checking `smol`, then `default`, then `slow`. If none resolve, `omp` selects the first enabled model in the catalog that has a valid API key configured.

### What happens if my configured role model is unavailable?

The resolution pipeline in `resolveRoleSelection` (lines 998–1015) walks the ordered priority list for the role until it finds a model that matches the pattern and is available in the current catalog. If no matches exist, the function returns `null`, and the calling utility typically falls back to the next role in the default cycle.

### How do thinking level selectors (:high, :xhigh) affect model selection?

When parsing the model string, `resolveModelRoleValue` extracts thinking-level suffixes (e.g., `:high`, `:xhigh`) and stores them in the `thinkingLevel` property of the resolved value. These selectors instruct compatible providers to use extended reasoning modes, though the final availability depends on whether the selected model and provider support the requested thinking level.

### Where are role aliases like "pi/smol" defined?

Role aliases are expanded by the `expandRoleAlias` function in [`model-resolver.ts`](https://github.com/can1357/oh-my-pi/blob/main/model-resolver.ts) (lines 15–30). The `pi/smol` alias specifically maps to the value stored in the `smol` key of the `modelRoles` record, allowing you to reference role configurations indirectly without hardcoding specific model identifiers throughout your code or CLI commands.