You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Proposal: model aliases so one agent works in every tool #830
Today. An agent names one model, and TeamAI copies it into every tool as is.
agents/implementer.md model: opus
Claude Code opus works
Codex opus breaks, unknown model
OpenCode opus breaks, unknown model
Proposal. The agent says what kind of model it wants. The team says which model that is in each tool.
agents/implementer.md model: strong
team repo strong:
claude: opus
codex: gpt-5.6
opencode: ...
Claude Code opus works
Codex gpt-5.6 works
OpenCode ... works
A member can change a mapping on their own machine, the way model profiles use team: and local:.
A tool with no mapping gets its default model, and pull and doctor warn about it.
model: opus keeps working as it does today.
An alias could also carry reasoning effort, which most agent tools expose.
Every team that deploys agents to more than one tool needs this, and it is on the roadmap in #647 (Team Execution: "Improve and expand support for different Agents"). Workflows (#818) need it too, since each member runs agents in their own tool.
Open question. Should the team name its aliases, or should TeamAI ship a fixed set such as strong and fast? I lean toward team names.
changed the title [-]Proposal: tool-independent model aliases for agents[/-][+]Proposal: model aliases so one agent works in every tool[/+]on Sep 25, 2026
I think strong and fast are enough as the initial aliases. It would be useful to allow multiple model options within each tier, though, so teams can choose among them based on availability or preference. The default choice should be explicit, with local overrides when needed.
Starting with strong and fast makes sense to me, and so do several options per alias, an explicit default and local overrides. Below is a shape that tries to fit those together, as a starting point for discussion rather than a settled design. The main thing I'd add is team names on top of the two, so a team that wants a reviewer model doesn't have to bend strong to get it.
Goal. One agent file runs in every tool a member uses, on the model the team chose for that tool. This works with or without an AI gateway.
Terms. A model alias names a kind of model, such as strong. A mapping says which model that is in one tool, and optionally which reasoning effort to use.
flowchart LR
A["agents/implementer.yaml<br/>model: strong"] --> R{{resolve per tool}}
T["models/aliases.yaml<br/>team mapping"] --> R
L["~/.teamai/models/aliases.yaml<br/>local override"] --> R
R --> C["Claude Code<br/>model: opus<br/>effort: high"]
R --> X["Codex<br/>model = gpt-6-sol<br/>model_reasoning_effort = high"]
R --> O["OpenCode<br/>model: anthropic/..."]
R --> G["Codex on the team gateway<br/>model = glm-5.3"]
R --> U["tool with no mapping<br/>no model field, warning"]
Loading
The agent says what kind of model it wants. model stays optional. An agent without it runs on each member's default model, which is effectively the middle option between strong and fast.
# agents/implementer.yamlname: implementerdescription: Implements a planned changemodel: strong # an alias, or a concrete model as todayinstructions: ...
The team says what each alias means in each tool, in that tool's own format. Each tool gets an ordered list: the first entry is the default, and the rest are options the team supports.
# models/aliases.yaml, example 1: members on their own accounts (IDs are illustrative)strong:
claude: [{ model: opus, effort: high }, { model: fable }]codex: [{ model: gpt-6-sol, effort: high }, { model: gpt-6-astra }]opencode: [{ model: anthropic/claude-opus-5-5 }]fast:
claude: haiku # a single model, no effortcodex: { model: gpt-6-luna, effort: low }reviewer: # a team aliasclaude: [{ model: opus, effort: max }]
With a gateway. A team whose gateway serves the same models to several tools maps each alias once per gateway, keyed by the model profile. It applies to every tool a member has switched to that profile, and TeamAI writes the model in each tool's form, since it set up that tool's provider. Tools not on the gateway keep using their own entries.
# models/aliases.yaml, example 2: with a gateway (IDs are illustrative)strong:
gateways:
team:tokenhub: glm-5.3 # Claude, Codex, OpenCode, CodeBuddy on this profileclaude: [{ model: opus, effort: high }] # members on their own accountscodex: [{ model: gpt-6-sol, effort: high }]fast:
gateways:
team:tokenhub: deepseek-v4-flash
team:tokenhub, glm-5.3
claude model: glm-5.3
codex model = "glm-5.3"
opencode model: teamai-chat/glm-5.3
codebuddy model: glm-5.3
A member can use another model on their own machine. The override can name any model, not only the team's options. This follows the same team/personal split that model profiles use.
# ~/.teamai/models/aliases.yamlstrong:
codex: { model: gpt-6-astra, effort: xhigh }gateways:
local:my-gateway: qwen-4-coder # a personal model profile
Resolution, per agent and tool:
tool_extras.<tool>.model explicit in the agent, skips aliases
> local override
> gateways.<profile the tool is switched to>
> <tool> entry (first option)
> no model field: the tool's default, and pull and doctor warn
No gateway needed. A mapping holds each tool's native value (opus, gpt-6-sol, provider/model), which works with the member's own account. Model profiles come in only when a member has run teamai models switch for that tool. In that case, the alias's gateways entry for that profile applies, and pull and doctor warn if a model isn't in the gateway's catalog.
No built-in mappings. I'd have TeamAI reserve the names strong and fast but ship no models for them. A tool's own alias like opus doesn't go stale, but the judgement that opus is strong does: Fable already sits above it. I think that judgement belongs in the team repo, where a team can change it without waiting for a TeamAI release. An agent that says strong still works as-is in any team that maps strong once.
What I'd put in v1.
model: <alias> in agents, with the reserved strong and fast plus team aliases.
models/aliases.yaml and models/<ns>/aliases.yaml, activated by resources.models like model profiles. A namespace alias replaces the root alias of the same name, whole.
~/.teamai/models/aliases.yaml for local overrides.
Optional effort per mapping, written in the tool's own field and values.
gateways entries keyed by model profile, team or personal, for every tool switched to that profile.
Checks in pull and doctor: an alias with no mapping for a deployed tool, a mapping that doesn't fit the tool's format, and a resolved model missing from an active gateway.
push writes the alias back when the deployed value matches what it resolved to.
What could wait.
An effort on the agent that overrides the alias's effort, on a scale TeamAI translates per tool.
Per-tool exceptions inside a gateways entry, such as another model or an effort for Claude on the same gateway.
Acceptance check. Alice uses Claude Code and Codex with her own accounts. Bob uses Codex through the team gateway. Both deploy the same agents/implementer.yaml with model: strong, and nobody edits it. Alice gets opus with high and gpt-6-sol with high. Bob gets glm-5.3 in Codex from the gateway entry, without the team writing a Codex mapping for the gateway. Carol switches her strong in Codex to gpt-6-astra locally. Nothing changes for anyone else, and her next push doesn't propose an edit.
Design notes: proposed details and open questions
Proposed:
Alias or model. A model value that matches a reserved or team alias is an alias. Any other value is written as-is, as today. A team alias named after a tool's own alias (opus, sonnet, haiku, inherit, ...) is rejected.
New reserved names. If TeamAI reserves another name later, a team alias with that name keeps winning, and doctor notes it.
Keys. A mapping is keyed by tool id. Only variants that share a model catalog inherit: claude-internal and tclaude from claude, and codex-internal and tcodex from codex. Qoder, for example, doesn't inherit opus.
Format. Each tool's mapping uses that tool's native values and fields: effort for Claude and CodeBuddy, model_reasoning_effort for Codex, and variant for OpenCode. The output only carries fields the tool knows, since Gemini CLI's schema rejects unknown keys. Tools handle a bad model ID differently (silent fallback, a warning, a hard error), so TeamAI checks the mapping at deploy time instead of relying on the tool.
Shorthand. A single string or object stands for a one-entry list.
Push. If the deployed value equals what the alias resolved to, push writes the alias back. Any other value counts as an edit to model, with today's conflict rules. A local override is resolved the same way, so it never shows up as an edit.
Legacy agents. Aliases apply to YAML agents. A legacy agents/<name>.md is copied as-is, so it should keep a concrete model; pull could warn when its model is an alias.
Gateways. A gateways entry wins over the tool's own entry only when that tool is switched to the profile, since it describes the member's real provider. It is an ordered list like the others, and carries no effort in v1, because effort levels depend on the model. A model missing from the profile's catalog is skipped with a warning, then the next option, then the tool's entry. A profile that isn't active for the member is ignored without a warning. push doesn't check the catalog, since a namespace override can change it per member. Only the tools model profiles support (Claude, Codex, OpenCode, CodeBuddy, WorkBuddy) use these entries.
Claude on a gateway. Claude Code 2.1.283 sends an unknown subagent model to the API unchanged. It logs unrecognized_model and doesn't fall back to the inherited model, so a gateway ID like glm-5.3 reaches the gateway. This was tested against the Anthropic API, which returns 404 for that ID, and not yet against a gateway that serves it.
Separate file.models/models.yaml is parsed strictly, so an aliases key there would break model profiles for members on older CLIs. A separate file doesn't.
Naming. Local config already has a modelAliases key, used only to price gateway models. It could get a clearer name in its own change first, to avoid two meanings for one word.
Older CLIs. They ignore models/aliases.yaml, but write model: strong into the tool as-is. Auto-update is on by default, so most members get a CLI that resolves aliases without doing anything. The release notes tell teams with autoUpdate: false to update before their agents use an alias. There is no minimum-version check.
Agreed. Keep the mappings team-defined. strong and fast are enough as the reserved default tiers, and a team should be able to add its own aliases, such as reviewer.
TeamAI can reserve those two names, but it should not ship model IDs for them. What counts as strong changes over time, and that choice belongs in the team repo.
For v1, put reasoning effort on the alias only. An effort on the agent that overrides it can wait.
Gateway mappings can wait too. v1 only resolves the per-tool entries, for members on their own accounts. A tool already switched to a model profile keeps its current model.
The Cursor half of that open question is now a separate PR: #856 writes the agent's model verbatim into the Cursor frontmatter (which reverseFromCursor already read back), so a Cursor agent stops silently losing the team-declared model. The model[effort=...] form stays with the alias proposal here.
Activity
[-]Proposal: tool-independent model aliases for agents[/-][+]Proposal: model aliases so one agent works in every tool[/+]jeff-r2026 commentedon Sep 25, 2026
I think strong and fast are enough as the initial aliases. It would be useful to allow multiple model options within each tier, though, so teams can choose among them based on availability or preference. The default choice should be explicit, with local overrides when needed.
SaulMoro commentedon Sep 26, 2026
Starting with
strongandfastmakes sense to me, and so do several options per alias, an explicit default and local overrides. Below is a shape that tries to fit those together, as a starting point for discussion rather than a settled design. The main thing I'd add is team names on top of the two, so a team that wants areviewermodel doesn't have to bendstrongto get it.Goal. One agent file runs in every tool a member uses, on the model the team chose for that tool. This works with or without an AI gateway.
Terms. A model alias names a kind of model, such as
strong. A mapping says which model that is in one tool, and optionally which reasoning effort to use.flowchart LR A["agents/implementer.yaml<br/>model: strong"] --> R{{resolve per tool}} T["models/aliases.yaml<br/>team mapping"] --> R L["~/.teamai/models/aliases.yaml<br/>local override"] --> R R --> C["Claude Code<br/>model: opus<br/>effort: high"] R --> X["Codex<br/>model = gpt-6-sol<br/>model_reasoning_effort = high"] R --> O["OpenCode<br/>model: anthropic/..."] R --> G["Codex on the team gateway<br/>model = glm-5.3"] R --> U["tool with no mapping<br/>no model field, warning"]The agent says what kind of model it wants.
modelstays optional. An agent without it runs on each member's default model, which is effectively the middle option betweenstrongandfast.The team says what each alias means in each tool, in that tool's own format. Each tool gets an ordered list: the first entry is the default, and the rest are options the team supports.
With a gateway. A team whose gateway serves the same models to several tools maps each alias once per gateway, keyed by the model profile. It applies to every tool a member has switched to that profile, and TeamAI writes the model in each tool's form, since it set up that tool's provider. Tools not on the gateway keep using their own entries.
A member can use another model on their own machine. The override can name any model, not only the team's options. This follows the same team/personal split that model profiles use.
Resolution, per agent and tool:
No gateway needed. A mapping holds each tool's native value (
opus,gpt-6-sol,provider/model), which works with the member's own account. Model profiles come in only when a member has runteamai models switchfor that tool. In that case, the alias'sgatewaysentry for that profile applies, andpullanddoctorwarn if a model isn't in the gateway's catalog.No built-in mappings. I'd have TeamAI reserve the names
strongandfastbut ship no models for them. A tool's own alias likeopusdoesn't go stale, but the judgement thatopusisstrongdoes: Fable already sits above it. I think that judgement belongs in the team repo, where a team can change it without waiting for a TeamAI release. An agent that saysstrongstill works as-is in any team that mapsstrongonce.What I'd put in v1.
model: <alias>in agents, with the reservedstrongandfastplus team aliases.models/aliases.yamlandmodels/<ns>/aliases.yaml, activated byresources.modelslike model profiles. A namespace alias replaces the root alias of the same name, whole.~/.teamai/models/aliases.yamlfor local overrides.effortper mapping, written in the tool's own field and values.gatewaysentries keyed by model profile, team or personal, for every tool switched to that profile.pullanddoctor: an alias with no mapping for a deployed tool, a mapping that doesn't fit the tool's format, and a resolved model missing from an active gateway.pushwrites the alias back when the deployed value matches what it resolved to.What could wait.
efforton the agent that overrides the alias's effort, on a scale TeamAI translates per tool.gatewaysentry, such as another model or an effort for Claude on the same gateway.Acceptance check. Alice uses Claude Code and Codex with her own accounts. Bob uses Codex through the team gateway. Both deploy the same
agents/implementer.yamlwithmodel: strong, and nobody edits it. Alice getsopuswithhighandgpt-6-solwithhigh. Bob getsglm-5.3in Codex from the gateway entry, without the team writing a Codex mapping for the gateway. Carol switches herstrongin Codex togpt-6-astralocally. Nothing changes for anyone else, and her nextpushdoesn't propose an edit.Design notes: proposed details and open questions
Proposed:
modelvalue that matches a reserved or team alias is an alias. Any other value is written as-is, as today. A team alias named after a tool's own alias (opus,sonnet,haiku,inherit, ...) is rejected.doctornotes it.claude-internalandtclaudefromclaude, andcodex-internalandtcodexfromcodex. Qoder, for example, doesn't inheritopus.effortfor Claude and CodeBuddy,model_reasoning_effortfor Codex, andvariantfor OpenCode. The output only carries fields the tool knows, since Gemini CLI's schema rejects unknown keys. Tools handle a bad model ID differently (silent fallback, a warning, a hard error), so TeamAI checks the mapping at deploy time instead of relying on the tool.model, with today's conflict rules. A local override is resolved the same way, so it never shows up as an edit.agents/<name>.mdis copied as-is, so it should keep a concrete model;pullcould warn when itsmodelis an alias.gatewaysentry wins over the tool's own entry only when that tool is switched to the profile, since it describes the member's real provider. It is an ordered list like the others, and carries no effort in v1, because effort levels depend on the model. A model missing from the profile's catalog is skipped with a warning, then the next option, then the tool's entry. A profile that isn't active for the member is ignored without a warning.pushdoesn't check the catalog, since a namespace override can change it per member. Only the tools model profiles support (Claude, Codex, OpenCode, CodeBuddy, WorkBuddy) use these entries.modelto the API unchanged. It logsunrecognized_modeland doesn't fall back to the inherited model, so a gateway ID likeglm-5.3reaches the gateway. This was tested against the Anthropic API, which returns 404 for that ID, and not yet against a gateway that serves it.models/models.yamlis parsed strictly, so analiaseskey there would break model profiles for members on older CLIs. A separate file doesn't.modelAliaseskey, used only to price gateway models. It could get a clearer name in its own change first, to avoid two meanings for one word.models/aliases.yaml, but writemodel: stronginto the tool as-is. Auto-update is on by default, so most members get a CLI that resolves aliases without doing anything. The release notes tell teams withautoUpdate: falseto update before their agents use an alias. There is no minimum-version check.Open questions:
modelas-is (fix(agents): carry the agent's model into the Cursor render (#830) #856). Should an alias's effort map into Cursor'smodel[effort=...]form?inheritentry, so a team can say "this tool uses its default" and silence the warning.Feedback from anyone who deploys agents to more than one tool would help:
strongandfastcover how you pick models today, or do you need a third name?jeff-r2026 commentedon Sep 26, 2026
Agreed. Keep the mappings team-defined.
strongandfastare enough as the reserved default tiers, and a team should be able to add its own aliases, such asreviewer.TeamAI can reserve those two names, but it should not ship model IDs for them. What counts as strong changes over time, and that choice belongs in the team repo.
For v1, put reasoning effort on the alias only. An effort on the agent that overrides it can wait.
Gateway mappings can wait too. v1 only resolves the per-tool entries, for members on their own accounts. A tool already switched to a model profile keeps its current model.
ydflow commentedon Sep 27, 2026
The Cursor half of that open question is now a separate PR: #856 writes the agent's
modelverbatim into the Cursor frontmatter (whichreverseFromCursoralready read back), so a Cursor agent stops silently losing the team-declared model. Themodel[effort=...]form stays with the alias proposal here.fix(agents): carry the agent's model into the Cursor render (#830) (#856
fix(agents): scope local override failures to alias agents and warn o…
fix(agents): reject aliases files without an aliases key, report fast…
docs(agents): note that an extras model pin never adopts an alias on …
fix(pull): preview model holds in dry-run and do not report a held pu…
fix(agents): hold only tools that fail resolution and keep resolved v…
fix(agents): name the held tools when a broken aliases file holds onl…
fix(agents): write a model edit over a tool's own extras pin back to …
fix(agents): deliver a deleted recorded copy on the fast path, adopt …
test(agents): cover push of a tclaude hand edit under each kind of mo…
fix(pull): name an edited agent copy the fast path keeps for a change…
feat(agents): model aliases so one agent works in every tool (#830) (#…
fix(agents): prove an agent copy an older CLI rendered teamai's (Tenc…
test(pull): pin delivery of an agent held at the team revision once i…
fix: delivery and local-state bugs (#993) (#995)