# Model routing and specialization

> **Status:** Reference — updated 2026-08-13 for issue #142 (role-based routing). Reviewed 2026-07-09 for GPT-5.6, Claude Fable 5 / Opus 5, GLM-5.2, Gemini 3.5/3.6 Flash, and the local Qwen route.

This document defines how this installation routes workflow **roles** without giving up final-output quality. The guiding policy is **local-first execution, evidence-first escalation, frontier verification**.

Issue #142 replaced the author-facing `small`/`medium`/`big` size-tier abstraction with four semantic routing roles: **worker**, **conductor**, **advisor**, **security**. A role expresses **what job** the agent is doing; the machine-local config decides the concrete provider/model. Size tiers remain accepted only as deprecated migration inputs for existing saved workflows and journals.

## Runtime facts

The runtime resolves four roles from `~/.pi/workflows/model-tiers.json`. The authoritative layer is `roles`; a profile with only the legacy `tiers` block keeps working, with roles derived via the deprecation alias (small→worker, medium→conductor, big→advisor; security has no size-tier ancestor and derives from `big` on a tier-only profile).

```jsonc
{
  "roles": {
    "worker":    { "default": "litellm-ny2/local-qwen27", "routes": { "escalation": "openai-codex/gpt-5.6-luna" } },
    "conductor": { "default": "litellm-ny2/oc-glm52",      "routes": { "escalation": "openai-codex/gpt-5.6-terra" } },
    "advisor":   { "default": "openai-codex/gpt-5.6-sol",
                   "routes": { "long-context": "meridian/claude-opus-5",
                               "independent":  "ollama-cloud/deepseek-v4-flash" } },
    "security":  { "default": "meridian/claude-fable-5" }
  },
  "tiers": { "small": "litellm-ny2/local-qwen27", "medium": "litellm-ny2/oc-glm52", "big": "openai-codex/gpt-5.6-sol" }
}
```

Binding precedence (most specific first):

1. `agent(..., { model })` — exact provider/id (also carries agentType/phase model folded by the workflow layer)
2. model pinned by `agentType`
3. `agent(..., { modelRole, modelRoute })` — semantic role + optional named specialist route
4. `agent(..., { tier })` — DEPRECATED size tier (migration only)
5. phase model in `meta.phases[]`
6. untagged agent → `conductor` role default (old `medium` successor)
7. session model

Important consequences:

- A role route is **not** a fallback pool. There is no automatic provider failover.
- `retries` rerun the same route. They do not move from worker to conductor to advisor.
- An escalation is a **new, separately journaled `agent()` call** carrying the evidence that justified it (failed host checks, repeated tool/schema failure, a verifier rejection, known complexity/context). A retry of the same call stays on the same model; bad output never silently triggers a switch.
- An unknown role/route or unavailable explicit route **fails with an actionable error**; it never silently drops to the session model.
- Pinning a model in an escalation-capable `agentType` defeats role routing.
- The role config is **snapshotted once per run** and inherited by nested workflows. On resume, changing the model behind a role invalidates that call's cached journal suffix; an unchanged mapping replays.
- The security-only model (Fable) is rejected outside the `security` role — after every selection source, including an exact `model` and an agentType pin. A quota/availability failure must surface, never silently downgrade a required security gate.
- API-billed (`google-ai-studio/*`) models are never role defaults/routes/fallbacks; an exact use requires a visible `googleBillingOptIn` opt-in.

Optional `routingNotes` in `model-tiers.json` are injected into the model-facing workflow-authoring prompt. They carry machine-specific specialization that cannot fit into the role slots.

## Role decision table

| Role | Default | Named routes | Use it for | Do not use it for |
|---|---|---|---|---|
| **worker** | `litellm-ny2/local-qwen27` | `escalation`→`openai-codex/gpt-5.6-luna` | Repo inventory, targeted reads, narrow edits, repetitive transformations, first worker attempt, low-risk reporting, high-volume fan-out | Sole final verifier for consequential changes; ambiguous architecture/security decisions |
| **conductor** | `litellm-ny2/oc-glm52` | `escalation`→`openai-codex/gpt-5.6-terra` | Planning, DAG decomposition, orchestration, correction coordination, project-scale synthesis, ordinary final aggregation | Final authority merely because it has a large context window; "a larger worker" |
| **advisor** | `openai-codex/gpt-5.6-sol` | `long-context`→`meridian/claude-opus-5`, `independent`→`ollama-cloud/deepseek-v4-flash` | Adversarial review, investigation, independent judgment, final semantic verification, architecture decisions, high-consequence decisions spanning the full context | Mechanical checks, broad cheap fan-out, work already proved by deterministic tooling |
| **security** | `meridian/claude-fable-5` | _(none)_ | Read-only review of authority-boundary changes: secrets, auth/authorization, command execution, sandbox escape, unsafe mutation, supply-chain risk | Worker/conductor/advisor/generic-review/bulk-fan-out defaults; a quota failure must surface, not silently downgrade |

### Escalation evidence rules

Quality escalation is always a **new, explicit, journaled `agent()` call** with a recorded reason. The reason vocabulary:

| Reason | Meaning | Example trigger |
|---|---|---|
| `failed-host-checks` | deterministic host validation rejected the work | `stageCheck()` returned failures |
| `tool-schema-failure` | repeated tool/schema failures on the same call | structured output kept failing validation |
| `verifier-rejection` | an independent verifier rejected the result | the advisor rejected the worker output |
| `known-complexity` | complexity/context was known before dispatch | a multi-file refactor needs a larger window |
| `long-context` | input would not fit the default route's window | advisor input exceeds Sol's effective input window → Opus |
| `family-diversity` | independent model-family judgment is materially useful | an Anthropic-family second opinion |
| `unresolved-finding` | a prior role left an unresolved cross-file/contract ambiguity | conductor could not resolve a contract |

- **Worker → Luna** only after evidence (failed host checks, repeated tool/schema failure, a verifier rejection, or known complexity/context). A retry stays on Qwen.
- **Conductor → Terra** when GLM leaves unresolved cross-file/contract ambiguity, a correction loop fails, OpenAI-family tool behavior is needed, or the task is consequential enough. Conductor is orchestration, not a larger worker.
- **Advisor → Opus** (`long-context`) when input would not safely fit the Codex route's effective input window, or a long/cache-sensitive trajectory favors Meridian's larger Anthropic context. **Advisor → Sol** is the default for compact-to-moderate context that fits the Codex route. **Advisor → DeepSeek V4 Flash** (`independent`) for a low-cost model-family-diverse second opinion (not a final security authority).
- **No arbitrary round-robin.** Record the reason for every escalation.

### Deprecation alias table

| Legacy tier | Maps to role | Notes |
|---|---|---|
| `small` | `worker` | Migration only; new authoring uses `modelRole: 'worker'` |
| `medium` | `conductor` | Migration only; new authoring uses `modelRole: 'conductor'` |
| `big` | `advisor` | Migration only; new authoring uses `modelRole: 'advisor'` |
| _(none)_ | `security` | Security has no size-tier ancestor |

Existing `tier: small|medium|big` workflow calls continue for at least one major compatibility cycle and emit a deduplicated deprecation warning per run. Migration never destroys machine-local config.

## Context windows (verified from models.json / pi-ai anthropic.json, not vendor marketing)

| Route | Context window | Max output | Notes |
|---|---:|---:|---|
| `litellm-ny2/local-qwen27` (worker) | 131,072 | 32,768 | TIGHTEST window in the fleet — size fan-out prompts against 131k, not the conductor's 1M |
| `litellm-ny2/oc-glm52` (conductor) | 1,048,576 | 32,768 | Automatic context caching |
| `openai-codex/gpt-5.6-sol` (advisor default) | 272,000 | 128,000 | 128k output reserve → ~144k effective input; cap workflow agents at `maxContextTokens: 140000` |
| `openai-codex/gpt-5.6-terra` (conductor escalation) | 272,000 | 128,000 | Fastest GPT-5.6 SKU; correct conductor escalation target |
| `openai-codex/gpt-5.6-luna` (worker escalation) | 272,000 | 128,000 | Cheapest-to-run worker escalation |
| `meridian/claude-opus-5` (advisor long-context) | 1,000,000 | — | Independent Anthropic-family judgment; later knowledge cutoff (~May 2026) |
| `meridian/claude-fable-5` (security) | 1,000,000 | — | Security-only; read-only by tool policy |
| `ollama-cloud/deepseek-v4-flash` (advisor independent) | — | — | Low-cost model-family-diverse critic/refuter; NOT a final security authority; findings require deterministic evidence |

The worker's 131k window is the binding constraint on worker prompts: chunk large inputs rather than assuming conductor-scale context.

### Codex subscription route boundaries

All three GPT-5.6 SKUs share the same 272,000/128,000 shape on our route, so the choice between them is latency and depth, not context or cost: terra is the fastest and the correct conductor escalation target; luna is the cheapest-to-run worker escalation; sol is the deepest and is pinned-only (no role default slot, by design, so it cannot be reached as a default). The bare string `gpt-5.6` is a vendor alias for sol; always pin the explicit SKU (`-sol`/`-terra`/`-luna`) so the route is unambiguous.

`openai-codex/gpt-5.6-sol` is CALLED, NEVER LEFT RUNNING — and it should be used, not wasted. Reach it via the advisor role default for high-consequence final semantic verification, architecture decisions, and difficult judgment on a PRE-ASSEMBLED prompt: no exploratory tool loop, readOnly, `maxContextTokens: 140000`. If the task must explore to reach its verdict, it is an advisor task — use Opus (`long-context`).

No doc may claim the public-API 1.05M window is usable through `openai-codex`. Setting Codex registry entries to 1.05M is unsafe: Pi would defer compaction and occupancy warnings until long after the provider starts rejecting requests. The enforced route window is **272,000 total tokens** (input + output), confirmed 2026-08-12 against the ChatGPT Codex subscription hard limit (the earlier ~372k probe conclusion was superseded; `~/.pi/agent/models.json` was corrected from `contextWindow: 372000` to `272000` for all three GPT-5.6 SKUs). With the 128,000-token output reserve, the effective input budget is ~144,000 tokens, so cap GPT-5.6 workflow agents at `maxContextTokens: 140000`. That cap is currently **advisory only** — enforced after a completed turn, not before the next provider request (issue #143); until #143 lands, keep Sol prompts pre-assembled and tool-free.

### Google API-billed models

`google-ai-studio` is the ONLY API-billed provider (every routine route is subscription- or self-hosted and costs $0 marginal per token). Gemini models must never be role defaults, automatic fallbacks, routine diversity fan-out, or hidden escalation routes. An exact explicit `model` use requires a visible `googleBillingOptIn` opt-in, permitted only for an operator-requested benchmark or a documented capability gap (e.g. Google-native multimodal handling). Current entries: `gemini-3.6-flash` ($1.50/$7.50 per 1M), `gemini-3.5-flash` ($1.50/$9.00), `gemini-3.5-flash-lite` ($0.30/$2.50) — if a Gemini call is genuinely warranted, prefer 3.6-flash over 3.5-flash (same input rate, cheaper output). `litellm-ny2/oc-gemini3-flash` is subscription-routed (cost 0) but retired from routine use, superseded by `gpt-5.6-luna`. `gpt-5.5` is a benchmark control only. DeepSeek V4 Flash is an explicit low-cost critic/refuter route (`advisor` `independent`), not a fifth default role and not an automatic fallback.

## Quality-preserving workflow patterns

### Normal issue-sized implementation

```text
worker (Qwen)
  -> host stageCheck
  -> conductor (GLM) correction only if needed
  -> host stageCheck
  -> advisor (Sol) semantic verifier
```

The cheap model does most token-heavy work. Quality comes from constrained scope, mechanical checks, correction feedback, and an independent frontier gate—not from sending every token to the frontier model.

### Difficult or repository-scale implementation

```text
worker (Qwen) scout
  -> advisor (Sol) planner
  -> conductor (GLM) project-scale worker, or conductor escalation (Terra) when OpenAI-family behavior is required
  -> host checks
  -> advisor (Sol) verifier
  -> advisor long-context (Opus) / security (Fable) only for unresolved high-risk findings
```

### Adversarial review

```text
worker (Qwen) finders
  -> conductor (GLM) consolidation
  -> advisor independent (DeepSeek) / advisor long-context (Opus) family-diverse refuters as signaled by risk
  -> advisor (Sol) controller verdict
```

Do not use model count as a proxy for confidence. A source-backed refutation or deterministic test should outweigh majority voting.

## Cache-aware routing

Cache behavior belongs to the **provider route plus harness**, not just the model name.

- GPT-5.6: writes cost 1.25x uncached input on API billing; reads cost 10% of input; the current API requires a stable cache key for improved matching. The Codex adapter supplies a session-derived key but does not currently expose explicit breakpoints from workflow scripts.
- GLM-5.2: Z.AI documents automatic cache recognition and `usage.prompt_tokens_details.cached_tokens`; verify whether the selected LiteLLM/Ollama route forwards those fields.
- Opus via Meridian: reliable cache reuse across discrete calls with a shared prefix. Re-run before assuming that behavior for a different model or bridge version.
- Local Qwen: no provider bill, so compaction/throughput and GPU occupancy matter more than cached-token price.

Never route solely on advertised context size. Long prompts above 272k on GPT-5.6 receive higher long-context pricing, and excessive context can reduce focus even when it fits. Route-specific context checks happen before dispatch: an over-limit advisor input is sent to an explicitly selected Opus route (`long-context`), not accidentally to Sol after Sol fails.

## Saved-workflow policy

Saved workflows should use **roles** by default. An exact `model` is justified only for:

- explicit provider/model-family diversity;
- a measured capability unavailable from the configured role;
- a deliberate provider fallback;
- a temporary qualification benchmark requested by the operator (with `googleBillingOptIn` for API-billed models).

Existing saved workflows using `tier: small|medium|big` keep working (deprecated alias). Audit saved workflows whenever the model pack changes:

1. Remove retired generation pins (`gpt-5.5`, old Opus revisions, stale Gemini defaults).
2. Ensure `model` does not accidentally override a `modelRole`/`tier` on a worker/verifier.
3. Ensure retry rounds actually change route (a retry stays on the same model; escalation is a new call).
4. Keep final controllers/verifiers on `advisor` unless a documented diverse frontier override is intentional.
5. Keep model-specific benchmark fixtures pinned so historical comparisons remain reproducible; label them as controls, not defaults.

## `/workflows-models`

`/workflows-models` is the role-routing editor. It views/edits role defaults and named routes, and labels the legacy tier section as compatibility-only (deprecated migration). Editing a role default or route writes the `roles` block; the legacy `tiers` block is preserved for migration. Reset-to-defaults populates both layers so role routing and legacy tier paths agree until the user customizes one.

## Sources and requalification

Capability claims are time-sensitive. Re-run local qualification after a provider, bridge, model snapshot, system prompt, or tool schema changes.

- [OpenAI GPT-5.6 model guidance](https://developers.openai.com/api/docs/guides/latest-model)
- [OpenAI prompt caching](https://developers.openai.com/api/docs/guides/prompt-caching)
- [GPT-5.6 Sol model card](https://developers.openai.com/api/docs/models/gpt-5.6-sol)
- [GPT-5.6 Terra model card](https://developers.openai.com/api/docs/models/gpt-5.6-terra)
- [GPT-5.6 Luna model card](https://developers.openai.com/api/docs/models/gpt-5.6-luna)
- [OpenAI Codex model catalog (272k route metadata)](https://github.com/openai/codex/blob/2e8c3756f95789c215d9ea9a5ade6ec377934b3f/codex-rs/models-manager/models.json)
- [Claude model overview](https://platform.claude.com/docs/en/about-claude/models/overview)
- [Claude Fable 5](https://platform.claude.com/docs/en/about-claude/models/introducing-claude-fable-5-and-claude-mythos-5)
- [Claude Opus 5](https://platform.claude.com/docs/en/about-claude/models/whats-new-claude-5)
- [GLM-5.2 overview](https://docs.z.ai/guides/llm/glm-5.2)
- [Z.AI context caching](https://docs.z.ai/guides/capabilities/cache)
- [Gemini 3.6 Flash](https://ai.google.dev/gemini-api/docs/models/gemini-3.6-flash)
- [Gemini 3.5 Flash](https://ai.google.dev/gemini-api/docs/models/gemini-3.5-flash)
- [Provider-behavior benchmark](./provider-behavior-benchmarks.md)