# Phase 1: Fork Subagent — Specification

**Priority:** P0 · **Effort:** 2–3 days · **Dependencies:** None  
**Reference:** `claude-code-main/src/tools/AgentTool/forkSubagent.ts`, `src/utils/forkedAgent.ts`

---

## 1. Problem Statement

In the Claude Code system, the fork subagent is the primary delegation pattern. When the LLM omits `subagent_type`, the Agent tool implicitly creates a fork child that inherits the **full parent context** — system prompt, conversation history, tool pool, and thinking config — producing byte-identical API request prefixes for prompt cache sharing. pi-subagents always requires an explicit `subagent_type`, which means:

1. **Context duplication** — the LLM must re-explain context that the parent already has.
2. **No prompt cache sharing** — each agent spawn produces a fresh API request with no shared prefix with the parent.
3. **No `/fork <directive>` flow** — the fast "do this related work" pattern isn't available.

## 2. Design

### 2.1. Overview

When `subagent_type` is omitted from the Agent tool call, the system creates a **fork child** instead of a typed agent. The fork child:

- Inherits the parent's **full system prompt** (byte-exact, already-rendered)
- Inherits the parent's **conversation history** (filtered for incomplete tool calls)
- Inherits the parent's **exact tool pool** (same set, same definitions)
- Runs in **background** — fork children are always async
- Gets a **recursive fork guard** — fork children cannot spawn their own fork children
- Gets a **worktree notice** if running with `isolation: "worktree"`

### 2.2. Fork Boilerplate

When building a fork child's conversation, all `tool_use` blocks from the parent's last assistant message are replaced with placeholder `tool_result` blocks containing identical placeholder text (`"Fork started — processing in background"`). This ensures byte-identical API request prefixes across all fork children, maximizing prompt cache hits.

The fork child's conversation structure:

```
[...parent history up to last assistant message]
[parent assistant message with all tool_use blocks]
[user message: placeholder tool_results (identical) + per-child directive text]
```

The directive text wraps the LLM's prompt in a `<fork_boilerplate>` tag with strict rules:
- "You are a forked worker process. You are NOT the main agent."
- Do not spawn sub-agents; execute directly
- Do not converse, ask questions, or suggest next steps
- USE tools directly: Bash, Read, Write, etc.
- If modifying files, commit changes before reporting
- Keep report under 500 words
- Begin response with "Scope:"
- Output structured format: Scope / Result / Key files / Files changed / Issues

### 2.3. Recursive Fork Guard

A `isInForkChild()` function scans the conversation history for the `<fork_boilerplate>` tag. If found, the Agent tool refuses to create another fork child. This prevents infinite fork recursion.

### 2.4. `/fork <directive>` Slash Command

A new `/fork <directive>` slash command is registered. It:
1. Gets the parent's last assistant message
2. Calls `buildForkedMessages()` to produce the fork conversation
3. Spawns the fork as a background agent
4. Returns the agent ID

### 2.5. Worktree Integration

When a fork child runs with `isolation: "worktree"`, a worktree notice is prepended to the directive telling the child:
- It's operating in an isolated git worktree
- Paths in inherited context refer to the parent's directory — translate them
- Re-read files before editing (parent may have changed them)
- Changes stay in the worktree

---

## 3. API Changes

### 3.1. Agent Tool Schema

`subagent_type` becomes **optional** (currently required). When omitted:

```typescript
// Current (required):
subagent_type: Type.String({ description: "The type of specialized agent..." })

// New (optional — fork path when omitted):
subagent_type: Type.Optional(Type.String({ ... }))
```

### 3.2. New: `/fork` Slash Command

```
/fork <directive>
```

Spawns a fork child with the given directive as the user message. The agent type is `"fork"`. Results arrive via the same `subagent-notification` path.

### 3.3. New Module: `fork-subagent.ts`

Exports:
- `isForkSubagentEnabled(): boolean` — feature gate
- `FORK_SUBAGENT_TYPE = "fork"` — synthetic type name
- `buildForkedMessages(directive, assistantMessage): Message[]` — builds fork conversation
- `buildChildMessage(directive): string` — builds the fork boilerplate text
- `buildWorktreeNotice(parentCwd, worktreeCwd): string` — worktree isolation notice
- `isInForkChild(messages): boolean` — recursive fork guard

### 3.4. New `"fork"` Agent Type

A synthetic agent definition (not registered in defaults — only used by the fork path):

```typescript
{
  name: "fork",
  displayName: "Fork",
  description: "Implicit fork — inherits full conversation context",
  builtinToolNames: [...BUILTIN_TOOL_NAMES], // All tools
  extensions: true,
  skills: true,
  systemPrompt: "",  // Replaced with parent's rendered prompt
  promptMode: "replace",
  isDefault: true,
}
```

---

## 4. Integration Points

### Existing code that changes:
| File | Change |
|---|---|
| `src/index.ts` | `subagent_type` becomes optional; fork branch in Agent.execute |
| `src/agent-runner.ts` | Accept pre-built messages and exact tool pool |
| `src/default-agents.ts` | Add `"fork"` entry (hidden from normal type selection) |

### New files:
| File | Purpose |
|---|---|
| `src/fork-subagent.ts` | Fork boilerplate builder, guards, helpers |
| `test/fork-subagent.test.ts` | Tests for fork logic |

---

## 5. Edge Cases

| Case | Behavior |
|---|---|
| No assistant message exists | Fork fails with descriptive error ("Cannot fork — no parent conversation to fork from") |
| No tool_use blocks in last assistant message | Falls through to a simple continuation message |
| Fork within a fork | Refused by recursive fork guard |
| Fork with `inherit_context` | Ignored — fork always inherits context (that's the point) |
| Fork with explicit `subagent_type` | Normal agent spawn (not a fork) |
| Fork with `run_in_background: false` | Overridden to `true` (fork children always background) |
| `/fork` in empty session | Returns error ("No conversation to fork from") |

---

## 6. Testing Plan

| Test | What it verifies |
|---|---|
| Fork boilerplate structure | Builds correct message sequence: history + assistant + tool_results + directive |
| Placeholder text identical | All tool_results use identical placeholder |
| Recursive fork guard | `isInForkChild()` detects `<fork_boilerplate>` tag |
| Worktree notice | Correct path translation instructions |
| Empty tool_blocks fallback | Graceful handling of assistant with no tool_use blocks |
| `/fork` command | Registers, parses directive, spawns background agent |
