Skip to content
Back to skills

Build

ASecurity

Implement planned tasks by executing them wave-by-wave, committing each, and logging errors and learnings. Reads tasks.md and drives the build loop. The longest-running phase of the specclaw lifecycle. Run after /specclaw:plan has produced spec.md, design.md, and tasks.md.

  • 13 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added August 31, 2026
ai-agentsgobashrailsazurecode-reviewgit

Works with

  • cli

Security analysis

A100/100

Scanned September 28, 2026

npx -y skills add chan4lk/specclaw --skill build --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Build?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Build
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/chan4lk-build/badge)](https://www.skillsdirectory.com/skills/chan4lk-build)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
description: Implement planned tasks by executing them wave-by-wave, committing each, and logging errors and learnings. Reads tasks.md and drives the build loop. The longest-running phase of the specclaw lifecycle. Run after /specclaw:plan has produced spec.md, design.md, and tasks.md.
---

# specclaw build

**First, run** `specclaw-ensure-init .specclaw` — idempotently creates `.specclaw/` if it doesn't exist (silent if already initialized; auto-inits using the current directory's basename as the project name).

Execute the planned tasks.

## Step 0 — Validate

Run `specclaw-validate-change .specclaw <change> build`. If it fails, report missing prerequisites and stop.

## Step 1 — Setup

```bash
specclaw-build setup .specclaw <change>
```

Returns JSON config with `parallel_tasks`, `models.coding`, `git.strategy`, `notifications.channel`. Capture this — you'll use `parallel_tasks` and `model` throughout the build.

**Worktree strategy:** when `git.strategy: worktree-per-change`, setup creates an isolated worktree at `.specclaw/worktrees/<change>/`. Use the `worktree_path` from the JSON as the working directory when spawning coding agents.

**Jira sync** (if `jira.enabled: true`): `specclaw-jira-issue transition .specclaw <change> build` so the card moves to In Progress as the build starts, rather than sitting in the backlog until archive.

Send a **build started** notification:

```
🦞 **Build Started**
**Change:** <change>
**Branch:** specclaw/<change>
**Tasks:** <total_count> across <wave_count> waves
```

## Step 2 — Parse tasks

```bash
specclaw-parse-tasks --status pending .specclaw/changes/<change>/tasks.md
```

Outputs JSON: `[{"id":"T1","title":"...","wave":1,"depends":[],"files":[...],"estimate":"small"}, ...]`.

**Retry:** to re-run failed tasks, parse with `--status failed`, reset each to `pending` via `specclaw-update-task-status .specclaw/changes/<change>/tasks.md <TASK_ID> pending`, then re-parse with `--status pending`.

## Step 3 — Wave loop

For each wave number (1, 2, 3, ...):

**a.** Filter tasks for this wave:
```bash
specclaw-parse-tasks --wave N --status pending .specclaw/changes/<change>/tasks.md
```
If empty, the build is complete — skip to Step 4.

**b.** Skip blocked tasks: if a task's dependency failed in a prior wave, mark it failed:
```bash
specclaw-update-task-status .specclaw/changes/<change>/tasks.md <TASK_ID> failed
```

**b'.** Compute the memory-aware concurrency ceiling for this wave:
```bash
specclaw-parallel-budget .specclaw
```
Prints one integer — `min(parallel_tasks, memory_budget)`. Use it as the concurrency ceiling for THIS wave in place of raw `parallel_tasks`. When no `build.memory` config is present it returns `parallel_tasks` unchanged (opt-in — no behavior change).

**c.** For each task in the wave (up to the memory-aware budget from `specclaw-parallel-budget` (≤ `parallel_tasks`) concurrent):

1. Mark in-progress:
   ```bash
   specclaw-update-task-status .specclaw/changes/<change>/tasks.md <TASK_ID> in_progress
   ```
2. Build the agent context payload:
   ```bash
   specclaw-build-context .specclaw <change> <TASK_ID>
   ```
3. Spawn a coding agent with that payload as the task. Run independent tasks in parallel up to the memory-aware budget from step **b'** (≤ `parallel_tasks`). Calibrate delegation: spawn agents for tasks that are parallel, isolated, or independent workstreams; for a trivial sequential edit where spawning costs more than doing, apply the change directly and record it against the task as usual.

   **Dynamic subagents (`build.dynamic_agents.enabled: true`):** instead of the generic coder with `models.coding`, synthesize a bespoke agent per task:
   1. Synthesize the scaffold:
      ```bash
      specclaw-build synth-agent .specclaw <change> <TASK_ID>
      ```
      Returns JSON `{kind, tier, role, tools, model, downgrade, sig, system_prompt}` (and caches it under `.specclaw/changes/<change>/agents/<TASK_ID>.json` when `cache: true`). A cache hit with an unchanged task signature is reused.
   2. **LLM-fill (hybrid):** replace the `{{SPEC_DESIGN_SLICE}}` marker in `system_prompt` with the task's relevant slice of `spec.md` / `design.md` (the acceptance criteria this task serves + the design decisions touching its files). Write the enriched spec back to `agents/<TASK_ID>.json`.
   3. **Dispatch:** spawn the agent with `system_prompt` as its system prompt, the `specclaw-build-context` output as its task, restricted to the synthesized `tools`, at the synthesized `model`.
   4. **Provenance:** record the task's `role` and `model` in `status.md`'s Agent Runs table.
   5. **Fallback:** if synthesis fails (helper error, malformed JSON), fall back to the generic coder with `models.coding` for that task and continue — never block the build.

   When `build.dynamic_agents.enabled: false` (default), skip all of the above and use the generic coder exactly as before — no synthesis, no `agents/` directory.

**c'.** **Stub tasks** — only when `spec.md` has a `## Bypassed Dependencies` section. For a task implementing an `ST-###` stub, add `$CLAUDE_PLUGIN_ROOT/references/stub-discipline.md` to that agent's context alongside the usual payload, and hold it to two things:

- **The hard rule: dev/test scope only.** The stub must be *structurally unreachable* from any production code path — a test-only source set, a dev-profile-only registration, a flag that is off by default in production rather than by assertion. Use whatever mechanism the repo already has; inventing a new isolation mechanism for a stub is itself the signal to stop and report. "Unlikely to be hit" is not scoping. A stub that can serve a real user is not a bypass, it is a fabricated response in production.
- **The stub must match the strategy the human chose.** If implementation shows the chosen strategy is wrong, stop and report it — that is a decision to hand back, not one to make. Never widen a stub's reach to make a test pass.

After the task lands, complete its registry entry with the real citation:

```bash
specclaw-bf-rebuild-collect stub-update .specclaw ST-### \
  --fakes "<what it concretely does instead of the real thing>" \
  --implementation "<path/File.ext:88> — <how it is dev/test scoped>"
```

Both are citations, not summaries: a reviewer must be able to jump to that `file:line` and see the claim is true. **Never add a stub that has no registry entry** — an unregistered stub is invisible to `/specclaw:bf-replay`'s taint stamping, so a report will later claim a clean PASS that was earned against fabricated behaviour.

**c''.** **Split changes** — only when `spec.md` has a `## Item Split` or `## Resumed From Split` section. Add `$CLAUDE_PLUGIN_ROOT/references/split-discipline.md` to the relevant agents' context, and hold the build to three things:

- **Never build deferred scope.** The spec's now-slice is the whole job. If a task cannot be completed without the deferred scope, **stop and report** — that means the partition is wrong, which is a decision to hand back, not a boundary to move. Widening the slice to make a test pass is the same failure as widening a stub's reach.
- **On a resume, never rebuild what the earlier slice already built.** Read the `IS-###`'s `Implemented now`, `Rules implemented` and `Change`/`Evidence` fields and treat that code as existing — you are integrating with it. Criteria labelled `[already built: IS-###]` are out of scope and must not be re-implemented.
- **Complete the entry's evidence fields** once the change lands:

```bash
specclaw-bf-rebuild-collect split-update .specclaw IS-### \
  --change "<change-name>" --evidence "<PR url or merge sha>"
```

**Never flip a split's Status yourself.** `READY-TO-RESUME` is computed by bash during `/specclaw:bf-rebuild-plan --refresh` from the blocked-until items' own declared `BUILT:` notes; `COMPLETE` requires a clean `/specclaw:bf-replay --item BL-###` run to cite, and `split-update` refuses `COMPLETE` straight from `ACTIVE`.

**c3. Timing (change 028).** Open a span per wave before dispatching it, and one per task as it is
dispatched — **every call ends in `|| true`**, because a build that fails because its stopwatch broke
is strictly worse than the unaccountability this measures:

```bash
specclaw-timer start .specclaw <change> "W<N>" --kind wave --label "wave <N>" || true
specclaw-timer start .specclaw <change> "<TASK_ID>" --kind task \
  --label "<title>" --parent "W<N>" --model "<model>" --attempt "<n>" || true
```

While the wave runs, print a progress line on the heartbeat interval
(`timing.heartbeat_seconds`, default 60):

```bash
specclaw-progress .specclaw <change> --phase build
```

That line is the whole point: it names the **active step**, its **elapsed time** and the **current
bottleneck**, so an operator or a watchdog can judge liveness instead of guessing. A pane emitting it
every 60s is never "no reply for 13 min" — which is the teardown this exists to prevent.

**d.** Wait for all agents in the wave to complete.

**e.** For each succeeded agent:
   0. **Evidence before done — always, and not configurable.** Write the agent's report to
      `.specclaw/changes/<change>/reports/<TASK_ID>.md` and check it:

      ```bash
      specclaw-build check-report .specclaw/changes/<change>/reports/<TASK_ID>.md --task <TASK_ID>
      ```

      **Exit 1 means the task is `failed`, not `complete`** — reason `no-verification-evidence` — and
      it goes down path **f** below with the printed line as the failure summary; the retry restates
      the footer requirement. An agent that reports "implemented and tested" having run nothing is
      the single most common way a build ends green and broken, and this is the only place a script
      can catch it. Do not paraphrase the check's verdict, and never mark a task complete on a report
      it rejected.
   1. Mark complete: `specclaw-update-task-status .specclaw/changes/<change>/tasks.md <TASK_ID> complete`. If the task previously failed, run `specclaw-log-error .specclaw <change> --resolve <TASK_ID>`.
   2. Commit: `specclaw-build commit .specclaw <change> <TASK_ID> "<title>" <files...>`.
   2b. **Per-task review — only when `build.task_review` is `spec` or `full`** (it ships `off`, in
      which case skip this entirely and build behaves exactly as it did before):

      ```bash
      specclaw-build review-package .specclaw <change> <TASK_ID>
      ```

      Spawn the existing `code-reviewer` agent on `models.review` — **always `models.review`, never
      the `dynamic_agents` ladder**: the ladder sizes implementation difficulty, and reading one
      task's diff is not that work. Give it the task-scoped prompt from
      `$CLAUDE_PLUGIN_ROOT/references/agent-prompts.md`, and tell it the mode (`spec` = compliance
      only, `full` = compliance then quality).

      Read the verdict token it ends with and act on it mechanically:

      | Verdict | Do |
      |---|---|
      | `PASS` / `NOTE` | record it in the Agent Runs `Review` column; continue |
      | `WARN` | record `WARN(n)`; the findings stay in `reviews/<TASK_ID>.md`; continue |
      | `BLOCK` | mark the task **failed**, write the findings into `errors.md`, and send it down path **f** |

      **A `BLOCK` retry shares the task's normal retry budget.** It does not get one of its own — a
      task that fails review and a task that fails its tests are both "this task is not done", and
      two counters would let a task alternate between them and exhaust neither.
   3. Close the span: `specclaw-timer stop .specclaw <change> <TASK_ID> --status ok || true`.
   4. Notify: `✅ Task Complete: <TASK_ID> — <title>`.

**f.** For each failed agent:
   0. Close the span: `specclaw-timer stop .specclaw <change> <TASK_ID> --status fail || true`.
   1. Mark failed: `specclaw-update-task-status .specclaw/changes/<change>/tasks.md <TASK_ID> failed`.
   2. Log: `specclaw-log-error .specclaw <change> <TASK_ID> <wave> <agent_label> "<summary>"`.
   3. Update status.md with the failure reason.
   4. Notify: `❌ Task Failed: <TASK_ID> — <title>`.
   5. Mark dependent tasks in later waves as skipped/failed.
   6. **GitHub sync** (if enabled): `specclaw-gh-sync comment .specclaw <change> "❌ Task <TASK_ID> failed: <summary>"`.
   7. **Azure Boards sync** (if `azdo.boards.sync: true`): `specclaw-azdo-issue comment .specclaw <change> "❌ Task <TASK_ID> failed: <summary>"`.
   8. **Jira sync** (if `jira.enabled: true`): `specclaw-jira-issue comment .specclaw <change> "❌ Task <TASK_ID> failed: <summary>"`.

**g.** GitHub sync (if enabled): `specclaw-gh-sync update .specclaw <change>` to refresh task checkboxes.
**g'.** Azure Boards sync (if `azdo.boards.sync: true`): `specclaw-azdo-issue update .specclaw <change>` to refresh the Work Item description with the latest task checklist; optionally `specclaw-azdo-issue comment .specclaw <change> "Wave <N> complete: <X>/<total> tasks done"`.
**g''.** Jira sync (if `jira.enabled: true`): `specclaw-jira-issue update .specclaw <change>` to refresh the issue description with the latest task checklist. The card is already In Progress from Step 1 — do not re-transition per wave.

**h.** Repeat for the next wave.

## Step 4 — Finalize

```bash
specclaw-build finalize .specclaw <change>
```

Runs the configured `test_command` (if any) and merges the branch per `git.strategy`.

## Step 5 — Post-build review

If `automation.post_build_review: true`:

**a.** Scope deviation: compare `git diff --name-only main...HEAD` against files declared in tasks. Flag any file modified but not declared.

**b.** Evaluate the build (~150 words):
- Were any spec requirements ambiguous or incomplete?
- Did the design need adjustment during build?
- Were any files modified outside declared scope?
- Did any agents struggle with context?
- Any reusable patterns discovered?

Log each finding:
```bash
specclaw-log-learning .specclaw <change> <category> <priority> "<detail>" "<action>"
```

**c.** Auto-log scope deviations as `design_gap`:
```bash
specclaw-log-learning .specclaw <change> design_gap medium "File <path> modified but not declared in any task" "Review task file declarations"
```

**c2. Size drift — report it, never fix it.** When a task's `files:` list grew past the file map in
`spec.md`, or a task failed with a `design_gap` learning, the change may have outgrown its declared
size. Say so, name the command, and **stop there**:

```
⚠ size-upgrade-needed — <change> is `bounded` but T5 touched 4 files outside the spec's map.
  specclaw-set-size .specclaw <change> architectural --reason "<why>"
```

Detecting the drift is mechanical; acting on it is not. **An upgrade changes what the operator
approved**, and a bounded → architectural upgrade makes `design.md` required again, so the next
`validate-change` will stop until `/specclaw:plan --design-only` fills it. That is a decision to hand
back, exactly as `reconcile --fix` declines downgrades and `party.block` leaves the verdict advisory.
Never call `specclaw-set-size` on the operator's behalf, and never downgrade — the ratchet refuses it
by name anyway.

**d.** Pattern scan: `specclaw-detect-patterns .specclaw scan <change>`.

**e.** If any pattern has recurrence ≥ 3, alert the user.

## Step 5b — Render the timeline

```bash
specclaw-timer stop   .specclaw <change> "W<N>" --status ok || true
specclaw-timer report .specclaw <change> --baseline --write || true
```

`--write` installs `timeline.md` in the change dir, where `specclaw-pr` quotes it into the PR body's
**Time accounting** section. Fill the `Agent Runs` table from the ledger rather than from memory:

```bash
specclaw-timer agent-runs .specclaw <change>
```

That table's `Duration` column has existed since `templates/status.md` was written and no script has
ever filled it.

## Step 6 — Update dashboard

```bash
specclaw-update-status .specclaw
```

## Step 7 — Notify

Send a final **build summary**:

```
🦞 **Build Complete**
**Change:** <change>
**Status:** <succeeded|partial|failed>
**Tasks:** <completed>/<total> complete, <failed> failed, <skipped> skipped
**Branch:** specclaw/<change> → pushed (not merged)
**Next:** /specclaw:verify, then /specclaw:pr
```

**Build never creates or announces a pull request.** It ends at "branch pushed". Every guarantee in
`specclaw-pr` — the artifact staging, the hard constraint that the planning trail is committed, the
staged-files gate — is unreachable when a PR is opened any other way, and a build summary that names
a PR URL is how a hand-rolled `gh pr create` gets normalised. If a PR is wanted, run
`/specclaw:verify` and then `/specclaw:pr`.

## Key Principles

- **Fresh context always** — each agent gets ONLY what `specclaw-build-context` produces. No stale context.
- **Parallel within waves, sequential across waves.**
- **Fail-fast on dependencies** — if a task fails, all dependents are immediately marked failed.
- **Agent guardrails** — every coding agent is auto-prepended four behavioral rules (Think Before Coding, Simplicity First, Surgical Changes, Goal-Driven Execution), vendored verbatim from Andrej Karpathy's CLAUDE.md. See `references/agent-guardrails.md`. Injection happens inside `specclaw-build-context`; no config flag.
- **Loop-aware** — when `loop.enabled: true` (the default), this build is one turn of the autonomous loop driven by `/specclaw:loop`, which re-runs verify+review and fixes the smallest diff until every gate is green or a guardrail halts. Build produces the first implementation; the loop remediates it. When `loop.enabled: false`, build behaves single-pass exactly as documented above — no loop, no extra files.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.