Nested subagent gets a broken tool schema for launching further subagents — no working `task` tool, contradicts docs

Where does the bug appear (feature/product)?

Cursor SDK

Describe the Bug

Environment

  • @cursor/sdk 1.0.31 (current latest on npm as of 2026-09-17)
  • Local runtime (Agent.create({ local: { cwd, settingSources: ['project'] }, model, mode: 'agent' })), headless Node host, no IDE involved
  • Model: claude-sonnet-5 (also reproduced with grok-4.6)
  • Linux (Debian) VM, not sandboxed/restricted network

Summary

A direct (depth-1) subagent, launched via the built-in task tool from a top-level Agent, does not itself get a working task tool — even though both the subagents FAQ and the TypeScript SDK docs state that “the main agent and its direct subagents can launch subagents” (only a subagent-of-a-subagent, one level further, should be blocked).

What we actually observe is stricter than documented: the direct, depth-1 subagent itself never gets a working subagent-launch mechanism at all.

Root cause (confirmed via raw on-disk transcript, not model self-report)

We have two custom subagents defined in .cursor/agents/: an orchestrator (reviewer) that’s supposed to fan out to four specialist subagents (api-checker, api-auditor, etc.) via the task tool.

  1. Top-level agent’s own tool-call log shows a plain, native task tool call ("name": "task") launching reviewer. This works exactly as documented.
  2. reviewer’s own raw transcript (found at ~/.cursor/projects/<worktree-hash>/agent-transcripts/<parentAgentId>/subagents/<subagentId>.jsonl in the on-disk local agent store), for its own attempt to launch api-checker, shows this tool call instead:
{
  "type": "tool_use",
  "name": "CallDynamicTool",
  "input": {
    "namespace": "cursor",
    "toolName": "Task",
    "arguments": {
      "description": "API review",
      "subagent_type": "api-checker",
      "prompt": "Review this GitHub PR diff for API standards."
    }
  }
}

That’s the MCP-style dynamic-tool bridge (GetDynamicTools/CallDynamicTool, with a reserved cursor namespace for first-party utilities) — a completely different mechanism from the native task tool the top-level agent used successfully one level up. The call was rejected; the subagent’s own final report states (closely paraphrasing what was almost certainly a real, verbatim tool error it received): “Built-in tool ‘Task’ not found in namespace ‘cursor’… available tool is only GenerateImage.”

Earlier in the same transcript, the subagent also called GetDynamicTools({ pattern: "Task" }) and GetDynamicTools({}) (full catalog) while trying to figure out how to reach a specialist subagent — again, the MCP dynamic-tools discovery mechanism, not the native tool list.

So the nested subagent isn’t being denied task access by a deliberate policy — it’s handed an entirely different, and apparently incomplete, tool schema than the top-level agent gets: an IDE-agent-style surface (Shell, Read, Glob, Grep, GetDynamicTools, CallDynamicTool) with no real subagent-launching capability registered anywhere in it, instead of the plain SDK-native toolset (lowercase tool names, including a directly-callable task) that the docs describe and that the top-level agent actually has.

Actual behavior

orchestrator has no working subagent-launch mechanism at all — not even the depth-1→2 hop the docs say should work.

Impact

This breaks any orchestrator-style subagent pattern (a subagent whose whole job is to fan out to other subagents) whenever it’s invoked as a subagent itself rather than run at the top level. Workaround we’re using in the meantime: only fan out from true depth 0 (i.e. tell the top-level agent to directly follow the orchestrator’s own instructions inline, rather than “use the X subagent”), and have the orchestrator subagent gracefully self-apply its sub-checklists (with disclosure) when it detects it has no task access — but this loses per-specialist context isolation and real parallelism, which is the whole point of the pattern.

Questions for the Cursor team

  1. Is this a known regression in how nested subagent tool manifests are constructed for the local SDK runtime specifically, or does it also affect the IDE/interactive product?
  2. Is there an SDK option (something like local.allowNestedTaskTool or similar) to opt a subagent into the native toolset instead of the IDE-agent-style dynamic-tools surface?
  3. Should CallDynamicTool({ namespace: "cursor", toolName: "Task" }) ever be expected to work as a task-tool equivalent, or is that purely a model hallucination of a plausible-looking tool path that happens not to exist? (If the latter, it’d be good if the nested subagent’s tool list simply included a real task entry so the model doesn’t need to guess.)

Happy to share full raw transcripts (redacted) if useful.

Steps to Reproduce

  1. Define two subagents in .cursor/agents/: orchestrator.md (whose job is to task()-launch worker.md) and worker.md (trivial).
  2. Agent.create({ local: {...}, model, mode: 'agent' }) at the top level.
  3. Send a message instructing the top-level agent to “use the orchestrator subagent.”
  4. Inspect the on-disk local agent store for orchestrator’s own subagent transcript (.cursor/projects/<hash>/agent-transcripts/<parentId>/subagents/<subagentId>.jsonl).
  5. Observe: orchestrator cannot find or successfully call a native task tool; it either doesn’t attempt a nested launch at all, or (as here) discovers CallDynamicTool/GetDynamicTools and gets a “not found” error trying to route a Task call through them.

Expected Behavior

orchestrator, as a direct/depth-1 subagent, should have a working task tool and be able to launch worker as a depth-2 subagent.

Operating System

Linux

Version Information

@cursor/sdk 1.0.31 (current latest on npm as of 2026-09-17)

Does this stop you from using Cursor

Yes - Cursor is unusable

Hey @vlatko, thanks for the detailed report, and for digging out the raw transcript. That made this quick to confirm.

You are right that the behavior does not match the docs, and it is not caused by anything in your setup. Nested launches (a direct subagent launching its own subagent) are available in the IDE and the CLI. They are not available for sessions started through the SDK. In an SDK session, a direct subagent does not get the task tool, so there is nothing for it to call. This is the same for the local and cloud SDK runtimes. We’ve let the team know. I’ll post here when I have an update.

To your other two questions:

  1. There is no SDK option to opt a subagent into nested launches right now (nothing like local.allowNestedTaskTool). If that changes, it will show up in the SDK release notes.

  2. The dynamic-tool namespace your subagent found only lists tools that subagent actually has. Since task was not in that toolset, the call had nothing to route to. That error is expected given the missing tool, not a separate problem.

Your current workaround (fan out from the top-level agent and let the orchestrator prompt run inline) is the right approach for now.