# Agents - Model Selection and Catalogs Agent harnesses resolve model names through environment variables, settings files, and generated catalogs. The wrong layer wins silently. Aliases can resolve to retired model IDs, and catalogs fill omitted fields with placeholders. Pin explicit model IDs, verify from the shell, and re-verify catalog values after every refresh. ## Key points - Subagent model resolution order: `CLAUDE_CODE_SUBAGENT_MODEL` env var, then agent frontmatter `model`, then the tier default env var such as `ANTHROPIC_DEFAULT_SONNET_MODEL`. - Tier aliases are env-var resolvers, independent of the session default `model` key. The separation lets a fast implementer tier coexist with a deep-analysis tier. - `[1m]` is not a separate model ID. It toggles the 1M context window, valid only on explicit model IDs. Sync tooling normalizes `alias[1m]` back to the plain alias. - A frontmatter `model: sonnet` alias can resolve to a retired model ID and fail with 404 on every spawn. A user-scope agent shim with an explicit current model ID overrides it. - `ANTHROPIC_MODEL` ranks above the settings `model` field. Set it in the settings `env` block, and it survives restarts. `/model` alone is reclaimed by the pin on the next start. - A `:off` suffix on the subagent model id disables thinking when the backend rejects the model's default thinking setting. - Some orchestrators route subagent models per tier, not per agent. The executor and the non-plan main loop resolve through the same tier env var. One env var moves the whole tier. - pi loads `models.json` at startup only. A running session keeps the old model list until restart, and the quick-cycle picker waits for the restart. - The refresh generator fills omitted `contextWindow` and `maxTokens` with placeholders (128000/16384). A model with a real 1M window then runs at roughly 12 percent of capacity. - `modelOverrides` applies only to built-in and extension-registered models. Gateway entries are custom models in the generator's array, so their overrides are silently ignored. The durable fix is a post-generate transform. - `enabledModels` entries are not globs. A non-glob entry matches exact `provider/id`, then the bare model id, then substring in `id` and `name`. Different provider segments or dots do not match. - pi picks the first scoped `enabledModel` as the startup model. Moving entries between overlays silently changes the startup model, so the render must preserve entry order. - `enabledModels` only fills the quick-cycle list. It does not restrict the `/model` picker, where gateway models appear automatically. - Upstream `refresh-models` releases deliberately re-curate model values. Move such values into local `models.patch.json`, or they silently regress on every refresh. Guard tests should fail loudly on divergence from the curated policy. - `refresh-models` reads repo-local git config `user.email` first and can silently rewrite the gateway user tag. - Gateway ids can carry a doubled provider segment. Patches keyed on the short id form match nothing. - Built-in models in the binary need only an `enabledModels` entry. Confirm with the model-list command first. - `refresh-models` degrades any entry the curated rules have no rule for, and clobbers name, `contextWindow`, and `maxTokens`. Diff the uncurated entries after each refresh. - Built-in classifiers can read a provider entry straight from the catalog. Dropping that provider silently breaks classification. ## How to apply 1. Pin explicit model IDs in long-lived agent definitions. 2. Verify a tier alias: `claude -p "respond with only your model identifier" --model <alias>`. 3. Beat a managed-settings pin with `ANTHROPIC_MODEL` in the settings `env` block. 4. Add `:off` to the subagent model id when the backend rejects the default thinking setting. 5. Restart pi after you edit `models.json`. 6. Run the model-list command before you add a provider block for a built-in model. 7. After each `refresh-models` run, diff the uncurated entries before you commit. 8. Keep curated values in `models.patch.json`, keyed on the full gateway id. ## Observations - [model-resolution] Subagent model order: env var, agent frontmatter, then the tier default env var. #claude-code (source: agent sessions, 2026-03) - [model-resolution] A `model: sonnet` alias can resolve to a retired model ID and 404 on every spawn. #claude-code (source: agent sessions, 2026-07) - [configuration] `ANTHROPIC_MODEL` ranks above the settings `model` field and survives restarts. #claude-code (source: agent sessions, 2026-09) - [catalogs] pi loads `models.json` at startup only. Restart the session to see edits. #pi (source: agent sessions, 2026-07) - [catalogs] Placeholder defaults (128000/16384) can cap a 1M-window model at roughly 12 percent of capacity. #pi (source: agent sessions, 2026-09) - [catalogs] `modelOverrides` ignores gateway entries. A post-generate transform is the durable fix. #pi (source: agent sessions, 2026-09) - [catalogs] Upstream `refresh-models` releases re-curate values. Pin curated values in `models.patch.json`. #pi (source: agent sessions, 2026-09) - [catalogs] `refresh-models` reads repo-local git config `user.email` first and can rewrite the gateway user tag. #pi (source: agent sessions, 2026-10) - [catalogs] A built-in classifier can read a provider entry straight from the catalog. #pi (source: agent sessions, 2026-10) ## Relations - relates_to [[resources/documentation/Agents/Agents - Daily Working System]] (model tier pins are part of the daily agent setup) - relates_to [[resources/documentation/How I Work - Daily Driver Toolkit]] (daily-driver model choice and catalog upkeep) - relates_to [[resources/documentation/Agents/Agents Workflow]] (model resolution sits inside the agent workflow) ## Sources Personal agent-session notes, March 2026 to November 2026