SuperAPI AI Directory

build-phases

Coding & development

View repository

Updated 10-15 19:57

About this skill

Build Phases — Automated Phase-by-Phase Implementation + Verification Loop

Repo profile — read .claude/repo-profile.md first. This skill is repo-agnostic; arc is the reference implementation. Toolchain commands below are written as <package_manager> <script> (arc: pnpm build / pnpm check-types / pnpm test) and <formatter> (arc: biome check --write) — map them to your repo via the profile's Toolchain keys. Arc's issue-number provenance for any lessons is not inlined here.

Execute a planning document's phases sequentially, with mandatory three-layer verification, code simplification, and design review at each phase.

Drive to completion (default posture). The loop's job is to finish all phases in one continuous run — Phase 0 → 1 → … → last → final PR — not to stop after one phase and wait. Do not pause for a merge between phases, do not hand back "Phase N done, shall I continue?" when nothing is actually blocked. The loop stops for exactly two reasons: (a) all phases are complete, or (b) a genuine must-human escalation (the hard-stop conditions in "Escalation Rules" — real design fork, unresolvable failure, needs external creds/ops, irreversible architecture call). Everything else — next phase, respawn, rebase a stacked commit — the loop does itself. In autonomous / issue-native mode this is non-negotiable: the human may not return for hours, so an unnecessary pause strands the whole feature. When you must stop, it's an escalation (issue comment if issue-native, inline if a human is present), never a silent idle.

Usage

Recommended (with watchdog):

/loop /agentloop:build-phases <planning-dir> [--start-phase <N>] [--review-target <score>]

/loop without an interval puts the skill in self-pacing mode. Progress is primarily notification-driven (executor sub-agents push a task-notification when they finish); ScheduleWakeup provides a 30-minute fallback tick so a hung executor can never stall the chain silently. See Rule 4 for the watchdog state machine.

Direct (single dispatch, no watchdog):

/agentloop:build-phases <planning-dir> [--start-phase <N>] [--review-target <score>]

Direct invocation still spawns one phase and writes .build-progress.json, but there is no automatic watchdog — you'll need to re-invoke the skill manually to advance, respawn, or finish. Prefer the /loop form unless you know what you're doing.

  • <planning-dir> — Directory containing tasks.md (with phases) and optionally design.md
  • --start-phase <N> — Start from phase N (default: 0, useful for resuming)
  • --review-target <score> — Minimum design review score (default: 95)

Examples

/loop /agentloop:build-phases planning/provider-architecture-rethink/
/loop /agentloop:build-phases planning/provider-architecture-rethink/ --start-phase 2
/loop /agentloop:build-phases planning/aup-builder/ --review-target 90

Issue-driven plans (no planning/ file — manage in GitHub)

If the phases live in a GitHub issue rather than a planning/ dir (a human confirmed a TDD plan in the comments, e.g. <repo_slug>#N), do NOT commit a planning/ doc — the issue is the source of truth. Bridge mechanically:

  1. Render an ephemeral tasks.md (+ optional design.md) from the issue's confirmed plan into a scratch / gitignored dir. build-phases' .build-progress.json + logs/sN-e2e.log also live in scratch. None of it is committed.
  2. Model the work in GitHub, not in files. For a multi-phase / complex plan, put the phases/tasks as a checkbox task-list in the issue body (or a pinned tracking comment), and/or split into sub-issues. That is the durable, browsable tracker.
  3. Run /agentloop:build-phases <scratch-dir> normally. Per phase = one commit (TDD + 3-layer verification land together so history is bisectable), tick that phase's checkbox, and post a one-line progress comment.
  4. Durable record = issue thread + checkboxes / sub-issues + merged PR(s) + git history. The scratch files are throwaway. Nothing lands in planning/.

PR granularity ≠ phase granularity — decide by coupling, don't default to one-PR-per-phase. A phase is the unit of commit discipline; the PR is the unit of review + merge. Pick the PR shape per feature:

  • One feature PR (phases as commits; only the last commit Fixes #N) when the phases are tightly coupled and early phases have no standalone value — e.g. a Phase 0 pure-refactor "seam" that nothing consumes yet, or a feature that's only half-wired until the final phase. This is the default for a coherent feature: one review, one merge, main never carries a half-feature, and (crucial in autonomous mode) the human hits one merge gate, not N.
  • One PR per phase (Refs #N each, final Fixes #N) only when each phase independently ships and delivers value (e.g. unrelated doc deletions, or steps that can each go live on their own), or the diff is genuinely too large to review at once.

When unsure, prefer the single feature PR for a feature; reserve per-phase PRs for independently-shippable work. If a human is present, you may ask; in autonomous mode pick by the coupling test above and state the choice in the PR body.

Autonomous escalation → issue comment, not an inline wait. In this issue-native flow nobody is babysitting the session, so every escalation (see "Escalation Rules" below) that would normally ⏸ 停下来等用户指令 must instead be posted as a comment on the source issue — state the blocker, the options, and your recommendation — and then stop that work item without waiting in-session. The human answers asynchronously on the issue and the next sweep resumes. Still record the same executor_status: "error" + executor_error in the scratch .build-progress.json so a resumed run knows where it stopped. Only use an inline blocking prompt when a human is demonstrably present in the session.

How It Works

For each phase in tasks.md:

┌─────────────────────────────────────────────────────┐
│  Phase N                                             │
│                                                      │
│  1. IMPLEMENT                                        │
│     Read phase spec from tasks.md                    │
│     Write tests first (TDD)                          │
│     Implement until tests pass                       │
│     Use parallel subagents for independent tasks     │
│                                                      │
│  2. VERIFY (three layers, mandatory, not skippable)  │
│     Layer 1: build + type-check + test suite         │
│     Layer 2: Start service, send real requests        │
│            → write raw afs_exec output to            │
│            planning/<dir>/logs/s{N}-e2e.log          │
│            (HARD GATE — phase NOT done without it)   │
│     Layer 3: Adversarial — break it intentionally    │
│     → ALL must pass, or go back to 1                 │
│                                                      │
│  3. COMMIT "phase N: implement"                      │
│                                                      │
│  4. SIMPLIFY (/simplify skill)                       │
│     Clean up code for clarity and maintainability    │
│                                                      │
│  5. RE-VERIFY (Layer 1 only — ensure no regression)  │
│     → FAIL? Revert simplify changes                  │
│                                                      │
│  6. COMMIT "phase N: simplify"                       │
│                                                      │
│  7. DESIGN REVIEW (parent dispatches a clean-context │
│     reviewer — implementer and reviewer are           │
│     DIFFERENT agents)                                 │
│     Score must meet --review-target                   │
│     → NOT APPROVED? respawn executor with findings   │
│                                                      │
│  8. Report phase completion, proceed to Phase N+1    │
└─────────────────────────────────────────────────────┘

CRITICAL: Execution Continuity Rules

These rules prevent the agent from stopping midway through a phase.

Rule 1: A phase is atomic — output only after all 8 steps are complete

Before all 8 steps of a phase are complete, do not output any summary or report to the user.

  • ❌ Wrong: implement → commit → "Done! 4 tests added." → wait for the user to speak
  • ✅ Correct: implement → commit → simplify → re-verify → commit → review → fix if needed → THEN report

The only case where midway output is allowed is escalation (hard stop condition). In all non-escalation cases, continue to the next step without exception.

Rule 2: Do not stop between phases either

In multi-phase tasks, immediately start the next phase after one phase completes. Do not wait for user confirmation.

  • ❌ Wrong: Phase 0 complete → "Phase 0 done, shall I proceed to Phase 1?" → wait for user
  • ✅ Correct: Phase 0 complete → Phase 1 starts immediately → ... → all phases done → final report

For each phase, output a brief completion line (no more than 3 lines), then immediately start the next one.

Rule 3: Run to the end before producing the final report

Stop only in the following cases:

  1. All phases are complete → output final report
  2. An escalation condition is encountered → output a ⏸ report and wait for user instructions
  3. The user actively interrupts

Rule 4: Watchdog scheduling — the Parent Session is the only spawn initiator

/agentloop:build-phases Each invocation may fall into one of two modes:

  • Init mode:.build-progress.json does not exist → do pre-flight, write checkpoint, spawn the first phase, schedule the next wake
  • Watchdog mode:.build-progress.json already exists → read state, take one action according to the state machine, schedule the next wake (or stop the loop)

Core principle: Each phase is executed byone background sub-agent(Agent tool,run_in_background: true,general-purpose type)—clean context, runs only one phase, and never spawns the executor for the next phase itself. The Parent session is the only scheduler.

Historical note (2026-06-12 rewrite): The old implementation used claude -p to spawn an independent CC process (the subscription will soon no longer support headless). The sub-agent approach isstrongerin terms of completion guarantees: when a background agent completes/dies, the harness actively pushes a task-notification to wake the parent (no longer relying on pure polling),ScheduleWakeup is downgraded to a fallback heartbeat. The cost is that a background agent cannot survive detached from the session—.build-progress.json persistent state + /loop re-entrant recovery make up for this.

Dual-driven model:

  1. Notification-driven (primary) — when the executor agent finishes, the parent is automatically woken by task-notification and immediately runs the state machine (verify gate → review → advance/respawn)
  2. Wakeup fallback (secondary) — ScheduleWakeup(1800s) prevents the case where an executor hangs and never exits (so the notification never arrives): on wake, read the heartbeat; if stale, then TaskStop + respawn

Why do it this way:

  1. Watchkeeping and execution are decoupled — if the executor crashes, there is a notification; if it hangs, there is a fallback tick that reads the stale heartbeat and restarts it
  2. Context isolation — each phase is a fresh subagent; the parent only does scheduling + gatekeeping + review dispatch; the parent's own compaction does not lose state (.build-progress.json is the real memory)
  3. Failures are visible — an anomaly is silent for at most one fallback cycle (30 minutes), and is usually visible immediately

Recommended invocation method: /loop /agentloop:build-phases <planning-dir>(without interval, self-pacing). Direct invocation also works, but there is no fallback tick.

Parent session behavior (applies every time the skill is entered)

  1. Read .build-progress.json → if it does not exist, take the Init branch; if it exists, take the Watchdog branch
  2. Execute the corresponding branch'soneaction (spawn / gatekeep + review / respawn / stop)
  3. If the task is not finished → call ScheduleWakeup(delaySeconds=1800, prompt="/loop /agentloop:build-phases <planning-dir>", reason="fallback watchdog tick for phase N")— this is thefallback, normal progress relies on the task-notification when the executor finishes
  4. If everything is complete → output the final report, delete the progress file,do not reschedule(the loop ends naturally)

Watchdog state machine

There are two entry points: (a) the executor's task-notification arrives (main path); (b) the fallback wakeup tick. Both perform the same action: read .build-progress.json(cross-validating with TaskGet <executor_task_id> as needed against the harness-side state), and match by priority:

Condition Action
completed_phases.length === total_phases All complete — output the final report, delete the progress file, do not reschedule
executor_status === "done" and all gates pass + review approved and there are still phases not completed Chain advances — current_phase +1, spawn the executor for the next phase, reschedule the fallback tick
executor_status === "done" but the parent gatekeeping has not run Gatekeeping — the parent personally runs the E2E log gate (exists/non-empty/contains JSON/no deferred self-admission), passes → dispatch a clean-context review agent; review approved → advance; NOT APPROVED → write the review findings into the respawn prompt, respawn to fix (counting respawn_count)
executor_status === "running" and heartbeat < 30 min Everything is normal — do nothing, reschedule the fallback tick
executor_status === "running" and heartbeat stale ≥ 30 min Stuck — TaskStop old executor,executor_respawn_count +1, respawn the current phase, reschedule
The executor's task-notification shows the agent died/errored (or executor_status === "error") explicit failure — read executor_error;E2E_LOG_* category → escalation stops the loop; spec ambiguity/needs external action → stop the loop; otherwise respawn and reschedule
executor_status === "done" but e2e_logs[phase_N] is missing or the file does not exist/is empty Fake completion — treat as an error, respawn_count +1, respawn
Other (init has just been written but not yet spawned) Immediately spawn the current phase, reschedule

Continuous stall protection: the same phase executor_respawn_count ≥ 3 → stop the loop, report in escalation format.

Key differences from the old version: before the parent advancesit personally gatekeeps(bash verifies E2E log + deferred grep) andpersonally dispatches the design review(clean-context agent) — no longer trusts the executor's self-report. The reviewer and the implementer come from different agents, giving stronger independence than the old design.

Watchdog Tick Report (must be output on every wake)

Rule: on every watchdog wake, output a status report before deciding on an action. Even if the action is WAIT(do nothing), still output a brief report so the user can see the chain is moving rather than dead.

## 🐕 Watchdog tick — phase {current_phase}/{total_phases}

**Executor:** `{executor_status}` | started {executor_started_ago} ago
**Current task:** {executor_current_task}
**Heartbeat:** {heartbeat_ago} ({fresh|stale})
**Respawn count:** {n}/3
**Completed:** {completed_phases} | **Tests:** {latest_test_count}
**Log:** `{executor_log}`

**Recent output:**

{tail -10 of executor_log, or "(no log file yet)" if missing}


**→ Decision:** `{ACTION}` — {one-line reason}
**→ Next tick:** notification-driven; fallback wake in 30 min (ScheduleWakeup) | stopping (complete/escalated)

Log tail: watchdog reads the last ~10 lines of executor_log on every tick and inlines them. Users who want continuous output still have tail -f {executor_log} in a separate terminal, but the tick alone is enough to see whether the spawned process is making progress (new ▸ markers appearing) or stuck (same tail two ticks in a row with stale heartbeat).

In Init modeuse the simplified version (no executor state yet):

## 🐕 Watchdog init — phase 0/{total_phases}

**Planning:** {planning-dir}
**Design review:** ✓ passed at {score}%
**Log:** `{executor_log}` (tail -f to follow)

**→ Spawned phase 0.** Advancement is notification-driven; fallback tick in 30 min.

Why reporting is mandatory:

  • The biggest problem with the old chained spawn was "silent failure" — the user thought it was running, but it had long since died
  • Now the executor pushes a notification on completion, plus a fallback output every 30 minutes, so the user can see at any time what is currently running and whether the heartbeat is fresh
  • Even if it is WAIT(did nothing), still output so the user can see the watchdog itself is alive

Heartbeat ago formatting: < 60s → "Ns",< 60min → "Nm",> 60min → "Nh Mm", if stale add ⚠️。

Executor agent behavior (written into the spawn prompt)

  1. First action: use Bash to update .build-progress.json(before reading any other file):
    {
      "executor_status": "running",
      "executor_started_at": "<ISO>",
      "executor_current_task": "<phase name>",
      "executor_last_heartbeat": "<ISO>"
    }
    
  2. Read tasks.md, run the current phase's implement→verify→commit→simplify→re-verify→commit flow (Section 2.1-2.5.design review is not the executor's job— the parent personally dispatches an independent reviewer after receiving the completion notification)
  3. After completing each sub-task: update executor_last_heartbeat + executor_current_task, and append to <planning-dir>/.build-logs/phase-N.log a line ▸ <sub-task>(the progress panel the user tail -f's)
  4. E2E log gate self-check (mandatory, before writing done ): confirm that <planning-dir>/logs/s{N}-e2e.log exists, is non-empty, contains JSON-form output, and has no deferred self-confessions (out-of-scope/deferred/skipped/will be done later). If not satisfied → write executor_status: "error" + executor_error: {reason: E2E_LOG_MISSING|E2E_LOG_NO_JSON|E2E_LOG_HAS_DEFERRED, detail} and end. The parent will also re-check — the self-check is to save a round of respawn
  5. Phase complete → update:
    {
      "executor_status": "done",
      "completed_phases": [..., N],
      "test_counts": { ..., "phase_N": <count> },
      "commits": { ..., "phase_N": ["<sha>", ...] },
      "e2e_logs": { ..., "phase_N": "<planning-dir>/logs/s<N>-e2e.log" }
    }
    
  6. Keep the final message short(≤15 lines: phase, test count, commits, E2E log path, surprises encountered) — the status is all in the files; the final message is just a summary for the parent, do not paste large chunks of logs
  7. Do not spawn the next phase's executor. On escalation → write executor_status: "error" + executor_error: { reason, detail, attempt_count } → end and explain in the final message

Checkpoint format

{
  "planning_dir": "planning/xxx",
  "started_at": "2026-04-15T10:00:00Z",
  "total_phases": 5,
  "current_phase": 2,
  "completed_phases": [0, 1],
  "test_counts": { "phase_0": 1782, "phase_1": 1850 },
  "commits": { "phase_0": ["abc123"], "phase_1": ["def456"] },
  "e2e_logs": {
    "phase_0": "planning/xxx/logs/s0-e2e.log",
    "phase_1": "planning/xxx/logs/s1-e2e.log"
  },

  "executor_status": "running",
  "executor_started_at": "2026-04-15T10:42:00Z",
  "executor_current_task": "phase 2 — implement foo",
  "executor_last_heartbeat": "2026-04-15T10:47:00Z",
  "executor_respawn_count": 0,
  "executor_error": null,
  "executor_log": "planning/xxx/.build-logs/phase-2-20260415T104200Z.log"
}

Spawn template (Agent tool)

Use the Agent tool to launch a background executor. Before spawning, first create the log directory and write the log path and task id into the progress file:

Bash: mkdir -p {planning-dir}/.build-logs
      LOG={planning-dir}/.build-logs/phase-{N}.log
      jq --arg log "$LOG" '.executor_log = $log' .build-progress.json > tmp && mv tmp .build-progress.json

Agent(
  subagent_type: "general-purpose",
  run_in_background: true,
  description: "build-phases executor: phase {N}",
  prompt: <<<
    You are a build-phases EXECUTOR for exactly ONE phase. Repo root: {abs-repo-root}.

    Read {planning-dir}/tasks.md and execute ONLY Phase {N}, following
    .claude/plugins/agentloop/skills/build-phases/SKILL.md sections 2.1-2.5 (implement → 3-layer
    verify → commit → simplify → re-verify → commit). Do NOT run the design
    review — the parent session dispatches an independent reviewer.

    FIRST ACTION (before reading anything else): update
    {planning-dir}/.build-progress.json via Bash:
      executor_status: "running", executor_started_at/<heartbeat>: now (ISO),
      executor_current_task: "phase {N} — starting"

    Rules:
    - After each sub-task: update executor_last_heartbeat + executor_current_task,
      and append "▸ <sub-task>" to {planning-dir}/.build-logs/phase-{N}.log
    - E2E HARD GATE self-check before flipping to "done": logs/s{N}-e2e.log
      exists, non-empty, contains JSON-shaped afs output, no deferred-work
      admissions. Fail → executor_status: "error" + executor_error{reason,detail}.
    - On success update progress JSON: executor_status "done", append {N} to
      completed_phases, record test_counts/commits/e2e_logs.
    - TDD strictly; 3-layer verification per SKILL.md 2.2; escalation rules per
      SKILL.md(停下来写 error,不要猜).
    - NEVER commit run-generated logs/state (logs/*.log, .build-logs/,
      .build-progress*.json). Only `git add <specific-files>`.
    - Final message ≤15 lines: phase, tests, commits, e2e log path, surprises.
    {if respawn for review fixes: append the reviewer's findings here}
  >>>
)

Write back executor_task_id(the task id returned by Agent) to the progress file, for use by TaskGet/TaskStop .

Confirmation after spawn

The Agent tool's launch is a synchronous confirmation (returning an agentId means it has been accepted), so the old 30-second startup wait is not needed. After spawning, do only one thing: write executor_task_id into the progress file, then ScheduleWakeup(1800s) wait for the notification.

Key rule: one executor agent = one phase; the parent is the only spawn initiator; before advancing, the parent personally guards the gate + dispatches the review.

Regression testing

The state machine + tick rendering have a reference implementation and fixture tests in test/. Whenever you change the Watchdog state machine or the tick report format, first change test/watchdog.sh / test/render-tick.sh + fixtures, confirm all pass, then change this document:

.claude/plugins/agentloop/skills/build-phases/test/run-tests.sh

Fixture coverage: init / fresh / running-fresh / running-stale / phase-done / all-done / error / crashed / respawn-limit. The Render tests also cover the "Recent output" panel (tail the file when there is a log, show a placeholder when there is no log). After the sub-agent rewrite, the stale threshold changed from 10 minutes to 30 minutes; the script default and fixtures have been updated in sync (STALE_SECONDS default 1800).

Implementation Instructions

Step 0: Dispatch by Mode (current session only)

The current session NEVER writes implementation code. It only does pre-flight, dispatches spawns, and schedules watchdog wakes.

Read <planning-dir>/.build-progress.json. If it does not exist → Branch A (Init). Otherwise → Branch B (Watchdog).

Branch A: Init Mode

0a. Design Review Gate:

  • Check if the planning directory has a recent design review result
  • If no review on record, or last review was < 95% → STOP. Run /agentloop:design-review first.

0b. Parse tasks.md to determine total_phases and the phase list.

0c. Write .build-progress.json with initial state:

{
  "planning_dir": "<planning-dir>",
  "started_at": "<now>",
  "total_phases": <N>,
  "current_phase": <start-phase, default 0>,
  "completed_phases": [],
  "test_counts": {},
  "commits": {},
  "executor_status": null,
  "executor_respawn_count": 0,
  "executor_error": null
}

0d. Spawn the first phase using the Agent template in Rule 4; write executor_task_id into the progress file.

0e. Call ScheduleWakeup with delaySeconds: 1800 and prompt: "/loop /agentloop:build-phases <planning-dir>" as the fallback watchdog (primary advancement is the executor's task-notification).

0f. Output the Init variant of the Watchdog Tick Report (see Rule 4) including the log path. Tell the user how to tail it: tail -f <executor_log>.

Branch B: Watchdog Mode

0a. Read .build-progress.json and apply the Watchdog state machine from Rule 4.

0a'. Output the Watchdog Tick Report (see Rule 4) — mandatory even for WAIT action. The user needs to see the watchdog is alive every tick.

0b. Take at most ONE action: spawn / gate+review / respawn (TaskStop the stale executor first) / stop. Do not run the phase implementation in the current session — the only "work" the parent does directly is the E2E log gate check (bash) and dispatching the clean-context review agent.

0c. If task not complete → call ScheduleWakeup(delaySeconds: 1800, prompt: "/loop /agentloop:build-phases <planning-dir>", reason: "fallback watchdog tick for phase <N>").

0d. If task complete → output the Final Report (Section 3), delete .build-progress.json, do not reschedule.

0e. If escalation (executor_respawn_count ≥ 3 on same phase, or executor_status === "error" with unresolvable executor_error.reason) → output the escalation report format (see Escalation Rules), do not reschedule, wait for user input.

NEVER write implementation code in either branch. Spawning is the only way implementation happens. The parent's own hands-on work is limited to: progress-file bookkeeping, the E2E log gate (bash), dispatching the review agent, and fixing nothing — review findings go back to a respawned executor.

Step 0.5: Pre-Code Principle Check (in executor agent)

Before writing ANY code in any phase, verify the design does not violate:

  1. AFS-Only I/O — Does any part of the design bypass AFS? If you notice the tasks.md describing direct file access, HTTP fetch, or any I/O that doesn't go through AFS → STOP and escalate to user
  2. Abstraction reuse — Does the design reinvent something that already exists in AFS? → STOP and escalate
  3. Provider boundary — Does code outside a provider directly access underlying resources? → STOP and escalate

These checks apply at EVERY phase, not just the start. If during implementation you find yourself about to write code that violates these principles: STOP immediately and ask the user, even if it means the phase is incomplete.

Step 1: Parse tasks.md and identify phases

Read <planning-dir>/tasks.md. Identify all phases by looking for:

  • ## Phase N: headers
  • ## Task N: headers (some docs use tasks instead of phases)
  • Numbered sections with implementation steps

Build a list of phases with their:

  • Name / number
  • Acceptance criteria
  • Test files to create
  • Files to modify
  • Dependencies on previous phases

Parallel phase detection: If two phases have no dependency between them (both listed as "独立" or no cross-references), they CAN run in parallel using separate Agent subagents. Build a dependency graph and identify parallelizable groups.

Step 1.5: Pre-implementation check — what already exists?

Before implementing each phase, check if the work is already done:

For each phase:
1. Check if files-to-create already exist (ls/stat)
2. If they exist, check if they have substantial content (not just scaffold)
3. Check if tests already exist and pass
4. If phase is already implemented → SKIP with note "already done"
5. If partially implemented → adjust scope to only the missing parts

This prevents re-implementing work that was done outside of /agentloop:build-phases (manual coding, other sessions, etc.).

Step 2: Execute phases

If phases are independent (no dependency): Launch parallel Agent subagents, each implementing one phase. Merge results, then verify all together.

If phases have dependencies: Execute sequentially as described below.

For each phase:

2.1 IMPLEMENT

Read the phase spec carefully. Follow TDD strictly:

  1. Write test files first (all tests should fail initially)
  2. Implement until all tests pass
  3. For independent sub-tasks within a phase, use parallel subagents (Agent tool with worktree isolation)

2.2 VERIFY — Three Layers (MANDATORY)

This is the critical step. Do NOT skip any layer.

Layer 1: Static

<package_manager> build
<package_manager> check-types
<package_manager> --filter <affected-packages> test    # specific
<package_manager> test                                  # full suite
  • Compare full test pass count with previous phase
  • If pass count decreased → FAIL

Layer 2: Dynamic — Actually run the feature (E2E, not just unit tests)

MANDATORY: Follow the ### E2E Verification (mandatory) table from tasks.md for this phase. If the table doesn't exist, STOP and escalate — every phase must have one.

HARD GATE: E2E log file

Phase cannot be marked done unless <planning-dir>/logs/s{N}-e2e.log exists AND contains the raw afs_exec output.

Before running the E2E section:

mkdir -p <planning-dir>/logs
LOG_FILE="<planning-dir>/logs/s${PHASE}-e2e.log"
# Truncate at start of Layer 2 so each run is fresh
: > "$LOG_FILE"

For every afs_exec / afs_read / afs_list call specified in the phase's E2E Verification table:

  1. Run the call via the MCP tool (or <cli_binary> CLI / curl equivalent).
  2. Append a header line with the command + a JSON-serialised response to $LOG_FILE, e.g.:
    === S6.1 afs_exec /blocklets/demo-team-seq/.actions/run ===
    input: {"message": "hello"}
    output: {"success": true, "data": {"reply": "..."}, "_meta": {...}}
    
  3. Do NOT paraphrase ("verified via AFS", "tests passed"). Paste the raw JSON.
  4. Include at least one negative case (invalid session / bad path / missing field).

Phase-done check (spawned executor MUST run before flipping executor_status to "done"):

test -s "<planning-dir>/logs/s${PHASE}-e2e.log" || {
  # Log missing or empty — write error and exit
  jq '.executor_status = "error" | .executor_error = {reason: "E2E_LOG_MISSING", detail: "<planning-dir>/logs/s'${PHASE}'-e2e.log missing or empty"}' \
    <planning-dir>/.build-progress.json > /tmp/bp.json && mv /tmp/bp.json <planning-dir>/.build-progress.json
  exit 1
}

Also the log must contain at least one JSON object response (not just prose). A quick sanity check:

grep -E '^\s*[{\[]|"success"\s*:' "<planning-dir>/logs/s${PHASE}-e2e.log" > /dev/null || {
  # No JSON detected — treat as missing
  ...E2E_LOG_NO_JSON error...
}

On success, record the log path in .build-progress.json:

{
  "e2e_logs": { "phase_N": "<planning-dir>/logs/s{N}-e2e.log" }
}

Named sessions for deterministic access:

# 1. Restart daemon with latest build
afs service restart

# 2. Open target page with named session (Playwright or browser)
playwright → http://target.localhost:4900/?session=e2e-{phase-name}

# 3. Call AFS MCP paths directly — ZERO session discovery
afs_read /dev/ui/web/sessions/e2e-{phase-name}/inspect/viewport
afs_list /dev/ui/web/sessions/e2e-{phase-name}/dom/main

Choose additional verification based on change type:

Change Type Strategy
Provider Mount provider → list/read/write/exec through AFS MCP tools
Session/Protocol afs service restart → open page with ?session=e2e-test → call AFS paths
AUP/UI Use inspect capabilities: design-audit, overflow-scan, dom/@styles, accessibility
Inspect feature Test the new inspect path on a real page via named session
Pure utility/library Call functions directly via a REPL/one-off script — verify output
CLI Run CLI commands, verify stdout/exit code
Refactoring Layer 1 sufficient — Layer 2 = verify one happy path via AFS MCP

OUTPUT THE ACTUAL TOOL CALL RESULTS. Paste the afs_read / afs_list / afs_exec responses. Do not just say "verified via AFS". Show the JSON. These same outputs must also land in <planning-dir>/logs/s{N}-e2e.log (see HARD GATE above).

Layer 3: Adversarial — Try to break it Try at least ONE of:

  • Send empty/null/undefined where values are expected
  • Send oversized payload (>16MB for WS)
  • Path traversal attack (../, %2e%2e, null bytes)
  • Kill process mid-operation, check for data corruption
  • Concurrent operations, check for race conditions
  • Prototype pollution (proto, constructor)

OUTPUT THE RESULTS. Paste actual terminal output showing what you ran and what happened. Do not just say "tests passed."

If any layer fails → fix → re-run all three layers.

2.3 COMMIT

Always format before committing to avoid pre-commit hook failures:

<formatter> <changed-files>
git add <specific-files>
git commit -m "phase N: implement <description>"

Never commit run-generated log/state files. <planning-dir>/logs/*.log、 <planning-dir>/.build-logs/、.build-progress*.json are all covered by .gitignore —they are local evidence/state, not deliverables. Rules:

  • Only git add <specific-files>, never git add -A / git add .;
  • Never git add -f force-add an ignored log—the E2E hard gate verifies that the fileexists locally, it does not require it to be committed; the design review reviewer reads the local file directly.
  • If you changed a dependency → the lockfile must be added along with it. "specific files" Includethe changes incidentally produced this time: after changing a dependency of package.json , installing will update the lockfile of <package_manager> (e.g. pnpm-lock.yaml/package-lock.json/yarn.lock); committing only the manifest and not the lockfile → the two are inconsistent, and <package_manager> install --frozen-lockfile elsewhere / in a later phase / for other agents goes straight red.Before committing, first git status scan for incidental changes:
    • This time you touched dependencies and the lockfile has a corresponding diff → add them together, git add <lockfile>(git diff confirm the diff contains only the packages you added/removed, scoped);
    • This time you did not touch dependencies but the lockfile has a diff → it is a concurrent/unrelated change,do not get involved—this is exactly the point of precise add.

2.4 SIMPLIFY (conditional)

Skip if phase changed < 50 lines of production code (tests don't count). Small changes rarely benefit from a simplify pass.

If applicable, launch a code-simplifier:code-simplifier agent (or use /simplify skill). Focus on:

  • Recently modified files only
  • Clarity and maintainability
  • Remove unnecessary complexity
  • Do NOT change behavior

2.5 RE-VERIFY

Run Layer 1 only (build + types + tests). If simplify broke something:

  • Revert the simplify changes
  • Commit without simplify
  • Note what went wrong

Otherwise:

git add <simplified-files>
git commit -m "phase N: simplify"

2.6 DESIGN REVIEW (parent's responsibility, not within the executor)

After receiving the executor's completion notification and passing the E2E log gate,parent launch a clean-context review agent (same mode as /agentloop:design-review). The reviewer and the implementer are different agents—independence is a design requirement: when NOT APPROVED, the parent writes the review findings into the respawn prompt and reassigns the executor to fix them, rather than the reviewer fixing them itself. Review prompt:

你是一个独立的代码审查者。检查 Phase {N} 的实现是否符合 spec。

1. 读取 {planning-dir}/tasks.md 中 Phase {N} 的 spec
2. 读取实际代码变更(git diff HEAD~2 对比 phase 开始前)
3. 读取 E2E 日志 {planning-dir}/logs/s{N}-e2e.log:
   - 文件必须存在且非空
   - 必须包含 JSON-shaped 响应(至少一个 `{` 或 `"success":` 行)
   - 如果只是散文 ("verified via AFS"、"tests passed") → NOT APPROVED
   - 至少包含 tasks.md 的 E2E Verification 表中列出的每一个 afs_exec 调用
4. 检查:
   - 所有 acceptance criteria 是否满足
   - 测试是否覆盖 spec 中列出的场景
   - 是否有 spec 中描述但未实现的功能
   - 是否有实现了但 spec 中没提到的额外功能(scope creep)
   - E2E 日志中的返回值是否匹配 tasks.md 预期(比如 `success: true`、特定字段)
5. 打分 0-100%。E2E 日志缺失或不合格 = 自动 NOT APPROVED,不管其他维度。

If score < target:

  • Parent respawns the executor with the reviewer's findings appended to the prompt
  • Respawned executor fixes, re-runs verify (Layer 1), updates progress JSON
  • Parent re-dispatches review on the next notification
  • Repeat until approved (counts toward the same respawn_count ≤ 3 budget)

2.7 REPORT (parent outputs after review approved)

Output phase completion summary:

## Phase N Complete

**Tests:** X pass (up from Y)
**Verification:** Layer 1 ✓ | Layer 2 ✓ | Layer 3 ✓
**E2E log:** `planning/<dir>/logs/s{N}-e2e.log` ({bytes} bytes, {calls} afs_exec calls)
**Simplify:** Applied / Skipped
**Review:** {score}% — APPROVED
**Commits:** {hash1} (implement), {hash2} (simplify)

The E2E log line is required — omitting it (or pointing at a missing/empty file) means the phase did not pass the hard gate.

Step 3: Final report after all phases

## Build Phases Complete

**Planning:** {planning-dir}
**Phases completed:** {N} / {total}
**Total test count:** {before} → {after}
**All phases:** PASSED

Escalation Rules (when you must stop and ask the user)

These are hard stop conditions. When you encounter them, immediately stop automatic execution, report the situation to the user, and wait for instructions. Do not guess or work around them yourself.

Situations where you must stop

Condition Trigger Report content
3 consecutive failures The same test/build/verify fails 3 times, and each fix did not resolve it Paste the error messages from all 3 times + what you tried + your guess
E2E log cannot be written After Layer 2 has run one round, <planning-dir>/logs/s{N}-e2e.log is still missing/blank/no JSON Paste the command executed + the actual response + your diagnosis;Don'tfake logs to bluff your way through
Spec ambiguity tasks.md has two reasonable interpretations of a certain behavior, and which one is chosen will affect subsequent phases List the two interpretations + their respective impacts + your preference
External operations needed Requires the user to configure the environment, provide credentials, start external services, install system dependencies Explain what is needed + why + the user's steps
Architecture decision During implementation, a design choice not covered by tasks.md is discovered, and its impact is irreversible Describe the decision point + options + tradeoff
Scope overflow You discover that completing the current phase requires changing code outside the spec, and the amount of change exceeds expectations List the extra changes + why they are needed + whether the phase should be split
Test coverage question The test spec in tasks.md doesn't cover an important scenario you discovered Describe the scenario + why it matters + suggested tests
Performance anomaly verify Layer 2 finds performance worse than expected by more than 10x Paste the data + bottleneck analysis

Report format

When you hit a hard stop, use this format:

## ⏸ Phase N 需要你的输入

**停止原因:** {条件名}
**当前进度:** {做到哪一步了}
**问题描述:** {具体是什么}

**我尝试过的:**
1. ...
2. ...
3. ...

**我的判断:** {你觉得应该怎么做}
**需要你:** {具体需要用户做什么}

Cases where you shouldn't stop

Handle the following cases yourself and don't interrupt the user:

  • Ordinary type error → fix it yourself
  • Test fails but the cause is clear → fix it yourself
  • Wrong import path → fix it yourself
  • Need to install an npm dev dependency → do it yourself <package_manager> add -D
  • Lint/format errors → do it yourself <formatter>
  • A bug that gets fixed in one try → fix it yourself

Judgment criterion: if you are confident (>80%) that you can resolve it within 1-2 attempts, do it yourself. If you fail repeatedly or are unsure of the direction, stop.

Key Principles

  1. TDD is non-negotiable — write tests before implementation in every phase.

  2. Three-layer verification is not optional — Layer 2 (dynamic) catches the bugs that unit tests miss. Layer 3 (adversarial) catches security and resilience issues. Both must be done.

  3. Show your work — paste actual test output, not just "tests passed." This is how the user knows verification actually happened.

  4. Each phase is independently deployable — after each phase, the system must be fully functional. No "half-done" phases.

  5. Simplify preserves behavior — if simplify breaks tests, revert it. Code clarity is important but correctness is more important.

  6. Review is against the spec — the clean-context reviewer checks implementation vs. documented spec, not general code quality (that's what simplify does).

  7. When in doubt, test more — if you're unsure whether something works, run it. AFS's WS protocol makes everything testable programmatically.

  8. When stuck, stop and ask — escalation is not failure. Wasting 30 minutes guessing is worse than asking a 30-second question. Follow the escalation rules above.

★ sweep-trace instrumentation (round-awareness criterion / L2 observability layer)

At the end of each phase progress comment sent to the issue by this skillyou mustappend a line of sweep-trace HTML comment (invisible to humans, grep-searchable):

<!-- sweep-trace: {"ver":1,"issue":N,"gate":"phase","val":"<val>","run":"<ISO8601>","runner":"<runner>","skills":"<hash>"} -->

This is not just observability—it is the criterion for issue-sweep round awareness. sweep relies onmachine markers(sweep-trace / Generated by [Claude Code] footer / Bot author) to distinguish "agent adjudication (skip)" from "human input (respond)",not on the > 🤖 header—because humans and agents use the same agent-identity.sh generated header, byte-for-byte identical in format (real case arc#1722: a manually pasted instruction was treated as agent adjudication and skipped for 19h).If this skill's comments don't carry the trace, they will be misjudged by issue-sweep as "unprocessed human input" → repeated processing/repeated commenting every round(the reverse effect in arc#1722 is exactly this gap). The identity header and the runner:…·skills@… linedon't count asmachine markers (humans have them too).