Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

OpenCode/KiloCode Subagent Orchestration Analysis


title: OpenCode/KiloCode Subagent Orchestration Analysis authors:


OpenCode/KiloCode Subagent Orchestration Analysis

OpenCode implements a hierarchical agent delegation system where a primary agent can spawn specialized subagents via the Task tool. This creates a recursive session model where subagents operate in isolated contexts but share the same physical workspace.

1. Delegation Mechanism: The Task Tool

The primary mechanism for spawning subagents is the TaskTool, implemented in /packages/opencode/src/tool/task.ts.

1.1 Tool Parameters

The delegation is triggered by a structured tool call with the following schema:

// /packages/opencode/src/tool/task.ts
export const Parameters = Schema.Struct({
  description: Schema.String.annotate({ description: "A short (3-5 words) description of the task" }),
  prompt: Schema.String.annotate({ description: "The task for the agent to perform" }),
  subagent_type: Schema.String.annotate({ description: "The type of specialized agent to use for this task" }),
  task_id: Schema.optional(Schema.String).annotate({
    description: "This should only be set if you mean to resume a previous task...",
  }),
  command: Schema.optional(Schema.String).annotate({ description: "The command that triggered this task" }),
})

1.2 Execution Flow

When TaskTool.execute is called, the following sequence occurs:

  1. Agent Resolution: The system resolves the specialized agent using Agent.Service.

    const next = yield* agent.get(params.subagent_type)
  2. Session Instantiation: A new session is created and linked to the primary session via parentID.

    const nextSession =
      session ??
      (yield* sessions.create({
        parentID: ctx.sessionID,
        title: params.description + ` (@${next.name} subagent)`,
        // ... permissions
      }))
  3. Recursive Loop Trigger: The TaskTool invokes the prompt operation from TaskPromptOps, which triggers a new LLM loop for the subagent.

    const result = yield* ops.prompt({
      messageID,
      sessionID: nextSession.id,
      model: { modelID: model.modelID, providerID: model.providerID },
      agent: next.name,
      tools: { ... },
      parts,
    })

2. Session Isolation and Security

2.1 Context Isolation

Isolation is achieved through the Session model. Each subagent gets a unique sessionID, ensuring:

2.2 Permission Gating (Default-Deny)

OpenCode employs a strict permission model to prevent subagents from escalating privileges. In /packages/opencode/src/tool/task.ts, the system explicitly checks for todowrite and task (delegation) permissions.

If the resolved next agent does not explicitly possess these permissions, they are forcefully denied in the subagent’s session configuration:

// /packages/opencode/src/tool/task.ts
const canTask = next.permission.some((rule) => rule.permission === id)
const canTodo = next.permission.some((rule) => rule.permission === "todowrite")

// ... inside sessions.create
permission: [
  ...(canTodo
    ? []
    : [{ permission: "todowrite" as const, pattern: "*" as const, action: "deny" as const }]),
  ...(canTask
    ? []
    : [{ permission: id, pattern: "*" as const, action: "deny" as const }]),
  // ...
]

3. Orchestration Loop

The recursive nature of the system is managed in /packages/opencode/src/session/prompt.ts.

The SessionPrompt.Service provides the prompt method used by TaskTool. When a subagent is invoked, it enters a runLoop (via SessionPrompt.runner), which can in turn call the TaskTool again, enabling N-level deep delegation.

3.1 Result Integration

Once the subagent’s loop terminates, the TaskTool wraps the result in a specific XML-like tag to signal the primary agent:

return {
  // ...
  output: [
    `task_id: ${nextSession.id} (for resuming to continue this task if needed)`,
    "",
    "<task_result>",
    result.parts.findLast((item) => item.type === "text")?.text ?? "",
    "</task_result>",
  ].join("\n"),
}

Architectural Summary

FeatureImplementation DetailFile Reference
Delegation ToolTaskTool (via TaskPromptOps)/packages/opencode/src/tool/task.ts
Session LinkageparentID in sessions.create/packages/opencode/src/tool/task.ts
IsolationUnique SessionID per subagent/packages/opencode/src/session/schema.ts
Permission ModelExplicit deny rules for todowrite/task/packages/opencode/src/tool/task.ts
RecursionSessionPrompt.prompt →\rightarrow runLoop →\rightarrow TaskTool/packages/opencode/src/session/prompt.ts