- name
- plan-orchestrate
- description
- Execute implementation plans with parallel TDD workers. Use when ready to run, execute, or start a plan. Triggers on "run the plan", "execute the plan", "implement the plan", "start the plan", "start implementation", "orchestrate", "begin autonomous execution". Requires a plan created by plan-create.
- model
- sonnet
- argument-hint
- [plan-name]
- allowed-tools
- Read, Write, Edit, Bash, Glob, Grep, Task
# Plan Orchestrate
Execute all tasks in a plan using parallel TDD workers. Fully autonomous after invocation.
## Usage
```
plan-orchestrate {plan-name}
```
Example: `plan-orchestrate user-auth`
## Prerequisites
**First, resolve the plans directory,** once, and reuse `$PLANS_DIR` for every path below. It is `.claude/plans` unless the project overrides it in `.claude/hcf.json` (see [Plans Directory](#plans-directory) in the README). The script answers with an absolute path resolved from the project root, so the result does not depend on the working directory:
```bash
PLANS_DIR="$("{skill-base-dir}/../../hooks/resolve-plans-dir.sh")" || exit 1
```
**Never substitute a hand-written `jq` line or a literal `.claude/plans`.** A non-zero exit means the project root or the configured value is unusable; surface the script's stderr verbatim and stop. Quote every path built from `$PLANS_DIR` — a configured directory may contain spaces.
Then:
1. Plan must exist at `$PLANS_DIR/{plan-name}/`
2. Project must be configured (`.claude/testing.md` exists)
3. Plan status must be `ready` or `in_progress`
Check prerequisites:
```bash
ls "$PLANS_DIR/{plan-name}/_plan.md" .claude/testing.md 2>/dev/null
```
If not found, output error and stop.
4. Must be on the correct feature branch
Verify the current branch matches `feature/{plan-name}`:
```bash
git branch --show-current
```
If the current branch is not `feature/{plan-name}`:
- Output an error explaining which branch is expected
- Ask the user if they'd like to check out `feature/{plan-name}`
- Do NOT proceed until on the correct branch
## Project Configuration
<testing>
@.claude/testing.md
</testing>
<code-standards>
@.claude/code-standards.md
</code-standards>
## Execution Algorithm
### Step 0: Suggest Unattended Completion via /goal
Claude Code's built-in `/goal` command keeps a session working toward a
verifiable end state — its evaluator runs after each turn and pushes execution
to continue until the condition is met. Only the user can set a goal (`/goal`
is a user-typed command and cannot be invoked from a skill), so surface a
copy-pasteable tip and continue immediately. This is informational, never a
gate — do not wait for a response.
Display:
```
Tip: for large plans, you can keep this run going unattended with Claude Code's
built-in /goal command (interrupt me now to set it, or set it before a future run):
/goal the {plan-name} plan run reached a terminal state: plan-orchestrate output ALL_TASKS_COMPLETE or TASKS_BLOCKED
Either way, an interrupted run resumes from disk — just re-run plan-orchestrate {plan-name}.
```
The suggested condition deliberately names **both** terminal outputs. A goal
phrased as only `ALL_TASKS_COMPLETE` leaves the evaluator demanding more turns
after a legitimately blocked run, when the correct behavior is to stop and
report the blockage.
### Step 1: Load Plan Context
Read plan files:
- `$PLANS_DIR/{plan-name}/_plan.md` - Plan overview
- `$PLANS_DIR/{plan-name}/*.md` - All task files (excluding _plan.md)
Note: Testing and code standards are auto-included above.
Parse each task file to extract:
- Task number (from filename)
- Status (pending | in_progress | completed | blocked)
- Dependencies (from `Depends on` field)
- Requirements (checkboxes)
- Retry count
Build a dependency graph as a data structure.
### Step 2: Update Plan Status
If plan status is `ready`, change to `in_progress`:
- Edit `$PLANS_DIR/{plan-name}/_plan.md`
- Set `## Status` to `in_progress`
**Establish the run fingerprint.** Every hook call below passes this back via
`--expect=`, so that agent files changing mid-run halt the orchestration rather
than silently swapping the pipeline. Read
`$PLANS_DIR/{plan-name}/.hook-fingerprint` and handle three distinct states —
conflating them is the mistake to avoid:
| State | Action |
|-------|--------|
| **Present and parseable** (one line: `discover-hooks-fingerprint-v1 <64-hex>`) | Use it as `$RUN_FINGERPRINT`. Pass the file's contents **verbatim** — do not trim, reformat, or re-derive them. |
| **Missing** | Not an error. Plans created before this feature have none. Capture one and write it to the plan directory so a resumed run is covered too, then continue: `"{skill-base-dir}/../../hooks/discover-hooks.sh" --fingerprint > "$PLANS_DIR/{plan-name}/.hook-fingerprint"` |
| **Present but unparseable** (empty, truncated, prose, wrong length) | **Halt.** Do not silently recapture — that would mask a botched write. Tell the user to delete the file to re-baseline. |
**Never reconstruct, abbreviate, or recall a fingerprint from memory.** It is
only ever produced by running the script. A hallucinated digest fails every
subsequent hook with bogus drift and bricks the run.
### Step 2a: Pre-Implementation Hook
Run the `pre-implementation` hook **once**, after the status is set to
`in_progress` and **before** the first batch is launched.
Resolve and run enrolled agents via the **HOOKS.md discovery routine** (see
[Hook Discovery](#hook-discovery) below) with `HOOK = pre-implementation`. Pass
each agent the project context as described in
[Spawning hook agents](#spawning-hook-agents).
**Exit 0 with empty stdout** is an empty hook: return immediately, log nothing,
do no work, and proceed to Step 3. **Any non-zero exit stops the run** — see
[Hook Discovery](#hook-discovery) for the full result table.
### Step 3: Find Ready Tasks
Execution is a **rolling** loop, not a lockstep one. Each task starts as soon as
its own dependencies are complete; it never waits for unrelated tasks that
happened to start alongside its dependencies. Track a **running set** — the
tasks with a worker in flight in this session.
A task is **ready** when:
- Status is `pending` (an `in_progress` task from an interrupted run counts as
pending — see [Task Already In Progress](#task-already-in-progress))
- ALL dependencies have status `completed`
- It is **not** in the running set
```
ready_tasks = []
for each task in tasks (in task-number order):
if task.status == "pending" and task not in running:
if all(dep.status == "completed" for dep in task.dependencies):
ready_tasks.append(task)
```
### Step 4: Check Termination Conditions
**All Complete:**
```
if all(task.status == "completed" for task in tasks):
Run Step 4a: End-of-Run Hooks (quality gates + commit sequence before final completion)
STOP
```
**Waiting:**
```
if len(ready_tasks) == 0 and len(running) > 0:
# Nothing new can start yet, but workers are in flight
Go to Step 6 and wait for the next completion
```
**Blocked State:**
```
if len(ready_tasks) == 0 and len(running) == 0:
if any(task.status == "pending" for task in tasks):
# Tasks exist but none are ready and nothing is running - dependency deadlock or all blocked
blocked_tasks = [t for t in tasks if t.status == "blocked"]
Output: TASKS_BLOCKED: {list blocked task numbers and reasons}
STOP
```
## Hook Discovery
All hooks in this skill (`pre-implementation`, `pre-batch`, `post-batch`,
`post-implementation`, `pre-commit`, `post-commit`) resolve their enrolled
agents by running **`hooks/discover-hooks.sh`**, the single implementation of
[HOOKS.md → Discovery Routine](../../HOOKS.md#discovery-routine). **Never
enumerate agent files by hand and never write a glob loop to do it.** For a
given `HOOK`:
```bash
"{skill-base-dir}/../../hooks/discover-hooks.sh" --hook=<HOOK> --expect="$RUN_FINGERPRINT"
```
`{skill-base-dir}` is the **`Base directory for this skill`** value stated when
this skill loaded — it is given verbatim, so no path inference is needed.
`${CLAUDE_PLUGIN_ROOT}` is **not** available in a skill's Bash calls.
`$RUN_FINGERPRINT` is the value established at [Step 2](#step-2-update-plan-status).
Then, by result:
- **Exit 0, empty stdout → empty hook.** Return immediately — no staging, no
diffing, no spawns, and **no logging or narration**. "No narration" is literal
and is the rule most often broken: do not name the hook, do not say it is
empty/skipped, do not explain *why* it is empty, and **do not say the
discovery script returned no agents**. A filtered query prints zero bytes
precisely so there is nothing to echo. An empty hook is **completely
invisible** in the user-facing output. See [HOOKS.md → Empty-hook fast
path](../../HOOKS.md#empty-hook-fast-path).
- **Exit 0, output → PRINT it verbatim** as the resolved order, then spawn.
- **Exit 1 or 2 → stop the run.** Surface stderr verbatim.
- **Exit 3 → stop the run.** An agent file declares an invalid `phase` or
`mode`. Surface stderr verbatim; it names the file and the fix.
- **Exit 4 → halt HCF.** Hook enrollment changed since this run started, so the
remaining hooks would execute a different pipeline than the plan was reviewed
against. Surface stderr verbatim. Stop launching (see
[Stopping mid-run](#stopping-mid-run)) and do **not** commit.
- **Script missing or not executable → hard failure.** Say so and stop. There is
no prose fallback; reconstructing the routine by hand is the failure this
design exists to end.
**Only exit 0 with empty stdout is an empty hook.** Every other non-zero exit is
an error to report loudly.
On a normal (exit 0, non-empty) result, spawn each agent per its **`mode` field**
(`single` → one subagent for the whole plan; `batch` → split the relevant file
list into batches of ~10 and spawn parallel subagents, one Task call per
batch, all in a single message). The spawn mode comes from the agent's `mode`
frontmatter field — never from sniffing the agent body text.
### Spawning hook agents
Hook agents are spawned with the Task tool using `subagent_type="{agent-name}"`.
The orchestrator only has `<testing>` and `<code-standards>` in context (see
[Project Configuration](#project-configuration)) — it does NOT have
`<architecture>`. Pass each hook agent the project context it needs verbatim:
> **CRITICAL: Pass the COMPLETE, VERBATIM content of the `<code-standards>` and
> `<testing>` tags above. Do NOT summarize, condense, or paraphrase. The full
> documents contain nuanced rules that are lost when summarized. Copy-paste the
> entire content between the tags.**
For a **`batch`** agent, send one prompt per batch:
```markdown
## Code Standards
{paste the COMPLETE content of <code-standards> verbatim — do NOT summarize}
## Testing Standards
{paste the COMPLETE content of <testing> verbatim — do NOT summarize}
## Files to Review
{list of files in this batch, one per line}
```
For a **`single`** agent, send one prompt covering the whole plan, including the
plan name, the changed-files list, and `<testing>` + `<code-standards>` verbatim.
> If a hook agent needs project architecture, that is out of scope for this
> orchestrator — it does not load `<architecture>`. Do NOT fabricate an
> `## Project Architecture` paste here.
### Step 4a: End-of-Run Hooks (Post-Implementation → Tests → Commit)
When all tasks are complete, run the end-of-run hook sequence. The control flow
is strictly:
**post-implementation → run full test suite → pre-commit → commit → post-commit**
> **CRITICAL INVARIANT: NOTHING is committed until AFTER the full test suite
> passes.** This ensures no broken code is ever committed. The `pre-commit` hook
> runs *after* tests pass and *before* the commit; `post-commit` runs *after*
> the commit and *before* the push/PR prompt.
**1. Run the `post-implementation` hook:**
Resolve and run enrolled agents via the [Hook Discovery](#hook-discovery)
routine with `HOOK = post-implementation`. To give batch agents a file list,
first compute the changed files (this stages everything only to read the list,
then unstages — nothing is committed). The plans directory is left out: plan
files are working state, not code for agents to review.
```bash
git add -A && git reset -q -- "$PLANS_DIR" && git diff --name-only --cached && git reset HEAD
```
Then spawn the resolved agents per their `mode` (see
[Spawning hook agents](#spawning-hook-agents)). **Exit 0 with empty stdout** is
an empty hook: return immediately, no logging, no work, and proceed to step 2.
**Any non-zero exit stops the run** — see [Hook Discovery](#hook-discovery).
**2. After ALL post-implementation agents complete, run validation:**
```bash
# Run full test suite
{parallel test command from testing.md}
```
> **CRITICAL: Nothing is committed until AFTER the full test suite passes.** This ensures no broken code is ever committed.
**3. On test failure** — isolate the cause (see
[Test-failure isolation](#test-failure-isolation) below), then either commit the
implementation only or output `TASKS_BLOCKED`.
**4. On tests passing — run the `pre-commit` hook:**
Resolve and run enrolled agents via [Hook Discovery](#hook-discovery) with
`HOOK = pre-commit`. These run *after* the suite passes and *before* the commit.
**Exit 0 with empty stdout** is an empty hook (silent no-op); **any non-zero
exit stops the run before the commit** — see [Hook Discovery](#hook-discovery).
> If a `pre-commit` agent modifies files, those edits are part of this commit. A
> pre-commit agent that changes files could break tests; that risk is covered by
> the [Test-failure isolation](#test-failure-isolation) stash, which now spans
> both post-implementation and pre-commit hook output.
**5. Commit:**
First, update `_plan.md` status to `completed`. Then stage and commit the implementation in a **single commit**, leaving the plans directory out:
```bash
# 1. Update plan status (local working state — it is not committed)
# (edit $PLANS_DIR/{plan-name}/_plan.md — set Status to "completed")
# 2. Stage implementation + hook agent fixes, then unstage the plans directory
git add -A
git reset -q -- "$PLANS_DIR"
git commit -m "feat({plan-name}): {plan title summary}"
```
> **IMPORTANT:** There must be exactly ONE commit here. **Never commit plan
> files.** Plans are ephemeral: once the work is committed, the code and its
> tests are the source of truth, and a plan kept in the repo goes stale
> alongside them. Unstaging `$PLANS_DIR` (rather than excluding it with a
> pathspec) works whether the directory is untracked, gitignored, or was
> committed by an older HCF version.
**6. After the commit succeeds — run the `post-commit` hook:**
Resolve and run enrolled agents via [Hook Discovery](#hook-discovery) with
`HOOK = post-commit`. These run *after* the commit and *before* the push/PR
prompt (the [Output Summary](#output-summary) at the end of this skill).
**Exit 0 with empty stdout** is an empty hook (silent no-op); **any non-zero
exit is reported loudly** — see [Hook Discovery](#hook-discovery). The commit
has already happened, so report the failure rather than trying to undo it.
> **`post-commit` agents that produce uncommitted changes are REPORTED, not
> silently committed.** The commit above already happened; do not amend or
> create a second commit. Surface any working-tree changes a post-commit agent
> left behind so the user can decide what to do.
Output: `ALL_TASKS_COMPLETE`
#### Test-failure isolation
If the full test suite fails at step 3 (or after pre-commit edits), isolate
whether the **hook agents** (any `post-implementation` or `pre-commit` agent
that edited files) broke things versus the implementation itself. The git stash
isolation spans **both** the post-implementation and pre-commit hook output:
```bash
git stash
Voir sur GitHub