# How Task Delegation and Spawning Create Subtasks in Roo Code: A Complete Technical Guide

> Discover how task delegation and spawning create subtasks in Roo Code. Explore the delegateParentAndOpenChild method for seamless task management and conversation history.

- Repository: [Roo Code/Roo-Code](https://github.com/RooCodeInc/Roo-Code)
- Tags: deep-dive
- Published: 2026-04-26

---

**Task delegation in Roo Code creates subtasks through the `delegateParentAndOpenChild` method in `ClineProvider`, which flushes parent state, instantiates a child task with linked metadata, and enforces a single-active-task invariant while preserving conversation history for seamless resumption.**

Roo Code implements task delegation as a deterministic, metadata-driven workflow where parent tasks are paused and child tasks are spawned with explicit lineage tracking. This architecture, defined in the `RooCodeInc/Roo-Code` repository, ensures that only one task remains active at any moment while maintaining a complete audit trail through the history schema. Understanding how task delegation and spawning create subtasks is essential for developers extending Roo Code's multi-agent capabilities or debugging complex task hierarchies.

## The Delegation Architecture

Roo Code treats every subtask as a **child task** created by delegating the current parent task to a new task instance. The entire flow is orchestrated by the **new-task tool** (`newTaskTool`) and the **`delegateParentAndOpenChild`** method of the `ClineProvider` class.

When delegation occurs, the system transitions from a single active parent to a delegated parent with an active child. This design guarantees that the global state always maintains exactly one open task while preserving the ability to resume parent conversations once children complete their work.

## The Eight-Step Delegation Process

The `delegateParentAndOpenChild` method in [`src/core/webview/ClineProvider.ts`](https://github.com/RooCodeInc/Roo-Code/blob/main/src/core/webview/ClineProvider.ts) executes a precise sequence to ensure data integrity and task isolation.

**1. Flush Pending Tool Results**

Any tool results belonging to the parent's conversation are persisted to the API history so the parent can resume later. This occurs in `ClineProvider.delegateParentAndOpenChild()` at lines 61-66.

**2. Dispose the Parent Task**

The parent is removed from the active stack, enforcing Roo Code's strict *single-open* invariant. This happens at lines 85-90 using `removeClineFromStack({ skipDelegationRepair: true })`.

**3. Switch Provider Mode**

The provider switches to the mode requested by the child, such as a specialized agent configuration. This mode transition occurs at lines 99-104 via `handleModeSwitch`.

**4. Create the Child Task**

A fresh `Task` instance is constructed with `initialStatus: "active"` and `startTask: false` to prevent premature execution before parent metadata is saved. This creation happens at lines 124-131.

**5. Persist Parent Delegation Metadata**

The parent's history entry receives critical linking fields at lines 132-141 through `updateTaskHistory`:

- `status` is set to `"delegated"`
- `delegatedToId` stores the child task ID
- `awaitingChildId` stores the child task ID for resumption tracking
- `childIds` array is extended to include the new child

**6. Start the Child Task**

Once the parent's delegation record is durable, the child safely initializes and begins execution at line 150 via `child.start()`.

**7. Emit Delegation Events**

The system broadcasts `TaskDelegated` events for UI updates and external listeners at lines 154-156.

## Data Model and Parent-Child Linking

The relationship between parent and child tasks is defined in [`packages/types/src/history.ts`](https://github.com/RooCodeInc/Roo-Code/blob/main/packages/types/src/history.ts) through a strict Zod schema:

```typescript
export const historyItemSchema = z.object({
  // ...
  status: z.enum(["active", "completed", "delegated"]).optional(),
  delegatedToId: z.string().optional(),
  childIds: z.array(z.string()).optional(),
  awaitingChildId: z.string().optional(),
})

```

When a child is created, the parent's record updates with `childIds` and `awaitingChildId` to establish the lineage. When the child finishes, `reopenParentFromDelegation()` (lines 660-720 in [`ClineProvider.ts`](https://github.com/RooCodeInc/Roo-Code/blob/main/ClineProvider.ts)) reads this metadata and rewrites the parent's status back to `"active"`, enabling seamless continuation of the original conversation.

## Entry Point: The New-Task Tool

The delegation flow is triggered by the model emitting a `new_task` tool call. The `NewTaskTool.handle()` method in [`src/core/tools/NewTaskTool.ts`](https://github.com/RooCodeInc/Roo-Code/blob/main/src/core/tools/NewTaskTool.ts) serves as the entry point:

```typescript
const child = await (provider as any).delegateParentAndOpenChild({
  parentTaskId: task.taskId,
  message: unescapedMessage,
  initialTodos: todoItems,
  mode,
})
pushToolResult(`Delegated to child task ${child.taskId}`)

```

The tool forwards arguments to the provider without pausing the parent directly, as `delegateParentAndOpenChild` already guarantees the single-open invariant through its internal synchronization.

## Resuming Parent Tasks After Delegation

When a child task completes, `reopenParentFromDelegation` restores the parent context through a specific sequence:

1. Loads the parent's persisted history and messages from storage
2. Injects a synthetic **subtask_result** message into the parent's conversation so the API sees the child's outcome
3. Clears the `awaitingChildId` field and updates status to `"active"`

```typescript
const { historyItem } = await this.getTaskWithId(parentTaskId)
// ... inject synthetic records ...
await this.updateTaskHistory({ 
  ...historyItem, 
  status: "active", 
  awaitingChildId: undefined 
})

```

## Practical Implementation Examples

### Delegating from a Provider Instance

To programmatically create a subtask from within a provider:

```typescript
// Assuming `provider` is a ClineProvider instance
await provider.delegateParentAndOpenChild({
  parentTaskId: "a1b2c3",
  message: "Write the unit tests for the new feature",
  initialTodos: [{ title: "Create test file", done: false }],
  mode: "code",
});

```

This creates a child task, marks parent `a1b2c3` as `delegated`, and activates the child as the sole active task.

### Tool-Based Delegation in Prompts

When the model returns a delegation request:

```json
{
  "tool": "newTask",
  "mode": "code",
  "content": "Implement the missing API endpoint",
  "todos": ["Add route", "Write handler", "Add tests"]
}

```

The `newTaskTool.handle()` function processes this JSON and executes the delegation flow described above.

### Monitoring Delegation Events

Track task relationships through event listeners:

```typescript
provider.on(RooCodeEventName.TaskDelegated, (parentId, childId) => {
  console.log(`Parent ${parentId} delegated to child ${childId}`);
});

```

You can also listen for `TaskSpawned` events emitted by the task itself to capture the exact moment a child is instantiated.

## Summary

- **Task delegation** in Roo Code creates subtasks by pausing the parent and instantiating a child with linked metadata, ensuring only one task remains active at any time.
- The **`delegateParentAndOpenChild`** method in [`src/core/webview/ClineProvider.ts`](https://github.com/RooCodeInc/Roo-Code/blob/main/src/core/webview/ClineProvider.ts) orchestrates the eight-step workflow including state flushing, mode switching, and history persistence.
- **Parent-child relationships** are tracked through the history schema fields `delegatedToId`, `childIds`, and `awaitingChildId` defined in [`packages/types/src/history.ts`](https://github.com/RooCodeInc/Roo-Code/blob/main/packages/types/src/history.ts).
- **Resumption** occurs via `reopenParentFromDelegation`, which restores parent context by injecting synthetic subtask results and clearing delegation metadata.
- The **`newTaskTool`** in [`src/core/tools/NewTaskTool.ts`](https://github.com/RooCodeInc/Roo-Code/blob/main/src/core/tools/NewTaskTool.ts) provides the primary interface for model-initiated delegation.

## Frequently Asked Questions

### What happens to the parent task when a subtask is created?

The parent task is marked with `status: "delegated"` and removed from the active task stack. Its state is flushed to persistent storage including any pending tool results, allowing it to resume exactly where it left off once the child completes. The parent remains in a suspended state tracked by `awaitingChildId` until `reopenParentFromDelegation` reactivates it.

### How does Roo Code prevent multiple tasks from running simultaneously?

Roo Code enforces a **single-open invariant** through the `removeClineFromStack` method called during delegation with `skipDelegationRepair: true`. This ensures the parent is disposed before the child starts, guaranteeing exactly one active task at any moment. The provider maintains this invariant by strictly sequencing the disposal and creation operations within `delegateParentAndOpenChild`.

### Can a child task create its own subtasks?

Yes, the delegation mechanism supports nested hierarchies. When a child task invokes the `new_task` tool or calls `delegateParentAndOpenChild`, it becomes a parent to its own child task. The `childIds` array in the history schema tracks all descendants, and the system maintains the delegation chain through successive `delegatedToId` references, allowing for arbitrarily deep task nesting while preserving the single-active-task constraint at each level.

### Where is the delegation state stored between sessions?

Delegation metadata persists in the VS Code global state through the history schema defined in [`packages/types/src/history.ts`](https://github.com/RooCodeInc/Roo-Code/blob/main/packages/types/src/history.ts). Fields including `status`, `delegatedToId`, `childIds`, and `awaitingChildId` are written to storage via `updateTaskHistory` before the child task starts, ensuring that parent-child relationships survive application restarts and can be reconstructed when `reopenParentFromDelegation` executes.