| name | deft-directive-swarm |
| description | Parallel local agent orchestration. Use when running multiple agents on story-level vBRIEFs simultaneously — to scan active/ for allocatable work, set up isolated worktrees, launch agents with proven prompts, monitor progress, handle stalled review cycles, and close out PRs cleanly.
|
Deft Directive Swarm
Structured workflow for a monitor agent to orchestrate N parallel local agents working on story-level vBRIEFs from vbrief/active/.
Legend (from RFC2119): !=MUST, ~=SHOULD, ≉=SHOULD NOT, ⊗=MUST NOT, ?=MAY.
⚠️ See also: swarm.md | deft-directive-review-cycle
Platform Requirements
! This skill requires GitHub as the SCM platform and the GitHub CLI (gh) to be installed and authenticated. Issue fetching, PR creation, and post-merge verification all depend on gh.
Branch-Protection Policy Guard
! Before any state mutation (creating worktrees, dispatching sub-agents, opening PRs), run the skill-level branch-policy guard documented in scripts/policy.py / scripts/preflight_branch.py (#746 / #747). Halt with the actionable disclosure message when the project's plan.policy.allowDirectCommitsToMaster is unresolvable AND DEFT_ALLOW_DEFAULT_BRANCH_COMMIT is unset:
uv run python scripts/preflight_branch.py --project-root . --quiet || exit 1
or invoke task verify:branch. The swarm skill creates branches per agent so the guard is mostly informational here, but a malformed PROJECT-DEFINITION (missing plan.policy block AND no legacy narrative) is a fail-closed signal worth surfacing before the swarm spawns N agents.
Deterministic Questions Contract
! Every numbered-menu prompt rendered in this skill (Phase 0 Step 0 queue-driven promote prompts (#1142 / N2), Step 0.5 bridge approval gate, Step 5 final-approval gate, Phase 1 Step 3 file-overlap audit gate, Phase 5->6 ready-to-merge gate) MUST follow ../../contracts/deterministic-questions.md: the final two numbered options MUST be Discuss and Back, in that order. The Discuss-pause semantic is documented verbatim there -- on Discuss selection the agent MUST halt the in-progress sequence immediately, prompt What would you like to discuss?, and resume only on an explicit user signal. Implicit resumption is forbidden.
When to Use
- User says "run agents", "parallel agents", "swarm", or "launch N agents on stories"
- Multiple independent story-level vBRIEFs in
vbrief/active/ need to be worked on simultaneously
- A batch of stories are ready and have no mutual dependencies
Running Swarms in Grok Build / Non-Warp Environments
Minimal runtime contract for running swarms outside Warp:
- One isolated git worktree per agent (identical to the Warp path — see Phase 2)
- Workers launched via
spawn_subagent dispatch (Phase 3 Step 2d)
- Monitor coordination via worktree-state polling (
git status, git log) and get_command_or_subagent_output
- Review-cycle sub-agents spawned via
spawn_subagent (not start_agent)
This path became first-class in #1342 (platform adapter slices 1-3) and is fully documented in Phase 3 Step 2d and Phase 4. Grok Build + Windows users should also see #1353 (§3.5 in templates/agent-prompt-preamble.md) for shell output capture limitations that affect get_command_or_subagent_output in PowerShell 5.1 contexts. Refs #1342, #1331.
~ Windows + Grok Build (#1353): When issuing shell commands via run_terminal_command on this platform, avoid |, >, or 2>&1 in the command string — use Python pathlib/subprocess or plain task targets instead to avoid wrapper leakage. See templates/agent-prompt-preamble.md §3.5 for the full escape hatch list.
Prerequisites
- !
vbrief/active/ contains one or more story-level vBRIEFs with status running
- ! GitHub CLI (
gh) is authenticated
- !
git supports worktrees (git worktree available)
- ~
oz CLI available (for oz agent run-cloud cloud launch — see Phase 3 Step 2c)
Phase 0 — Allocate
! Before assigning work to agents, build the cohort from the triage queue (queue-driven per #1142 / N2; see Step 0 below), then read project state and plan allocation against the activated cohort.
Headless cohort fast-path: low-ceremony launch (C1 / #1387)
! When the operator supplies a pre-approved cohort via the C1 task swarm:launch CLI, Phase 0 runs in headless / low-ceremony mode: the per-phase interactive approval gates (the Step 0c promote-fill prompts, the Step 0.5 lifecycle-bridge approval, and the Step 4/5 allocation approval) collapse into a SINGLE consent -- the ## Allocation context token (#1378) carried in the dispatch envelope. The interactive promote-fill loop (Step 0a -- 0d below) is SKIPPED.
! The C1 signature is task swarm:launch -- --stories <ids|paths> [--group <label>] [--worktree-map <path>] [--base-branch <branch>] [--autonomous]. --stories names the pre-approved story ids or vBRIEF paths; --group is an optional cohort label; --worktree-map points at the pre-created C3 worktree-map JSON consumed in Phase 2; --base-branch overrides the default master; --autonomous runs without the interactive launch confirmation.
! The SINGLE consent is the #1378 ## Allocation context token with dispatch_kind: swarm-cohort and a NON-NULL allocation_plan_id AND batching_rationale (the recognition contract in templates/agent-prompt-preamble.md § 2.5). That token IS the batched approval for the whole cohort -- the deterministic-question gates the interactive path runs (per ../../contracts/deterministic-questions.md) are bypassed wholesale on the headless path, not asked once per phase.
⊗ Re-prompt the operator for per-phase batching approval, or run the interactive promote-fill loop (Step 0a -- 0d), when a pre-approved cohort is supplied via task swarm:launch -- the headless path's single #1378 consent already authorizes the batch, and re-prompting mid-cohort violates the all-or-nothing dispatch-envelope rule (#954).
? The interactive queue-driven path (Step 0 below) remains the DEFAULT when no pre-approved cohort is supplied; the headless fast-path is the opt-in low-ceremony route for a cohort the operator has already curated and approved upstream.
Step 0: Queue-driven cohort selection (#1142 / N2)
! Phase 0 is queue-driven: consult the triage cache (D2 / #1122 + D11 / #1128) for the ranked promotion candidates, then fill the WIP cap. Do NOT pick the cohort by hand from vbrief/pending/ or vbrief/active/ -- the queue is the canonical record of "what's next?" per AGENTS.md ## Cache-as-authoritative work selection (#1149). The four sub-phases below run in canonical order; existing Step 0.5 (lifecycle bridge) and Steps 1-5 (readiness / blockers / allocation / present / approval) proceed unchanged after Phase 0d.
Phase 0a -- State overview via task triage:summary (D2 / #1122)
- ! Run
task triage:summary to emit the current triage-cache one-liner ([triage] N untriaged ... WIP X/Y [⚠]). The monitor uses the result to:
- confirm the cache is fresh enough to act on (the D5 / #1127
task verify:cache-fresh warning is silent on a fresh cache; D2's one-liner is the human-readable parallel for the operator);
- read the current
pending/ + active/ count against the configured wipCap (default 10 per umbrella #1119 Current Shape v3, exposed via plan.policy.wipCap).
- ! If the summary reports an empty cache (no candidates ever ingested), surface the bootstrap remediation (
task triage:bootstrap or the N3 / #1143 onboarding ritual task triage:welcome) and HALT Phase 0 -- there is no queue to drive cohort selection from.
task triage:summary
# [triage] 12 untriaged · 3 in-flight · WIP 4/10
Phase 0b -- Ranked candidates via task triage:queue (D11 / #1128)
- ! Run
task triage:queue --state=accept --limit=20 to surface the top-20 ranked promotion candidates. The queue is grouped ([RESUME] -> [URGENT] -> untriaged -> other) and ordered by updated_at within group (D11); the --state=accept filter restricts to issues whose latest triage decision is accept (the canonical "promote-ready" subset).
- ! Treat the queue as authoritative. Do NOT supplement the list with agent recall, open-GitHub-issue intuition, or memory of recent commits -- the queue is the rank; swarm does not re-rank.
- ! Present the candidate list to the operator as a numbered table (issue number, title, age in queue, top-line ranking rationale).
task triage:queue --state=accept --limit=20
Phase 0c -- Promote-fill-cap loop
! While pending/ + active/ count < wipCap AND the queue is non-empty, prompt the operator to promote the next ranked candidate to vbrief/pending/.
Loop body, per candidate (top-of-queue first):
-
! Render the next queue candidate with brief context (issue title, labels, top-1 ranking rationale).
-
! Prompt the operator: Promote #<N> to vbrief/pending/? [yes/skip/stop]. The final two numbered options remain Discuss and Back per ../../contracts/deterministic-questions.md.
-
On yes -- promote via the canonical lifecycle verb:
# D18 #1136 fallback: the eventual --from-issue=<N> shape is OPEN but not
# yet implemented. Until #1136 lands, the monitor resolves the candidate's
# vBRIEF file from the issue number (file lives in vbrief/proposed/ from a
# prior triage:accept step, D10 / #1129) and passes the path to
# `task scope:promote`. Same lifecycle command, just routed through the
# file path rather than the issue-number shortcut.
task scope:promote vbrief/proposed/<file>.vbrief.json
# TODO(#1136): when D18 ships, replace the two-step (resolve file from #N,
# then pass to `task scope:promote`) with the deterministic one-step
# `task scope:promote --from-issue=<N>` invocation. The integration point
# is this Phase 0c loop body; the operator-facing prompt collapses from
# "Promote #<N>? [resolved to <path>]" to "Promote #<N>?" with the path
# resolution done inside the task.
Re-run task triage:summary (or read the post-promote count directly) to refresh the pending/ + active/ total before the next loop iteration.
-
On skip -- drop this candidate from the current session's cohort; it stays in the queue for the next session. Advance to the next ranked candidate.
-
On stop -- exit the loop early; the partial cohort proceeds to Phase 0d.
! D18 #1136 integration point: the eventual task scope:promote --from-issue=<N> shape (D18 / #1136) is OPEN but not yet implemented. When it lands, the prompt above will be replaced with a deterministic task scope:promote --from-issue=<N> invocation; the operator no longer needs to resolve the vBRIEF file path manually. Until then, the file-path fallback above is the canonical Phase 0c verb -- it is the same task scope:promote lifecycle command, just routed through the file path rather than the issue-number shortcut. Track via #1136.
! WIP-cap exit-clean prose: When WIP cap is reached, swarm Phase 0 stops adding to the cohort and exits cleanly with a count of what was filled. Operator can demote (D1 / #1121, task scope:demote <existing> or task scope:demote --batch --older-than-days 30) to free slots or --force to override (the override is audit-logged as wip_cap_override in vbrief/.eval/scope-lifecycle.jsonl per D4 / #1124).
! Cohort recovery on cap-fill exit: If the queue surfaces 10 candidates but the cap allows only 4 more slots, the unpicked 6 stay queued for the next session. No state is lost; the queue is the canonical record. The operator can free a slot via task scope:demote <existing> (D1 / #1121) before re-running Phase 0, or accept the smaller cohort for this session.
Phase 0d -- Cohort dispatch
- ! After the promote-fill loop exits (cap reached, queue empty, or operator
stop), vbrief/pending/ now holds the cohort. The existing Step 0.5 (Lifecycle Bridge -- Promote and Activate Proposed Scope vBRIEFs, #1025) below moves the cohort pending/ -> active/, and Steps 1-5 (readiness report, blockers, allocation, present, approval) proceed against the activated set. Existing swarm Phase 1+ (Select, Setup, Launch, Monitor, Review, Close) proceeds unchanged.
Manual / GitHub-issue escape hatch
? When the operator explicitly opts out of the queue (e.g. a one-off ad-hoc cohort that has not been ingested into the triage cache yet, or a swarm batch driven from a hand-supplied list of issue numbers), the monitor MAY fall back to the legacy GitHub-issue path:
- ! Fetch issue data:
gh api repos/<owner>/<repo>/issues/<N> (REST per templates/agent-prompt-preamble.md § 5; never the GraphQL gh issue view --json surface).
- ! Generate a minimal vBRIEF in
vbrief/proposed/ following the YYYY-MM-DD-descriptive-slug.vbrief.json naming convention (slug rules: ../../conventions/vbrief-filenames.md) and conforming to the canonical v0.6 schema (vbrief/schemas/vbrief-core.schema.json, strict const: "0.6"; see ../../conventions/references.md).
- ! Promote through the canonical lifecycle (
task scope:promote -- <path> then task scope:activate -- <path>), respecting the WIP cap and the same --force audit-logged override semantics as the queue-driven loop.
- ! Surface the opt-out reason in the Step 4 (Present Analysis) summary so a reviewer can see WHY the queue was bypassed.
⊗ Default to the manual escape hatch when the queue is non-empty -- the cache-as-authoritative directive (AGENTS.md ## Cache-as-authoritative work selection (#1149)) requires consulting the queue first.
Step 0.5: Lifecycle Bridge -- Promote and Activate Proposed Scope vBRIEFs (#1025)
! Before running the Step 1 preflight gate, scan vbrief/proposed/ and vbrief/pending/ for candidate scope vBRIEFs and bridge them to vbrief/active/. The deft-directive-setup skill Phase 3 (Output -- Light Path / Output -- Full Path) deposits new scope vBRIEFs in vbrief/proposed/; the deft-directive-refinement skill Phase 4 (Promote/Demote) deposits them in vbrief/pending/. The swarm Phase 0 Step 1 preflight gate (task vbrief:preflight) only accepts vBRIEFs in vbrief/active/ with plan.status == "running", so candidates in proposed/ or pending/ MUST be bridged through the canonical lifecycle (proposed -> pending -> active) before allocation. Without this bridge, the monitor discovers the gap at runtime as a wholesale preflight rejection (Invalid transition: 'activate' requires file in pending/), as in the originating 2026-05-10 first-session consumer swarm.
! Scan: list every *.vbrief.json under vbrief/proposed/ and vbrief/pending/. Cross-reference each candidate against the user's stated swarm scope (the issue numbers / vBRIEF filenames the user asked the monitor to swarm on). Candidates outside the stated scope MUST NOT be promoted or activated by this bridge -- they may be in a deliberate refinement queue owned by skills/deft-directive-refinement/SKILL.md Phase 4.
! Present: render a numbered list of in-scope candidates to the user with their current lifecycle folder (proposed/ vs pending/) and plan.status. Render per the host's structured-tool mode (click-commit vs plain-text typed) per skills/deft-directive-interview/SKILL.md Rule 2 Always-Structured Rendering. The final two numbered options MUST be Discuss and Back per ../../contracts/deterministic-questions.md.
! Approve: wait for explicit user approval (yes, confirmed, approve) before any lifecycle mutation. Broad affirmative continuation phrases (proceed, do it, go ahead) are NOT authorisation -- the bridge MUST be explicitly confirmed because promoting + activating a scope vBRIEF is a lifecycle commitment that flips plan.status to running and clears the #810 implementation-intent gate for downstream agent dispatch.
! Bridge: for each approved candidate, run the canonical lifecycle commands in order:
- For candidates in
vbrief/proposed/: task scope:promote -- <path> (moves to pending/, status pending), THEN task scope:activate -- <path-in-pending> (moves to active/, status running).
- For candidates already in
vbrief/pending/: task scope:activate -- <path> alone (moves to active/, status running).
Both commands are idempotent: a same-folder move with matching status is a no-op (see scripts/scope_lifecycle.py). If either command exits non-zero, surface the exit message verbatim, do NOT attempt to allocate against the failed candidate, and ask the user how to route.
! Verify: re-run the scan and confirm each approved candidate now lives in vbrief/active/ with plan.status == "running". Only candidates that pass this verification advance to Step 1 (Read Project State); the rest stay surfaced as preflight rejections.
⊗ Auto-promote + activate every candidate in vbrief/proposed/ or vbrief/pending/ without explicit user approval -- proposed-stage vBRIEFs may be in a deliberate refinement queue (skills/deft-directive-refinement/SKILL.md Phase 4) and silent promotion bypasses the user's lifecycle intent.
⊗ Skip the lifecycle bridge and let the Step 1 preflight gate (task vbrief:preflight) reject the candidates wholesale -- the gate's exit message tells the user WHAT failed but not WHY the source folder was wrong; the bridge is the contract that prevents that confusion before it surfaces.
⊗ Promote candidates outside the user's stated swarm scope. The bridge is scope-bounded by what the user asked the monitor to swarm on; out-of-scope candidates remain in proposed/ / pending/ for the refinement skill to own.
Cross-references:
- Setup-side deposit point:
skills/deft-directive-setup/SKILL.md Phase 3 Output -- Light Path / Output -- Full Path (scope vBRIEFs land in vbrief/proposed/).
- Refinement-side deposit point:
skills/deft-directive-refinement/SKILL.md Phase 4 -- Promote/Demote (lifecycle transitions via the same task scope:promote / task scope:activate surface).
- Underlying CLI:
scripts/scope_lifecycle.py (the deterministic state machine; idempotent on same-folder moves; three-state exit 0 / 1 / 2).
- Recurrence record: issue #1025 (2026-05-10 first-session consumer tic-tac-toe swarm; monitor hit
Invalid transition: 'activate' requires file in pending/ on all four candidate vBRIEFs because they were still in proposed/).
Step 1: Read Project State and Readiness Report
- ! Scan
vbrief/active/ for candidate vBRIEFs (files matching *.vbrief.json)
- ! For each candidate vBRIEF, MUST run
task vbrief:preflight -- <path> (the structural intent gate, #810; wraps scripts/preflight_implementation.py so the same invocation works whether deft is the project root or installed as a deft/ subdirectory) to validate lifecycle eligibility before allocation work. Skip any vBRIEF that exits non-zero -- the helper's stderr message is the actionable redirect (task vbrief:activate <path>). Surface the exit message in the Phase 0 Step 4 analysis so the user can route the lifecycle move; do NOT attempt to allocate, dispatch, or implement against a vBRIEF that fails the preflight.
- ! Run
task swarm:readiness -- vbrief/active/*.vbrief.json before any agent allocation. This deterministic report is the allocator's source of truth for ready stories, blocked stories, decomposition-needed epics/phases, dependency waves, conflict groups, file overlap matrix, and missing fields.
- ! Treat
plan.metadata.kind = "epic" and plan.metadata.kind = "phase" as needs decomposition, not merely incomplete. Route broad scopes to skills/deft-directive-decompose/SKILL.md instead of assigning them to workers.
- ! Read only readiness-approved story fields for allocation:
plan.title, plan.status, non-empty plan.items, planRef, references, plan.metadata.kind, and plan.metadata.swarm.
- ! Read
vbrief/PROJECT-DEFINITION.vbrief.json for project-wide context (narratives, scope registry)
- ! Determine the base branch: ask the user which branch to target for worktree creation, PR targets, and rebase cascade (default:
master). Record this as the configured base branch for all subsequent phases.
- ⊗ Spawn an implementation agent (via
start_agent, oz agent run, Warp tab dispatch, or any other path) for a vBRIEF that has not passed task vbrief:preflight (which wraps scripts/preflight_implementation.py) -- the gate is the only authorization signal; affirmative continuation phrases and workflow-shape vocabulary are NOT (#810).
- ⊗ Allocate concurrent workers unless candidates are swarm-ready
kind=story vBRIEFs with non-empty executable plan.items and task swarm:readiness exits 0.
- ⊗ Use manual file-overlap reasoning as the only safety check; use the readiness report first, then explain any additional human judgment.
Step 2: Surface Blockers
- ! Identify blocked vBRIEFs (status
blocked) and their blocking reasons (check narrative fields)
- ! Identify vBRIEFs with incomplete acceptance criteria (no
plan.items or empty items array)
- ! Identify epic/phase scope vBRIEFs from the readiness report and route them to decomposition
- ! Identify dependency conflicts between candidate vBRIEFs (e.g. story A depends on story B via
planRef or edges, but B is assigned to a different agent or is incomplete)
- ! Flag any candidate vBRIEFs whose prerequisites are unmet
Step 3: Plan Allocation
! The monitor allocates one or more vBRIEFs to each agent based on scope, complexity, and dependencies. There is no fixed per-agent limit.
- ! Small/independent stories can be batched to a single agent only after explicit operator approval or an approved allocation plan -- group related or low-complexity vBRIEFs together and record the batching rationale
- ! Large/complex stories get dedicated agents — a story with broad file scope or high acceptance criteria count should not share an agent
- ! Dependency-aware grouping — vBRIEFs that share
planRef to the same epic or have edges between them should be assigned to the same agent when possible, OR sequenced with clear ordering
- ! The monitor decides allocation dynamically — no hardcoded 1:1 rule
- ! WIP cap awareness (#1124 / D4 of #1119) — the cohort + any bridge-promoted candidates (Step 0.5) MUST fit within
plan.policy.wipCap (default 10 per umbrella #1119 Current Shape v3). When pending/ + active/ count is at-or-above the cap, task scope:promote refuses with an error message naming task scope:demote <existing> and task scope:demote --batch --older-than-days 30 as the relief valves. The monitor MUST drain the WIP set via task scope:demote (D1 / #1121) before promoting more candidates, OR open a per-promote task scope:promote <file> --force (audit-logged as wip_cap_override in vbrief/.eval/scope-lifecycle.jsonl) for the genuinely time-critical case. task triage:summary (D2 / #1122) surfaces the cap as WIP X/Y with a warning glyph when at-or-above cap.
Step 4: Present Analysis
! Present a summary to the user containing:
- Candidate vBRIEFs: story-level vBRIEFs eligible for assignment (with titles, statuses, and origin references)
- Readiness report: ready stories, blocked stories, decomposition-needed epics/phases, dependency waves, conflict groups, file overlap matrix, and missing fields from
task swarm:readiness.
- Preflight rejections (#810): any vBRIEFs that failed
task vbrief:preflight (wraps scripts/preflight_implementation.py) in Step 1 -- include the file path AND the helper's exit message verbatim so the user can route the appropriate task vbrief:activate <path> move. These vBRIEFs MUST NOT be allocated until they pass the preflight on a re-run.
- Blockers found: blocked vBRIEFs, unresolved dependencies, items requiring design decisions
- Decomposition needed: epic/phase scopes that must go through
skills/deft-directive-decompose/SKILL.md before swarm allocation
- Incomplete vBRIEFs: stories with missing or empty acceptance criteria
- Allocation plan: which agent gets which vBRIEF(s), with reasoning for batching decisions; multi-story batching is allowed only after explicit operator approval or approval of this allocation plan
- Tentative version bump: current version (from CHANGELOG.md or latest git tag) and proposed next version (patch/minor/major) based on the scope and nature of candidate items — this is advisory and will be confirmed before merge cascade
Step 5: Get User Approval
- ! Wait for explicit user approval (
yes, confirmed, approve) before proceeding to Phase 1 (Select)
- ! If the user requests changes to the allocation plan, re-analyze and re-present
- ⊗ Proceed to Phase 1 (Select) without completing the allocate phase and receiving explicit user approval
Phase 1 — Select
! Finalize assignments from the allocation plan. Each agent gets a coherent set of related work.
Step 1: Confirm Candidates
- ! Use the allocation plan and vBRIEF analysis from Phase 0 as the starting point
- ! Re-read
vbrief/active/ only if Phase 0 was skipped (user override) or context was lost
- ! For each candidate vBRIEF, verify its
plan.status is running (not blocked or completed)
- ! Exclude vBRIEFs that are blocked, have unresolved dependencies, or require design decisions
Step 2: File-Overlap Audit
! Before assigning tasks to agents, start from the task swarm:readiness file-overlap matrix and conflict groups, then list every file each vBRIEF's acceptance criteria are expected to touch.
- ! Verify ZERO file overlap between agents — no two agents may modify the same file
- ! Check transitive file touches, not just primary scope — trace each vBRIEF's acceptance criteria to specific files. A task may require changes to files outside its obvious scope (e.g., an enforcement task adding an anti-pattern to a skill file owned by another agent).
- ! Shared files (CHANGELOG.md) are exceptions — each agent adds entries but does not edit existing content
- ! If overlap exists, reassign tasks until overlap is eliminated
⊗ Proceed to Phase 2 while any file overlap exists between agents (excluding shared append-only files).
⊗ Assume a task only touches files in its primary scope — always check acceptance criteria for cross-file requirements.
Step 3: Present Assignment
- ! Show the user: agent number, branch name, assigned vBRIEF(s) (with origin issue numbers), and files each agent will touch
- ~ Wait for user approval unless the user explicitly said to proceed autonomously
Phase 2 — Setup
Step 1: Create Worktrees
! Two modes (C3 / #1387): Phase 2 either CONSUMES a pre-created worktree map (the headless path, when task swarm:launch --worktree-map <path> supplied one) or creates worktrees itself (the interactive path). Mode A is preferred whenever a map is present; Mode B is the default otherwise.
Mode A -- Pre-created worktree map (C3, headless via --worktree-map)
- ! When
task swarm:launch -- ... --worktree-map <path> supplied a pre-created worktree map (C3), Phase 2 CONSUMES it instead of running git worktree add per agent. The C3 map is a JSON array of { "story_id": str, "worktree_path": str, "base_branch": str }.
- ! The launch engine resolves the map via
resolve_worktree_map(mapping, base_branch, create_missing=True) in scripts/swarm_worktrees.py, which returns normalized C3 records and RAISES on same-path collisions or base-branch mismatches. The monitor MUST surface any such raise verbatim and HALT setup -- a same-path collision means two agents would share one worktree (the Duplicate-Agent Failure Mode in Phase 4).
- ! Each resolved record's
worktree_path and base_branch feed straight into Phase 3 dispatch and MUST match the C2 launch-manifest's worktree_path / branch fields for the same story_id.
Mode B -- Monitor-created worktrees (interactive path)
For each agent, create an isolated git worktree:
git worktree add <path> -b <branch-name> <configured-base-branch>
- ! One worktree per agent (e.g.
E:\Repos\deft-agent1, E:\Repos\deft-agent2)
- ! Branch naming:
agent<N>/<type>/<issue-numbers>-<short-description> (e.g. agent1/cleanup/31-50-23-strategy-consolidation) — the agent number prefix aids traceability since GitHub PR numbers won't match agent numbers
- ! All worktrees branch from the same base (the configured base branch from Phase 0)
Step 2: Generate Prompt Files
! Create a launch-agent.ps1 (Windows) or launch-agent.sh (Unix) in each worktree using the Prompt Template below.
~ Also prepare plain-text prompt versions for pasting into Warp agent chat or other terminal interfaces.
Phase 3 — Launch
Step 0: Populate the allocation-context consent token (#1378)
! Before dispatching ANY worker prompt -- swarm cohort OR solo -- the dispatcher MUST populate a ## Allocation context section (the frozen schema defined in templates/agent-prompt-preamble.md, Story A of #1378) in every launched agent's dispatch envelope. Populate all five fields in order: dispatch_kind (solo | swarm-cohort), allocation_plan_id, batching_rationale, cohort_vbriefs, and operator_approval_evidence.
- ! For a swarm cohort, set
dispatch_kind: swarm-cohort with a non-null allocation_plan_id (the Phase 0 allocation-plan snapshot path or the monitor session id) AND a non-null batching_rationale (the one-line rationale from the Phase 0 Step 4 allocation plan), and list the full cohort in cohort_vbriefs. This is the structured consent token the worker's build-skill Step 0 recognizes mechanically (#1378 Story B), so the worker processes its cohort without re-prompting the parent for batching approval mid-cohort.
- ! For a solo dispatch, set
dispatch_kind: solo and list the single assigned vBRIEF in cohort_vbriefs; allocation_plan_id and batching_rationale MAY be null. Populating the section even for solo dispatches keeps the recognition surface uniform across every launch path.
⊗ Dispatch a worker prompt (cohort or solo) without a populated ## Allocation context section -- an absent section forces the worker back onto the #1371 prose carve-out fallback and forfeits the deterministic consent-token recognition the structured section enables (#1378).
Step 0.5: Consume the launch-manifest before dispatch (headless path, C2 / #1387)
! On the headless path, before dispatching ANY worker, the monitor consumes the C2 launch-manifest emitted by task swarm:launch -- a JSON array of { "story_id": str, "vbrief_path": str, "worktree_path": str, "branch": str, "allocation_context": {...} }, where each record's allocation_context is the #1378 token (its five fields dispatch_kind, allocation_plan_id, batching_rationale, cohort_vbriefs, operator_approval_evidence, per templates/agent-prompt-preamble.md § 2.5). Each record carries everything one worker dispatch needs.
! On the headless path the manifest's per-record allocation_context already satisfies Step 0 above -- the consent token is pre-populated, so the monitor READS it from the manifest rather than re-assembling the ## Allocation context section by hand.
! Manifest consumption is PREP ONLY. It supplies the per-agent dispatch parameters (worktree_path, branch, vbrief_path, allocation_context); the spawn itself remains agent-driven via the runtime-detected launch path (Step 2a start_agent / Step 2d spawn_subagent). task swarm:launch emits the manifest and STOPS -- it does NOT spawn agents.
⊗ Treat the C2 launch-manifest as the spawn itself -- it is dispatch-prep / handoff data, not an agent-launch primitive. The actual dispatch still goes through the platform adapter (Step 2a / 2d per the runtime detection below); the manifest replaces the manual per-agent parameter assembly, NOT the spawn primitive.
? On the interactive path (no task swarm:launch, no manifest), the monitor assembles each dispatch's parameters from the Phase 1 assignment plus the Step 0 token by hand, as before.
Step 1: Runtime Capability Detection
! Before selecting a launch method, probe the environment to determine the best available path.
- ! Probe for
start_agent tool — check the available tool set for start_agent (or equivalent agent-orchestration tool). Its presence indicates a Warp environment with native orchestration support.
- ! Probe for Warp environment — if
start_agent is not available, check for WARP_* environment variables (e.g. WARP_TERMINAL_SESSION, WARP_IS_WARP_TERMINAL). Their presence indicates Warp without orchestration.
- ! Probe for
spawn_subagent tool — when neither start_agent nor WARP_* is present, check for spawn_subagent (Grok Build / non-Warp TUI launch adapter, #1342 slice 2). Its presence indicates the grok-build platform.
- ! Select launch path automatically based on detection results — do NOT present static options:
start_agent available → Orchestrated launch (Step 2a) — preferred path, fully automated, no manual tab management
start_agent unavailable, Warp detected → Interactive Warp tabs (Step 2b) — full MCP, global rules, warm index; requires manual tab management
grok-build (spawn_subagent available, no start_agent, no WARP_*) → Grok Build launch (Step 2d) — first-class non-Warp path
- No orchestration primitive detected → Manual terminal launch (Step 2b fallback) — paste prompt into any terminal with access to the worktree
- ! Return a stable platform descriptor for downstream phases — one of
warp-orchestrated (start_agent available), warp-manual (Warp without start_agent), grok-build (spawn_subagent available, non-Warp), or generic-terminal (no orchestration primitives). The detection matrix MUST include explicit absence checks for start_agent and WARP_* so the four descriptors are unambiguous. Phase 4 monitoring and Phase 6 sub-agent dispatch read this stable platform descriptor as a single source of truth instead of re-running detection per call.
- ? Cloud escape hatch — use
oz agent run-cloud (Step 2c) ONLY if the user explicitly requests cloud execution. Never default to cloud.
⊗ Present static launch options (A/B/C) instead of detecting capabilities at runtime.
⊗ Offer Warp-specific launch paths (tabs, start_agent) when not running inside Warp — gate on WARP_* environment variables or start_agent tool presence.
Step 2a: Orchestrated Launch (start_agent available)
! When start_agent is detected in the tool set, use it directly to launch each agent.
- ! Launch one agent per worktree using
start_agent with the generated prompt and worktree path as the working directory
- ! Agents inherit the current environment's MCP servers, Warp Drive rules, and codebase index — equivalent to interactive Warp tabs but without manual tab management
- ! No user intervention needed — launch is fully automated
- ~ This is the preferred path: richest context with zero manual overhead
Step 2b: Interactive Warp Tabs (start_agent unavailable, Warp detected)
! When start_agent is not available but Warp is detected (via WARP_* environment variables), fall back to manual Warp tab launch — briefly note that orchestrated launch is not available in this session, then proceed with the tab instructions below.
! Warp tabs cannot be opened programmatically. There is no API or CLI command to open a new Warp terminal tab from an agent or script.
Ask the user to open N new Warp terminal tabs. For each tab, the user:
- Navigates to the worktree:
cd <worktree>
- Pastes the prompt directly into the Warp agent chat input (not the terminal)
Context advantages of Warp tabs:
- Global Warp Drive rules (personal rules auto-injected)
- MCP servers via UUID (GitHub, etc. — zero-config)
- Warp Drive notebooks, workflows, and other auto-injected context
- Warm codebase index from the active Warp session (no cold-start delay)
- Agent is interruptible and steerable mid-run
Tradeoff: Requires the user to manually open and manage one Warp tab per agent.
? If not running inside Warp at all (no WARP_* variables, no start_agent), use the same tab approach but with any terminal emulator — the user pastes prompts into their preferred terminal or agent interface.
Step 2c: Cloud Agents (explicit user request only)
! Use oz agent run-cloud ONLY when the user explicitly requests cloud execution. Never default to this path.
oz agent run-cloud --prompt "TASK: You must complete..."
Agents execute on remote VMs without local MCP servers, codebase indexing, or Warp Drive rules. Agents MUST use gh CLI for GitHub operations. AGENTS.md is the only behavioral control surface.
Tradeoff: Fully automated with zero tab management, but context-starved — no MCP, no Warp Drive rules, no codebase indexing. Best for self-contained tasks that don't need rich local context.
⊗ Default to cloud launch — it is an escape hatch, not a default path.
⊗ Use oz agent run-cloud when the user expects local execution — run-cloud routes to remote VMs with no local context.
Step 2d: Grok Build Launch (spawn_subagent available)
! When the platform descriptor is grok-build (spawn_subagent detected, no start_agent, no WARP_*), dispatch each worker via spawn_subagent with:
- The canonical
templates/agent-prompt-preamble.md content as the preamble
- The standard worktree prompt (STEP 1-6 from the Prompt Template below), adapted to use
get_command_or_subagent_output for polling rather than start_agent lifecycle events
- The worktree path set to the agent's isolated git worktree
~ This is the first-class non-Warp path. Workers use worktree state polling (git status, git log) and get_command_or_subagent_output as their coordination channel instead of Warp tab state.
Phase 4 — Monitor
Polling Cadence
- ~ Check each agent's worktree every 2–3 minutes:
git status --short and git log --oneline -3
- ~ After 5 minutes with no changes, check if the agent process is still running
Heartbeat liveness check (#1365)
! On the Grok Build hybrid path (spawn_subagent dispatch, no native lifecycle channel back to the monitor), worktree git state alone is INSUFFICIENT to distinguish a healthy mid-poll sub-agent from a stalled one. Long-running review-cycle pollers spend most of their wall-clock waiting on Greptile and emit no commits during that wait -- the #1166 swarm session is the recurrence record (two of three dispatched pollers went silent with zero observable signals; the monitor could not tell).
! The canonical alive-check on the Grok Build hybrid path is the heartbeat contract documented in docs/subagent-heartbeat.md. Every long-running sub-agent (pollers, watchdogs, implementation agents whose tool loop exceeds ~3 min) writes a JSON heartbeat to .deft-scratch/subagent-status/<agent-id>.json per the canonical poller template + agent preamble; the monitor reads those records via scripts/subagent_monitor.py (three-state exit 0 ok / 1 stale-or-malformed / 2 config error). Default threshold is 30 minutes; --threshold-minutes overrides.
# Scan all worktrees in the cohort
uv --project . run python scripts/subagent_monitor.py \
--scratch-dir <worktree-1>/.deft-scratch/subagent-status \
--scratch-dir <worktree-2>/.deft-scratch/subagent-status
! Run the heartbeat sweep alongside the worktree git checks at every monitor polling iteration (~2-3 min). When a record is reported STALE (mid-flight, terminal_state unpopulated, age > threshold), treat it as a candidate for the Takeover Triggers below; when it is reported MALFORMED, surface the diagnostics to the user and re-dispatch the agent with a fresh prompt that re-establishes the heartbeat contract. A TERMINAL record (terminal_state set) is NEVER stale -- the agent reached its exit on its own terms.
~ The heartbeat is filesystem-only by design; a network partition or rate-limit ceiling cannot mask agent liveness. Pair the on-disk sweep with the worktree git checks (git status --short, git log --oneline -3) and the per-PR readiness gate (task pr:merge-ready) for the full alive + progressing + clean picture.
⊗ Spawn a replacement sub-agent for a worktree where the heartbeat record reports OK or TERMINAL -- the agent is alive (or finished cleanly) and a replacement would re-trigger the Duplicate-Agent Failure Mode below.
⊗ Treat the absence of a .deft-scratch/subagent-status/<agent-id>.json record on the Grok Build hybrid path as "agent is alive but quiet" -- a sub-agent that never wrote a heartbeat is either pre-startup (acceptable for the first ~30s) OR violated the contract (treat as stalled and verify via worktree state before any replacement decision).
Checkpoints
Track each agent through these stages:
- Reading — agent is loading AGENTS.md, vBRIEF files, project files (no file changes yet)
- Implementing — working tree shows modified files
- Validating — agent running
task check
- Committed — new commit(s) in
git log
- Pushed — branch exists on
origin
- PR Created — PR visible via
gh pr list --head <branch>
- Review Cycling — additional commits after PR creation (Greptile fix rounds)
Takeover Triggers
! Pre-spawn verification: Before spawning a replacement agent, verify the original is truly unresponsive by waiting for an idle/blocked lifecycle event — verified via worktree state (git status, git log --oneline -3) and sub-agent lifecycle signals showing no in-flight work (for grok-build / spawn_subagent agents: polling is via worktree state + get_command_or_subagent_output rather than tab observation). Do NOT spawn a replacement based solely on message timing, absence of recent commits, or a perceived delay — original agents (Warp tabs or spawn_subagent processes) can resume after apparent failure, and spawning a new agent creates two concurrent agents on the same worktree (see Duplicate-Tab Failure Mode below).
! Take over an agent's workflow if ANY of these occur:
- Agent process has exited and PR has not been created
- Agent process has exited and Greptile review cycle was not started
- Agent is idle for >5 minutes after PR creation with no review activity
- Agent is stuck in an error loop (same error 3+ times)
When taking over: read the agent's current state (git log, diff, PR comments), complete remaining steps manually following the same deft process.
Duplicate-Agent Failure Mode (a.k.a. Duplicate-Tab Failure Mode)
⚠️ Root cause of #261 and #263 (generalized for #1342 slice 3): This is the Duplicate-Agent Failure Mode -- it fires on every platform descriptor, not just Warp tabs. Original Warp agent tabs may resume after apparent failure (network hiccup, temporary Warp UI freeze, context window pressure); the same failure mode applies to spawn_subagent-launched grok-build sub-agents that appear stalled but later resume. If the monitor spawns a new agent for the same worktree, two concurrent agents execute on the same branch simultaneously. This corrupts the tool_use/tool_result message chain — both agents issue tool calls, but responses are interleaved unpredictably, causing one or both agents to act on stale or incorrect state.
Recovery guidance:
- ! Keep original agents active until their PR is merged — do not terminate agent processes that appear stalled (for Warp tabs: keep the tab open; for grok-build / spawn_subagent agents: verify via
get_command_or_subagent_output before replacing)
- ! If an agent appears stalled, attempt to resume it in its original context (for Warp: go to the original Warp tab and say "continue from where you left off"; for grok-build: re-query via
get_command_or_subagent_output or send a resume message) rather than spawning a replacement
- ! If the original agent is truly unrecoverable (Warp crash, tab closed, or spawn_subagent process terminated), only then create a new agent — and first verify the worktree state (
git status, git log, gh pr list) to avoid conflicting with any in-flight work
Context-Length Warning
! Long monitoring sessions accumulate large conversation history (hundreds of tool_use/tool_result pairs) and are susceptible to conversation corruption — the tool_use/tool_result mismatch observed in #263 occurred at approximately message 158 in a single monitor conversation. To mitigate:
- ! Offload rebase, review-watch, and merge sub-tasks to ephemeral sub-agents using the tiered approach from
skills/deft-directive-review-cycle/SKILL.md (spawn via the platform adapter's dispatch primitive when available (e.g. spawn_subagent for Grok Build), discrete tool calls with yield otherwise) — this keeps the monitor conversation shallow
- ~ Target <100 tool-call round-trips in any single monitor conversation before considering a fresh session handoff
- ! If the monitor detects degraded output (repeated errors, inconsistent state references, tool call failures), stop and hand off to a fresh session with a state summary rather than continuing in a corrupted context
Phase 5 — Review & Complete
Verify Review Cycle Completion
For each agent's PR:
- ! Check that Greptile has reviewed the latest commit (compare "Last reviewed commit" SHA to branch HEAD)
- ! Verify Greptile confidence score > 3
- ! Verify no P0 or P1 issues remain (P2 are non-blocking style suggestions)
- ! If the agent did not complete its review cycle, the monitor runs it per
skills/deft-directive-review-cycle/SKILL.md
Complete vBRIEFs
! The cohort's story vBRIEFs are completed by the deterministic cohort completion sweep in Phase 6 (task swarm:complete-cohort, Phase 6 Step 1.5 below), which runs AFTER the merge cascade. Do NOT move story vBRIEFs out of vbrief/active/ before their PRs merge — a pre-merge move creates premature state if the merge cascade fails. This section is where the monitor records, per story, what the post-merge sweep will finalize:
- ! For each story vBRIEF an agent's PR fully resolves, note that it is ready to complete (
vbrief/active/ -> vbrief/completed/, status completed). The underlying primitive is task scope:complete <file>; the Phase 6 sweep wraps it across the whole cohort so nothing is missed on the headless / multi-worker path.
- ! If a story carries a
planRef to a parent epic, the sweep also completes that epic once ALL its children are settled — you do NOT reconcile epic parents by hand, and you do NOT manually repair parent/child references (the lifecycle helper keeps task vbrief:validate green via the #1485 / #1487 reference maintenance).
⚠️ Both the vBRIEF lifecycle moves AND origin/issue closure happen in Phase 6 (after merge), not here — completing vBRIEFs or closing issues before merge creates premature state if the merge cascade fails.
Exit Condition
All PRs meet ALL of:
- Greptile confidence > 3
- No P0 or P1 issues remain (P2 issues are non-blocking style suggestions)
task check passed (or equivalent validation completed)
- CHANGELOG entries present under
[Unreleased]
! Mandatory cohort verifier (#1364): After every poller (Phase 6 review-cycle sub-agent) reports back, the monitor MUST run task swarm:verify-review-clean -- <pr-numbers...> (script: scripts/swarm_verify_review_clean.py) and confirm exit 0 BEFORE evaluating the rest of the Exit Condition or surfacing the Phase 5 -> 6 gate. The verifier re-uses the Greptile rolling-summary parser from scripts/pr_merge_readiness.py so the per-PR merge gate and the cohort gate stay in lockstep (a parser fix lands in both surfaces at once). Exit codes: 0 (cohort CLEAN -- all PRs simultaneously have SHA match + confidence > 3 + zero P0/P1 + not errored on current HEAD); 1 (one or more PRs unclean with per-PR diagnostics -- re-dispatch the poller for the unclean PR or address findings, then re-run the verifier); 2 (config error -- empty cohort, malformed vBRIEF glob, gh missing). The verifier is the structural answer to the #1166 swarm execution recurrence where multiple pollers exited with clean_gate_holdout=confidence (confidence == 3) and the monitor still raised the Phase 5 -> 6 gate because the trigger keyed on "all pollers have reported back" rather than "every PR in the cohort is objectively CLEAN".
! Resilient long-running monitor (#1368): When a Phase 5 monitor needs to wait on an in-flight PR for an extended window (cascade rebase + re-review, late Greptile pass, CI sweep), use scripts/monitor_pr.py <N> --repo <owner>/<repo> as the canonical wait-until-ready helper. The script loops scripts/pr_merge_readiness.py with adaptive cadence (~1m for the first 3 polls, ~3m next, ~5m thereafter), routes subprocess capture through _safe_subprocess.run_text (#1366), and tolerates layered fallback responses without going blind on a transient gh failure. Exit codes: 0 (PR reached primary/fallback1 CLEAN), 1 (poll cap reached -- escalate to operator), 2 (config error -- gh missing / invalid args), 3 (PR merged or closed out from under the monitor before reaching CLEAN). The helper writes one terse status line per poll to stderr so the orchestrator transcript shows progress; the final verdict (JSON when --json is passed) lands on stdout.
! Fallback-chain discriminator semantics (#1368): scripts/pr_merge_readiness.py --json ALWAYS emits a via discriminator on every response. via="primary" and via="fallback1" are authoritative -- a merge_ready: true verdict on either is CLEAN. via="fallback2" is the coarse PR-view + check-run last-resort signal: it surfaces the PR's state / merged / mergeable / flattened check-run summary so a monitor can keep stepping forward through transient gh failures, but it is NEVER CLEAN -- the failure list carries the sentinel "fallback2 is a coarse signal, not a CLEAN verdict ..." and the merge cascade MUST keep waiting for a primary/fallback1 CLEAN. via="error" (every layer failed) is also non-CLEAN; the response carries error (one-line summary) + partial_data (per-layer diagnostics) so the monitor can step forward without blinding. Both task swarm:verify-review-clean and task pr:merge-ready treat fallback2 and error as merge-blocked.
⊗ Surface or discuss the Phase 5 -> 6 merge cascade gate while task swarm:verify-review-clean has not yet exited 0 on the current cohort (#1364). Keying the transition on poller lifecycle completion alone -- i.e. treating "every poller sub-agent returned a terminal message" as sufficient -- is the exact recurrence pattern this rule closes. The verifier is the only authoritative cohort-level CLEAN signal; a poller's clean_gate_holdout=confidence / clean_gate_holdout=has_blocking / clean_gate_holdout=sha_match / clean_gate_holdout=errored exit IS a non-CLEAN report and MUST hold the gate even if every sub-agent has technically returned.
⊗ Treat a via="fallback2" or via="error" response from scripts/pr_merge_readiness.py as CLEAN, regardless of the surrounding merge_ready field (#1368). Fallback2 is structurally never CLEAN -- the Greptile rolling-summary comment was unreachable on both the primary and fallback1 paths, so any merge taken on the basis of the coarse signal alone bypasses the SUCCESS-with-findings blind spot the per-PR gate was designed to close (#796 / #652). The merge cascade MUST keep waiting for a primary/fallback1 CLEAN.
Phase 5→6 Gate: Release Decision Checkpoint
! Before proceeding to Phase 6 (Close), the monitor MUST present the proposed release scope and version bump to the user for confirmation.
⊗ Context-pressure bypass prohibition: Even under long-context or time pressure (large conversation history, many tool calls, approaching context limits), this gate MUST NOT be bypassed. The Phase 5→6 gate is mandatory regardless of conversation length, elapsed time, or perceived urgency. If the monitor's context is degraded, hand off to a fresh session rather than skipping the gate.
-
! Present a summary containing:
- PRs ready to merge: list of PRs with titles, issue numbers, and current review status
- Proposed version bump: the tentative version from Phase 0 (patch/minor/major) with rationale — updated if scope changed during implementation
- Release scope: brief description of what this batch of changes represents
-
! Merge-readiness checklist: Before any gh pr merge call, the monitor MUST emit a structured checklist confirming each PR is merge-ready. For each PR, verify and explicitly confirm:
- Greptile confidence score > 3
- No P0 or P1 issues remaining
task check passed on the branch
- CHANGELOG.md entry present under
[Unreleased]
- Explicit user approval received for this merge cascade
! Cohort gate (#1364): Before the merge-readiness checklist is even emitted, the monitor MUST have already passed task swarm:verify-review-clean -- <pr-numbers...> per the Phase 5 Exit Condition above. The cohort gate is the structural pre-condition for this entire Phase 5 -> 6 sequence -- without exit 0 on the verifier, the checklist below MUST NOT be presented to the user. The per-merge task pr:merge-ready gate below remains the merge-time freshness-window-atomic check; the cohort verifier is the once-after-pollers gate that gates the discussion at all.
! Programmatic gate: Before each gh pr merge call, the monitor MUST run task pr:merge-ready -- <N> (script: scripts/pr_merge_readiness.py) and abort the cascade on non-zero exit. The Taskfile target parses the Greptile rolling-summary comment body (confidence, P0 / P1 badge counts, errored sentinel, HEAD-SHA freshness) -- not the GitHub CheckRun status. The CheckRun goes green when Greptile finishes its review pass, irrespective of findings; relying on it alone is the SUCCESS-with-findings blind spot that started the PR #652 incident merge cascade against Confidence: 3/5 + 1×P1 + 2×P2.
! Atomic gate (freshness window): The monitor MUST invoke task pr:merge-ready -- <N> and gh pr merge <N> in the same shell call (e.g. task pr:merge-ready -- <N> && gh pr merge <N> --squash --delete-branch --admin) so no time elapses between verdict and merge. A readiness check more than ~60 seconds stale is a Mode-1 false-positive risk: in the elapsed window an unrelated commit may land on master, auto-rebase trigger a fresh Greptile pass, and the new pass surface a P1 the cached verdict did not see. Re-invoking the gate is cheap (single gh api call); the shell-&& chain makes the freshness window structurally enforceable rather than prose-trust.
⊗ Merge on the basis of a SUCCESS Greptile CheckRun alone. The CheckRun signals review completion, not review approval. Parse the comment body (confidence + P0/P1 count) via task pr:merge-ready -- <N> before merging.
⊗ Run task pr:merge-ready -- <N> upstream of gh pr merge <N> (e.g. as a separate batched check during cascade prep, then later run gh pr merge after intervening rebase / sub-agent dispatch / user discussion). Stale verdicts risk Mode-1 false positives -- always chain readiness and merge in the same shell call.
-
! Wait for explicit user approval (yes, confirmed, approve) before proceeding to Phase 6 merge cascade
-
! If the user requests changes (e.g. different version bump, defer a PR), adjust and re-present
⊗ Begin merge cascade without presenting the version bump proposal and receiving explicit user approval.
Phase 6 — Close
Sub-Agent Role Separation (#727)
! Post-PR sub-agents are review-cycle agents (#727): Sub-agents addressing review findings, waiting for re-review, and iterating to clean MUST embody skills/deft-directive-review-cycle/SKILL.md end-to-end as a single coherent role. Do NOT split the review-cycle into separate "poll" and "fix" agents -- pollers that spawn separate fix agents create cross-agent state-handoff hazards and double the chance of an agent exiting at the wrong lifecycle boundary.
! Sub-agents MUST emit a heartbeat (#1365): every long-running review-cycle / poller sub-agent dispatched under Phase 6 MUST write a heartbeat record to .deft-scratch/subagent-status/<agent-id>.json per the contract in docs/subagent-heartbeat.md. The canonical poller template (templates/swarm-greptile-poller-prompt.md bounded poll loop) already encodes the per-iteration heartbeat write and the final terminal heartbeat, and the canonical orchestrator preamble (templates/agent-prompt-preamble.md § 10.5) restates the contract for any non-poller long-running sub-agent. The monitor watches via scripts/subagent_monitor.py -- see Phase 4 Heartbeat liveness check. Without the heartbeat, a spawn_subagent-dispatched poller that stalls is indistinguishable from a healthy mid-poll one (the #1166 recurrence).
! Post-PR monitoring runs in a fresh sub-agent (#727): Post-PR monitoring (Greptile, CI checks, downloadCount drift, lifecycle events, etc.) MUST be done by spawning a fresh short-lived sub-agent via the platform adapter's dispatch primitive for the detected runtime (e.g. spawn_subagent when the Grok Build / non-Warp platform is active, start_agent for Warp-orchestrated environments). The parent yields with no tool calls and waits for the sub-agent's messages -- this preserves conversation steerability so the user can interrupt or redirect while the watch is pending. The platform adapter (introduced in slices 1-3 of #1342) supplies the appropriate async callback channel and spawn surface per the runtime capability detection matrix; every Taskfile / shell-sleep / time.sleep / synchronous tool-call alternative blocks the parent's turn for the duration of the watch.
! Canonical poller template (#727): When delegating to a poller / review-cycle sub-agent, MUST use the canonical poller-prompt template at templates/swarm-greptile-poller-prompt.md with placeholders ({pr_number}, {repo}, {poll_interval_seconds}, {poll_cap_minutes}, {parent_agent_id}) filled in. Do NOT hand-author per-watch prompts -- the template encodes parsing fixes (markdown-link Last reviewed commit: regex, badge-based / negation-aware P0/P1 detection) that hand-authored variants have repeatedly missed (Agent D, post-#721 swarm; #727 comment 2).
! Destructive commands run alone (#727): Sub-agent prompts MUST instruct the agent to run destructive commands (rm, Remove-Item, del, git clean, etc.) in their OWN shell call, never chained with non-destructive commands. Chaining poisons Warp's is_risky classification on the entire pipeline and forces manual approval on every otherwise-safe operation -- a multi-commit branch hits the user N times per agent.
! Commit-message temp file is leave-alone (#727): When using the canonical PowerShell UTF-8-safe commit-message pattern (create_file <tmp> -> git commit -F <tmp>), MUST NOT clean up the temp file in the same shell call. Leave it orphaned -- worktree teardown or git clean -fd reclaims it. The two-step value (separate cleanup) is not worth the per-commit approval prompt the chained rm triggers.
⊗ Run a poll loop in the parent's own turn (via task, shell sleep, time.sleep, or any synchronous tool call). The conversation must remain user-steerable while watches are pending.
⊗ Bundle "watch for Greptile" / "monitor CI" instructions into an implementation agent's dispatch prompt (regardless of the platform adapter's spawn primitive) -- implementation agents exit at PR-open via the succeeded lifecycle, so any post-exit monitoring instruction is unreachable.
⊗ Spawn a "pure poller" sub-agent for a PR that has likely findings. Pure pollers are appropriate ONLY when no fixes are expected (CI watch on known-good HEAD, post-merge state checks, lifecycle observers). Default for post-PR work is review-cycle, NOT poller.
⊗ Chain rm (or any destructive command) with git commit / git push / any non-destructive command in a single shell pipeline.
Step 1: Merge
! Per-PR sub-agent identity gate: Before acting on any PR (merge, force-push, status check), query the specific sub-agent responsible for that PR for live status. Do not infer a PR's status from a different agent's tab, from message timing, or from the absence of recent commits. If the responsible agent is unreachable, verify PR state directly via gh pr view <number> and gh pr checks <number> before proceeding.
! Idempotent pre-check pattern: Before each action in the merge cascade, verify the current PR/branch state to ensure the action is still needed and safe to execute. Check: is this PR already merged (gh pr view <number> --json state --jq .state)? Is this branch already rebased onto the latest master? Has this issue already been closed? This makes recovery re-runs safe — a crash mid-cascade can resume from any point without duplicate actions or errors.
! Pre-merge protected-issue link inspection (Layer 3, #701): Before any gh pr merge call where a referenced issue MUST remain OPEN (umbrella, anchor, follow-up tracker), inspect GitHub's persistent linked-issue list:
gh pr view <N> --repo <owner/repo> --json closingIssuesReferences --jq '.closingIssuesReferences[].number'
The optional task pr:check-protected-issues -- <pr-number> --protected <N1,N2,...> Taskfile target (tasks/pr.yml) wraps this inspection and exits non-zero if any protected issue is GitHub-side linked.
! Layer 0 (prevention) cross-reference (#737): before reaching this Layer 3 recovery surface, the operator should already have run task pr:check-closing-keywords -- --pr <N> per skills/deft-directive-pre-pr/SKILL.md Phase 4 (Diff). Layer 0 scans the PR body + every commit message for closing-keyword tokens in negation / quotation / example / code-block contexts and refuses to push when findings surface; Layer 3 (this rule) is the persistent-link recovery for cases where Layer 0 was bypassed OR the link was attached via the Development sidebar. The two layers complement each other -- Layer 0 prevents the false-positive from being authored, Layer 3 catches the durable-link case Layer 0 cannot see.
If any protected (umbrella / staying-OPEN) issue number appears in the output, the link is persistent in GitHub's database from a prior PR body revision (or a manual sidebar attachment) and survives subsequent body edits; on squash merge, GitHub will close the issue regardless of the current PR body, commit messages, or explicit --subject / --body-file overrides. The merger MUST manually unlink via the PR's Development sidebar panel (web UI -> PR -> right-side Development section -> X next to the linked issue) before merging. The gh CLI does not expose a direct unlink mutation; the GraphQL surface (disconnectPullRequestFromIssue and friends) shifts over time -- the web UI is the reliable path. See meta/lessons.md ## GitHub Closing-Keyword False-Positive Layer 3 for the incident history (PR #700 closed #233; PR #401 closed #642).
! Merge authority: Monitor proposes merge order and executes merges; user approves before the first merge. Do not merge without explicit user approval.
! Rebase cascade ownership: Monitor owns rebase cascade sequencing. Swarm agents do not rebase -- by the time merges begin, swarm agents are idle or complete. The monitor fetches the updated configured base branch, rebases each remaining branch, resolves conflicts, and force-pushes.
! Read-back verification after conflict resolution: After resolving any rebase conflict and BEFORE running git add, re-read the resolved file and verify structural integrity:
- ! No conflict markers remain (
<<<<<<<, =======, >>>>>>>)
- ! No collapsed or missing lines (compare line count to pre-rebase version if feasible)
- ! No encoding artifacts (BOM injection, mojibake, replacement characters)
- ! For
CHANGELOG.md [Unreleased]-section conflicts: the canonical resolution path is task changelog:resolve-unreleased (#911) -- it union-merges HEAD entries with branch entries, deduplicates by (#NNN) issue-number heuristic, and atomically writes back. Three-state exit (0 resolved / 1 unresolvable / 2 config error). The 2026-05-04 v0.25.1 cascade (PRs #909 -> #907 -> #908 -> #906) honoured the edit_files rule below but used a HEAD-take-and-discard pattern that silently dropped each rebasing branch's CHANGELOG entry on every cascade rebase (PR #908 lost #900's entry; PR #906 lost #901's). The helper closes that recurrence by codifying the union-merge pattern. Manual fallback (when the helper exits 1 -- e.g. nested markers, conflicts inside a released ## [0.X.Y] section, or non-trivial structural conflicts the helper cannot mechanize): use edit_files over shell regex (sed, Select-String -replace) for resolution -- edit_files preserves encoding and provides exact match verification, while regex substitutions risk silent line collapse or encoding corruption. The manual path MUST still apply the union-merge pattern (keep ALL HEAD entries; prepend each branch entry whose (#NNN) set does not overlap an existing HEAD entry under the same ### subsection), NOT the legacy HEAD-take-and-discard.
- ⊗ Run
git add on a conflict-resolved file without first re-reading it and verifying structural integrity
- ⊗ Resolve a
CHANGELOG.md [Unreleased] conflict by HEAD-take-and-discard (taking only the HEAD side of each conflict block and discarding the branch side). The rebasing branch's new CHANGELOG entry MUST land in the resolved file -- run task changelog:resolve-unreleased for the canonical union-merge, or apply the union-merge pattern manually when the helper cannot mechanize the conflict (#911)
! Non-interactive rebase: Monitor MUST set GIT_EDITOR=true (Unix/WSL/Git Bash) or $env:GIT_EDITOR="echo" (Windows PowerShell) before running git rebase --continue during merge cascade to prevent the default editor from blocking the agent.
! Merge cascade warning: Shared append-only files (CHANGELOG.md) cause merge conflicts when PRs are merged sequentially — each merge changes the insertion point, conflicting remaining PRs. Each conflict requires rebase → push → wait for checks (~3 min) + ~2-5 min Greptile re-review per rebase. Plan for N-1 rebase cycles × ~3 min CI + ~2-5 min Greptile re-review per rebase when merging N PRs.
! Greptile re-review on rebase force-push: Force-pushing a rebased branch triggers a full Greptile re-review (not an incremental diff), even if the rebase introduced no logic changes. Expected latency is ~2-5 minutes per PR in the cascade. Factor this into merge sequencing.
! Autonomous re-review monitoring after force-push: After each --force-with-lease push of a rebased branch in the cascade, the monitor MUST autonomously wait for the Greptile re-review to complete before proceeding to the next merge. Use the tiered monitoring approach defined in skills/deft-directive-review-cycle/SKILL.md Step 4 Review Monitoring (Approach 1: spawn sub-agent via the platform adapter's dispatch primitive (e.g. spawn_subagent or start_agent) to poll and report back; Approach 2 fallback: discrete run_shell_command wait-mode calls with yield between polls, adaptive cadence -- see deft-directive-review-cycle SKILL.md). Do NOT duplicate the full monitoring logic here -- follow the canonical skill.
~ Resilient wait-until-ready helper (#1368): For the in-cascade wait between a force-push and the next merge, the canonical surface is scripts/monitor_pr.py <N> --repo <owner>/<repo> --cap-minutes <M>. It loops scripts/pr_merge_readiness.py with adaptive cadence (~1m -> 3m -> 5m), routes through _safe_subprocess.run_text (#1366), tolerates via="fallback1" / via="fallback2" / via="error" responses without blinding, and exits 0 only on a primary or fallback1 CLEAN (never fallback2 -- the coarse signal is a monitor heartbeat, not a merge gate). A via="fallback2" payload reporting partial_data.merged == true short-circuits the loop with exit code 3 (PR-TERMINAL) so a cascade can detect a sibling-merged-out-from-under-us state without burning the full cap. Use this in place of hand-rolled time.sleep polling loops in long-running cascade waits.
! Cascade automation surface (#1369): The canonical one-verb compose-point for "wait until PR is mergeable, then squash-merge with admin" is task pr:wait-mergeable-and-merge -- <N> --repo <owner>/<repo> (script: scripts/pr_wait_mergeable.py). The helper wraps scripts/monitor_pr.py (#1368) for the resilient wait loop and scripts/pr_check_protected_issues.py (#701) for the Layer-3 protected-issue link inspection AHEAD of any merge call, then invokes gh pr merge <N> --squash --delete-branch --admin only after the wait loop exits CLEAN on the current HEAD. Three-state exit (0 merged / 1 timeout-or-escalation / 2 config error) mirrors every other framework verb. Pass --protected <issue-numbers> for the Layer-3 chain when the PR is known to reference any umbrella / staying-OPEN issue -- the helper short-circuits with exit 1 BEFORE the merge call if a persistent closingIssuesReferences link is detected. The Wave-3 surface is the automated cascade wrapper; the per-PR atomic gate (task pr:merge-ready -- <N> && gh pr merge <N>) documented above remains the manual freshness-window-atomic check the monitor MUST use when running merges by hand. The two co-exist -- the cascade surface is the automation, the per-PR atomic gate is the manual fall-through. See AGENTS.md ## Cascade automation surface (#1369).
⊗ Hand-roll a cascade while ...; do task pr:merge-ready ...; done shell loop (or equivalent ad-hoc Python monitor) when task pr:wait-mergeable-and-merge is available (#1369). The Wave-1+2 hardening (_safe_subprocess.run_text #1366, pr_merge_readiness.py layered fallbacks #1368, monitor_pr.py resilient wait loop #1368) is composed inside the helper; hand-rolled loops re-introduce the head: None / babysit-each-PR failure mode #1369 closes.
! Gate: Do NOT proceed to the next merge in the cascade until the Greptile review for the rebased branch is current (pushed SHA matches "Last reviewed commit" SHA) AND the exit condition is met (confidence > 3, no P0/P1 issues remaining). A stale or in-progress review is not sufficient; an errored review is also not sufficient; follow the escalation procedure below.
! Greptile service errored state (#526): If the Greptile comment on the current HEAD is the exact string "Greptile encountered an error while reviewing this PR", treat the review as errored (distinct from stale, in-progress, or ready). The GitHub CheckRun will read COMPLETED/NEUTRAL; do NOT interpret that as passing.
Retry ONCE via an @greptileai review comment with a 10-minute cap. If the retry also errors, escalate to the user with a three-way choice:
(a) wait longer (another ~15-20 min in case the service recovers);
(b) push an empty chore: retrigger greptile commit to force a fresh review pass;
(c) merge with documented override, where the rationale MUST be recorded in the merge commit body (not just the PR body) citing prior Greptile success on a pre-rebase SHA, CI/Go + CI/Python success on the current SHA, and the rebase being a pure conflict-resolution merge with no new business logic.
⊗ Loop the monitor indefinitely on the errored state. The monitor MUST detect the "Greptile encountered an error" comment body and exit with an explicit errored report so the parent swarm monitor can route to the escalation procedure above.
⊗ Merge on the basis of the NEUTRAL CheckRun alone -- the service-side failure is indistinguishable from a clean pass at the CheckRun level.
! Polling sub-agent contract for errored state (#526): Short-lived polling sub-agents spawned under Phase 6 MUST detect the "Greptile encountered an error" comment body on the current HEAD and emit a distinct "PR # Greptile errored" message back to the parent, rather than silently continuing to poll or timing out. Sub-agents MUST separately track "Greptile last-reviewed SHA" and "Greptile errored on current HEAD" so an errored state on the current HEAD is not masked by a successful review on a prior SHA.
? Rebase-only annotation: If the force-push contains no logic changes (pure rebase onto updated master), the monitor MAY post a brief PR comment noting "rebase-only, no logic changes" to give Greptile context and help reviewers triage the re-review.
~ To minimize cascades: rebase ALL remaining PRs onto latest master before starting any merges, then merge in rapid succession.
~ Parallel rebase + review monitoring (platform dispatch available): When the platform adapter reports a dispatch primitive is available during the merge cascade, the monitor MAY launch parallel sub-agents to overlap rebase and review monitoring work. For example: while Greptile re-reviews PR #A after a rebase push, spawn a sub-agent to begin rebasing PR #B onto the latest master. Each sub-agent reports back via send_message_to_agent when its task (rebase complete, review passed) is done. This reduces total cascade wall-clock time from serial (rebase + review per PR) to overlapped. The gate remains: do NOT merge PR #B until its own Greptile review passes the exit condition.
- ! Undraft PRs:
gh pr ready <number> --repo <owner/repo>
- ! Squash merge:
gh pr merge <number> --squash --delete-branch --admin (if branch protection requires)
- ! Use descriptive squash subject:
type(scope): description (#issues)
- ! After each merge, rebase remaining PRs onto the updated configured base branch before merging the next
! Post-merge protected-issue reopen sweep (Layer 3, #701): After every squash-merge of a PR that referenced any umbrella / staying-OPEN issue (Refs #N with N a protected issue), verify each protected issue's post-merge state and reopen on regression:
for n in <protected-issue-numbers>; do
state=$(gh issue view "$n" --json state --jq .state)
if [ "$state" != "OPEN" ]; then
gh issue reopen "$n" --comment "Reopened: closing-keyword Layer 3 false-positive on squash merge of PR #<N>; issue is umbrella for ongoing work. See #701."
fi
done
This is defense in depth -- run it even when the pre-merge inspection above passed, because a sidebar-attached link not visible to a body scan, or a missed protected issue in the protected-issue list, can still slip through. The reopen comment MUST cite #701 and the PR that triggered the false-positive so future operators tracing the closed-then-reopened churn can find the root cause.
Step 1.5: Cohort Completion Sweep (#1487)
! REQUIRED. Once the cohort's PRs are merged (Step 1 complete), the monitor MUST run the deterministic cohort completion sweep so the finished swarm leaves NO stranded vBRIEFs. This step closes the gap where a completed cohort left its story vBRIEFs in vbrief/active/ and their decompose-created epic parents in vbrief/pending/ -- nothing in the swarm flow swept them to completed/ (observed in the 2026-06-03 swarm: after the cohort's PRs merged, the child story vBRIEFs stayed in active/ and their epic parents stayed in pending/).
# Sweep the whole cohort by glob (typical close-out)...
task swarm:complete-cohort -- --cohort 'vbrief/active/*.vbrief.json'
# ...or name the cohort's story vBRIEFs explicitly:
task swarm:complete-cohort -- vbrief/active/<story-a>.vbrief.json vbrief/active/<story-b>.vbrief.json
What the sweep does (script: scripts/swarm_complete_cohort.py):
- ! Stage 1 -- stories: every cohort story vBRIEF still in
vbrief/active/ is completed (active/ -> completed/, status completed). A story already terminal (completed/ / cancelled/) is an idempotent no-op, so the sweep is safe to re-run.
- ! Stage 2 -- epic parents: each decompose-created epic parent is completed once ALL of its
x-vbrief/plan children are settled (in completed/ or cancelled/). A parent in pending/ is bridged activate -> complete; a parent in active/ is completed directly. The sweep iterates to a fixpoint, so nested decomposition (phase -> epic -> story) collapses bottom-up. A parent with even one still-active sibling outside the cohort is left untouched.
- ! D4 stays green automatically: every move routes through
scripts/scope_lifecycle.py, which keeps the decomposed parent<->child references in sync on BOTH directions -- child moves update the parent's forward x-vbrief/plan reference (#1485) and parent moves update each child's planRef back-pointer (#1487). Do NOT hand-edit references to "fix" linkage; the helper already does it.
- ! After the sweep, the monitor MUST run
task vbrief:validate and confirm it exits 0 (no D4 regressions). Exit codes for the sweep itself: 0 (sweep clean), 1 (one or more transitions failed -- per-item diagnostics printed), 2 (config error -- empty cohort or missing vbrief/).
! Interactive path: the monitor runs task swarm:complete-cohort by hand (or --dry-run first to preview the planned transitions) once the merge cascade finishes, then runs task vbrief:validate.
! Headless / multi-worker path: the cohort sweep is NOT optional here -- it is the structural fix for the #1487 recurrence where the multi-worker close-out never executed the per-cohort completion. The launching monitor (or the close-out automation that follows task pr:wait-mergeable-and-merge, #1369) MUST invoke task swarm:complete-cohort -- --cohort '<cohort-glob>' after the last cohort PR merges and MUST gate on its exit 0 plus a green task vbrief:validate before declaring the swarm closed. The --json flag emits a structured verdict for a parent monitor agent to consume.
⊗ Declare a swarm closed while any cohort story vBRIEF remains in vbrief/active/ or any fully-childless decompose-created epic parent remains in vbrief/pending/ -- run task swarm:complete-cohort and confirm task vbrief:validate is green first (#1487).
Step 2: Close Issues and Update Origins
- ! Close resolved issues with a comment referencing the PR
- ~ Issues with "Closes #N" in PR body auto-close on squash merge
- ! After each squash merge, verify issues actually closed:
gh issue view <N> --json state --jq .state. If not closed, close manually with a comment referencing the merged PR. Squash merge + closing keywords can silently fail to close issues (#167).
- ! For each completed vBRIEF: read its
references array and update each origin:
- For
github-issue references: verify the issue is closed (auto-close from PR body or Phase 6 Step 2 above); if not, close with gh issue close <N> --comment "Completed in #<PR>"
- For other reference types: document the completion as appropriate
Step 3: Update Master
- ! Pull merged changes:
git pull origin <configured-base-branch> from the merger's OWN worktree only.
- ⊗ Run
git checkout (any branch) in a worktree the merging agent does not own. Post-merge git pull origin <base-branch> semantics MUST be performed via git fetch origin <base-branch> from the merger's own worktree, OR by leaving the master update entirely to the human operator. NEVER touch HEAD of a sibling worktree another agent is using.
- ! After a successful squash merge, the merger MAY remove its own worktree via
git worktree remove <path> and delete the now-orphaned local feature branch via git branch -D <branch>. The merger MUST NOT alter any other worktree's HEAD or branch state.
- ! Worktree-boundary discipline (#800, companion to #727): the
⊗ rule above extends the same boundary discipline as the ### Sub-Agent Role Separation (#727) companion rules earlier in Phase 6 -- #727 codifies sub-agent spawn shape; #800 codifies worktree HEAD operations. Recurrence record: PR #797 merge session (2026-05-01) -- Agent B (the merger) ran cd C:\repos\Deft\directive; git checkout master --quiet against Agent A's sibling worktree after merging its own PR; HEAD detached on Agent A's branch and was retroactively restored. No work was lost (Agent A had pushed) but recovery was incident-driven, not preventative.
Step 4: Clean Up
- ! Remove worktrees:
git worktree remove <path>
- ! Delete local branches:
git branch -D <branch>
- ~ Delete launch scripts if still present
- ? If worktree removal fails (locked files from open terminals), note for manual cleanup
Step 5: Generate Slack Release Announcement
! After creating the GitHub release (or after the final merge if no formal release is created), generate a standard Slack announcement block and present it to the user for copy-paste into the team channel.
! The announcement block MUST include all of the following fields:
:rocket: *{Project Name} {version}* -- {release title}
*Summary*: {one-sentence description of the release scope}
*Key Changes*:
- {bullet per significant change, 3-5 items max}
*Stats*: {N} agents | ~{duration} elapsed | {N} PRs merged
*PRs*: {#PR1, #PR2, ...}
*Override merges*: {#PRX: <one-line rationale from merge commit body>, ...} -- omit this line only if no PR in the release used the Greptile-service-errored override path
*Release*: {GitHub release URL}
- ! Populate version from the CHANGELOG promotion commit or git tag
- ! Populate release title from the CHANGELOG section heading or GitHub release title
- ! Key changes summarized from CHANGELOG
[Unreleased] entries (not raw commit messages)
- ! Agent count and approximate duration from the swarm session (Phase 3 launch to Phase 6 close)
- ! PR numbers from the merged PRs in this swarm run
- ! Override merges line (#526): For any PR in the release that was merged via the Greptile-service-errored override path (Phase 6 Step 1 choice (c)), explicitly call it out in the announcement with the one-line rationale taken from the merge commit body so downstream readers of the release notes can trace the documented rationale. Detect override merges by scanning each merged PR's merge commit body for the override rationale footprint (prior Greptile success on a pre-rebase SHA + CI green on current SHA + pure conflict-resolution rebase). Omit the
*Override merges* line only when no merged PR in this release used the override path.
- ~ Cascade automation citation (#1369): When the release used
task pr:wait-mergeable-and-merge to drive the merge cascade (the canonical Wave-3 surface introduced by #1369), the operator MAY include a one-line announcement footnote -- e.g. _Merge cascade automated via task pr:wait-mergeable-and-merge (#1369)._ -- so downstream readers of the release notes know the cascade ran through the deterministic three-state-exit surface rather than a hand-rolled monitor. The per-PR atomic gate (task pr:merge-ready && gh pr merge) remains the manual fall-through and does NOT need to be cited; only the automated cascade path warrants the explicit footnote.
- ! GitHub release URL from the
gh release create output (or gh release view --json url if already created)
- ~ Present the block as a code-fenced snippet the user can copy directly
- ? If no formal GitHub release was created (e.g. user deferred), still generate the announcement with a placeholder URL and note that the release is pending
Crash Recovery
When a monitor session crashes or a new session must take over an in-progress swarm, follow these steps to safely reconstruct and continue.
Checkpoint Guidance
! At each major Phase 6 milestone, record progress so a new session can reconstruct state:
- PR merged — note the PR number, merge commit SHA, and which issues it closes
- Rebase done — note which branches have been rebased onto the latest master
- Review passed — note which PRs have passed the Greptile exit condition post-rebase
~ Use a brief structured note (in the conversation or a scratch file) after each milestone — this is the checkpoint a recovery session will read.
Recovery Steps
! On a fresh session taking over a swarm, reconstruct the cascade state before taking any action:
- ! Run
gh pr list --repo <owner>/<repo> --state all to see all PRs from the swarm (filter by branch prefix, e.g. agent1/, agent2/)
- ! For each PR, run
gh pr view <number> --json state,mergeCommit,headRefName,title to determine:
- Is this PR already merged? (state = MERGED) → skip, move to issue verification
- Is this PR still open? → check if it needs rebase, re-review, or merge
- Is this PR closed without merge? → investigate (was it superseded?)
- ! For open PRs, check rebase status:
git --no-pager log --oneline <branch> ^origin/<configured-base-branch> -5 — if empty, the branch is already up-to-date with the configured base branch
- ! For open PRs, check review status:
gh pr checks <number> and gh pr view <number> --comments to verify Greptile review state
- ! Resume the cascade from the first incomplete step — the idempotent pre-check pattern (see Step 1 above) ensures re-running any step on an already-completed PR is safe
Idempotent Safety
! Every Phase 6 action MUST be safe to re-run:
- Merging an already-merged PR →
gh pr merge will report "already merged" and exit cleanly
- Rebasing a branch already on latest configured base branch → rebase is a no-op
- Closing an already-closed issue →
gh issue close will report "already closed"
- Force-pushing a branch that hasn't changed → push reports "Everything up-to-date"
Prompt Template
! Use this template for all agent prompts. The first line MUST be an imperative task statement.
TASK: You must complete N [type] fixes on this branch ([branch-name]) in the deft directive repo.
This is a git worktree. Do NOT just read files and stop — you must implement all changes,
run task check, commit, push, create a PR, and run the review cycle.
DO NOT STOP until all steps are complete.
STEP 1 — Read directives: Read AGENTS.md, vbrief/vbrief.md, and the assigned vBRIEF(s) from vbrief/active/.
Read skills/deft-directive-review-cycle/SKILL.md.
STEP 2 — Implement these N tasks (see assigned vBRIEF(s) for full acceptance criteria):
Task A (vBRIEF: [filename], issue #[N]): [one-paragraph description with specific acceptance criteria]
Task B (vBRIEF: [filename], issue #[N]): [one-paragraph description with specific acceptance criteria]
[...repeat for each task...]
STEP 3 — Validate: Run task check. Fix any failures.
STEP 4 — Commit: Add CHANGELOG.md entries under [Unreleased].
Commit with message: [type]([scope]): [description] — with bullet-point body.
STEP 5 — Push and PR: Push branch to origin. Create PR targeting <configured-base-branch> using gh CLI.
Note: --body-file must use a temp file in the OS temp directory ($env:TEMP on PowerShell,
$TMPDIR or /tmp on Unix) -- do NOT write temp files in the worktree. See scm/github.md.
STEP 6 — Review cycle: Follow skills/deft-directive-review-cycle/SKILL.md to run the
Greptile review cycle on the PR. Do NOT merge — leave for human review.
CONSTRAINTS:
- Do not touch [list files other agents are working on]
- New source files (scripts/, src/, cmd/, *.py, *.go) must have corresponding test files in the same PR
- Use conventional commits: type(scope): description
- Run task check before every commit
- Never force-push
Template Rules
- ! First line MUST start with
TASK: followed by an imperative statement
- ! Include
DO NOT STOP until all steps are complete in the preamble
- ! Each task MUST include its vBRIEF filename and origin issue number
- ! CONSTRAINTS section MUST list files the agent must not touch (other agents' scope)
- ! Review cycle step MUST reference
skills/deft-directive-review-cycle/SKILL.md explicitly
- ⊗ Start the prompt with context ("You are working in...") — agents treat this as passive setup and may stop after reading
Push Autonomy
! Swarm agents operating under this skill with a monitor agent may push, create PRs, and run review cycles autonomously after passing task check. The global "never push/commit without explicit user instruction" convention does not apply to swarm agents executing the full STEP 1-6 prompt workflow -- the skill's quality gates (task check, Greptile review cycle) replace the interactive confirmation gate.
Anti-Patterns
- ⊗ Start prompts with context or description instead of an imperative TASK directive
- ⊗ Use
--mcp with Warp MCP server UUIDs from standalone (non-Warp) terminals
- ⊗ Assign overlapping files to multiple agents
- ⊗ Merge PRs before Greptile exit condition is met (score > 3, no P0/P1)
- ⊗ Assume agents will complete the full workflow — always verify review cycle completion
- ⊗ Launch agents without checking vBRIEF acceptance criteria first
- ⊗ Skip the file-overlap audit in Phase 1
- ⊗ Use
git reset --hard or force-push in any worktree (swarm agents only -- monitor may --force-with-lease after rebase cascade per Phase 6 Step 1)
- ⊗ Present static launch options (A/B/C) instead of detecting capabilities at runtime — always probe for
start_agent and Warp environment variables before choosing a launch path
- ⊗ Offer Warp-specific launch paths (tabs,
start_agent) when not running inside Warp — gate on WARP_* environment variables or start_agent tool presence
- ⊗ Default to
oz agent run-cloud — cloud is an explicit user-requested escape hatch, not a default path
- ⊗ Use
oz agent run-cloud when the user expects local execution — run-cloud routes to remote VMs with no local context
- ⊗ Proceed to Phase 1 (Select) without completing Phase 0 (Allocate) and receiving explicit user approval
- ⊗ Begin merge cascade without presenting the version bump proposal and receiving explicit user approval — the Phase 5→6 gate is mandatory
- ⊗ Ignore Greptile re-review latency when planning merge cascade timing -- each rebase force-push triggers a full re-review (~2-5 min), not an incremental diff
- ⊗ Proceed to the next merge in the rebase cascade before confirming the Greptile re-review is current (SHA match) and exit condition is met (confidence > 3, no P0/P1) on the rebased branch -- see
skills/deft-directive-review-cycle/SKILL.md Step 4 for the monitoring approach
- ⊗ Spawn a replacement sub-agent without confirming the original is unresponsive via a lifecycle event (idle/blocked) — original agents (Warp tabs or Grok Build / spawn_subagent processes) can resume after apparent failure, and two concurrent agents on the same worktree will corrupt the tool_use/tool_result call chain (#261, #263)
- ⊗ Hardcode
start_agent (or any single primitive) for Phase 6 review-cycle poller / post-PR sub-agent dispatch -- always delegate spawn to the platform adapter (per runtime detection from slices 1-3) so Grok Build / spawn_subagent and future platforms are first-class (#1342 Phase 6 unification)
- ⊗ Skip Phase 5 or the Phase 5→6 confirmation gate under time pressure or due to long context — the gate is mandatory regardless of conversation length, elapsed time, or context-window pressure
- ⊗ Run
git add on a conflict-resolved file without re-reading and verifying structural integrity (no conflict markers, no collapsed lines, no encoding artifacts) -- see Phase 6 Step 1 read-back verification rule (#288)
- ⊗ Use shell regex (
sed, Select-String -replace) to resolve CHANGELOG.md rebase conflicts -- prefer task changelog:resolve-unreleased (#911) for [Unreleased] conflicts; fall back to edit_files for encoding safety and exact match verification when the helper exits 1 (#288, #911)
- ⊗ Resolve a
CHANGELOG.md [Unreleased] conflict by HEAD-take-and-discard -- the rebasing branch's new entry MUST land in the resolved file. Use task changelog:resolve-unreleased (#911) for the canonical union-merge or apply the union-merge pattern manually when the helper cannot mechanize the conflict
- ⊗ Hardcode a 1:1 vBRIEF-per-agent allocation rule — the monitor decides allocation dynamically based on scope, complexity, and dependencies
- ⊗ Complete a story without moving its vBRIEF from
active/ to completed/ and updating its origin references
- ⊗ Declare a swarm closed without running the Phase 6 Step 1.5 cohort completion sweep (
task swarm:complete-cohort) and confirming task vbrief:validate is green -- skipping it leaves the cohort's story vBRIEFs stranded in active/ and their decompose-created epic parents stranded in pending/, the exact #1487 recurrence (the headless / multi-worker close-out is where the sweep was historically missed)
- ⊗ Hardcode
master as the base branch -- always use the configured base branch from Phase 0
- ⊗ Treat a Greptile GitHub CheckRun of COMPLETED/NEUTRAL as equivalent to a passing review without inspecting the comment body. NEUTRAL is the result both when Greptile intentionally has nothing to say AND when it errored out mid-review; the two cases require opposite responses (#526)
- ⊗ Loop the monitor indefinitely on the Greptile-service-errored state or time out silently at the poll cap -- detect the "Greptile encountered an error" comment body, retry once via
@greptileai review with a 10-minute cap, and on second error escalate to the user with the three-way choice (wait / empty retrigger commit / documented override) per Phase 6 Step 1 (#526)
- ⊗ Merge a rebased PR on the basis of the NEUTRAL CheckRun alone when the Greptile comment body is the error sentinel -- the service-side failure is indistinguishable from a clean pass at the CheckRun level, and any merge taken must be recorded as a documented override in the merge commit body (#526)
- ⊗ Omit override-merged PRs from the Phase 6 Step 5 Slack release announcement -- any merge that used the Greptile-service-errored override path MUST be called out with its one-line rationale so downstream readers can trace the documented override trail (#526)
- ⊗ Run
gh pr merge on a PR that has any protected (umbrella / staying-OPEN) issue listed in gh pr view <N> --json closingIssuesReferences -- the link is persistent in GitHub's database from a prior PR body revision (or sidebar attachment) and survives body edits, commit-message edits, and explicit --subject / --body-file overrides; manually unlink via the PR's Development sidebar panel before merging (Layer 3, #701)
- ⊗ Skip the post-merge protected-issue reopen sweep for any squash merge that referenced an umbrella / staying-OPEN issue -- defense in depth catches Layer 3 false-positives the pre-merge inspection missed (#701)
- ⊗ Merge on the basis of a SUCCESS Greptile CheckRun alone -- the CheckRun signals review completion, not review approval (PR #652 incident; symmetric blind spot to the NEUTRAL CheckRun #526 case). Always run
task pr:merge-ready -- <N> before gh pr merge to parse the comment body for confidence + P0 / P1 findings
- ⊗ Run
git checkout (any branch) -- including the brief cd <other-worktree>; git checkout master --quiet shape -- in a worktree the merging agent does not own during Phase 6 Step 3 (Update Master) or Step 4 (Clean Up). Post-merge state-update semantics MUST be performed via git fetch origin <base-branch> from the merger's OWN worktree, never by switching HEAD on a sibling worktree another agent is actively using. Recurrence record: PR #797 merge session (2026-05-01); companion to the Sub-Agent Role Separation rules (#727) -- this anti-pattern extends the same boundary discipline from sub-agent spawn shape to worktree HEAD operations (#800)
- ⊗ Skip the Phase 0 Step 0.5 lifecycle bridge (#1025) and let the Step 1 preflight gate reject candidate scope vBRIEFs wholesale. The setup skill deposits scope vBRIEFs in
vbrief/proposed/ and the refinement skill leaves them in vbrief/pending/; the swarm Phase 0 Step 1 preflight only accepts vbrief/active/ with plan.status == "running". The bridge step (task scope:promote -- <path> then task scope:activate -- <path>) is the contract that converts proposed/pending candidates to active before allocation -- bypassing it re-surfaces the originating 2026-05-10 first-session consumer-swarm failure mode (Invalid transition: 'activate' requires file in pending/)
- ⊗ Auto-promote + activate every candidate in
vbrief/proposed/ or vbrief/pending/ during the Phase 0 Step 0.5 bridge without explicit user approval (#1025). Proposed-stage vBRIEFs may be in a deliberate refinement queue (skills/deft-directive-refinement/SKILL.md Phase 4); silent promotion bypasses the user's lifecycle intent and may flip plan.status to running on scopes the user has not yet refined. Broad affirmatives (proceed, do it, go ahead) do NOT satisfy the bridge approval gate -- require an explicit yes / confirmed / approve
- ⊗ Fall through to the manual-terminal fallback (Step 2b) when spawn_subagent is available -- Step 2d is the first-class grok-build launch path; manual terminal is for environments with no orchestration primitive at all (#1331)
- ⊗ Surface, propose, or discuss the Phase 5 -> 6 merge cascade gate while
task swarm:verify-review-clean -- <pr-numbers...> has not yet exited 0 on the current cohort (#1364). Keying the transition on poller lifecycle completion alone -- i.e. treating "every poller sub-agent returned a terminal message" as sufficient to surface the merge gate -- is the recurrence pattern from the #1166 swarm execution where multiple pollers exited with clean_gate_holdout=confidence (confidence == 3) and the monitor still raised the Phase 5 -> 6 gate. The cohort verifier is the only authoritative CLEAN signal at the cohort level; a poller's clean_gate_holdout=* exit IS a non-CLEAN report and MUST hold the gate even when every sub-agent has technically returned