r-build · git:20260924.dad7868 · 2026-09-24 · sha256 c74cacab207a0fe3
r-build git:20260924.dad7868A
Immutable. This exact content never changes and is served at /api/v1/blob/c74cacab207a0fe3.
---
name: r-build
description: >
Use when a plan exists and you want it built: dispatches the plan-execution orchestrator (engineer/QA/review gates) per phase at the right tier.
---
You are the build command. You prepare context and dispatch the
dispatcher subagent to execute an implementation plan.
## Invocation
`/rdf:r-build [N | N-M | --parallel] [--worktree] [--max N] [--consistency-warn-only "<reason>"]`
Arguments:
N — single phase (existing behavior)
N-M — range of phases (e.g., 1-4) — dispatch in parallel
--parallel — auto-batch all pending phases by dependency graph
--worktree — force git worktree isolation (overrides auto-derivation)
--max N — maximum concurrent dispatchers (default: 4)
--consistency-warn-only "<reason>" — downgrade a consistency-gate structural
block to a warning; requires a stated reason (see Section 1)
(no args) — next pending phase, serial (existing behavior)
## Protocol
### 1. Locate and Validate the Active Plan
- Source `~/.rdf/state/rdf-bus.sh` and call `rdf_session_init`. If the helper
is absent (helpers not yet bootstrapped — fresh plugin install before its
first session restart), stop and tell the user: `/rdf:r-build` needs the
`~/.rdf/state` helpers — restart your session so the RDF plugin can
bootstrap them, or run `rdf deploy claude-code` from a checkout.
- `plan_path="$(rdf_active_plan_path)"` — resolves via three-tier
fallback (session pointer → un-suffixed pointer → root PLAN.md).
- If `$plan_path` is empty, report error and stop:
"No active plan found. Create one with /rdf:r-plan or write it manually,
then run /rdf:r-plan --resume <path> to set the pointer."
- `tier="$(rdf_active_tier)"` — resolve the plan's task-class tier
(`full` when no `**Tier:**` marker); carried into the Section 5
dispatch payload so the dispatcher can cap gates.
- Read `$plan_path` as the plan input from here forward. Validate
the plan against
[reference/plan-schema.md](../reference/plan-schema.md). Apply
Plan-Version Awareness first, then Rules 1-9 in order. On the first
violation, print the rule number and the exact failure message from
the schema doc, then stop without dispatching.
Rule 9 (test-count self-consistency) is conditional — it fires only
when a phase contains an explicit test-count assertion. Apply the same
trigger check as `/rdf:r-plan` Step 2.7: scan each phase's `**Test**`
field and step prose for an integer adjacent to a test noun; if found
and not marked `TODO`, verify the declared count matches the `@test`
references in the phase body. On mismatch, stop with the Rule 9
failure message before dispatching.
/rdf:r-plan Step 2.7 should have caught any schema violations before the
plan was committed. If validation fails here, the plan was authored
manually, edited after planning, or the pre-reviewer pass was skipped
— either fix the plan and re-run /rdf:r-build, or re-run /rdf:r-plan to
regenerate.
- **Consistency micro-gate (spec↔plan↔tasks).** After schema validation,
run the deterministic cross-check:
```bash
bash ~/.rdf/state/rdf-consistency.sh check "$plan_path"
```
(If a source spec is known, pass it as the second argument for goal /
edge-case coverage.) Exit 2 = structural break (File-Map/phase mismatch
or phase-count mismatch) → print the findings and STOP without
dispatching (fix via `/rdf:r-plan`). Exit 1 = advisory drift (uncovered
goal/edge case, missing `**Goals:**` field, tier-size) → surface the
findings and proceed. Exit 0 = clean. Spec Kit `/analyze` precedent;
mechanical checks only.
**Escape hatch.** For a rare legitimate structural false-positive (an
intentional File-Map entry a reviewer approved), re-run with
`~/.rdf/state/rdf-consistency.sh check --warn-only "$plan_path"` to downgrade
the exit-2 block to an exit-1 warning. Using `--warn-only` REQUIRES the
operator to state the reason in the `/rdf:r-build` invocation (e.g.
`/rdf:r-build --consistency-warn-only "reason: File-Map intentionally lists
the generated foo.sh"`) — exit-2-with-no-override is too brittle for
real plans.
### 2. Identify Target Phase
- If `$ARGUMENTS` contains a number N: target Phase N
- If Phase N does not exist in the active plan, report error and stop
- If Phase N has `Status: complete`, warn and ask for confirmation
- If no argument: scan phases in order, target first with
`Status: pending`
- If all phases are complete, report "All phases complete. Use
/rdf:r-ship for release workflow." and stop
- If a phase has `Status: in-progress`, warn that a phase is
already in progress and ask for confirmation before restarting it
### 2b. Identify Parallel Batch
If arguments contain a range (N-M) or --parallel:
1. Read Phase Dependencies from the active plan preamble
- Parse structured list: `- Phase N: none` or `- Phase N: [deps]`
- If no structured list found, fall back to serial with warning:
"Phase Dependencies section not in structured format. Running
serially. Use the format: `- Phase N: none` or `- Phase N: [1, 2]`"
2. Determine target phases:
- Range (N-M): phases N through M inclusive
- --parallel: all phases with Status: pending
- If any phase has Status: in-progress, warn and ask:
"Phase {N} is in-progress (may be from a prior session).
Include in parallel batch? [Y/skip/abort]"
3. Compute parallel batches from dependency graph:
- A phase is eligible for a batch when all its dependencies are
complete (already done or in a prior batch)
- Phases with `none` dependencies are eligible for the first batch
- Group eligible phases into batches, respecting --max ceiling
- Result: ordered list of batches, each batch is a set of
independent phases
4. Validate file ownership within each batch:
- For each batch: collect all files from all phases in the batch
- Parse the **Files:** field from each phase: extract paths from
lines matching `Create: \`path\``, `Modify: \`path\``, or
`Delete: \`path\``. This is a best-effort heuristic — if paths
cannot be extracted (free-form text), skip validation with
warning: "Cannot parse file list for Phase {N}. Proceeding
without file ownership validation."
- If any file appears in more than one phase: split conflicting
phases into separate batches, warn:
"Phases {N} and {M} both modify {file}. Serializing."
- Re-validate after splitting
5. Derive isolation level per batch:
- For each phase in the batch, derive scope classification
(same rules as dispatcher: file list + description + governance)
- Batch isolation = highest scope in the batch:
scope:multi-file or below → parallel-agent (file-gated)
scope:cross-cutting or sensitive → parallel-worktree
- If --worktree flag is set: force parallel-worktree regardless
6. Present dispatch plan to user:
"Parallel dispatch plan:
Batch 1 (parallel, {isolation}): Phases {list}
Batch 2 (serial): Phase {N} (depends: batch 1)
Batch 3 (parallel, {isolation}): Phases {list}
Batch 4 (serial): Phase {N} (depends: all)
{total phases} phases in {total batches} batches. Proceed? [Y/n]"
Wait for user confirmation.
### 3. Create Task List
Read all phases from the active plan (`$plan_path`) and create a task for each one:
```
For each phase in the active plan, in phase order, one TaskCreate per message:
TaskCreate:
subject: "Phase {N}: {description}"
activeForm: "Building Phase {N}: {short desc}"
Mark already-complete phases as completed immediately.
Mark target phase as in_progress before dispatching.
Mark target phase as completed when dispatcher returns PASS.
```
Issue each `TaskCreate` in its own message — see
[reference/progress-tracking.md](../reference/progress-tracking.md).
Do NOT batch phase TaskCreates in a single message: parallel
execution produces non-deterministic display order (e.g. Phase 1,
7, 6, 5, 3, 4, 2 instead of 1-7).
### 4. Load Governance Context
- Read `.rdf/governance/index.md`
- If governance index does not exist, warn: "No governance found.
Run /rdf:r-init to generate governance, or proceed without it."
- Load all governance files unconditionally:
- conventions.md, constraints.md, verification.md,
anti-patterns.md, architecture.md
- Read the current operational mode (if `.rdf/governance/index.md`
has a Mode field other than "development")
### 5. Assemble Dispatch Payload
Build the dispatch prompt for the dispatcher subagent:
```
PHASE: <N>
DESCRIPTION: <phase description from the active plan>
MODE: <execution mode tag: serial-context | serial-agent | parallel-agent>
TIER: <rdf_active_tier — full|quick-plan|bugfix, read at Section 1>
FILES: <file list from the active plan>
ACCEPT: <acceptance criteria from the active plan>
PLAN_PHASE_COUNT: <total phases in the active plan>
PARALLEL_BATCH: <true if dispatched as part of parallel batch, false otherwise>
GOVERNANCE:
index: .rdf/governance/index.md
conventions: .rdf/governance/conventions.md
constraints: .rdf/governance/constraints.md
verification: .rdf/governance/verification.md
anti-patterns: .rdf/governance/anti-patterns.md
architecture: .rdf/governance/architecture.md
OPERATIONAL_MODE: <mode or "development">
PROJECT_ROOT: <absolute path to project root>
```
### 6. Dispatch Dispatcher Subagent
Dispatch the `rdf-dispatcher` subagent with the assembled payload.
The dispatcher handles all execution from here: TDD cycles, engineer
dispatches, quality gates, commit strategy.
### 6b. Dispatch Parallel Batch
Before any worktree creation, source `~/.rdf/state/rdf-bus.sh` and call
`rdf_session_init` to ensure `RDF_SESSION_ID` is set. Each Bash call is a
fresh shell, so every block below that uses `${RDF_SESSION_ID}` starts with
`source ~/.rdf/state/rdf-bus.sh && rdf_session_init` in the same call.
Worktree paths and branch names use the full session id for collision-free
identification across concurrent sessions on the same repository (a resumed
session can reuse its id — see session-safety.md).
For each batch in the dispatch plan (sequential between batches,
parallel within each batch):
**File-gated dispatch (parallel-agent):**
1. Create task per phase in the batch
2. Dispatch N rdf-dispatcher subagents simultaneously
- Each gets the standard dispatch payload (Section 5) plus:
PARALLEL_BATCH: true
- Each operates on the shared working tree
- File ownership enforced by the plan (validated in 2b.4)
3. Wait for all subagents in the batch to complete
4. Collect results: PASS or FAIL per phase
**Worktree dispatch (parallel-worktree):**
1. Create task per phase in the batch
2. For each phase, create a git worktree. A retry (Option 2) or a resume
(Option 3) in the same session reuses the session id, so first clear
any leftover worktree and branch for this phase, logging the branch tip
so a failed attempt's commits stay recoverable (`git branch <name> <tip>`):
```
source ~/.rdf/state/rdf-bus.sh && rdf_session_init
[ -n "$RDF_SESSION_ID" ] || { echo "rdf: no session id; refusing worktree setup" >&2; exit 1; }
root="$(cd "$(git rev-parse --git-common-dir)/.." && pwd)" || exit 1
wt="${root}/.worktrees/rdf-phase-{N}-${RDF_SESSION_ID}"; br="rdf/phase-{N}-${RDF_SESSION_ID}"
if tip=$(git rev-parse --verify -q "refs/heads/$br"); then
echo "removing leftover $br (tip $tip)"
git worktree remove --force "$wt" 2>/dev/null || true # worktree may already be gone
git branch -D "$br"
fi
git worktree add "$wt" -b "$br" HEAD
```
(RDF_SESSION_ID is the full session id; prevents cross-session collisions)
After the batch's `git worktree add` calls, activate the phase scope
guard from the main worktree (idempotent; once per batch is enough):
```
source ~/.rdf/state/rdf-bus.sh
rdf_phase_hook_install "$(git rev-parse --show-toplevel)" \
|| echo "warn: phase scope guard (layer 1) not installed; post-merge scope check still applies" >&2
```
The helper copies `~/.rdf/state/git-hooks/pre-commit` (RDF
self-hosting: `state/git-hooks/pre-commit`) into the repo's
`rdf-hooks/` and adds an `includeIf "onbranch:rdf/phase-**"` include,
so the hook runs on phase branches only and chains the project's own
hooks; rc 2 means git < 2.23. The hook enforces phase scope
(Files ∪ Tests-may-touch) at `git commit` time. See `plan-schema.md`
Rule 8 and dispatcher.md "Worktree Pre-Commit Hook Installation".
3. Before each `Task` dispatch, the controller MUST change directory
into the target worktree:
```
cd .worktrees/rdf-phase-{N}-${RDF_SESSION_ID}
```
The `Task` tool inherits the controller's CWD; the SDK picks an
adjacent repo non-deterministically when CWD has no `.git/`
(see workspace CLAUDE.md "Worktree CWD"). This `cd` is the
actual mechanism that closes the non-deterministic-CWD class.
For parallel dispatches in a batch, the controller serializes
the `cd → Task` pair per-phase (parallelism comes from the
`Task` calls returning before the subagent finishes, not from
simultaneous `cd`s).
Then dispatch N rdf-dispatcher subagents simultaneously:
- Each gets the standard dispatch payload plus:
PARALLEL_BATCH: true
PROJECT_ROOT: {worktree path}
PROJECT_ROOT_MAIN: {main worktree toplevel}
- Each dispatched with isolation: "worktree"
4. Wait for all subagents in the batch to complete
5. Merge completed worktrees in plan order:
For each completed phase (in plan order, N ascending):
git rebase {base-branch} rdf/phase-{N}-${RDF_SESSION_ID}
Where {base-branch} is the branch HEAD was on when worktrees were
created (captured at step 2 of worktree dispatch).
git merge --ff-only rdf/phase-{N}-${RDF_SESSION_ID}
This produces a clean linear history — phase commits appear in
plan order with no merge commit artifacts.
If rebase conflict: stop, report conflicting phases, enter
failure handling (Section 8)
6. Clean up worktrees:
git worktree remove .worktrees/rdf-phase-{N}-${RDF_SESSION_ID}
git branch -d rdf/phase-{N}-${RDF_SESSION_ID}
7. Collect results: PASS or FAIL per phase
**Constraint:** Worktree dispatch MUST be invoked from a top-level
session, not from a subagent. Subagents inherit `RDF_SESSION_ID`
from their parent and would create colliding worktree paths.
The `PARALLEL_BATCH` downgrade in `dispatcher.md` (lines 45-49)
already prevents nested parallel dispatch; this is its
worktree-specific explicit form.
**Post-batch quality gate (worktree dispatch only):**
After merging all worktrees in a batch, run a batch-level QA check:
- Dispatch rdf-qa subagent across the combined diff of all phases
in the batch
- This catches semantic conflicts that file ownership validation
cannot detect (e.g., two phases both adding the same function name
to different files)
- If QA finds issues: enter failure handling (Section 8)
**Progress tracking:**
Write batch progress to `.rdf/work-output/build-progress-${RDF_SESSION_ID}.md`
(derived via `rdf_scoped_filename` from `~/.rdf/state/rdf-bus.sh`):
DISPATCH_MODE: parallel
TOTAL_PHASES: {N}
TOTAL_BATCHES: {N}
CURRENT_BATCH: {N}
BATCH_PHASES: [list]
COMPLETED_PHASES: [list]
FAILED_PHASES: [list]
After each batch completes, update and proceed to the next batch.
After all batches complete, proceed to end-of-plan sentinel
(unchanged — runs on cumulative diff from phase 1 to HEAD).
### 7. Report Result
After the dispatcher returns:
- Read the dispatcher's status output from .rdf/work-output/
- Report phase result to the user: PASS (phase complete) or FAIL
(with failure context and which gate failed)
- If PASS and more phases remain:
> **Phase {N} complete** — {description}
> Next: Phase {N+1} — {description}. Run `/rdf:r-build` to continue.
- If PASS and all phases are complete:
- If PLAN_PHASE_COUNT >= 3: the dispatcher runs end-of-plan sentinel
automatically (this is dispatcher-internal — the build command
does not dispatch it separately)
> **All {N} phases complete.** End-of-plan review: {verdict}.
> Run `/rdf:r-ship` to begin the release workflow.
- If PLAN_PHASE_COUNT < 3:
> **All {N} phases complete.**
> Run `/rdf:r-ship` to begin the release workflow.
### 8. Parallel Failure Handling
When one or more phases in a parallel batch fail:
1. Wait for all phases in the batch to complete (do not interrupt
running phases on peer failure)
2. Classify each failure:
- Gate 1 (engineer self-report) failure → recommendation: retry
- Gate 2 (QA) failure → recommendation: retry
- Gate 3 (sentinel) MUST-FIX → recommendation: retry
- Gate 3 (sentinel) architectural concern → recommendation: pause
- Merge conflict → recommendation: serialize conflicting phases
- Post-batch QA failure → recommendation: pause
3. Present to user with Recommendation:
"Batch {N} results:
[PASS] Phase 1: Replace dispatcher gate selection
[FAIL] Phase 2: Update agent finding vocabularies (Gate 2: lint)
[PASS] Phase 3: Simplify r-plan metadata
[PASS] Phase 4: Simplify r-build dispatch payload
Phase 2 failed at Gate 2 (QA lint error).
**Recommendation: retry** — lint errors are typically fixable.
Options:
[1] Merge phases 1, 3, 4 now — retry phase 2 after merge
[2] Retry phase 2 in isolation (attempt 2/3)
[3] Pause — review failure before proceeding"
4. Execute user's choice:
- Option 1: Merge successful phases in plan order, then dispatch
phase 2 serially against new HEAD
- Option 2: Re-dispatch phase 2's dispatcher subagent (same
isolation level, max 3 total attempts); worktree dispatch clears the
failed attempt's worktree and branch first (step 2)
- Option 3: Write progress to
`build-progress-${RDF_SESSION_ID}.md`, stop. User can resume
with `/rdf:r-build --parallel` (which calls `rdf_session_init`
and reads the scoped progress file); in the same session (or after
`claude --resume <id>`) the id matches, and step 2 clears the paused
phase's leftover worktree before re-dispatching it.
## Constraints
- Never execute plan phases directly — always dispatch to dispatcher
- Never modify the active plan — the dispatcher updates phase status
- If governance is missing, dispatch anyway (dispatcher degrades
gracefully) but warn the user
- Respect the plan's execution mode tags — pass them through unchanged
- Parallel dispatch is additive — /rdf:r-build N (single phase) works unchanged
- Nested parallel downgrade: dispatchers in parallel batches receive PARALLEL_BATCH: true