Home
Home/s06
s06110 lines of code

Subagent

Specialists for Every Job

Key Insight:

Subagents give each subtask a clean context while preserving the main thread.

OpenCode's subagent system provides 10 named agents, each with documented expertise. Oracle handles architecture, explore searches the codebase, librarian looks up documentation, and more. Subagents receive isolated context with a clean message history and can be dispatched via @mention or programmatically.

Architecture Flow

The Problem: Context Pollution in Single-Agent Systems

In a single-agent system, every tool result, error message, and intermediate thought pollutes the same conversation. The agent must constantly refilter what is relevant from the growing noise. Subagents solve this problem by creating isolated contexts. Each subagent is a fresh agent loop with its own message history. The parent dispatches a task, and the subagent works independently, returning only the final result. This prevents the parent's context from being diluted by exploration that only the subagent needs to see.

Composition Through Isolation

Each subagent runs its own agentLoop(), the same function introduced in s01. This means subagents inherit all capabilities, including tools, hooks, and permissions, without requiring any special code. The only differences are that the message history starts clean and the system prompt tailors behavior. The parent can dispatch multiple subagents in parallel, as explored in s09, and collect results as they complete. This transforms the agent into an orchestrator that decomposes complex tasks, delegates pieces to specialists, and synthesizes the final results.

Real Implementation: Task Tool and BackgroundJob

OpenCode's actual subagent dispatch uses the task tool (packages/opencode/src/tool/task.ts) combined with BackgroundJob (packages/core/src/background-job.ts). Instead of making a direct function call, the task tool creates a child session with its own permission scope. This scope inherits the parent's deny rules and adds the subagent's own ruleset. Subagents can run in two modes. In foreground mode, the parent awaits the result via background.wait(). In background mode, the call returns immediately and results are injected when the subagent finishes. The task_id parameter allows resuming the same subagent session across multiple calls, unlike the simplified version where each call creates a new context.

Design Decisions

Subagents are dispatched with a clean context, but the parent can pass relevant context snippets. The prompt building function extracts only the portions of the conversation that are relevant to the subagent's specialty.

Subagent results are returned as structured data rather than being appended to the parent's message history as a flat string. This enables the parent to parse, validate, and selectively incorporate the subagent's output.

Comparison: Claude Code

Both support subagent delegation. Claude Code does so through its agent mode, while OpenCode uses its subagent system. OpenCode's approach is more granular: each subagent gets its own loop, tool set, and permission context. The specialized agent types in OpenCode, such as Explorer, Librarian, and Oracle, mirror real engineering roles. Each comes with tuned system prompts and tool access. The parent agent can dispatch tasks to multiple subagents in parallel and synthesize the results.

Deep Dive: Design Decisions

Named Agents over Anonymous Workers

Each subagent has a name (oracle, explore, librarian, etc.) and a documented specialty. Users and the orchestrator can reference agents by name, building a mental model of the team.

Alternatives: Anonymous worker threads would be simpler but harder to reason about. Named agents make the system self-documenting.

Each Subagent Gets Fresh Context

Subagents start with a clean message history containing only their task-specific system prompt and instructions. They don't inherit the parent's conversation, preventing context pollution.

Alternatives: Shared context (passing the full history) would give subagents more background but at the cost of token waste and potential confusion from irrelevant messages.

Learn OpenCode — Built with Next.js