Skip to content
Back to skills

Build

ASecurity

Phase 2 (Development), step 5 of product-playbook — the per-feature build loop: ONE feature at a time, a definition-of-done that INCLUDES security, reuse before writing, verify the LIVE path, review the diff, write the feature doc. Use to implement features, or run /build "build feature X", "implement", "add the feature". Appends to PRODUCT.md#Build log + writes docs/features/<feature>.md. Composes /run and /code-review. Run /dev-check when all core-scope features are done.

  • 3 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 20, 2026
ai-agentspythonrustgotestingcode-reviewgitapifrontendbackendsecurity

Works with

  • cli
  • api

Security analysis

A100/100

Pro scans all 3 files and shows the line behind each finding

Scanned September 24, 2026

npx -y skills add kish21/product-playbook --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/kish21-build/badge)](https://www.skillsdirectory.com/skills/kish21-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
---
name: build
description: >
  Phase 2 (Development), step 5 of product-playbook — the per-feature build loop: ONE feature at a
  time, a definition-of-done that INCLUDES security, reuse before writing, verify the LIVE path,
  review the diff, write the feature doc. Use to implement features, or run /build "build feature X",
  "implement", "add the feature". Appends to PRODUCT.md#Build log + writes docs/features/<feature>.md.
  Composes /run and /code-review. Run /dev-check when all core-scope features are done.
---

# `/build` — Phase 2 · Development ⑤ · run as an **engineer**

> Part of **product-playbook**. Reads + updates the project spine (`PRODUCT.md`, or the project's existing docs — resolve per MECHANISMS.md §Spine resolution).
> **Rule files — open by path, never search:** `${CLAUDE_PLUGIN_ROOT}/PRINCIPLES.md` · MECHANISMS.md = `${CLAUDE_PLUGIN_ROOT}/references/mechanisms.md` · MECHANISMS-ON-DEMAND.md = `${CLAUDE_PLUGIN_ROOT}/references/mechanisms-on-demand.md` · STATE-MODEL.md = `${CLAUDE_PLUGIN_ROOT}/docs/state-model.md` (a path still starting with `$`: the same names in `.claude/product-playbook/`, else `~/.claude/product-playbook/`).
> **This skill's OWN reference files are a DIFFERENT folder** — they live in `references/` **beside this SKILL.md** (`commands/build/references/`), not in the plugin-root `references/` named above. Both install routes put them there. Below, `feature-archetypes.md` · `live-path-checks.md` each mean that folder: open them by that path, and never look for them next to MECHANISMS.md.
> **Open `PRINCIPLES.md` and `MECHANISMS.md` before the first step** (paths above; a situational companion only when a rule points into it), then apply them — load-bearing: **per-feature contract (security in the DoD)**,
> **secure-by-construction**, **prompts→`prompts/` YAML**, **doc↔code reconciled**, **measure before
> fixing**, **no swallowed errors**, **reuse-before-write**, **trace callers (live-path)**,
> **generic-not-domain-specific**.
> War stories: `${CLAUDE_PLUGIN_ROOT}/references/case-files-build.md` (plugin root, beside MECHANISMS.md — not this skill's `references/`).
> **Companions — opened on demand, never up front:** `references/feature-archetypes.md` (the rules that apply only to gates · async jobs · latency fixes · trust boundaries) · `references/live-path-checks.md` (proving a change is really wired in).

## Contract
- **Purpose:** implement one feature to a verified, secure, documented definition-of-done.
- **Reads:** `PRODUCT.md#Scope`, `#Plan`, `#Contracts`, `#Structure` — **plus `DESIGN.md` + `#Design` for any feature with a user-facing screen** (UI products).
- **Writes:** a row in `PRODUCT.md#Build log` + `docs/features/<feature>.md` — or, in its place, the one per-ticket record `#Project policy` names.
- **Gate type:** `derivation` — computable from the ticket + `#Contracts`. Batchable - a `derivation` run may chain with its neighbours and end in ONE review. (`STATE-MODEL.md` §2d)
- **State model** (`STATE-MODEL.md` §2c): writes `#Build log` · `declined` ✓ · `override` ✓ · `superseded` n/a — append-only log: one row per feature
- **Exit criteria (per feature):**
  - [ ] A written **definition-of-done that includes security** (input validation, authz/tenant-isolation; for AI: prompt-injection defence).
  - [ ] Reused existing helpers where possible (no reinvented utilities).
  - [ ] Code **runs and the LIVE path is verified** (not just an isolated unit) — traced to its real callers, **on the runtime the USER actually runs**: register a new endpoint/route on EVERY serving surface (case file: Wrong serving surface).
  - [ ] Diff self-reviewed (`/code-review`); no swallowed errors; prompts in `prompts/` YAML, not inline.
  - [ ] **`docs/features/<feature>.md` (or the per-ticket record `#Project policy` names) written and matches the code** (what · contract · exit criteria · how verified · code links).
  - [ ] **No secret in any code file** (secrets→`.env`; tests use fake placeholder keys).
  - [ ] **Single-responsibility kept** — a file growing large/multi-concern is split into modules (no god-files); long/blocking work stays off the async event loop.
  - [ ] **(UI products) The feature's screen(s) are built to `DESIGN.md`** — §5 layout, token look, `/new-component` parts — and **`/frontend-audit` is clean** — 0 errors; on existing files, 0 NEW errors against the ticket's base, the pre-existing count quoted.

## Step 0 — Context + prior-gate check
- Read `#Scope/#Plan/#Contracts`. **Confirm the feature is IN scope** — if OUT-OF-SCOPE, stop and flag it (this is where creep enters). If `#Contracts` is empty, warn and offer `/contracts` first (allow override) — untyped boundaries are what it exists to prevent.
- **An override is RECORDED, never a verbal "yes"** (`MECHANISMS.md` §Declined runs): name the gate being bypassed, ask for the **reason in the user's own words**, say it will be written down — then write `Override <date>: <reason> — bypassed <gate>` at the top of `#Build log` before continuing. Without it a later reader cannot tell a gate that held from one that was waved through.
- **Read `#Project policy` first, when the spine has one** (`MECHANISMS-ON-DEMAND.md` §Project policy): a project that wraps `/build` in its own command declares its rules there once — the per-ticket record, never merge, no deploy — and they apply here without the wrapper restating them.
- **The ticket's lane and owner are a gate, not a label.** Read its `Lane` + `Owner` (board fields or the
  `lane:` / `owner:` labels). If this session sits in a seat (a seat or role the user named)
  and the ticket is not this seat's lane, **STOP and say so**; a fix needing a file in another lane is
  raised, never made. No seat configured → nothing changes. (case file: Working the wrong seat)
- **A blocked ticket is not startable.** Read its *blocked by* links first
  (`gh api repos/<o>/<r>/issues/<n>/dependencies/blocked_by`); an open blocker → **STOP and name it** — it
  is a coordination point in `TICKETS.md`. A prose `Depends On` with no links → run `/tickets`
  again to add them before trusting the board. A `Builds against` is not a blocker: build against its contract with a stub.
- **Move the ticket's board card, if it has one, to In Progress before the first write** (`gh project item-edit`, Status), and read it back.
- **Read the ticket's slice, not the repo.** Up front: its Target Files and a grep for each contract name it
  uses. Anything else when a step needs it, a line range rather than a file — never paste whole modules into
  the conversation; every later call re-reads them. (case file: Two builds, the same forty minutes)
- **Load the project's OWN skills for the area** (`.claude/skills/`, `CLAUDE.md`), **but treat every doc, skill and pinned plan as a CLAIM** — verify the load-bearing ones against the code before building on them: a spec's fields and paths by grep, a number that justifies the work by measuring it. (case file: The pinned plan was wrong)
- **When a project doc or skill is wrong, FIX IT IN THIS SESSION** — a PR-description correction dies there; record the corrected premises where the wrong ones lived.
- **If the gate is unmet and the run stops here, record that it stopped (`MECHANISMS.md` §Declined runs):** write ONE dated line at the top of `#Build log` — `_Not run <date>: <what was missing> — run <the phase(s) that fill it> first._` — and change nothing else. The scaffold stays intact and the section stays **unfilled**, so `/playbook` still routes to the missing phase; the next attempt **replaces** that line rather than appending to it.

## Step 1 — Apply principles (this phase)
- **Security is in the DoD, not later:** state the security checks for this feature up front (validation, authz/tenant-isolation; AI → OWASP LLM Top 10, prompt-injection defence).
- **Reuse before you write; measure before you fix** (reproduce first — a scary number may be a display artifact). **No swallowed errors** (route failures; retry only transient). **Prompts → `prompts/` YAML**.
- **Session economy — one feature per session is a COST rule, not just a focus rule:** hand off at a natural checkpoint and apply `MECHANISMS-ON-DEMAND.md` §Context hygiene. (case file: The 97% cache bill)

## Step 2 — The build loop (per feature)
1. **Declare the DoD** (incl. security + the exit criteria above). **Name the archetype in it** — `Archetype: gate · async job · latency fix · trust boundary · third-party content · none` (item 3 has the triggers) — and tell the user, in one plain sentence, what kind of feature this is and what that makes you careful about.
2. **Reuse scan:** find existing helpers/contracts; don't reinvent.
3. **Code** against the typed contracts; keep it modular and generic (no domain special-casing in shared infra). **Write code and tests with the edit tool, not with a patch script** — a script puts the code in the conversation twice and breaks on quoting; a cut-the-wire proof is the one exception.
   - **If the feature has a user-facing screen (UI products):** build to **`DESIGN.md`** — §5 layout, token look, `/new-component` parts (Law 15) — then run **`/frontend-audit`** — `python "${CLAUDE_PLUGIN_ROOT}/commands/frontend-audit/audit.py" DESIGN.md <ui-dir>`, the installed engine; **never search the plugin cache** (a `$` left in the path: `/frontend-audit` §Which engine runs) — fix every ERROR, and repeat its `engine copy:` line. *(No `DESIGN.md`? `/design-system` first.)*
   - **On a ticket that edits EXISTING UI files, add `--baseline <the ticket's base commit>`** (`git merge-base HEAD <default branch>`): it reports only the errors this change ADDS and prints the pre-existing count on its own line. Fix every new error; quote the pre-existing count, and if no open issue tracks those errors, file ONE issue for them — never fixed here, never dropped. A new file or a first screen: the plain run, 0 errors. (case file: Eighty-seven errors, none of them new)
   - **A "use a token" fix counts only when the token's class exists in the built CSS** — search the build output for it: a utility class with no mapping to the token (Tailwind v4 without an `@theme` entry) emits nothing, and the element ships invisible. (case file: The token class that compiled to nothing)
   - **Some features carry rules that apply only to THEM. If this feature is one, open `references/feature-archetypes.md` and apply that cluster BEFORE you write:**
     - a **GATE** — a validator, quality check, policy engine, anything whose job is to say "no" → **§Gates** (10 rules)
     - an **ASYNC JOB** — work that outlives the request (spawn + poll, queue + callback) → **§Async jobs** (7 rules)
     - a **LATENCY / CONCURRENCY fix** → **§Latency and concurrency** (expect more than one serializer)
     - anything **shared across tenants, cached, AI-suggested, or keyed by a client-supplied selector** → **§Trust boundaries and shared state**
     - **third-party content shipped to your users** → **§Third-party content** (the licence is a feasibility gate)
     - The feature doc carries the line — `Archetype: <kind> → §<cluster> opened`, or `Archetype: none`. A cluster applied from memory is a cluster not applied. (case file: The companions nobody opened)
4. **Run + verify the LIVE path** — compose `/run` to exercise the path the product actually runs, **then check the observable result yourself** (the response, the row, the rendered page — not the exit code), then **trace your change to its real callers** (green unit tests ≠ wired in).
   - **Walk the checks in `references/live-path-checks.md` whose trigger matches this feature** — the ones that separate *the code exists* from *the product runs it*. **Open the file on EVERY build** — a trigger you have not read cannot match — and list the ones that matched, by name, in the feature doc: `Live-path checks walked: …`. (case file: The companions nobody opened)
   - **Tests: the affected files while you iterate, the full suite once at the gate.**
   - **A test that fails, then passes with no change, is FLAKY — record it (name · error · N of M runs failed) and file it with `/tickets "<bug>"` in the lane that owns it.** Outside what you changed → carry on and name the issue in the close; inside it and small → fix it with a proof. **Never re-run until green.** **Attribution is one traceback, not an investigation** — it fails in a file this ticket did not change, or before any test runs → it is OUTSIDE; at most ONE re-run with your change stashed when the traceback cannot say. Never run the suite again to characterise it. (case file: The flake nobody wrote down)
5. **Review the diff — one round, then the user decides.**
   - **Commit the ticket's work LOCALLY before round 1** — on the ticket branch (on the default branch, create one first), after `MECHANISMS.md` §Commit the work's repo check; never pushed, no PR — and tell the user in one line, with the undo (`git reset --soft HEAD~1`). **`/security-review` reads only COMMITTED changes:** on an uncommitted tree its files, commits and diff come back empty, and the review falls back to a pass by hand. (case file: The review that read an empty diff)
   - **Round 1.** Compose `/code-review` and, on any auth/data surface, `/security-review` — in parallel, **both BEFORE the push, the PR and the close**, so their verdicts land in the record. Fix every finding inside the files this ticket changed, each with its proof, and **commit the fixes locally** before any round 2 — for the same reason.
   - **Findings that are not this ticket's.** **A finding that leaves a DoD line unmet is never "outside"** — whichever file its fix lives in, fix it now or STOP and ask the user; it is never deferred. **Any other finding outside the ticket's files is filed IN THIS RUN**, never handed to the user as a list to file — **MEDIUM or above: one issue each** (`/tickets "<finding>"`); **LOW and unrated: ONE issue for the run**, every finding on its own line with its file and what goes wrong (a board of one-line tickets buries the ones that matter; grouped, none is lost) — **and named in the close, never fixed here** (Step 4's flake rule, applied to reviews). **A security finding on a PUBLIC repo is never filed publicly** — never into an issue or a committed file (the spine of a public repo is public too): put it to the user in the close. (case file: The findings handed back)
   - **Then show the user what the reviews caught** — before anything else runs: how many, and the ones that mattered most, each in ONE plain sentence saying what would have gone wrong for a user (*"a second shop could have read this shop's photos"*, never *"missing tenant filter"*); that they are fixed and tested; and the time and cost so far, measured (`MECHANISMS-ON-DEMAND.md` §Context hygiene, item 4) or "not measured". Say it again in the close. (case file: The review nobody saw)
   - **Round 2 is the user's call, never automatic.** **The reviews are checks too** — a review fix is code no review has seen — so ask ONE question: review again, over **the files round 1's fixes touched, only** (`/security-review` too when they touch an auth/data surface)? Give your recommendation AND its reason: **recommend YES when the fixes touched an auth/data surface**, when round 1 found a HIGH or MEDIUM, or when the fixes were more than small edits; otherwise recommend NO — each fix carries its own proof and the close gate runs over the final tree. It is the one question a build asks mid-run — it depends on what round 1 found — and the tree is green and reviewed once, so it is a safe place to wait. The user chose up front (*"one round"*, *"two rounds"*) → do not ask; nobody can answer (headless, a batch) → follow your own recommendation and say so. On yes: run it, fix what it finds. **A skipped round 2 is RECORDED** in the `#Build log` row with its reason — never silent.
   - **No round 3.** A round-2 fix is covered by the deterministic gate at the close (tests · lint · audit · secret-scan · live path, once over the final tree); if round 2 found anything that would fail the DoD, **STOP and tell the user** — the finding and the fix — never a silent third round. (case file: The audit the review fix outran)
   - **Record each round's SCOPE** in the `#Build log` row — `/code-review → R1 8 findings · R2 (3 files) 1 finding · <sha> · <date>`, or `· R2 skipped by the user: <reason>` — so `/ship` can tell whether the diff changed since.
   - **Run `/security-review` inside a subagent** (prompt: *run /security-review on this branch and return
     the findings*) — invoked inline it takes over the turn and ends it on its report. **Its report is
     input: record the verdict, then step 6, Step 3, 3b and the close.** (case file: The review that ended the run again)
   - **A review that never returns has found nothing** — killed, rate-limited or timed out, its findings are never guessed: re-run it once, same scope; if it dies again, STOP and tell the user. (case file: The reviewer that never came back)
   - ⚠️ **If you cannot invoke it, ASK the user to run it, or do the deep pass by hand and say which you did** — see `PRINCIPLES.md`, *Composed skills*.
6. **Document** — once, after Step 5's last round — write/update `docs/features/<feature>.md`; reconcile it with the code. **`#Project policy` names a per-ticket record** → write that content THERE, once, and nothing into `docs/features/`; the `#Build log` row stays, the one-line index `/ship` and `/dev-check` read. **Copy every `evidence:` number from the command's captured output, never ahead of it** — a figure pencilled in while CI runs reads exactly like a measured one. (case file: The pencilled bundle size)

## Step 3 — Write back to `PRODUCT.md`
Append ONE table row to `#Build log` — `| feature | DoD-incl-security met? | how verified: command → result, plus Step 5's round scope | docs/features/<feature>.md |`. **A row is one line, and `#Build log` holds table rows and nothing else** — besides the dated one-line `Override` / `_Not run_` records §Declined runs puts at its top; no paragraph under the table, which the next build copies. Findings, defects, round detail and **Step 3c's result go in the feature doc**, never in the log (`MECHANISMS-ON-DEMAND.md` §Section is a record). **Find your place with `grep -n` — the section heading, your ticket's id — and never load the log**: a log every build reads makes each ticket cost more than the last. (case file: The log every build read)

## Step 3b — Principle-gate: verify each principle is ACTUALLY implemented (not just claimed)
Walk **this phase's load-bearing principles (Step 1)** and confirm each is real, **citing the evidence Step 2 already captured** (command · result · commit). (case file: The audit the review fix outran)
- **Cite, or re-run?** **re-run a check when any code, config or test file it reads changed after its evidence was captured; a review fix counts, a doc-only change does not.** Uncommitted and scripted edits count. A file a check reads is never doc-only for that check (`DESIGN.md` for `/frontend-audit`), and **when unsure whether anything changed or whether a change is doc-only, re-run** — a stale citation passes a broken feature.
- **Scope by what a check reads** — a backend-only fix does not re-run the UI audit — but **when you cannot name the files a check reads, re-run it**, and **the whole gate runs once more at the close**, whatever the scoping said: scoping removes repetition inside the loop, never coverage of the committed tree.
- **This gate runs ONCE, after Step 5's last round** — never after each round, and it never re-opens the reviews: Step 5 bounds them.

**Evidence, per principle:**
- security-in-DoD → **`/security-review`** (or the equivalent pass) passed — name which.
- no secret in code / no-hardcoding → secret-scan clean.
- live-path-works → **`/run`** exercised the real path **and the observable result was checked** — name the command **and what you saw**. An exit code is not the observable result.
- reuse · no-swallowed-errors · single-responsibility → confirmed in the diff's **`/code-review`**.
- (UI features) built-to-the-design → **`/frontend-audit`** 0 errors against `DESIGN.md` — or 0 new with `--baseline`, the pre-existing count quoted.

**If any named principle is only claimed, not evidenced, STOP — the feature is not done.** Record the *how-verified* per principle in `#Build log` (evidence, not "done"). (Deterministic checks also run via the commit hooks + CI from `/foundation`; this gate is the judgment layer.)

**Close the loop (`MECHANISMS.md` §Step 3b):** update the `Stage:`/`Last updated:` header, reconcile any number this phase introduced against `#Vision` (surface a contradiction, never write over it), and **offer to commit the change** (`MECHANISMS.md` §Commit the work — check the repo exists, name the branch, offer the message, push only if a remote exists and the user says so). Then **run the transition guard** (`MECHANISMS.md` §Step 3b, item 4): re-run this phase's own `evidence:` lines and report a verdict for every exit criterion — `UNVERIFIED` is a normal outcome, silence is not — and check the transition is legal. **Close in plain language** (`MECHANISMS.md` §Plain-language close): two or three sentences of *what just happened* with no playbook dialect, then a numbered *what YOU do next* — the user's own actions, dated where they are time-bound, or "Nothing — you're done". **The close is the run's last message** — a composed skill's report is input to it, never the close itself. (case file: The report that became the close) After the PR merges, set the card to **Done** and read it back; merged later → the close gives the user that command.

## Step 3c — Contradiction check (before the gate closes)
Per `MECHANISMS.md` §Step 3c, check what this phase just produced against decisions **already recorded** — here: `#Contracts` (types crossing boundaries), `#Architecture` (adapters — no vendor SDK in logic), `#Scope` (non-goals) and `DESIGN.md` (UI tokens) — the richest surface for contradiction, because this is the phase that writes real code. On a conflict, **name both sides, ask which wins, and update the loser** (fix the artefact, or add a dated `superseded by` line to the earlier section) — never leave it standing in two places. Adding detail to an earlier decision is not a contradiction. **Step 3c's result goes in the feature doc** — never a paragraph in `#Build log`, which holds table rows and nothing else.

## Step 4 — Handoff
"Feature done, verified, and documented. Build the next core-scope feature with `/build`, or when the
core scope is complete run **`/dev-check`** — the checkpoint that verifies everything before testing."

Files in this skill

  • SKILL.md19.7 KB
  • references/feature-archetypes.md8.7 KB
  • references/live-path-checks.md6.9 KB

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.