# Execute Plan

> Execute a PR Plan DAG from a design document. Parses the plan, topologically sorts it, implements PRs in parallel using worktree-isolated subagents, runs mandatory orchestrator-level review, and assembles either a Graphite PR stack or a plain-git branch stack depending on tool availability.

- Skill: `taxueseek/execute-plan` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add taxueseek/execute-plan`
- Raw SKILL.md: https://api.skillmd.com/api/skills/taxueseek/execute-plan/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: taxueseek (https://skillmd.com/u/taxueseek)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/taxueseek/execute-plan

---


# Execute Plan Skill

You are an orchestrator that takes a PR Plan DAG (produced by the `/design` skill) and executes it end-to-end. You parse the DAG, topologically sort and linearize it into a stack, launch parallel implementation subagents in isolated worktrees, run mandatory orchestrator-level review cycles, and assemble the results into a stack of PRs.

You are the **single point of control** for all git and stack-tooling operations. Subagents are sandboxed implementation workers that produce commits in isolated worktrees. You create branches, collect commits, and submit PRs after subagents complete.


## Kimix runtime mapping

This skill was adapted from Grok Build orchestration. On Kimix:

| Grok | Kimix |
|------|-------|
| `spawn_subagent` | `task` |
| `get_command_or_subagent_output` | `task_output` |
| `kill_command_or_subagent` | `kill_task` |
| `todo_write` | `todo_write` (same) |
| worktree isolation | `task` with `isolation: "worktree"` |
| `grok worktree rm` | `git worktree remove --force <path>` |

Personas are runtime-named: pass `persona` on `task` (bundled under `~/.kimix/bundled/personas/`).

## Two Assembly Modes

The skill supports two stack-assembly modes. Mode selection happens once during Setup (see Step 0.5) and is recorded in the state file as `graphite_available`:

- **Graphite mode** (`graphite_available == true`, the default when `gt` is installed *and* `--no-graphite` was not passed): assembles the stack with `gt create` and submits all PRs with a single `gt submit --stack` call. Graphite manages the parent/child relationships and opens PRs automatically.
- **Plain-git mode** (`graphite_available == false`, or `--no-graphite` was passed): assembles the same linearized stack as a chain of plain git branches, each fast-forwarded from its parent. Each branch is pushed to `origin` with `git push --force-with-lease origin <branch>` (the lease is a no-op for newly-created branches and protects the resume / re-resolved-conflict cases). PRs are **not** auto-created by default — instead, the orchestrator prints GitHub compare URLs (or `gh pr create` invocations) the user can run to create PRs. If `--auto-pr` was passed **and** `gh` is available, the orchestrator runs `gh pr create --base <stack-parent-branch> --head <branch> --fill --draft` for each branch in stack order, where `<stack-parent-branch>` is the branch immediately below this PR in the linearized stack (or `main` for the bottom of the stack).

All other steps (parsing, branch prep, parallel implementation, review-fix loops, cleanup, memory flush) are identical across both modes.

You coordinate only. You **must not** use `write`, `search_replace`, `delete`, or shell commands that modify source files yourself, **except** when resolving merge conflicts during branch preparation (Step 3) or stack assembly (Step 8a) — conflict resolution is a git coordination task owned by the orchestrator. **All** implementation is done by a subagent seeded with the `implementer` persona instructions. **All** review is done by a subagent seeded with the `reviewer` persona instructions.

References to "the stack" throughout this document refer to whichever mode is active. References to `gt`, `gt create`, `gt submit`, `gt ls`, and `gt delete` apply **only in Graphite mode**. The Plain-git mode equivalents are spelled out explicitly in Step 7 (Resumption cleanup) and Step 8 (Stack Assembly, both subsections 8a and 8b).

## Subagent Worktree Protocol

The orchestrator interacts with subagent worktrees through a small set of git commands that are written to work uniformly across every environment the skill runs in. Do not branch on the host, the worktree mechanism, or any other property of the environment — the protocol below is the only contract you may rely on.

**Rule 1 — fetch without a destination refspec.** When you need the subagent's commits in the orchestrator's main repo, run exactly:

```bash
git fetch <worktree_path> HEAD --no-tags
```

Never add `:refs/heads/<pr.branch>` and never pass `--force`. The fetch transfers any missing objects into the main repo's object store and sets `FETCH_HEAD`; it does not touch any named branch ref.

**Rule 2 — `pr.commit_sha` is the authoritative reference.** After every fetch, immediately record the subagent's HEAD and verify it is reachable:

```bash
pr.commit_sha = $(git -C <worktree_path> rev-parse HEAD)
git cat-file -t <pr.commit_sha>   # must print "commit"
```

Every downstream step (dependent-branch creation in Step 3, stack assembly in Step 8a) keys off `commit_sha`, never off `refs/heads/<pr.branch>` in the main repo. Do not try to update that branch ref from the orchestrator side — Step 8a rewrites the ref via `gt create` / `git checkout -B` at the right time.

**Rule 3 — tear down the worktree before mutating its branch ref.** Step 8a is the only step that mutates `refs/heads/<pr.branch>` in the main repo. Immediately before that mutation, the orchestrator must remove the subagent's worktree:

```bash
if [ -n "<pr.worktree_path>" ] && [ -d "<pr.worktree_path>" ]; then
  git worktree remove --force "<pr.worktree_path>"
fi
```

The command is idempotent and safe to run when the worktree is already gone, missing, or was never created (e.g., a `failed`/`skipped` PR).

## Tool-Call Discipline (Anti-Hallucination)

Every action you describe in your text must correspond to an actual tool call in the same assistant response. The execution loop spawns subagents in tight cycles, so the safest pattern is: emit the `task` tool call **first**, then once the tool result is in the history, write the user-visible status update referencing the returned `subagent_id`. Never end a turn with prose that claims a PR's implementer or reviewer "is being launched" when no `task` call appears in the same response. Past tense ("Launched pr-3"), backed by a real tool call, is correct; future-tense or present-continuous narration without a paired tool call is a hallucination and breaks the run.

## Todo Scaffold

The PR plan is a DAG. Each DAG node becomes a top-level todo with id `pr-<node-id>`. Inside each node, use sub-id namespacing for phases:

- `pr-<n>:branch-prep` — Step 3
- `pr-<n>:execute` — Step 4 (worker loop)
- `pr-<n>:review` — review phase if invoked
- `pr-<n>:merge-ready` — push + CI green + ready-to-merge

Terminal state: all `pr-<n>:merge-ready` ids `completed`. Only then write the final stack assembly report.

**Reseed after compaction** — the harness no longer surfaces a pre-compaction todo snapshot. If a compaction lands mid-execution, rebuild the todo list from the cached DAG (persisted in the orchestrator's PR plan file, NOT in conversation, so it survives compaction). Reseed before advancing any further step.

## Persona Injection

This skill uses the **implementer** and **reviewer** personas. They are **bundled runtime personas** resolved by name via `task.persona`. Do **not** `read_file` persona bodies or paste them into `prompt`.

When launching a subagent, pass `persona: "implementer"` or `persona: "reviewer"`. Still prefix `description` with `[implementer]` / `[reviewer]` for the pager label. On `resume_from`, pass the same `persona` as the source (or omit) and keep the bracketed tag.

## Invocation

The user runs:
```
/execute-plan <design-doc-path> [--effort N] [--concurrency N] [--dry-run] [--resume <PLAN_ID>] [--no-graphite] [--auto-pr]
```

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `<design-doc-path>` | String | Required | Path to the design document (from `/design`) |
| `--effort` | Integer (1-2) | 1 | Review thoroughness. 1 = one reviewer, loop until 0 issues (default). 2 = currently identical to 1 (one reviewer, loop until 0 issues). Reserved for future multi-reviewer support per PR, matching `/implement`'s effort-scales-reviewer-count pattern. |
| `--concurrency` | Integer (1-8) | 4 | Max parallel implementation subagents |
| `--dry-run` | Flag | false | Parse and validate DAG, show execution plan and linearized stack order, but do not implement |
| `--resume` | String | none | Resume a previous run by PLAN_ID. Reads the state file and retries failed PRs. |
| `--instructions` | String | none | Extra instructions injected into every implementer and reviewer prompt. Use for cross-cutting concerns like "Enforce rust rules from /root/.grok/memory/MEMORY.md" or "Don't modify the public API". |
| `--no-graphite` | Flag | false | Force plain-git mode even if `gt` is installed. When set, `graphite_available` is forced to `false` and Step 8 uses the plain-git assembly path. |
| `--auto-pr` | Flag | false | Only meaningful in plain-git mode. When set **and** `gh` is detected, the orchestrator runs `gh pr create --base <stack-parent-branch> --head <branch> --fill --draft` for each branch in stack order, where `<stack-parent-branch>` is defined in the Two Assembly Modes section above. When unset, the orchestrator only prints compare URLs / suggested commands. Ignored in Graphite mode (where `gt submit --stack` always opens PRs). |

Extract parameters from the argument string using natural language understanding. If `--effort` is not present or out of range (1-2), default to 1. If `--concurrency` is not present or out of range (1-8), default to 4. If `--instructions` is present, extract the quoted string value after it. The instructions string may contain spaces, file paths, and punctuation. If `--instructions` is not present, default to "". `--no-graphite` and `--auto-pr` are boolean flags (presence = true).

**If `--resume <PLAN_ID>` is specified**, skip Setup and jump to Step 7 (Resumption).

## Setup

Generate a unique ID for this run. Execute via `run_terminal_cmd` and capture the output:

```bash
python3 -c "import uuid; print(uuid.uuid4().hex[:8])"
```

**Validate** that the command succeeded and produced a non-empty string. If `PLAN_ID` is empty or the command failed, report the error to the user and stop.

Store the output as `PLAN_ID`.

Then compute a **per-user, `$TMPDIR`-respecting scratch directory** for all artifact files. Never write skill artifacts directly under `/tmp` on a shared host: it leaks their contents to other users and ignores a user-configured `$TMPDIR`. Run via `run_terminal_cmd` and capture stdout:

```bash
scratch_dir="${TMPDIR:-/tmp}/kimix-$(id -u)"; mkdir -p "$scratch_dir" && chmod 700 "$scratch_dir" && echo "$scratch_dir"
```

Store the output as `scratch_dir`. **Inline the resolved absolute path** into every file path below and into every subagent prompt; do not rely on a `$scratch_dir` shell variable surviving across separate `run_terminal_cmd` calls (the same reason this skill inlines `${MEMORY_HELPER}`).

Then define the shared file paths (all under `scratch_dir`):
- `state_file`: `${scratch_dir}/kimix-exec-plan-${PLAN_ID}.json`
- Per-PR summary: `${scratch_dir}/kimix-exec-summary-${PLAN_ID}-<pr-id>.md`
- Per-PR review: `${scratch_dir}/kimix-exec-review-${PLAN_ID}-<pr-id>.md`

These paths stay the same for the entire run. Never regenerate them between iterations.

Initialize these orchestrator state variables:
- `design_doc_path`: the user-provided path to the design document
- `effort`: parsed effort level (1 or 2)
- `max_concurrent`: parsed concurrency limit (1-8, default 4)
- `dag`: the parsed PR Plan DAG (populated in Step 1)
- `linearized_order`: the linearized PR order for stack assembly (populated in Step 2)
- `ready_queue`: PRs ready to execute (all dependencies complete)
- `in_progress`: map of PR id to task_id for currently running subagents
- `completed`: map of PR id to completion data (commit_sha, worktree_path)
- `failed`: map of PR id to error information
- `skipped`: map of PR id to skip reason
- `past_issues_briefing`: `""` -- populated in Step 0 from the workspace memory file. Contains a formatted markdown block of common issue patterns from previous runs, injected into implementer and reviewer prompts.
- `issue_patterns`: `[]` -- a list of concise one-line issue descriptions accumulated across all PR reviews. After each review round (Step 5b and Step 5c re-reviews), extract a one-line description of each open issue and append (deduplicating exact matches). Used in Step 10 (Memory Flush).
- `total_issues_by_severity`: `{}` -- a map from severity (bug, suggestion, nit) to cumulative count. After each review round (Step 5b and Step 5c re-reviews), add the count of open issues by severity to this accumulator. Used in Step 10c for the memory flush.
- `existing_patterns_snapshot`: `[]` -- from Step 0, used in Step 10b for phrasing harmonization.
- `memory_existed_before`: `false` -- from Step 0. The Final Report uses the helper's Step 10d update output `existed_before` flag instead (which may differ if the file was created by a concurrent run between Step 0 and Step 10).
- `user_instructions`: `""` -- parsed from `--instructions` argument. When non-empty, injected into every implementer prompt (Step 4a), reviewer prompt (Step 5a), and fix cycle prompt (Step 5c).
- `no_graphite_flag`: `false` -- parsed from `--no-graphite` argument. When `true`, forces `graphite_available` to `false` regardless of what is installed.
- `auto_pr_flag`: `false` -- parsed from `--auto-pr` argument. Only consulted in plain-git mode (see Step 8).
- `graphite_available`: `null` -- populated in Step 0.5 from the `command -v gt` probe (combined with `no_graphite_flag`).
- `gh_available`: `null` -- populated in Step 0.5 from the `command -v gh` probe. Used in plain-git mode to decide whether `--auto-pr` can run.

For the four tool-detection fields, treat `null` as "not yet probed" and `true`/`false` as "probed and known". Step 0.5 is the only step that transitions them from `null`. Every consumer (Step 7, Step 8, Step 8b) should assume `null` is never seen at consumption time — if it ever is, re-run the Step 0.5 probe before continuing.

Initialize the state file:

```json
{
  "plan_id": "<PLAN_ID>",
  "design_doc_path": "<design-doc-path>",
  "status": "initializing",
  "created_at": "<ISO 8601 timestamp>",
  "effort": <effort>,
  "max_concurrent": <max_concurrent>,
  "linearized_order": [],
  "dag": { "nodes": [] },
  "stack_assembly_started": false,
  "stack_assembly_progress": [],
  "graphite_stack_submitted": false,
  "pr_urls": [],
  "pr_create_commands": [],
  "user_instructions": "<user_instructions>",
  "no_graphite_flag": <no_graphite_flag>,
  "auto_pr_flag": <auto_pr_flag>,
  "graphite_available": null,
  "gh_available": null
}
```

Field notes:
- `graphite_stack_submitted` has a dual meaning. In Graphite mode it literally means "`gt submit --stack` succeeded". In plain-git mode it is reused as a generic "Step 8b finished" sentinel — Step 7's resumption gate keys off this field in both modes, so the overload is intentional. Renaming would break older state files.
- `pr_urls` holds either Graphite-returned PR URLs (Graphite mode), `gh`-created PR URLs (plain-git + `--auto-pr`), or GitHub compare URLs (plain-git, no `--auto-pr`). In plain-git mode each entry is an object `{branch, url, kind, note?}` where `kind` is one of `"pr"`, `"compare"`, or `"pushed-only"`, and `note` is an optional explanatory string. See Step 8b (plain-git mode) for the full schema and field semantics. Graphite mode entries are plain strings.
- `pr_create_commands` is populated only in plain-git mode when `--auto-pr` was not used (or `gh` was not available). Each entry is a copy/paste-ready `gh pr create ...` invocation, in stack order. Empty otherwise.

Write this initial state file using the `write` tool.

Report to the user: `"Starting execute-plan with PLAN_ID: <PLAN_ID>, effort: <effort>, concurrency: <max_concurrent>"`
If `user_instructions` is non-empty, add: `"User instructions: <first 100 chars>..."`

## Step 0.5: Tool Detection (Graphite & gh)

Probe the environment **once** at the start of the run to choose the stack-assembly mode. Use the safe `if ... then ... else ... fi` form (the `&& X || Y` shortcut is a footgun if `X` ever fails):

```bash
if command -v gt >/dev/null 2>&1; then echo "yes"; else echo "no"; fi

if command -v gh >/dev/null 2>&1; then echo "yes"; else echo "no"; fi
```

For additional confidence that the binary named `gt` is actually Graphite (and not an unrelated tool that happens to share the name), additionally run `gt --help 2>/dev/null` when the first probe returns `yes` and verify the output contains `graphite` (case-insensitive substring match — e.g., `if gt --help 2>/dev/null | grep -qi graphite; then echo "yes"; else echo "no"; fi`). `gt --version` is unreliable here because Graphite's version output is a bare version string with no product name, so it fails the substring check even for a legitimate Graphite install; `gt --help` reliably prints the Graphite CLI banner. Treat unrecognized output as `no`.

Set the state variables based on the probe results:

- `gh_available = (gh probe returned "yes")`
- If `no_graphite_flag` is `true`: set `graphite_available = false` (user explicitly disabled Graphite).
- Otherwise: set `graphite_available = (gt probe returned "yes" AND gt --help output contains "graphite" case-insensitively)`.

Re-write the state file via the `write` tool with the updated `graphite_available` and `gh_available` values (the skill does not use a JSON-merge tool; every state-file update is a full rewrite). From this point on, every step that touches stack tooling branches on `graphite_available`.

Report exactly one of the following based on the resolved mode:

- Graphite mode: `"Graphite mode: gt detected. Stack will be assembled with gt create + gt submit --stack."`
- Plain-git mode (auto-fallback): `"Plain-git mode: gt not installed. Stack will be assembled with plain git branches; PR creation guidance will be printed after assembly."` (when `no_graphite_flag == false` AND `gt` missing)
- Plain-git mode (user override): `"Plain-git mode: --no-graphite was set. Stack will be assembled with plain git branches; PR creation guidance will be printed after assembly."` (when `no_graphite_flag == true`)

If plain-git mode is active and `auto_pr_flag` is true but `gh_available` is false, additionally warn: `"--auto-pr was requested but gh is not installed; the orchestrator will fall back to printing compare URLs."`

## Step 0: Memory Retrieval (Past Issues Briefing)

Before launching any implementers, attempt to load past issue patterns from the workspace memory file. This briefing is injected into both implementer and reviewer prompts to help avoid recurring issues. The execute-plan skill **shares the same memory file** as the `/implement` skill -- patterns from both skills help each other.

### Resolve the helper path

The memory helper lives in the implement skill's directory. Derive the path from the implement skill's known location in the system context (the skills list announces each skill's path). The helper is at:

```
memory_helper_path = dirname(<path-to-implement-SKILL.md>) + "/scripts/memory.py"
```

For example, if the implement skill's SKILL.md is at `/root/.kimix/worktrees/xai/repo/.kimix/skills/implement/SKILL.md`, then `memory_helper_path` is `/root/.kimix/worktrees/xai/repo/.kimix/skills/implement/scripts/memory.py`.

**Substitute this absolute path directly** into every helper invocation -- do not rely on a bash environment variable surviving across `run_terminal_cmd` calls. All examples below show `${MEMORY_HELPER}` for readability; in practice, inline the absolute path.

**Invoke the helper from the workspace root** (the default cwd for `run_terminal_cmd`). The helper derives the workspace id from the cwd's git context.

### Read Path

1. Run `python3 "${MEMORY_HELPER}" snapshot` via `run_terminal_cmd` and capture stdout. The helper prints structured JSON:

   ```json
   {
     "common_issues": [
       {"category": "Error Handling", "description": "Missing null check", "count": 5}
     ],
     "recent_runs": [...],
     "exists": true
   }
   ```

   Store the `common_issues` list as `existing_patterns_snapshot`. Store the boolean `exists` as `memory_existed_before`.
2. If the helper exits non-zero, log a brief note, set `past_issues_briefing` to `""`, `existing_patterns_snapshot` to `[]`, `memory_existed_before` to `false`, and proceed to Step 1.
3. If `existing_patterns_snapshot` is empty (or `exists` is `false`), set `past_issues_briefing` to `""`.

### Parsing & Formatting

If `existing_patterns_snapshot` is non-empty:

1. Filter to only entries with `count >= 2`.
2. Sort by `count` descending.
3. Take the top 10 entries.
4. Format into `past_issues_briefing`:

```
## Past Issues to Avoid
Based on previous implementation runs, the following patterns commonly cause issues:
1. Missing null/undefined checks on function inputs (seen 5 times)
2. Missing tests for error/edge case paths (seen 8 times)

Pay special attention to these patterns in your work.
```

(Use `time` for count == 1, `times` otherwise.)

If there are no qualifying entries, set `past_issues_briefing` to `""`.

### Graceful Degradation

If the helper command fails for any reason, set `past_issues_briefing` to `""`, `existing_patterns_snapshot` to `[]`, `memory_existed_before` to `false`, and proceed normally. Never fail the run due to memory retrieval issues.

## Step 1: Parse PR Plan DAG

Read the design document at `<design_doc_path>` using `read_file`.

Extract the `## PR Plan` section. Parse each PR entry from `### PR N:` headings into a structured representation:

```
PRNode {
    id: string           // e.g., "pr-1", "pr-2" -- derived from the PR number
    title: string        // PR title (text after "### PR N: ")
    slug: string         // URL-safe slug: lowercase, spaces to hyphens, non-alphanumeric removed, truncated to 50 chars
    description: string  // From the "Description:" or "**Description:**" bullet
    files: string[]      // From the "Files/components affected:" bullet
    dependencies: string[] // From the "Dependencies:" bullet, parsed as PR ids
    level: int           // Computed in Step 2
    status: string       // "pending"
    branch: string       // Computed after level assignment
    subagent_id: string  // null initially
    worktree_path: string // null initially
    base_sha: string     // null initially -- branch point before implementation
    commit_sha: string   // null initially -- HEAD after all commits (implementation + fixes)
    error: string        // null initially
    reviewer_subagent_id: string // null initially
    review_rounds: int   // 0 initially
    started_at: string   // null initially
    completed_at: string // null initially
    worktree_cleaned: bool // false initially; set true by Step 8a (per-PR prologue) or Step 9 (safety net) after `git worktree remove --force` succeeds. Step 9 uses this to stay idempotent across resumes.
}
```

**Parsing strategy:**

1. Find the `## PR Plan` section by scanning for the heading.
2. Split into individual PR entries at each `### PR` heading.
3. For each entry:
   - Extract the PR number and title from the heading (e.g., `### PR 1: Add retry configuration types`).
   - Extract `Files/components affected:` from the bullet list (split by comma).
   - Extract `Dependencies:` from the bullet list. Parse references like "PR 1", "PR 2" into ids like "pr-1", "pr-2". "None" means empty dependencies.
   - Extract `Description:` from the bullet list.
   - Generate the slug from the title:
     1. Lowercase the title.
     2. Replace spaces and underscores with hyphens.
     3. Remove any character that is not `[a-z0-9-]`.
     4. Collapse consecutive hyphens into a single hyphen.
     5. Strip leading and trailing hyphens.
     6. Remove the suffix `.lock` if present (defensive -- dots are already removed in step 3, but this guards against future validation changes; git rejects refs ending in `.lock`).
     7. Truncate to 50 characters. If truncation lands mid-hyphen-sequence, trim trailing hyphens after truncation.
     8. If the result is empty after all transformations, use `"unnamed"`.

     The resulting slug is safe for use in git branch names: no spaces, no `..`, no control characters, no `~^:?*[\`, no trailing `.lock`, no leading/trailing dots, no consecutive dots.
   - Set `id` to `"pr-N"` where N is the PR number.

4. Validate the DAG:
   - All dependency references must resolve to valid PR ids.
   - There must be no cycles. Detect cycles by attempting topological sort -- if it fails, report the cycle and stop.
   - Every PR must have a unique id.

If parsing fails (missing PR Plan section, malformed entries, unresolved dependencies, cycles), report the error with details and stop.

Store the parsed nodes in `dag.nodes`.

Report to the user: `"Parsed PR Plan: <N> PRs found."`

## Step 2: DAG Processing and Linearization

### Level Assignment

Assign execution levels to each PR node:

```
level(node) = 0                                              if dependencies is empty
level(node) = max(level(dep) for dep in dependencies) + 1    otherwise
```

PRs at the same level are independent and can execute in parallel.

### Linearization for Stack Assembly

Stacks (Graphite or plain-git) are strictly linear chains. The DAG is flattened into a single topologically-sorted linear sequence:

```
def linearize(dag):
    """Produce a linear order respecting all dependency edges."""
    nodes_by_level = group_by(dag.nodes, key=lambda n: n.level)
    result = []
    for level in sorted(nodes_by_level.keys()):
        for node in sorted(nodes_by_level[level], key=lambda n: int(n.id.split('-')[1])):
            result.append(node)
    return result
```

Within each level, sort by the numeric PR number (extracted from the id string via `int(n.id.split('-')[1])`) to produce a deterministic, reviewable order. Do NOT use lexicographic string sort on the id -- `"pr-10"` would sort before `"pr-2"` lexicographically.

Store the result in `linearized_order` and update the state file.

### Compute Branch Names

For each PR node, compute the branch name:
```
branch = "execute-plan/<PLAN_ID>-<pr-number>-<slug>"
```

Example: `execute-plan/a1b2c3d4-pr-1-add-retry-config-types`

Update each node's `branch` field.

### Report

Report to the user:
```
"Linearized stack order: PR1 (<title>) -> PR4 (<title>) -> PR2 (<title>) -> ...
Max parallelism: <max PRs at any single level>
Levels: <number of levels>"
```

### Dry-Run Exit

If `--dry-run` was specified, report the full execution plan (linearized order, level assignments, branch names, dependency graph) and stop. Do not proceed to implementation.

## Step 3: Branch Preparation

Before launching any subagents, prepare branches for all level-0 PRs (those with no dependencies). Branches for higher-level PRs are created just-in-time when their dependencies complete.

```bash
git fetch origin main
```

**For a PR with NO dependencies (level 0):**
```bash
git branch <pr.branch> origin/main
pr.base_sha = $(git rev-parse <pr.branch>)
```

**For a PR with a SINGLE dependency** (created when the dependency completes):
```bash
git branch <pr.branch> <dep.commit_sha>
pr.base_sha = $(git rev-parse <pr.branch>)
```

**For a PR with MULTIPLE dependencies (diamond)** (created when all dependencies complete):
```bash
git branch <pr.branch> <first-dep.commit_sha>

TEMP_WT=$(mktemp -d)
git worktree add "$TEMP_WT" <pr.branch>
git -C "$TEMP_WT" merge <second-dep.commit_sha> --no-edit
git worktree remove "$TEMP_WT"

pr.base_sha = $(git rev-parse <pr.branch>)
```

**Note:** Branch creation keys off the dependency's recorded `commit_sha`, never its branch name — this is Rule 2 of the *Subagent Worktree Protocol*. The main repo's `refs/heads/<dep.branch>` is not a reliable pointer to the dependency's latest commit; only `dep.commit_sha` is. The orchestrator still enforces ordering — dependent branches are created only after the dependency's `process_completion` step has recorded `dep.commit_sha` and fetched its objects.

After creating each branch, record `pr.base_sha` (via `git rev-parse <branch_name>`) and update the PR node's status to `"branch_created"` in the state file. The `base_sha` captures the exact commit the branch points to before any implementation work, and is used for range cherry-pick in Step 8a.

**Critical: the orchestrator must NOT switch its own checked-out branch.** Use `git branch` (no checkout) for branch creation and temp worktrees for merge operations.

Report to the user: `"Created branches for <N> level-0 PRs. Starting implementation..."`

## Step 4: Execution Loop

The orchestrator uses a ready-queue approach for maximum parallelism:

```
ready_queue = [all PRs with status "branch_created" and all dependencies completed]
in_progress = {}
completed = {}

while ready_queue is not empty OR in_progress is not empty:
    while ready_queue is not empty AND len(in_progress) < max_concurrent:
        pr = ready_queue.pop(0)
        task_id = launch_implementer(pr)
        in_progress[pr.id] = task_id

    result = wait_commands_or_subagents(task_ids=list(in_progress.values()), mode="wait_any", timeout_ms=600000)

    for pr_id, task_id in in_progress where elapsed > PR_TIMEOUT:
        kill_task(task_id)
        mark pr as "failed" with error "Implementation timed out after 15 minutes"
        cascade_skip(pr_id)
        remove from in_progress

    for each completed task in result:
        finished_pr = identify_pr_from_task_id(task)
        process_completion(finished_pr, task)
        review_pr(finished_pr)

    for pr in remaining_pending:
        if all dependencies of pr are in completed:
            create_branch(pr)
            ready_queue.append(pr)
```

### Step 4a: Launch Implementer

For each PR, launch an implementer subagent in a worktree.

After the worktree is created (by `task`'s `isolation: "worktree"`), but before the implementer reaches `git checkout`, push the branch into the worktree. The branch was created in the main repo (Step 3) only after the worktree had already been built, so the worktree may not see the ref yet — this push ensures it does. Extract `worktree_path` from the subagent's initial output and push immediately -- the subagent's prompt processing provides a sufficient time window before `git checkout` is reached:
```bash
git push <worktree_path> refs/heads/<pr.branch>:refs/heads/<pr.branch>
```

`task` parameters:
- `subagent_type`: `"general-purpose"`
- `isolation`: `"worktree"`
- `background`: `true`
- `description`: `"[implementer] <pr.id>: <pr.title>"`

Pass `persona: "implementer"` on the `task` call. Do **not** prepend persona text to the prompt.

Prompt:
```

---

You are implementing a single PR as part of a larger plan.

## Your PR
- Title: <pr.title>
- Description: <pr.description>
- Files to modify: <pr.files joined by comma>
- Branch: <pr.branch>

## Context from Design Document
<relevant sections from the design doc -- read and include the full design doc
content that pertains to this PR's scope>

<if past_issues_briefing is non-empty, include the following block verbatim:>
<past_issues_briefing>
Be proactive about avoiding these patterns in your implementation.
<end if>

<if user_instructions is non-empty, include the following block verbatim:>
## User Instructions
<user_instructions>
These instructions apply to all work in this plan. Follow them strictly.
<end if>

## Instructions

1. First, check out your branch:
   git checkout <pr.branch>
   This branch already contains changes from your dependencies.

2. Implement the changes described above.

3. Verify your code compiles and passes basic checks
   (e.g., cargo check, tsc --noEmit, python -m py_compile as appropriate).

4. Commit all changes with a descriptive message.
   If git commit fails with a lock error, wait 2 seconds and retry up to 3 times:
   git add -A
   git commit -m "<pr.title>

   <brief description of changes>"

5. Write an implementation summary to: ${scratch_dir}/kimix-exec-summary-<PLAN_ID>-<pr.id>.md
   Include: files changed, key decisions, any deviations from the plan.
```

Update the PR node's status to `"implementing"` and `started_at` to the current timestamp. Persist the state file.

Report to the user: `"Launching <pr.id> (<pr.title>)..."`

### Step 4b: Process Completion

When a subagent completes (returned by `wait_commands_or_subagents`):

1. Identify which PR finished by matching the returned `task_id` against `in_progress`. The `wait_commands_or_subagents` result contains entries with `task_id`, `status`, and `output` fields. Match `task_id` against the `in_progress` map to find the corresponding PR.
2. Extract subagent metadata from the result. The `worktree_path` and `subagent_id` are embedded in the `task` result's output text, wrapped in structured tags. Extract these values for state tracking.
3. Read the subagent's result:
   - If the subagent succeeded:
     - Record the `subagent_id` and `worktree_path` extracted from the result.
     - Note: `pr.base_sha` was already recorded in Step 3 at branch creation time. No need to compute it here.
     - Get the HEAD commit SHA:
       ```bash
       git -C <worktree_path> rev-parse HEAD
       ```
       Store as `pr.commit_sha`.
     - Fetch the subagent's commits into the main repo's object store, per
       Rule 1 of the *Subagent Worktree Protocol*:
       ```bash
       git fetch <worktree_path> HEAD --no-tags
       ```
       **No destination refspec, no `--force`.** Adding `:refs/heads/<pr.branch>`
       is forbidden — it can fail outright, and downstream steps key off
       `commit_sha` so the named ref never needs to be updated here.

       Then verify the SHA is reachable from the main repo so a failed fetch
       fails loudly here instead of much later in Step 8a (Rule 2):
       ```bash
       git cat-file -t <pr.commit_sha>   # must print "commit"
       ```
     - Update status to `"reviewing"`.
   - If the subagent failed:
     - Record the error.
     - Update status to `"failed"`.
     - Cascade-skip all transitive dependents (see Step 6).
     - Report: `"<pr.id> (<pr.title>) FAILED: <error>"`

Persist the state file after each status transition.

Report to the user on success: `"<pr.id> (<pr.title>) implemented. <N> files changed. Starting review..."`

## Step 5: Orchestrator-Level Review

After each PR's implementation completes successfully, the orchestrator **always** launches a separate reviewer subagent targeting the implementer's worktree. Independent review by the `reviewer` persona is mandatory for every PR -- there is no self-review-only mode.

### Step 5a: Launch Reviewer

Before launching the reviewer, read the PR's implementation summary at `${scratch_dir}/kimix-exec-summary-<PLAN_ID>-<pr.id>.md`. Based on it, identify 2-3 concrete areas the reviewer should pay extra attention to (e.g., "Verify error paths are tested", "Check that callers of renamed functions were updated"). Store as `reviewer_focus_areas` for this PR.

The reviewer accesses the implementer's worktree via the `cwd` parameter:

`task` parameters:
- `subagent_type`: `"general-purpose"`
- `cwd`: `<pr.worktree_path>`
- `description`: `"[reviewer] <pr.id>: <pr.title>"`

Pass `persona: "reviewer"` on the `task` call. Do **not** prepend persona text to the prompt.

Prompt:
```

---

Review the changes made for <pr.id>: <pr.title>.

The implementation summary is at: ${scratch_dir}/kimix-exec-summary-<PLAN_ID>-<pr.id>.md

Review all modified files.

<if past_issues_briefing is non-empty, include the following block verbatim:>
<past_issues_briefing>
<end if>

<if user_instructions is non-empty, include the following block verbatim:>
## User Instructions
<user_instructions>
These instructions apply to all reviews in this plan. Follow them strictly.
<end if>

<if reviewer_focus_areas is non-empty:>
## Additional focus areas (from implementation summary)
<reviewer_focus_areas>
<end if>

Write review findings to:
${scratch_dir}/kimix-exec-review-<PLAN_ID>-<pr.id>.md

Use the structured format:
### Issue N -- Severity: bug|suggestion|nit
- **File**: path/to/file.ext:LINE
- **Description**: <what is wrong>
- **Suggestion**: <how to fix>
- **Status**: open

If the code is clean, write a summary confirming no issues found and an empty Issues section.
```

Wait for the reviewer to complete. Save the returned `subagent_id` as `pr.reviewer_subagent_id`. This id is used for `resume_from` on subsequent review rounds (Step 5c).

### Step 5b: Check Review Results

Read the review file at `${scratch_dir}/kimix-exec-review-<PLAN_ID>-<pr.id>.md`. Count issues with `Status: open`.

For each open issue found, extract a concise one-line description and append it to `issue_patterns` (skip exact duplicates already in the list). These are accumulated across all PRs and all review rounds for the entire run, and used in Step 10 (Memory Flush).

Count open issues by severity (bug, suggestion, nit) and add the counts to `total_issues_by_severity`.

Increment `pr.review_rounds` (this counts total reviews performed, including the initial one).

**If 0 open issues:**
- The PR is done. Update status to `"completed"`, set `completed_at`.
- Persist the state file.
- Report: `"<pr.id> review: 0 issues found. PR complete."`
- Return to the execution loop (Step 4).

**If any open issues:**
- Enter a review-fix loop. Resume the implementer to fix (Step 5c), then
  resume the reviewer to re-review. Repeat until 0 open issues.
- There is no iteration cap. Every issue -- including nits and suggestions --
  must be addressed before the PR is marked completed.
- See Step 5c.

Report: `"<pr.id> review round <review_rounds>: <N> issues found (<X> bugs, <Y> suggestions, <Z> nits). Fixing..."`

### Step 5c: Fix Cycle

Resume the original implementer to fix all review issues:

`task` parameters:
- `subagent_type`: `"general-purpose"`
- `resume_from`: `<pr.subagent_id>`
- `description`: `"[implementer] Fix review issues for <pr.id>"`

Prompt:
```
The reviewer found issues. The review file is at:
${scratch_dir}/kimix-exec-review-<PLAN_ID>-<pr.id>.md

Read the review file. Address ALL issues with Status: open -- including nits,
suggestions, and any style or hint-level feedback. Nothing is too small to fix.

For each issue, implement the fix, then update the review file:
- Change Status: open -> Status: fixed
- Add a Response field explaining what you changed

You are encouraged to push back on feedback that doesn't make sense, is
contradictory, or would make the implementation worse. If you disagree with
an issue:
- Set Status: wontfix
- Write a clear, technical explanation of why the reviewer's suggestion is
  wrong or counterproductive
- Do NOT comply with feedback just to make a reviewer happy -- defend good
  implementation decisions

Commit all fixes:
git add -A
git commit -m "fix: address review feedback for <pr.title>"

<if user_instructions is non-empty, include the following block verbatim:>
## User Instructions
<user_instructions>
These instructions apply to all work in this plan. Follow them strictly.
<end if>
```

Wait for the implementer to complete. Update `pr.subagent_id` with the new returned id. Read the review file to note any issues the implementer marked `Status: wontfix` (needed for stalemate detection below).

After the fix, re-fetch the subagent's new commits using the same form as Step 4b (Rule 1 of the *Subagent Worktree Protocol*):
```bash
git fetch <worktree_path> HEAD --no-tags
```
Then update the commit SHA:
```bash
pr.commit_sha = $(git -C <worktree_path> rev-parse HEAD)
git cat-file -t <pr.commit_sha>   # must print "commit"
```
No destination refspec, no `--force` — both are unnecessary because `commit_sha` is what downstream steps use, and the subagent is the sole writer for this branch so the fetch is always a simple object pull.

Resume the reviewer to re-review.

`task` parameters:
- `subagent_type`: `"general-purpose"`
- `resume_from`: `<pr.reviewer_subagent_id>`
- `description`: `"[reviewer] Re-review <pr.id>: <pr.title> (round <review_rounds

…(truncated)
