# What Are spawnableAgents in Codebuff? A Complete Guide to Agent Composition

> Discover spawnableAgents in Codebuff AI. Learn how this declarative composition mechanism enables modular, reusable agent workflows by programmatically launching other agents during execution without code duplication.

- Repository: [Codebuff/codebuff](https://github.com/CodebuffAI/codebuff)
- Tags: deep-dive
- Published: 2026-03-09

---

**Spawnable agents in Codebuff are a declarative composition mechanism that allows one agent to programmatically launch other agents during execution, creating modular, reusable workflows without code duplication.**

In the CodebuffAI/codebuff repository, `spawnableAgents` serve as the foundation for building complex multi-agent systems. By declaring which child agents can be instantiated at runtime, developers create a composition graph that enables dynamic task delegation, isolated execution contexts, and sophisticated orchestration patterns.

## Understanding spawnableAgents in Codebuff

At its core, the `spawnableAgents` field transforms static agent definitions into dynamic, composable units. When you define an agent in Codebuff, you specify an array of agent references—either fully-qualified IDs (`publisher/agentId@version`) or short local IDs—that this agent is permitted to instantiate during its execution cycle.

This architecture solves three critical problems in agent development:

- **Reusability**: A single "file-picker" agent can serve multiple higher-level agents (code-reviewers, bug-finders, documentation generators) without copying logic
- **Isolation**: Each spawned agent operates in its own sandboxed execution context, ensuring failures in child agents don't corrupt parent state
- **Dynamic orchestration**: Parent agents can decide at runtime which children to spawn based on user input or intermediate results, enabling adaptive workflows

## How spawnableAgents Enable Agent Composition

The composition system operates across three distinct phases: definition, validation, and execution.

### Declaring Spawnable Agents in Agent Definitions

In [`agents/types/agent-definition.ts`](https://github.com/CodebuffAI/codebuff/blob/main/agents/types/agent-definition.ts), the `AgentDefinition` interface includes the `spawnableAgents` field as an array of strings. This declaration acts as a whitelist—only agents listed here can be instantiated by this agent at runtime.

```typescript
// agents/types/agent-definition.ts
export interface AgentDefinition {
  id: string;
  version: string;
  publisher: string;
  displayName: string;
  model: string;
  // Agents that this agent is permitted to spawn
  spawnableAgents: string[]; // e.g., ['my-org/file-picker@0.2.1', 'my-org/code-searcher@0.3.0']
  spawnerPrompt?: string;
  handleSteps: GeneratorFunction;
}

```

The `spawnerPrompt` field complements this by describing when the orchestrator should be used, providing context for both the runtime system and UI visualization tools.

### Publishing and Validation via Subagent Resolution

When you publish an agent using `codebuff publish`, the system validates all `spawnableAgents` references in [`web/src/app/api/agents/publish/subagent-resolution.ts`](https://github.com/CodebuffAI/codebuff/blob/main/web/src/app/api/agents/publish/subagent-resolution.ts). This module ensures composition integrity before the agent becomes available in the registry.

The `resolveAndValidateSubagents` function performs several critical checks:

1. **Reference normalization**: Converts short local IDs to fully-qualified IDs (`publisher/agentId@version`)
2. **Version resolution**: Resolves simple references to the latest published version
3. **Existence validation**: Ensures referenced agents are either already published or included in the same publish request
4. **Cycle detection**: Prevents circular dependencies that could cause infinite spawn loops

```typescript
// web/src/app/api/agents/publish/subagent-resolution.ts
export async function resolveAndValidateSubagents({
  agents,
  requestedPublisherId,
  getLatestPublishedVersion,
  existsInSamePublisher,
}: {
  agents: Array<{ id: string; version: string; data: AgentDefinition }>;
  requestedPublisherId: string;
  getLatestPublishedVersion: (publisher: string, agentId: string) => Promise<string | null>;
  existsInSamePublisher: (publisher: string, agentId: string, version: string) => boolean;
}): Promise<void> {
  // Validates spawnableAgents array, resolves versions, checks for cycles
  // Implementation spans lines 9-99 in the source file
}

```

This validation guarantees that only resolvable, published agents can be spawned, maintaining the integrity of the composition graph.

### Runtime Execution via the spawn_agents Tool

During execution, the `spawnableAgents` declaration enables the `spawn_agents` tool call within the `handleSteps` generator function. When an agent yields a `spawn_agents` call, the engine creates separate execution contexts for each child agent.

The runtime behavior defined in [`agents/types/agent-definition.ts`](https://github.com/CodebuffAI/codebuff/blob/main/agents/types/agent-definition.ts) (lines 44-52) specifies that:

1. The engine creates isolated execution contexts for each spawned agent
2. Child agents can optionally inherit the parent's system prompt
3. Results from child agents return to the parent upon completion
4. The parent continues execution after receiving child outputs

```typescript
// Example handleSteps implementation showing spawn_agents usage
handleSteps: function* ({ logger, toolResult }) {
  // Determine which agent to spawn based on context
  const task = yield {
    toolName: 'ask_user',
    input: { prompt: 'Select task: (1) pick files, (2) search code' },
  };
  
  if (task === '1') {
    // Spawn file-picker agent declared in spawnableAgents
    yield {
      toolName: 'spawn_agents',
      input: {
        agents: [{ agent_type: 'file-picker', prompt: 'Select relevant files' }],
      },
    };
  }
  
  // Wait for child completion and receive results
  const { toolResult: childOutput } = yield { toolName: 'wait_for_children' };
  logger.info('Child agent completed:', childOutput);
}

```

This runtime mechanism transforms static `spawnableAgents` declarations into dynamic, conditional workflow orchestration.

## Visualizing Agent Relationships with spawnableAgents

Codebuff provides comprehensive tooling to visualize the composition graphs created by `spawnableAgents`, aiding debugging and documentation.

### Building the Agent Tree

The [`web/src/lib/agent-tree.ts`](https://github.com/CodebuffAI/codebuff/blob/main/web/src/lib/agent-tree.ts) module constructs an in-memory tree representation of agent spawn relationships. This tree captures:

- **Spawner prompts**: Descriptions of when each agent should be used
- **Availability status**: Whether referenced agents are published and accessible
- **Cycle detection**: Identification of circular dependencies that would cause infinite loops
- **Depth limits**: Enforcement of maximum nesting levels to prevent runaway spawning

```typescript
// web/src/lib/agent-tree.ts
export interface AgentTreeNode {
  publisher: string;
  agentId: string;
  version: string;
  displayName: string;
  spawnerPrompt: string | null;
  children: AgentTreeNode[];
  isAvailable: boolean;
  cycleDetected: boolean;
}

export async function buildAgentTree(params: {
  rootPublisher: string;
  rootAgentId: string;
  rootVersion: string;
  rootDisplayName: string;
  rootSpawnerPrompt: string | null;
  rootSpawnableAgents: string[];
  lookupAgent: (publisher: string, agentId: string, version: string) => Promise<AgentLookupResult | null>;
  maxDepth?: number;
}): Promise<AgentTreeNode> {
  // Implementation builds tree recursively, checks cycles, validates availability
  // Lines 21-34 in agent-tree.ts
}

```

### Generating Mermaid Diagrams

The `generateMermaidDiagram` function (lines 29-90 in [`agent-tree.ts`](https://github.com/CodebuffAI/codebuff/blob/main/agent-tree.ts)) converts the agent tree into Mermaid flowchart syntax, enabling visual documentation of complex agent hierarchies.

```typescript
// Generate Mermaid diagram from agent tree
const diagram = generateMermaidDiagram(tree);
console.log(diagram);
// Output:
// flowchart TD
//   A[orchestrator<br/>Task Orchestrator] --> B[file-picker<br/>File Picker]
//   A --> C[code-searcher<br/>Code Searcher]
//   style A fill:#f9f,stroke:#333

```

The diagram generator applies distinct styling for root nodes, unavailable agents, and cyclic references, making it immediately obvious when `spawnableAgents` references are broken or problematic.

## Practical Implementation Examples

### Defining an Orchestrator with spawnableAgents

Here's a complete example showing how to define an agent that utilizes `spawnableAgents` to delegate tasks:

```typescript
// .agents/orchestrator.ts
import { AgentDefinition } from '../agents/types/agent-definition'

export const orchestrator: AgentDefinition = {
  id: 'orchestrator',
  version: '0.1.0',
  publisher: 'my-org',
  displayName: 'Task Orchestrator',
  model: 'anthropic/claude-opus-4.6',
  // Declare which agents this orchestrator can spawn
  spawnableAgents: [
    'my-org/file-picker@0.2.1',
    'my-org/code-searcher@0.3.0',
  ],
  spawnerPrompt: 'Use this agent to coordinate file selection and code search.',
  handleSteps: function* ({ logger, toolResult }) {
    // Ask user which sub-task to perform
    const { toolResult: choice } = yield {
      toolName: 'ask_user',
      input: { prompt: 'Pick a task: (1) pick files, (2) search code' },
    }

    if (choice === '1') {
      // Spawn the file-picker agent
      yield {
        toolName: 'spawn_agents',
        input: {
          agents: [{ agent_type: 'file-picker', prompt: 'Select files' }],
        },
      }
    } else {
      // Spawn the code-searcher agent
      yield {
        toolName: 'spawn_agents',
        input: {
          agents: [{ agent_type: 'code-searcher', prompt: 'Search code' }],
        },
      }
    }

    // Wait for child completion
    const { toolResult: childOutput } = yield { toolName: 'wait_for_children' }
    logger.info('Child finished:', childOutput)
  },
}

```

### Publishing with Automatic Resolution

When publishing the orchestrator, Codebuff automatically resolves and validates all `spawnableAgents` references:

```typescript
// This happens internally when running: codebuff publish .agents/orchestrator.ts

import { resolveAndValidateSubagents } from './web/src/app/api/agents/publish/subagent-resolution'

await resolveAndValidateSubagents({
  agents: [{ id: 'orchestrator', version: '0.1.0', data: orchestrator }],
  requestedPublisherId: 'my-org',
  getLatestPublishedVersion: async (pub, id) => {
    // Returns latest version or null
    return '0.2.1' 
  },
  existsInSamePublisher: (pub, id, ver) => {
    // Checks if agent exists in current publish batch
    return true
  },
})

```

This validation ensures that only published, available agents can be referenced in `spawnableAgents`, preventing runtime errors from unresolved dependencies.

## Summary

- **Spawnable agents** enable one Codebuff agent to programmatically launch other agents via the `spawn_agents` tool, creating dynamic composition graphs.
- The `spawnableAgents` field in [`agents/types/agent-definition.ts`](https://github.com/CodebuffAI/codebuff/blob/main/agents/types/agent-definition.ts) acts as a whitelist of eligible child agents, declared using fully-qualified IDs or local references.
- During publishing, [`web/src/app/api/agents/publish/subagent-resolution.ts`](https://github.com/CodebuffAI/codebuff/blob/main/web/src/app/api/agents/publish/subagent-resolution.ts) validates and normalizes these references, ensuring only resolvable agents can be spawned and preventing circular dependencies.
- At runtime, the `spawn_agents` tool creates isolated execution contexts for each child agent, allowing parents to delegate subtasks while maintaining fault isolation.
- The [`web/src/lib/agent-tree.ts`](https://github.com/CodebuffAI/codebuff/blob/main/web/src/lib/agent-tree.ts) module provides visualization capabilities, building trees of spawn relationships and generating Mermaid diagrams to help developers understand complex agent hierarchies.

## Frequently Asked Questions

### What is the difference between spawnableAgents and sub-agents?

**Spawnable agents are explicitly declared dependencies that a parent agent *can* instantiate, while sub-agents refer to the actual runtime instances created via the `spawn_agents` tool.** The term "spawnable" emphasizes that these agents are eligible to be launched on demand—the parent chooses at runtime which declared agents to actually spawn, if any. This differs from static parent-child relationships where sub-agents are always instantiated; spawnable agents provide dynamic, conditional composition.

### How does Codebuff prevent circular dependencies in spawnableAgents?

**Codebuff detects circular dependencies during both the publishing phase and tree visualization.** In [`web/src/app/api/agents/publish/subagent-resolution.ts`](https://github.com/CodebuffAI/codebuff/blob/main/web/src/app/api/agents/publish/subagent-resolution.ts), the validation logic checks that referenced agents don't create dependency cycles before allowing publication. Additionally, [`web/src/lib/agent-tree.ts`](https://github.com/CodebuffAI/codebuff/blob/main/web/src/lib/agent-tree.ts) explicitly tracks cycles during tree construction, setting a `cycleDetected` flag on nodes that would create infinite loops. This prevents runtime deadlocks where agent A spawns B, which spawns C, which attempts to spawn A again.

### Can spawnableAgents reference agents from other publishers?

**Yes, spawnableAgents can reference agents from any publisher using fully-qualified IDs in the format `publisher/agentId@version`.** The resolution system in [`web/src/app/api/agents/publish/subagent-resolution.ts`](https://github.com/CodebuffAI/codebuff/blob/main/web/src/app/api/agents/publish/subagent-resolution.ts) handles cross-publisher references by validating that the specified version exists in the target publisher's registry. However, agents can only spawn other agents that have been published and are available; unpublished or private agents from other publishers cannot be referenced unless explicitly shared.

### What happens if an agent tries to spawn an agent not listed in spawnableAgents?

**The runtime system enforces the spawnableAgents whitelist, preventing agents from spawning undeclared dependencies.** If an agent attempts to use the `spawn_agents` tool with an agent_type not present in its `spawnableAgents` array, the execution engine rejects the request. This constraint ensures composition integrity—developers must explicitly declare dependencies at definition time, allowing the publishing pipeline to validate availability and prevent runtime errors from missing or incompatible agents.