Skip to content

feat: allow custom subagents to delegate tasks via task()#1908

Open
Stranmor wants to merge 3 commits intocode-yeongyu:devfrom
Stranmor:feat/configurable-subagent-task-access
Open

feat: allow custom subagents to delegate tasks via task()#1908
Stranmor wants to merge 3 commits intocode-yeongyu:devfrom
Stranmor:feat/configurable-subagent-task-access

Conversation

@Stranmor
Copy link
Copy Markdown
Contributor

@Stranmor Stranmor commented Feb 16, 2026

Summary

Custom subagents defined in oh-my-opencode.json cannot use task() to delegate work to other agents. This PR fixes three independent issues that collectively prevent the pipeline from working.

Problem

When a user defines custom agents (e.g., critic, breaker, type-sentinel) in oh-my-opencode.json, those agents:

  1. Cannot call task()buildSubagentTools() hardcodes task: false for background tasks and only allows task for plan-family agents in sync flows
  2. Are never registered with opencodeapplyAgentConfig() passes custom agents as overrides to createBuiltinAgents(), which only processes known builtin names
  3. Are blocked by global permission denyapplyToolConfig() sets config.permission.task = "deny" globally, then only whitelists hardcoded agents

Changes

Commit 1 (agent-tool-restrictions.ts): Check AGENT_RESTRICTIONS instead of hardcoding task: false. 4 code paths fixed.

Commit 2 (agent-config-handler.ts, tool-config-handler.ts): Register custom agents from config. Grant task: "allow" to non-restricted agents.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 11 files

Confidence score: 2/5

  • Potential deadlock in src/features/background-agent/spawner.ts when nested agents share a low-limit concurrency key and both try to acquire it, which can block parent/child execution
  • Severity is high (8/10) with plausible user-facing hangs, so merge risk is elevated despite being a single issue
  • Pay close attention to src/features/background-agent/spawner.ts - nested concurrency acquisition can stall agents
Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/features/background-agent/spawner.ts">

<violation number="1" location="src/features/background-agent/spawner.ts:143">
P1: Potential deadlock when nested agents share concurrency key with low limits. Parent acquires slot and invokes task tool (now enabled), child attempts to acquire same key but blocks because parent holds it while waiting for child completion.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

call_omo_agent: true,
question: false,
},
tools: buildSubagentTools(input.agent),
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot Feb 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Potential deadlock when nested agents share concurrency key with low limits. Parent acquires slot and invokes task tool (now enabled), child attempts to acquire same key but blocks because parent holds it while waiting for child completion.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/features/background-agent/spawner.ts, line 143:

<comment>Potential deadlock when nested agents share concurrency key with low limits. Parent acquires slot and invokes task tool (now enabled), child attempts to acquire same key but blocks because parent holds it while waiting for child completion.</comment>

<file context>
@@ -140,12 +140,7 @@ export async function startTask(
-        call_omo_agent: true,
-        question: false,
-      },
+      tools: buildSubagentTools(input.agent),
       parts: [{ type: "text", text: input.prompt }],
     },
</file context>
Fix with Cubic

@sisyphus-dev-ai
Copy link
Copy Markdown
Collaborator

@Stranmor Thanks for the PR! There are a couple of items to address before we can merge:

  1. Merge conflicts: This branch currently has conflicts that need to be resolved.

  2. Cubic review feedback: The AI reviewer identified a potential deadlock issue in src/features/background-agent/spawner.ts around line 143. The concern is about nested agents sharing a concurrency key with low limits - when a parent acquires a slot and invokes the task tool, a child attempting to acquire the same key could block because the parent holds it while waiting for child completion.

Could you take a look at these issues? Once the conflicts are resolved and the deadlock concern is addressed (or explained if it is not a real issue), we can proceed with the review.

Thanks!

@code-yeongyu
Copy link
Copy Markdown
Owner

[sisyphus-bot]

Triage Assessment for PR #1908

Summary

This PR enables custom subagents defined in oh-my-opencode.json to use the task() function for delegating work. It addresses three key issues:

  1. Removes hardcoded task: false restrictions in buildSubagentTools()
  2. Registers custom agents properly with opencode via applyAgentConfig()
  3. Grants task: "allow" permission to non-restricted agents

Current Status: ⚠️ BLOCKED

Merge Readiness: NOT READY

Criteria Status
CI Checks ✅ All passing (3/3)
Review Decision ❌ Not approved
Merge Conflicts ❌ Conflicts exist (needs resolution)
AI Review Issues ⚠️ High-severity deadlock concern
Draft Status ✅ Not a draft

Critical Issues Requiring Attention

1. Merge Conflicts
The branch has conflicts that must be resolved before merge. Please rebase on the latest dev branch.

2. Deadlock Risk (High Severity)
As identified by @cubic-dev-ai, there is a potential deadlock in src/features/background-agent/spawner.ts (around line 143):

  • Scenario: Nested agents sharing a concurrency key with low limits
  • Risk: Parent acquires slot → invokes task tool → child attempts same key → blocks because parent holds it while waiting for child
  • Impact: User-facing hangs (severity 8/10)

Recommendation: Review the concurrency acquisition logic in spawner.ts. Consider:

  • Separate concurrency keys for parent/child relationships
  • Timeout mechanisms for slot acquisition
  • Documentation warning users about low concurrency limits with nested agents

Assessment

This is a feature PR (not a bugfix), so automatic merge is not applicable. The changes look architecturally sound for enabling custom subagent delegation, but the deadlock concern should be addressed or documented before merge.

Next Steps:

  1. Resolve merge conflicts
  2. Address or respond to the deadlock concern from cubic review
  3. Request re-review from maintainers

This assessment was generated by sisyphus-bot. Please reach out if you have questions!

Stranmor added 3 commits March 3, 2026 04:44
Replace hardcoded `task: false` in all subagent spawning paths with
`buildSubagentTools()` — a centralized function that respects
AGENT_RESTRICTIONS.

Built-in agents (explore, librarian, oracle, metis, momus,
sisyphus-junior) keep `task: false` via their AGENT_RESTRICTIONS entries.
Custom/user-defined agents (not in AGENT_RESTRICTIONS) now get
`task: true`, enabling multi-level agent delegation (e.g. a critic
agent spawning a breaker agent).

This unblocks workflows where specialized review agents need to
orchestrate sub-pipelines without routing through the top-level
orchestrator.
Custom agents defined in oh-my-opencode.json (e.g. breaker, type-sentinel)
were silently dropped because they were passed as overrides to
createBuiltinAgents() which only processes known builtin names.

Additionally, the global config.permission.task = 'deny' blocked custom
agents from calling task() since they were never whitelisted.

Changes:
- applyAgentConfig: add custom agents from pluginConfig.agents that aren't
  already registered (both sisyphus-enabled and disabled paths)
- applyToolConfig: grant task='allow' to all agents not explicitly blocked
  by AGENT_RESTRICTIONS
AgentOverridesSchema used strict z.object() with only hardcoded builtin
agent names. Zod strips unknown keys during safeParse, silently dropping
any custom agents (breaker, critic, type-sentinel, etc.) from the parsed
config.

Adding .catchall(AgentOverrideConfigSchema) preserves unknown agent keys
while still validating them against the same schema.
@Stranmor Stranmor force-pushed the feat/configurable-subagent-task-access branch from c78aab8 to fa40c25 Compare March 3, 2026 01:46
@Stranmor
Copy link
Copy Markdown
Contributor Author

Stranmor commented Mar 3, 2026

Thanks for the review and for highlighting the deadlock concern! I've looked into how the custom agent permissions interact with the concurrency model.

While the theoretical deadlock exists, here are a few findings:

  • Strict Scope: This PR strictly updates permission flags (task: "allow" for custom agents) and does not alter concurrency logic.
  • Pre-existing Behavior: The potential deadlock is a pre-existing property of the ConcurrencyManager and BackgroundAgentManager. Any agent previously allowed to use tasks (like sisyphus or prometheus) could already trigger this.
  • Contention Mechanics: The ConcurrencyManager uses per-agent-type keys. A deadlock only occurs if a parent exhausts all slots for its own agent type by spawning same-type children and synchronously waiting via background_output(block=true).
  • Low Practical Risk: In practice, orchestrators spawn different agent types (e.g., sisyphus spawns breaker), utilizing separate concurrency keys with zero contention. Given the default limit of 5 per type and the asynchronous nature of best practices, hitting this is extremely unlikely.
  • Future Improvement: Hardening against this (e.g., via hierarchical concurrency keys or excluding child tasks from the parent's pool) is a great idea, but it should be addressed in a dedicated PR targeting the ConcurrencyManager design.

Additionally, I've resolved the recent merge conflicts and rebased the branch on the latest dev. Let me know if this is good to merge!

@brandonwebb-vista
Copy link
Copy Markdown

@Stranmor @code-yeongyu I have this MR, which is heavily related. I believe we should try to merge these under the same release asap if possible

@Stranmor
Copy link
Copy Markdown
Contributor Author

@brandonwebb-vista Thanks for flagging this — I've reviewed #2299 and they're definitely complementary (this PR handles task() permissions for custom agents, yours handles dynamic agent discovery/resolution). Coordinating for the same release makes sense to avoid a window where one half works without the other. Happy to sync on merge order — I'd suggest yours (#2299) lands first since it wires up agent loading, then this one layers on the task delegation permissions. Let me know if that works or if you see a different dependency order.

@code-yeongyu code-yeongyu added triage:feature PR: Feature or enhancement triage:feature-request Feature or enhancement request labels Mar 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

triage:feature PR: Feature or enhancement triage:feature-request Feature or enhancement request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants