Repository navigation
Description
Summary
When a custom subagent has tools: task: true in its frontmatter, it can spawn a copy of itself as a child session, which spawns another copy, and so on without limit. There is no depth cap, no cycle detection, and no user-visible warning. The result is a silent runaway chain that consumes tokens for as long as the process runs.
This is a second distinct trigger path for the same underlying mechanism described in #17722. That issue requires "task": "allow" in the global opencode.json permission block. This one is triggered purely by the agent's own frontmatter — a natural and expected way to grant a subagent delegation ability — and is not covered by the existing docs warning in PR #17724.
Steps to reproduce
- Create a custom subagent with
tools: task: truein its frontmatter:
---
description: Explores codebases
mode: subagent
tools:
read: true
glob: true
grep: true
bash: true
task: true # ← trigger
---- Invoke the subagent with a task it cannot fully complete in one session (e.g. "find the X configuration in this codebase").
- The subagent, unable to finish, spawns a new instance of itself via the
tasktool with the same prompt. - Each child does the same. The chain grows indefinitely.
What happens under the hood
normalize() in config/agent.ts translates tools: { task: true } into permission: { task: "allow" }. When task.ts creates a child session it checks:
const canTask = next.permission.some((rule) => rule.permission === "task")Because canTask is true, the task tool is not stripped from the child's permission set:
...(canTask ? [] : [{ permission: "task", pattern: "*", action: "deny" }]),So every child inherits task: allow from its parent and can spawn further children. There is no depth counter, no cycle detection on prompt content, and no cap anywhere in the call chain.
This is mechanically identical to the #17722 case — canTask = true is the common condition — but reached via a different config path that PR #17724 does not cover.
Observed impact
A subagent with this configuration triggered a chain of 612 nested sessions over 73 minutes — roughly one new session every 7 seconds. The chain was not stopped by any OpenCode safeguard. It stopped only because the API credit limit was exhausted. Without that external constraint it would have continued indefinitely.
Why PR #17724 doesn't cover this
PR #17724 is docs-only and its warning is scoped to "task": "allow" in the global permission block. It explicitly states:
"You do not need an explicit
"task"permission for primary agents to spawn subagents — the default"*": "allow"already covers this."
That statement is correct for primary agents but misleading for subagent frontmatter, where tools: task: true is the natural way to enable delegation. A user following the docs would have no reason to suspect this triggers the same recursion trap.
Proposed fixes
Option A — Depth limit (addresses both this issue and #17722 at the root):
Track nesting depth via the parent_id chain in the session DB and refuse to spawn in task.ts if depth >= MAX_SUBAGENT_DEPTH (e.g. 10). This is the only option that provides a hard runtime guarantee regardless of how the permission was granted.
Option B — Strip task from subagent children by default:
Change the default so task is always stripped from child sessions unless the parent explicitly re-grants it. canTask becomes opt-in rather than opt-out. This would be a breaking change for users who rely on deliberate multi-level delegation.
Option C — Extend PR #17724's docs warning:
Add a note covering the tools: task: true frontmatter pattern alongside the existing global config warning. Near-term mitigation only — no runtime protection.
Option A is the cleanest fix and would close both this issue and #17722 with a single code change.
Related
- [FEATURE]: Document infinite subagent recursion risk when permission.task is set globally #17722 — same underlying mechanism, global config trigger
- PR docs: warn about infinite subagent recursion with global task permissions #17724 — docs-only mitigation for [FEATURE]: Document infinite subagent recursion risk when permission.task is set globally #17722, does not cover this trigger path
- bug(processor): doom loop detection misses cross-message repetitions and has inverted filter order #25254 — in-session tool-call repetition loop (related class of runaway behaviour)
Activity
github-actions commentedon May 4, 2026
This issue might be a duplicate of existing issues. Please check:
permission.taskis set globally (the issue you reference as a related trigger path)The core mechanism and proposed fixes (depth limit, stripping
taskfrom child sessions) appear identical to #18100. You may want to add your findings there as additional context rather than tracking this separately.tim-mohrbach-ikigai commentedon May 4, 2026
Closing as a duplicate of #18100, which covers the same underlying framework gap (no recursion depth limit on the Task tool).
The additional findings from this issue — the
tools: task: truefrontmatter trigger path, thenormalize()code trace, and the 612-session impact data — have been added as a comment on #18100 so they are available to whoever implements the fix.