Stable Names, Shifting Models

One matrix routes every agent

Agents ask for a job, not a model that might vanish tomorrow

Instead of hardcoding a provider and model, an agent declares a semantic role like coding or fast. A curated per-provider matrix resolves that role to a concrete model.

The catch: every agent still has to land on the right model. So is this real?

# an agent declares a role, not a model model_role: coding # the matrix resolves it per provider coding → a concrete model

Production-grade, not a proposal

The routing-matrix bundle ships as amplifier-module-hooks-routing v0.1.1 with a green suite — and eight curated matrices ready to switch between.

It works today. So why not just hardcode the model names?

53
commits, initial → v2
270
tests green in 0.46s
7
test files
8
curated matrices

Hardcoded names rot — and broad globs quietly downgrade you

The curator guide flags fake names like claude-opus-4.6-fast ("Not a real model"). And a broad claude-* glob crosses class boundaries.

Opus and Haiku both match claude-* — a premium role silently swaps to budget.

One stable role, resolved by a curated matrix

Agents declare a single semantic role. The balanced matrix defines 13 roles; every matrix must include the required general and fast roles or loading fails.

One indirection layer sits between agents and models. Now, how does it go live?

general* fast* coding ui-coding security-audit reasoning critique creative writing research vision image-gen critical-ops

A session:start hook wires the whole fleet at once

The routing-resolve hook (priority 5) reads each agent's model_role, resolves it, and patches provider_preferences — every agent resolved in parallel via asyncio.gather.

Update one matrix row and every agent using that role benefits. But does it go stale?

  1. 1
    session:start fires the routing-resolve hook (priority 5).
  2. 2
    It reads each agent's model_role and resolves it to a model.
  3. 3
    It patches provider_preferences — all agents in parallel via asyncio.gather.

It tracks version bumps on its own — and refuses the class-jump

Version-aware glob sorting strips date suffixes and natural-sorts so the highest clean version wins within a class. Copilot candidates stay pinned — its list_models() has no static fallback.

copilot.yaml notes it "avoids the 30x claude-opus-fast trap. Uses Haiku (0.33x)."

Re-route the whole fleet in one command — and pull a diverse pool

One command switches every agent's routing. And v2 (b559b10, 2026-07-16) added a keyword-only limit=N that draws an N-diverse reviewer pool, deduped on (provider, resolved_model).

Default stays limit=1 first-match; limit>1 opens the diverse pool. So what's the pattern?

# switch the entire fleet at once amplifier routing use balanced # v2: an N-diverse reviewer pool resolve_model_role(…, limit=N) # deduped on (provider, resolved_model)
The Pattern

Name the job, not the model — and the fleet re-routes as models move

In amplifier-foundation, 16 of 16 agent definition files already declare a model_role. Semantic roles are the durable interface to a shifting model landscape.

Sources

Research Methodology

Status: Shipping — v0.1.1

Data as of: 2026-07-16 (latest commit b559b10)

Primary source: ramparte/amplifier-bundle-routing-matrix (upstream microsoft/amplifier-bundle-routing-matrix); agent counts from amplifier-foundation.

Commands run:

Gaps: Cost multipliers 30x and 0.33x are quoted from copilot.yaml/README documentation, not independently benchmarked. No source found for any "66 agents" figure — omitted.

Primary contributors: Brian Krabach (38 commits); v2 limit=N commit authored by Sam Schillace (1).

More Amplifier Stories