cli_routing block in .evolve/policy.json has the keys clis, default, work, tiers and agents. cliroute.Compile (compile.go:23) compiles it once at start, and every launch path asks Router.Resolve (cliroute.go:123). A launch with no root router refuses a declared table (RefuseLaunchRouter, router.go:113).evolve cli-routing init|set|unset|migrate. Each write compiles the merged file before an atomic write. The verb refuses inside a phase or while a cycle holds a live lease. A pins key beside a table refuses every launch (findings.go:28), and evolve cli-routing migrate folds the old pins and workflow.universal_fallback_exclude keys into the table. evolve cli-routing explain <agent> prints the chain of an agent.clis and default are [agy, agy-claude, claude], and tiers.deep and tiers.top are [agy-claude, claude]. Thus a balanced phase runs agy-tmux (Gemini 3.8 Flash High) first. A deep or top seat runs agy-claude-tmux (Claude Opus 5.5 High), then claude-tmux (opus). Codex is in no chain: only --bypass-policy reaches it.profiles/family_floor.go:5): the auditor, adversarial-review, tdd-engineer, the spec verifiers and code-reviewer admit only the claude family (Table.allowed, table.go:83). Thus these agents run on Claude Code only.fast | balanced | deep | top (modelcatalog.CanonicalTiers, refresh.go:10). Profiles speak tiers, and the model_tier_map of each CLI manifest gives the concrete model. No tracked profile defaults to fast.llmroute.go:19): {80, 81, 85, 87, 124, 127}. They mean, in order: REPL boot timeout, artifact timeout, unknown prompt, model mismatch, command timeout and absent binary (bridge/exitcodes.go:14-21). agy-claude-tmux waits up to 10 s for a claude-family footer label, and it exits 87 if no label shows. Exit 87 is a trigger, so the bridge then walks the chain to claude-tmux.llmroute.Resolve, llmroute.go:70): EVOLVE_<AGENT>_CLI > EVOLVE_CLI > profile.cli > claude-tmux for the CLI, and env > profile.model_tier_default > default for the model. With a table, evolve loop and evolve cycle run exit 2 before any dispatch if an env or --cli value is outside the allowed set of the agent.llmroute.go:231-254): a quota or boot-timeout bench demotes a candidate in the chain. If all candidates are benched, the least recently benched candidate goes first.router/model_routing_clamp.go:29): the clamp validates every {CLI, tier} that the advisor proposes against allowed_clis, the tier envelopes and the live catalog. A tier below the floor clamps up. A profile that declares no envelope gets the universal envelope {balanced, top} (model_routing_clamp.go:12). The advisor walks the chain of the table with Decision.WalkAt (cliroute.go:156): the first unbenched CLI that the tier permits leads.routing-decision-N.json per decision, routing-plan.json per cycle — replayable with evolve routing.dynamic-phase-routing.md claims the advisor defaults to haiku ("lightweight routing"); code defaults to opus/deep and the constructor comment explicitly rebuts the doc (phase_advisor.go:92-100). Same doc’s status table still says "Default: Off" vs the shipped advisory default (config.go:508); dynamic-model-routing.md’s entire body describes a never-shipped bash design behind its supersession banner.ADR-0022 added the manifest realization. ADR-0024 and ADR-0052 added advisory routing and the clamps. Cycle 436 added the per-phase {cli, tier} plans and the clamp, and cycle 480 added the universal envelope floor. In October 2026, ADR-0119 added the one routing table in three steps. L1a built the resolver, and L1b sent every launch path through it. L2 made the operator’s table live.
A permanent rule of the operator says that profiles name tiers, not models, and that any CLI must run any phase with any model. The clamp and the manifest layers apply this rule.