[FEATURE] Configure a subagent's model and effort from settings, without forking its prompt (plugin-shipped agents)
Preflight Checklist
- [x] I have searched existing requests. Related requests exist and are linked below — this one is filed separately because it covers a different scope (plugin-distributed subagents and prompt drift), not because I believe it is unreported. Happy for it to be merged into #73552 if triage prefers.
- [x] This is a single feature request (one config surface, plus the inspector needed to verify it).
Problem Statement
The gap
A subagent's model can be configured from outside its definition file — CLAUDE_CODE_SUBAGENT_MODEL, and the model parameter the Agent/Task tool accepts at dispatch. Nothing else about a subagent can be. In particular effort is frontmatter-only.
So the only supported way to change one field of a subagent you did not author is to copy its entire markdown file — prompt body and all — into .claude/agents/.
For plugin-distributed subagents, that turns a one-line preference into a permanent, silent fork of someone else's prompt.
Why this is worse than it looks
Plugins can ship subagents. A team installs such a plugin and wants a small deviation from what it ships — typically raise a reviewer agent to effort: xhigh because this codebase is unforgiving, or drop a search agent to a cheaper tier because the default is overkill here.
The model half is solvable today. The effort half is not. So the workaround is:
cp <plugin>/agents/reviewer.md .claude/agents/reviewer.md # shadows the plugin agent
# edit exactly one line: effort: high -> effort: xhigh
That copy is now a frozen snapshot of the plugin's prompt at install time. Everything that follows is a consequence:
| Consequence | Why it hurts |
|---|---|
| Silent staleness | The plugin ships an improved prompt in its next release. The project keeps the old one forever. Nothing warns, nothing diffs, nothing surfaces it — the agent still runs, just worse. |
| Upgrades stop being upgrades | Plugin authors can no longer assume a fix reaches users. Anyone who wanted a different effort level is permanently pinned to whatever release they forked at. |
| Config spreads across N files | A repo adjusting nine shipped agents ends up with nine copied prompt files, most differing from upstream by a single frontmatter line. Answering "what did we actually change?" means diffing every one against a plugin path the user must locate by hand. |
| Plugin authors build workarounds | With no config surface, plugins invent their own — e.g. a config block in CLAUDE.md that the plugin's own skills parse at runtime and translate into the model dispatch parameter. That works for model and stops dead at effort. Every plugin reinvents it differently. |
| It scales with plugin adoption | This is a structural tax on the plugin ecosystem, not a niche annoyance, and it grows as more plugins ship subagents. |
I maintain a plugin that ships nine subagents. I have a repo where all nine are forked into .claude/agents/, and every prompt body is byte-identical to the plugin's — the forks exist purely to change model and effort frontmatter. Two of the nine turned out to be complete no-ops, forked for a delta that another mechanism already covered; nothing in the tooling could have told me that. The other seven are frozen copies of prompts that upstream has since moved past.
The underlying design issue
Subagent definitions currently conflate a prompt (authored by the plugin) with runtime configuration (a deployment choice belonging to the user). Everywhere else in Claude Code those are separate — permissions, env, model, and hooks are all settings, not prose. Subagents are the exception, and "copy the whole file" is what that exception costs.
Proposed Solution
1. An agents override map in settings
{
"agents": {
"some-plugin:reviewer": { "model": "opus", "effort": "xhigh" },
"some-plugin:scout": { "effort": "low" },
"my-local-agent": { "model": "haiku" }
}
}
Semantics
- Keys are agent names as already addressed at dispatch:
plugin:namefor plugin-shipped, barenameotherwise. - Values are a partial frontmatter object.
modelandeffortto start — the two runtime knobs — with room fortoolslater. - Prompt body is deliberately not overridable. This is configuration, not authorship. Anyone wanting to change the prompt should still copy the file, and that copy is then an honest fork rather than an accident.
- Merges per key:
{ "effort": "low" }changes effort and leaves the model pin intact. - Works in every settings scope with existing precedence (enterprise →
.claude/settings.local.json→.claude/settings.json→~/.claude/settings.json), so a team commits a shared policy and an individual deviates locally — exactly the layering permissions already have.
Suggested resolution order (extending the current chain, not replacing it):
CLAUDE_CODE_SUBAGENT_MODEL— unchanged, stays the top-level cost cap formodel- Agent/Task dispatch parameter (
modeltoday) agentsoverrides from settings (new)- Agent frontmatter (
model:,effort:) - Session defaults
Unknown / invalid entries: warn once and ignore, consistent with unknown settings keys generally. An override naming an agent that isn't installed is a typo, not a fatal error — a repo whose plugin set changes shouldn't fail to start.
Backward compatibility: total. Absent the key, nothing changes. No existing agent file needs editing. No plugin needs to opt in.
2. A way to inspect what actually won
$ claude agents resolve some-plugin:reviewer
some-plugin:reviewer
model fable (settings.json → agents) [frontmatter: opus]
effort xhigh (settings.json → agents) [frontmatter: high]
tools Read, Grep, Glob, Bash (frontmatter)
source ~/.claude/plugins/some-plugin/agents/reviewer.md
note shadowed by .claude/agents/reviewer.md
Small, and valuable today, independent of part 1:
- A pinned model unavailable on an account (org allowlist, plan tier) falls back to the session model silently. Users experience it as "reviews got worse" with no signal. There is currently no way to ask what a subagent will actually run as.
- A project agent shadowing a plugin agent of the same name is invisible until something behaves oddly.
- Once part 1 exists, "which layer won" becomes a question worth answering directly.
A --json mode would let plugin authors and CI assert that a routing policy is actually in force rather than assuming it.
Optional extension, lower priority: when a project agent shadows a plugin agent whose shipped body has changed since, say so. That one line would have caught every stale fork described above.
Why this is worth building
- It protects the plugin ecosystem. Plugins that ship subagents are only as good as their ability to ship improvements. Today the most common customization forces users to permanently opt out of those improvements. Fixing it makes plugin upgrades meaningful, which makes plugins worth publishing.
- It removes a footgun rather than adding surface. Silent model fallback and silent shadowing already have to be documented as traps by third parties.
- It's small and precedented. The resolution chain, settings layering, and frontmatter parsing all exist. This adds a merge step between two layers that already talk to each other, plus a read-only inspector over the result.
- It improves cost control, which is what effort is for. Effort is the one cost lever a user cannot set per agent without forking. Teams wanting cheap mechanical agents and expensive review agents in the same repo are exactly the teams watching spend.
- It puts configuration where configuration lives — declarative, inspectable, and consistent across plugins, instead of parsed out of prose at runtime by each plugin's own code.
Alternative Solutions
| Alternative | Why it's weaker |
|---|---|
| effort parameter on the Agent/Task tool (#77298, #72596) | Cheapest to build and genuinely useful — but it only applies when the dispatching prompt remembers to pass it. Settings apply deterministically, whether or not a model cooperates. A good complement, not a substitute. |
| CLAUDE_CODE_SUBAGENT_EFFORT env var (#79135, #43083) | Trivial, but the wrong granularity. Real repos want xhigh reviewers and low scouts simultaneously; one global value cannot express that. |
| extends: in agent frontmatter — inherit a plugin agent's body, override its frontmatter | Solves drift elegantly and would also be welcome. But it still needs a file per customized agent and doesn't layer across user/project/enterprise scopes. Settings do both. |
| Status quo — copy the file | The behavior this request is about. |
Priority
High - Significant impact on productivity
Feature Category
Configuration and settings
Use Case Example
A plugin ships a code-review subagent pinned to effort: high. One repo — a compiler with unusually
expensive mistakes — wants that reviewer at xhigh, and wants the plugin's cheap fact-finding scout
left alone at low.
Today: copy the reviewer's whole prompt into .claude/agents/, change one line, and silently
stop receiving every future improvement the plugin makes to that prompt.
With this feature:
{ "agents": { "some-plugin:reviewer": { "effort": "xhigh" } } }
One line, in the file where configuration belongs, reviewable in a PR, and the prompt keeps
updating with the plugin.
Additional Context
Prior art / related requests — deliberately linked rather than ignored:
- #73552 — same settings-map shape, scoped to built-in agents (
Explore) and motivated by org spend. This request covers the plugin-distributed case and the prompt-drift consequence, which that issue does not discuss. If triage would rather generalize #73552 to cover both, that is a fine outcome — please close this as a duplicate and carry the drift argument over. - #79135, #43083 —
CLAUDE_CODE_SUBAGENT_EFFORT/ configurable subagent effort (global granularity). - #77298 — per-call
efforton the Agent tool. #72596 — same, closed.
The volume of separate requests converging on "let me set subagent effort without forking" is itself
a signal about the shape of the gap.
Verified current behavior (docs + local install, CLI 2.1.216): the Agent/Task tool exposesmodel with no effort equivalent; effort is frontmatter-only; CLAUDE_CODE_SUBAGENT_MODEL has no
effort counterpart; no settings key configures a subagent. Applies equally to plugin agents
(<plugin>/agents/*.md), project agents (.claude/agents/*.md), and user agents
(~/.claude/agents/*.md).
Acceptance criteria
- [ ]
settings.jsonaccepts anagentsmap of agent name → partial config (model,effort). - [ ] Values merge per-key over frontmatter and honor existing settings-scope precedence.
- [ ] Unknown agent names and invalid values warn once and are ignored; startup never fails.
- [ ]
CLAUDE_CODE_SUBAGENT_MODELand dispatch-timemodelcontinue to take precedence. - [ ] A command reports an agent's effective configuration and the source of each value, including when a pinned model was unavailable and fell back.
- [ ] Documented on the subagents and settings pages, including the full resolution order.