Skip to content

Comments

feat(agent): add subagents config for per-agent task tool filtering#7271

Open
marcusquinn wants to merge 1 commit intoanomalyco:devfrom
marcusquinn:feature/per-agent-subagent-filtering
Open

feat(agent): add subagents config for per-agent task tool filtering#7271
marcusquinn wants to merge 1 commit intoanomalyco:devfrom
marcusquinn:feature/per-agent-subagent-filtering

Conversation

@marcusquinn
Copy link

Summary

Adds a new subagents configuration option that allows primary agents to specify which subagents appear in their Task tool description. This reduces token overhead when many subagents are configured but only a subset is relevant to a particular agent.

Closes #7269

Problem

The Task tool description includes all configured subagents, adding ~6-10k tokens to the system prompt regardless of whether the agent will use them. With 150+ subagents, this significantly impacts:

  • Token costs (especially with reasoning models)
  • Effective context window for actual work

Solution

Add a subagents field to agent config that filters which subagents appear in the Task tool description:

{
  "agent": {
    "build": {
      "subagents": ["explore", "general", "code-*"]
    }
  }
}
  • Supports glob patterns (e.g., code-*, *-reviewer)
  • If not set, all subagents are available (backward compatible)
  • Works alongside existing permission.task (which controls runtime access)

Changes

  • packages/opencode/src/config/config.ts - Add subagents field to Agent schema
  • packages/opencode/src/agent/agent.ts - Add subagents to Agent.Info and state
  • packages/opencode/src/tool/task.ts - Filter agents based on caller's subagents config
  • packages/opencode/test/tool/task-subagents.test.ts - Tests for filtering logic
  • packages/web/src/content/docs/agents.mdx - Documentation

Testing

cd packages/opencode && bun test test/tool/task-subagents.test.ts

All 9 tests pass.

Add a new 'subagents' configuration option that allows primary agents to
specify which subagents appear in their Task tool description. This reduces
token overhead when many subagents are configured but only a subset is
relevant to a particular agent.

- Add 'subagents' field to Agent config schema (supports glob patterns)
- Filter task tool description based on caller's subagents list
- Add tests for the new filtering behavior
- Update documentation with usage examples

Closes anomalyco#7269
@github-actions
Copy link
Contributor

github-actions bot commented Jan 8, 2026

The following comment was made by an LLM, it may be inaccurate:

Summary:

One potentially related PR found:

This addresses similar concerns around managing which subagents are included in context. Review it to ensure there's no duplicate effort or conflicting approaches.

@marcusquinn
Copy link
Author

Thanks for flagging #4119! After reviewing, these PRs address different problems:

PR Problem Solution
#4119 Parent session context passed to subagents is too large Filter what context is passed TO subagents at runtime
#7271 (this PR) Task tool description lists all subagents, bloating system prompt Filter which subagents APPEAR in the task tool description

#4119 optimizes the context sent to subagents when they're invoked.
#7271 optimizes the task tool's description in the system prompt (before any subagent is invoked).

They're complementary - both reduce token usage but at different points:

With 150 subagents, the task tool description alone adds ~6-10k tokens to every conversation's system prompt. This PR allows agents to specify which subagents they need, reducing that overhead.

@malhashemi
Copy link
Contributor

To let you know any subagent that you list as denied in the task tool using the new permission system is already hidden from the task tool. The functionality that you are proposing already exists, just use the new permission system

@marcusquinn
Copy link
Author

Thanks @malhashemi! I tested the permission.task approach and confirmed it works as you described.

However, I'd like to make the case that the allowlist approach is significantly more ergonomic for real-world usage at scale.

Real-World Numbers

Our setup (aidevops):

  • 14 primary agents (SEO, Accounts, Build+, Content, etc.)
  • 177 subagents (and growing rapidly)
  • Each primary agent needs only 5-20 relevant subagents

Config Comparison

Deny-list (current) - Accounts agent needing only quickfile:

"permission": {
  "external_directory": "allow",
  "task": {
    "*": "deny",
    "quickfile": "allow"
  }
}

Allowlist (proposed):

"subagents": ["quickfile"]

For Build+ needing ~20 subagents, the deny-list becomes:

"task": {
  "*": "deny",
  "code-standards": "allow",
  "code-simplifier": "allow",
  "best-practices": "allow",
  "git-workflow": "allow",
  "branch": "allow",
  "preflight": "allow",
  "postflight": "allow",
  "release": "allow",
  "version-bump": "allow",
  "conversation-starter": "allow",
  "osgrep": "allow",
  "augment-context-engine": "allow",
  "context-builder": "allow",
  "context7": "allow",
  "toon": "allow",
  "playwright": "allow",
  "stagehand": "allow",
  "github-cli": "allow",
  "coolify": "allow"
}

vs:

"subagents": ["code-standards", "code-simplifier", "best-practices", "git-workflow", "branch", "preflight", "postflight", "release", "version-bump", "conversation-starter", "osgrep", "augment-context-engine", "context-builder", "context7", "toon", "playwright", "stagehand", "github-cli", "coolify"]

Why Allowlist is Better

Aspect Deny-list Allowlist
Characters per entry "name": "allow" (16+) "name" (6+)
Boilerplate Requires "*": "deny" None
Semantic clarity "Deny all except these" "These are my subagents"
Consistency Different from tools pattern Matches tools: { "x": true }
14 agents × 15 avg subagents ~4,200 extra characters ~0 extra

Proposal

The subagents field could be syntactic sugar that internally generates permission.task rules. This:

  • Keeps the permission system as the source of truth
  • Provides a cleaner DX for the common "allowlist" case
  • Is fully backward compatible

Happy to revise the implementation if there's interest from maintainers. @rekram1-node @thdxr thoughts?

marcusquinn added a commit to marcusquinn/aidevops that referenced this pull request Jan 14, 2026
Add 'subagents:' frontmatter to primary agents that specifies which
subagents should appear in the Task tool description. This reduces
token overhead by filtering 220 subagents down to 3-30 per agent.

Changes:
- Add parse_frontmatter() to generate-opencode-agents.sh
- Generate permission.task deny-list rules from subagents list
- Add subagents frontmatter to all 13 primary agents

Token savings: ~6-10k tokens per conversation by hiding irrelevant
subagents from the Task tool description.

Related: anomalyco/opencode#7271
marcusquinn added a commit to marcusquinn/aidevops that referenced this pull request Jan 14, 2026
* feat(agents): add subagent filtering via frontmatter

Add 'subagents:' frontmatter to primary agents that specifies which
subagents should appear in the Task tool description. This reduces
token overhead by filtering 220 subagents down to 3-30 per agent.

Changes:
- Add parse_frontmatter() to generate-opencode-agents.sh
- Generate permission.task deny-list rules from subagents list
- Add subagents frontmatter to all 13 primary agents

Token savings: ~6-10k tokens per conversation by hiding irrelevant
subagents from the Task tool description.

Related: anomalyco/opencode#7271

* fix(parser): improve frontmatter parser robustness

Address Gemini Code Assist review feedback:
- Add encoding='utf-8' to file open
- Skip comments and empty lines in YAML parsing
- Use specific exception types instead of bare except
- Add warning message for parse failures

Co-authored-by: gemini-code-assist[bot] <176abortedflight+gemini-code-assist[bot]@users.noreply.github.com>

* fix(health): remove context7 subagent

context7 provides library/framework docs, not health information.
crawl4ai is sufficient for health research workflows.

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

---------

Co-authored-by: gemini-code-assist[bot] <176abortedflight+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@thdxr thdxr force-pushed the dev branch 3 times, most recently from f1ae801 to 08fa7f7 Compare January 30, 2026 14:37
@marcusquinn
Copy link
Author

Noting that #14961 (add model parameter to Task tool) takes a similar approach to per-subagent configuration at the call site. This PR tackles the complementary problem — filtering which subagents appear in the Task tool description to reduce token overhead.

Together these would give orchestrator workflows (like aidevops) fine-grained control over subagent routing: #14961 controls which model a subagent uses, this PR controls which subagents are visible to each agent.

Would be good to get both reviewed together since they touch adjacent code in the Task tool. Happy to rebase if needed.

@malhashemi
Copy link
Contributor

malhashemi commented Feb 25, 2026

Hi @marcusquinn this is already achieved with the new permission system. At least for filtering which subagent are visible via the task the tool. You can deny globally if you would like and only include the allow list in the agent definition

@marcusquinn
Copy link
Author

@malhashemi — appreciate the follow-up, and credit to you for building the permission system (I can see you authored the Task/Skill permission filtering in #5930, #6000, #7042, #7165, #8111). It works, and we use it.

The point of this PR isn't that the functionality is missing — it's that the DX for the common case is unnecessarily verbose. We acknowledged this in the January thread above, but the ergonomics argument hasn't been addressed:

14 agents × 15 subagents average. Current approach:

"permission": {
  "task": {
    "*": "deny",
    "subagent-a": "allow",
    "subagent-b": "allow",
    "subagent-c": "allow"
  }
}

That's 3 lines of boilerplate per entry ("name": "allow") plus the "*": "deny" preamble, repeated across every agent. For our setup that's ~210 permission entries across 14 agents.

Proposed:

"subagents": ["subagent-a", "subagent-b", "subagent-c"]

Same result. One line. The implementation can be syntactic sugar that generates permission.task rules internally — your permission system stays as the source of truth.

This is the same pattern as includeTools in MCP server config (#7399) — an allowlist shorthand for a common filtering need. Happy to hear counterarguments on why the verbosity is preferable, but "it already works" doesn't address the DX case being made here.

@rekram1-node @thdxr — would value a maintainer perspective on whether a shorthand is worth adding.

@malhashemi
Copy link
Contributor

malhashemi commented Feb 25, 2026

I take no credit for building the permission system 😅. Just merely refining issues that were present. In terms of the DX I agree with the argument you are making, apologies for misunderstanding the purpose of this PR. I was under the impression that this replaces the current system which I was against as it would be inconsistent with the current permission system. I do agree that it doesn't harm to add a less verbose method to define things. I hope you get a reply from the maintainers soon

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Reduce token overhead: Task tool injects all subagent descriptions into system prompt

2 participants