Docs Concepts

Model matching

Give each agent the tickets that fit the model it runs on: research on fast models, junctions on the strongest. It's off by default and switched on per trail.

Teamtrail never picks, starts or switches a model. It reads the model an agent already runs on and offers that agent the tickets set for its tier.

#Turn it on

In the Lookout, open Settings → Model matching and switch Match work to models on trail #n on. The grid below sets the tier for each ticket type on that trail. Changes apply to the next claim; nothing running is interrupted.

The setting lives with the trail. In local files it's in map.md:

md
---
model-matching: on
model-tiers: [research=balanced]
---

model-tiers holds only the types you changed from the defaults.

#Tiers

Three tiers, weakest first: fast, balanced, strongest.

Ticket typeDefault tier
researchfast
taskbalanced
executebalanced
junctionstrongest
prototypestrongest
reviewstrongest

Next to each type, the grid shows what Trail stats measured for it (tickets done, median time, rework). It's there to inform your choice; nothing changes a tier on its own.

#How an agent's model is found

The MCP server reads the model of the agent's latest call from its own local log: the Claude Code session transcript or the Codex session log (see Connect your agent). Otherwise it uses the model in the session's reported usage.

The model id is matched to a tier: first your project's models.json, then a built-in table of model families. For example, *claude-haiku-* and *-mini are fast, *claude-sonnet-* and gpt-4* are balanced, *claude-opus-*, gpt-5* and o3 are strongest. An agent that reports no model, or a model neither table knows, counts as balanced, so it never blocks work.

#models.json

Add new or custom models in .teamtrail/models.json. It's optional and committed.

json
{
  "v": 1,
  "models": {
    "my-finetune-v2": "strongest",
    "local-llama-*": "fast"
  }
}
Key
v1.
modelsModel id or glob to fast, balanced or strongest. * matches any run of characters; case doesn't matter. Exact ids win over globs.

Unknown keys and unknown tiers are errors. While the file has errors, only the built-in table counts; Settings → Model matching lists them.

#What agents get

With matching on, claim_ticket and next_ticket without a ticket offer the best ready ticket at the agent's tier, then lower tiers, nearest first. A strong agent is never idle while work waits, and a weaker one never gets a ticket set above its tier on its own.

FieldWhen
tierOn claim and next results while matching is on: { session, ticket, model? }.
tierNoteThe agent claimed a ticket by key that's set for a stronger tier than it runs. It tells you it took the ticket anyway.
reasonnext_ticket found nothing at or below the agent's tier: which tickets wait for a stronger model, and the agent's tier.

status and resume_trail include modelMatching: on or off, the tier per ticket type, and the session's tier with the reason.

An agent can always claim any ticket by key.

#Waiting for a stronger model

When a ready ticket is set for a stronger tier than any connected agent runs, it waits. It shows on the map as needing that tier, and as a model item in Waiting on you: connect an agent on a stronger model, or have one claim the ticket by key. Nothing waits while matching is off or no agent is connected.

The Lookout also shows each session's tier next to its name in Current trail step, and Settings → Model matching lists the agents connected now with their tiers.