scaffold-project
Skill0 starsChanged 5 months agoMITView on GitHub
Bootstrap a greenfield project to a bootable stack. Reads `docs/architecture-decision-record/` + the ADR-published `docs/stack.yaml` (fallback-distills it for older lock-ins), materializes backend/frontend/e2e/compose from templates (or a layout-pinning skeleton for stacks without one), verifies boot, seeds locked design tokens, wires CI + pre-commit/pre-push githooks, pushes, opens a PR. Activate on '/scaffold-project'. Do NOT activate if any scaffold surface exists.
- Installs packages
- Commits and pushes
11 other projects use a version of this.
Adopted by
Most recently taken up by
- mxrsv/agents-skillstheir own version, first seen Nov 1, 2026
- ankit4479/outbound-builder-plugintheir own version, first seen Oct 20, 2026
- navjyotnishant/nj-agentstheir own version, first seen Oct 15, 2026
- plugin87/ux-ui-agent-skillstheir own version, first seen Oct 13, 2026
- tejastn10/workbenchtheir own version, first seen Oct 13, 2026
- sendaifun/solana-newtheir own version, first seen Oct 9, 2026
Other versions11 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 11
- plugin87/ux-ui-agent-skills★ 3.1ksame name
- sendaifun/solana-new★ 178same name
- faizkhairi/claude-code-blueprint★ 73same name
- cardano-foundation/cardano-dev-skills★ 38same name
- eldermoraes/quarkus-agentic-scaffolding★ 27same name
- 0gfoundation/0g-agent-skills★ 15same name
- mxrsv/agents-skills★ 11same name
- navjyotnishant/nj-agents★ 1same name
- tejastn10/workbench★ 1same name
- ankit4479/outbound-builder-plugin★ 0same name
1 more not listed
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository74 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- create-bug-issueSkill
- create-enhancement-issueSkill
- create-feature-issuesSkill
- dream-summary-memorySkill
- memory-conventionSkill
- operation-gitSkill
- pattern-architect-api-endpointSkill
- pattern-architect-data-modelSkill
- pattern-architect-deep-moduleSkill
- pattern-e2e-coding-standardSkill
- pattern-engineer-apiSkill
- pattern-engineer-backend-standardSkill
- pattern-engineer-coding-standardSkill
- pattern-engineer-containerSkill
- pattern-engineer-databaseSkill
- pattern-engineer-fastapiSkill
- pattern-engineer-frontend-standardSkill
- pattern-engineer-goSkill
- pattern-engineer-javaSkill
- pattern-engineer-kotlinSkill
- pattern-engineer-nodeSkill
- pattern-engineer-non-functionalSkill
- pattern-engineer-observabilitySkill
- pattern-engineer-pythonSkill
- pattern-engineer-rustSkill
- pattern-engineer-securitySkill
- pattern-engineer-ssrSkill
- pattern-engineer-swiftSkill
- pattern-engineer-typescriptSkill
- pattern-engineer-viteSkill
- pattern-exploratory-testingSkill
- pattern-reviewer-apiSkill
- pattern-reviewer-backend-standardSkill
- pattern-reviewer-coding-standardSkill
- pattern-reviewer-containerSkill
- pattern-reviewer-contractSkill
- pattern-reviewer-databaseSkill
- pattern-reviewer-fastapiSkill
- pattern-reviewer-frontend-standardSkill
- pattern-reviewer-goSkill
- pattern-reviewer-javaSkill
- pattern-reviewer-kotlinSkill
- pattern-reviewer-nodeSkill
- pattern-reviewer-non-functionalSkill
- pattern-reviewer-observabilitySkill
- pattern-reviewer-pythonSkill
- pattern-reviewer-rustSkill
- pattern-reviewer-securitySkill
- pattern-reviewer-ssrSkill
- pattern-reviewer-swiftSkill
- pattern-reviewer-test-coverageSkill
- pattern-reviewer-typescriptSkill
- pattern-reviewer-viteSkill
- pattern-test-coverageSkill
- principle-engineer-tddSkill
- workflow-architect-interviewSkill
- workflow-designer-sample-pagesSkill
- workflow-design-interviewSkill
- workflow-e2e-authorSkill
- The first 60 shown.
The file
Show its rules and text
We split this skill into the rules it gives an agent
17 rules. 0 are common, 5 are distinctive, and 12 are very specific to this project.
0
Common
Most of the 11 edited versions we read keep these.
5
Distinctive
This author's own choices. Worth a look.
12
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 10
No feature endpoints, no routes, no migrations, no auth knobs, no contract-derived paths.
- Distinctive: line 18
Do NOT activate when:
- Very specific: line 83
If the directory is missing or empty, STOP.
- Distinctive: line 85
Read every ADR file and extract:
- Distinctive: line 123
If the branch already exists locally, STOP — a prior scaffold run is in flight, and we MUST NOT silently reuse it.
- Very specific: line 134
Keep [tool.ruff.lint] select at the baseline-or-stricter.
- Very specific: line 135
Leave the framework entry (app = FastAPI() or equivalent) untouched.
- Very specific: line 137
Never loosen a baseline rule to make ci-checks.sh pass.
- Distinctive: line 154
Leave the placeholder entry/component untouched.
- Very specific: line 156
Never relax a tsconfig strictness flag or disable a lint rule to make ci-checks.sh pass.
- Very specific: line 222
Commit the workflow and the hook together as the ci surface:
- Very specific: line 227
Backend absent: delete the entire backend block and remove backend-build from the e2e job's needs: list.
- Very specific: line 229
Frontend absent: delete the entire frontend block, remove frontend-build from the e2e job's needs: list, and drop the BASE_URL / …
- Very specific: line 250
Read the locked docs/design-system/tokens.md and seed it into the frontend (the design taste prose and ## Design taste section of CLAUDE.md …
- Very specific: line 252
Write frontend/src/styles/tokens.css with one :root { --<token-name>: <value>.
- Very specific: line 253
Add import './styles/tokens.css'.
- Very specific: line 300
Greenfield only: If any scaffold surface (backend/, frontend/, compose file, e2e/) already exists, STOP.
“Common” is measured: kept by at least 6 in 10 of the 11 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
scaffold-project
Take a greenfield project from empty to a stack that boots end-to-end: backend reachable on its framework-metadata endpoint, frontend reachable on its default page, every Dockerfile builds, docker compose up brings the whole topology up, a Playwright smoke spec drives the served frontend, and the design system locked upstream by /deep-dive-feature (its docs/design-system/tokens.md) is seeded into the frontend as CSS custom properties. Each surface commits as it lands, and the run ends by pushing the branch and opening a PR.
No feature endpoints, no routes, no migrations, no auth knobs, no contract-derived paths. Those land later, when a feature task brings them in via the engineer lane.
When to activate
Activate when:
- The user types
/scaffold-project, or phrases like 'scaffold the project', 'bootstrap the worktree', 'set up the project skeleton', 'make compose bring everything up', 'kickoff the project skeleton'.
Do NOT activate when:
- The project already has any scaffolded surface (
backend/,frontend/,compose.yaml/docker-compose.yaml, ore2e/) — this skill is greenfield only. Surface the gap and STOP; structural additions to an already-bootable project belong to the engineer lane. docs/architecture-decision-record/is empty or doesn't declare a stack choice and a compose topology — scaffold MUST NOT guess at frameworks or services. Surface the gap and STOP.- The work the user wants is feature work — adding a health endpoint at a contract path, wiring React Router, adding cookie knobs. Those belong to the engineer lane.
Scope
Scaffold has no feature code to test, no secrets to handle, no schema to model, and no migrations to ship. Those concerns are out of scope and are picked up once the engineer lane takes over. The design-system step is consumption, not authoring: the system is locked upstream by design-lead during /deep-dive-feature, and scaffold only seeds its already-committed tokens into the frontend as CSS custom properties — not as production components, and never by generating the design system itself.
Templates
Each templates/<variant>/ directory holds a working, bootable example. The skill picks variants from the ADR's stack declaration, then tailors the project configuration to the declared stack and the surfaces that actually land — a template is a baseline to adapt, not a verbatim drop. Two hard boundaries govern that tailoring:
- Configuration is tailored; application code is not authored. Manifests, lint/type/format rule sets, framework-specific lint whitelists, version pins, and surface wiring are adjusted to fit the ADR — e.g. the ruff
flake8-bugbear.extend-immutable-callswhitelist must name the actual DI framework (fastapi.Dependsfor FastAPI, the equivalent for Django/Flask);[tool.ruff] target-version/requires-pythonfollow the ADR's runtime; tsconfigtypesfollow the chosen test runner (vitest/globalsvs jest). Routes, components, middleware, settings, migrations, and router wiring are still never authored here — that is the engineer lane. - Tailoring only ever holds or raises a gate, never loosens it below the template baseline. Adding a rule or a framework whitelist is fine; dropping a lint rule, relaxing a tsconfig strictness flag, widening a security exclusion, or lowering
line-lengthdiscipline to make a check or the boot pass is forbidden. If a baseline gate genuinely cannot hold for the declared stack, STOP and surface — never weaken it silently (this is the same anti-masking invariant as the boot check at step 7).
| Asset | Purpose |
templates/python-fastapi/ | Backend variant: minimal app/main.py (app = FastAPI()), pyproject.toml (incl. mutmut + [tool.mutmut]), multi-stage Dockerfile, scripts/ci-checks.sh (the single-sourced backend gate: ruff + ruff format --check + mypy + full pytest against an ephemeral Postgres), and scripts/mutation.sh (the single-sourced diff-scoped mutation runner — its own CI job, never in the push path). The booted container responds 200 on GET /openapi.json. |
templates/react-vite/ | Frontend variant: index.html, main.tsx rendering a placeholder, package.json (with lint / format / mutation scripts + Stryker dev deps), biome.json (lint + format + import-organize config), stryker.config.json, multi-stage Dockerfile (build → static-serve via nginx, non-root, writable pid path), scripts/ci-checks.sh (the single-sourced frontend gate: biome ci + tsc --noEmit + vitest run), and scripts/mutation.sh (Stryker --since, diff-scoped). The booted container responds 200 on GET /. |
templates/githooks/pre-push | Committed pre-push hook wired via git config core.hooksPath .githooks. Runs the touched stack's scripts/ci-checks.sh — the same script CI runs — so a push that would fail CI is denied locally in one run. Bypassable with git push --no-verify. |
templates/githooks/pre-commit | Committed pre-commit hook (same core.hooksPath wiring). Runs gitleaks protect --staged so a secret is stopped before it enters a commit — push-time and CI scans are backstops that fire after the secret is already in history and must be rotated. Warns loudly (without blocking) when gitleaks isn't installed. |
templates/compose.yaml | Topology skeleton: backend + frontend + db services, ${VAR:-default} port indirection, named volumes. The skill fills in service names / image targets per the ADR. No migrate service — that comes when the first migration lands. |
templates/e2e/ | E2E variant: package.json (@playwright/test + npm test), playwright.config.ts (env-overridable baseURL, retries: 1 on CI, workers: 1), tests/smoke.spec.ts (goto('/') + one visibility assertion), .gitignore. |
templates/ci/pr-validation.yml | Minimal PR-validation pipeline. Triggers on pull_request (incl. draft open / ready_for_review). Jobs: per-stack checks (backend-checks / frontend-checks, each a single bash scripts/ci-checks.sh step — the same script the pre-push hook runs, so CI and local never drift), per-stack docker image build (backend-build, frontend-build), then e2e against docker compose up --build. Backend / frontend job blocks are delimited by # ---- BEGIN <surface> ---- / # ---- END <surface> ---- so the skill can remove a block when the ADR omits that surface. |
templates/commit-messages.md | Conventional Commits format. Scaffold-produced commits use chore(scaffold): <surface> or build: <surface>. |
Skeleton path (the declared stack has no template)
When the ADR declares a stack with no templates/<stack>/ directory, scaffold pins the layout and the gates and leaves the framework entry to the first engineer slice. This split exists because layout is exactly where engineer-authored scaffolding goes wrong: with the layout, manifests, and check gates already committed, the first engineer's framework scaffolding is bounded on every side — docs/stack.yaml pins the framework choice, the committed tree pins the shape (mirror, don't invent), scripts/ci-checks.sh gates the toolchain on its very first push, and the engineer pre-push hook's container-presence + container-smoke gates enforce that the Dockerfile lands and the stack actually boots.
Materialize for a skeleton surface (configuration only — still no application code):
- The canonical directory layout from the matching
pattern-engineer-<language>skill's layout section (e.g. Go: thincmd/<app>/+internal/; Rust:src/under aCargo.toml; JVM: Gradle Kotlin DSL multi-source layout), with.gitkeepin empty directories. - The build manifest + lint/format/type configs at that skill's baseline (
go.mod+.golangci.yml;Cargo.tomlwith clippy-warnings-as-errors; Gradle wrapper + ktlint/detekt or Spotless/ErrorProne;Package.swift+ SwiftLint) — the same never-loosen rule as template tailoring. scripts/ci-checks.shrunning that skill's tooling section verbatim (format check, lint, type/vet, tests). This is the single-sourced gate that CI, the committed githooks, and the engineer pre-push hook all reuse — it must pass on the empty-but-valid package before the skeleton commits..dockerignore. TheDockerfileand the framework entry are not authored here — the first engineer slice owns them, and the engineer pre-push hook's container-presence gate guarantees that ownership is exercised.
Adjustments while any skeleton surface exists: its compose service entry lands commented out with a # TODO(first-slice): marker (un-commented by the slice that lands the Dockerfile) so docker compose up and the CI e2e job stay green on the surfaces that do boot; the step-7 boot probe and the step-11 token seed skip skeleton surfaces (bootability transfers to the first engineer slice, enforced by the pre-push container-smoke gate).
Scripts
| Asset | Purpose |
scripts/check-scaffold-needed.sh | Static, no-build check of the project against each surface. Prints {"surfaces":["backend","frontend","compose","e2e"]} listing surfaces that still need scaffolding. For greenfield, all four MUST be present. Exits 0 always. |
Workflow
The skill operates on the current working directory. It MUST be a git repository with origin configured (so the final push + gh pr create succeed). If either is missing, surface and STOP.
1. Confirm greenfield
bash skills/scaffold-project/scripts/check-scaffold-needed.shThe surfaces array MUST contain every surface (backend, frontend, compose, e2e). If even one surface is already present, STOP and surface: "scaffold-project is greenfield-only; <surface> already exists — structural additions to an existing project belong to the engineer lane". Do not attempt a partial fill-in.
2. Read the ADR
ls docs/architecture-decision-record/ 2>/dev/null | headIf the directory is missing or empty, STOP. Surface "no ADR found under docs/architecture-decision-record/ — scaffold needs the architect's stack/topology decisions before it can pick templates".
Read every ADR file and extract:
- Backend stack — e.g.
python-fastapi. Whentemplates/<stack>/exists, steps 4–5 copy + tailor it (the template path). When it does NOT, the stack still scaffolds via the skeleton path (see "Skeleton path" below) — never STOP just because a template is missing, and never substitute a different stack that happens to have one. - Frontend stack — e.g.
react-vite. Same rule. - Compose topology — the list of services the product needs (e.g.
backend,frontend,db). Service names and image references in the renderedcompose.yamlcome from here. - Product slug — short kebab-case name used as the compose project name and image-tag prefix.
Then assert docs/stack.yaml exists — the machine-readable mirror of the ADRs' stack decision, published by the adr writer scope of workflow-writer-publish-architecture during /deep-dive-feature and kept current by that same scope whenever a later ADR changes the stack. Agents, workflow surface-classifiers, and hooks consume it to resolve framework-conditional patterns (fastapi vs generic api, vite vs ssr, node) without re-inferring from file spellings. Fallback (lock-in predates the manifest convention): distill it from the ADR now, using the writer skill's templates/stack-manifest.yaml shape, and commit — never introducing a choice the ADR didn't make:
# docs/stack.yaml — distilled from docs/architecture-decision-record/.
# Do not edit by hand; regenerate when an ADR changes the stack.
product: <slug>
backend:
stack: python-fastapi # <language>-<framework>, matches the ADR verbatim
language: python
framework: fastapi
frontend:
stack: react-vite
language: typescript
framework: react
rendering: csr # csr | ssr
services: [backend, frontend, db]git add docs/stack.yaml
git commit -m "chore(scaffold): stack manifest (fallback distillation from ADR)"(Skip this commit when the manifest already exists — the stack-manifest surface is a no-op then, and the commit order below starts at backend.)
3. Create the scaffold branch
git checkout -b chore/scaffold-projectIf the branch already exists locally, STOP — a prior scaffold run is in flight, and we MUST NOT silently reuse it. Surface the existing branch and ask the user how to proceed.
4. Scaffold backend → commit
(No template for the declared stack? Materialize per the Skeleton path section instead — same commit shape, layout + manifests + ci-checks.sh only.)
Copy templates/<backend-stack>/ into backend/ (per the ADR's layout). Do not edit the framework entry to add routes, middleware, or settings logic — the template ships a bare app = FastAPI() (or equivalent) intentionally. The copy includes backend/scripts/ci-checks.sh (the single-sourced check gate); ensure its executable bit survives the copy (chmod +x backend/scripts/ci-checks.sh) so the pre-push hook wired at step 9 can invoke it.
Tailor the config to the declared stack (config only — never author code). After copying, adapt the manifest to the ADR:
- Set
requires-pythonand[tool.ruff] target-versionto the ADR's Python version. - Keep
[tool.ruff.lint] selectat the baseline-or-stricter. If the ADR's backend framework is not FastAPI, replace the FastAPI[tool.ruff.lint.flake8-bugbear] extend-immutable-callswhitelist with the dependency-injection idiom the actual framework uses, so routes don't false-positive onB008— adjust the whitelist, never drop theBrule to dodge it. - Leave the framework entry (
app = FastAPI()or equivalent) untouched.
Never loosen a baseline rule to make ci-checks.sh pass; if it cannot pass for the declared stack, STOP and surface.
git add backend/
git commit -m "chore(scaffold): backend (<stack>) — framework entry, manifests, Dockerfile, ci-checks"5. Scaffold frontend → commit
(No template for the declared stack? Materialize per the Skeleton path section instead — same commit shape.)
Copy templates/<frontend-stack>/ into frontend/. Do not add router wiring, components, or pages beyond the template's placeholder. The copy includes frontend/scripts/ci-checks.sh (the single-sourced check gate); ensure its executable bit survives the copy (chmod +x frontend/scripts/ci-checks.sh) so the pre-push hook wired at step 9 can invoke it.
Tailor the config to the declared stack (config only — never author code). After copying, adapt the manifest and tool config to the ADR:
- Point
tsconfig.jsontypesand any test-runner-specific biome rules at the runner the ADR declares (e.g.vitest/globalsvs jest matchers), keeping every strictness flag at baseline-or-stricter. - Pin
@biomejs/biomeand thebiome.json$schemato the same major the baseline targets; do not silently downgrade to dodge a rule the newer major enforces. - Leave the placeholder entry/component untouched.
Never relax a tsconfig strictness flag or disable a lint rule to make ci-checks.sh pass; if it cannot pass, STOP and surface.
git add frontend/
git commit -m "chore(scaffold): frontend (<stack>) — entry, manifests, Dockerfile, ci-checks"6. Scaffold compose → commit
Copy templates/compose.yaml to the project root as docker-compose.yaml. Replace placeholders (<PRODUCT>, <DB_NAME>, <DB_USER>) with values from the ADR. Service names and image: / build: targets MUST match the ADR's topology. Use ${VAR:-default} indirection on every host-exposed port. Do not add a migrate service unless the ADR explicitly says migrations are bootstrapped at scaffold time — by default, migrations come later with the first feature migration.
git add docker-compose.yaml
git commit -m "chore(scaffold): compose topology (<services>)"7. Verify the full stack boots
This is the gate that distinguishes a "templated" project from a "bootable" one. Skeleton-path surfaces are excluded — their compose entries are still commented out and bootability transfers to the first engineer slice (enforced by the engineer pre-push container-smoke gate); probe only the template-backed surfaces. Run:
docker compose up -d --buildThen poll, with a sensible per-service timeout:
- Backend —
curl -fsS http://127.0.0.1:${BACKEND_PORT:-8000}/openapi.json(FastAPI) or the equivalent framework-metadata endpoint for the chosen stack. Must return 200. - Frontend —
curl -fsS http://127.0.0.1:${FRONTEND_PORT:-5173}/. Must return 200. - Db (if in topology) —
docker compose psreportshealthy.
If any check fails, capture the failing container's logs (docker compose logs <service> --tail 100), surface the diagnostic, and STOP before committing any fix — the user must see what the template produced and decide whether to patch the template, the ADR, or the run. Do not silently mutate templates to make the boot succeed.
On success, bring the stack down:
docker compose down8. Scaffold e2e → commit
Copy templates/e2e/ into e2e/. Run npm install inside e2e/ so package-lock.json is produced; commit the lockfile alongside the manifest. Do not author task specs here — only tests/smoke.spec.ts lands.
cd e2e && npm install && cd ..
git add e2e/
git commit -m "chore(scaffold): e2e (playwright + smoke spec)"9. Scaffold CI pipeline + CI-parity pre-push hook → commit
Materialize a minimal PR-validation pipeline so the draft PR opened at step 12 has CI signal from the first commit. Copy templates/ci/pr-validation.yml to .github/workflows/pr-validation.yml. The workflow triggers on pull_request (opened, synchronize, reopened, ready_for_review) — both draft and ready PRs run. It includes a per-stack diff-scoped mutation job (bash scripts/mutation.sh "origin/${{ github.base_ref }}", fetch-depth: 0) that gates on a surviving mutant on a changed line and uploads the surviving-mutant report as an artifact — kept a SEPARATE job from the checks (mutation runs the suite once per mutant, so it never goes in ci-checks.sh or the pre-push hook). Ensure both scripts/ci-checks.sh and scripts/mutation.sh keep their executable bit through the copy.
Materialize and wire the CI-parity pre-push hook (mandatory). The workflow's per-stack check jobs run bash scripts/ci-checks.sh; the committed pre-push hook runs the same script for every touched stack, so a push that would fail CI is denied locally in one run — no peeling failures apart one PR-cycle at a time. Wire it:
Also materialize the pre-commit secret gate. gitleaks protect --staged runs before every commit, stopping a secret before it enters history at all — the push-time and CI scans are backstops that fire after the leak has landed and the credential must be rotated regardless. Wire both hooks together:
mkdir -p .githooks
cp skills/scaffold-project/templates/githooks/pre-push .githooks/pre-push
cp skills/scaffold-project/templates/githooks/pre-commit .githooks/pre-commit
chmod +x .githooks/pre-push .githooks/pre-commit
git config core.hooksPath .githookscore.hooksPath is a local git setting (not committed), so the hook files alone aren't enough — every clone must run git config core.hooksPath .githooks once. Record that one-liner in the repo's README.md (or CONTRIBUTING.md) setup section so contributors enable it; the hooks themselves are committed under .githooks/ so they travel with the repo. (The per-stack scripts/ci-checks.sh the pre-push hook invokes already landed with the backend/frontend surfaces at steps 4–5.)
Commit the workflow and the hook together as the ci surface:
Shape the rendered file to the surfaces that landed:
- Backend present (per the ADR): leave the
# ---- BEGIN backend ... ---- END backend ----block in place. The check step itself is stack-agnostic (bash scripts/ci-checks.sh); only the toolchain setup step is stack-specific — keepactions/setup-python+ uv forpython-*stacks, swap it for the declared stack otherwise (actions/setup-go,dtolnay/rust-toolchain,actions/setup-java,swift-actions/setup-swift,actions/setup-node). For a skeleton-path backend the block stays too —ci-checks.shalready passes on the empty-but-valid package — butbackend-buildis commented out with the same# TODO(first-slice):marker as its compose entry. - Backend absent: delete the entire backend block and remove
backend-buildfrom thee2ejob'sneeds:list. - Frontend present (per the ADR): leave the
# ---- BEGIN frontend ... ---- END frontend ----block in place; same setup-step-swap rule as the backend block. - Frontend absent: delete the entire frontend block, remove
frontend-buildfrom thee2ejob'sneeds:list, and drop theBASE_URL/FRONTEND_PORTenv wiring and the "Wait for frontend" step.
Do not add deploy jobs, registry pushes, OIDC role assumptions, or environment gates — those belong to the sre agent's lane, not to a scaffold-time validation pipeline. Do not add paths: filters that skip e2e — the e2e job is the only signal that the system composes correctly.
git add .github/workflows/pr-validation.yml .githooks/pre-push .githooks/pre-commit
git commit -m "chore(scaffold): ci (pr-validation pipeline + ci-parity pre-push hook + gitleaks pre-commit)"10. Assert the locked design system exists
The design system is locked upstream by design-lead and committed by design-writer during /deep-dive-feature — scaffold no longer generates it, it consumes it. Before seeding, assert the artifact is present:
test -f docs/design-system/tokens.md && test -f docs/design-system/surfaces.mdIf either file is missing, STOP and fail loudly: surface "docs/design-system/ is absent or incomplete (tokens.md / surfaces.md not found) — the design system must be locked via /deep-dive-feature before scaffolding. Run the design phase first, then re-run /scaffold-project." Do NOT invoke any UI/UX skill, do NOT invent tokens, do NOT proceed to the seed step. This assertion is what prevents a silent regression to the old "scaffold generates the design system" behavior.
11. Seed design tokens into the frontend → commit
Read the locked docs/design-system/tokens.md and seed it into the frontend (the design taste prose and ## Design taste section of CLAUDE.md are already authored by design-writer — scaffold does not re-write them):
- Write
frontend/src/styles/tokens.csswith one:root { --<token-name>: <value>; ... }block. Each property's name MUST match the token name intokens.md(e.g.color/brand/500→--color-brand-500). Every color, font, spacing, radius, shadow, and motion token intokens.mdMUST appear here. - Add
import './styles/tokens.css';tofrontend/src/main.tsx(or the entry file the chosen frontend stack uses) so the tokens are loaded at boot. Do not author components, pages, or further styling — the seam stops at "tokens are reachable from production code".
Commit both together:
git add frontend/src/styles/tokens.css frontend/src/main.tsx
git commit -m "chore(scaffold): seed locked design tokens into frontend"12. Push branch and open the draft PR
git push -u origin chore/scaffold-projectThen open the PR as a draft with gh pr create --draft, so the CI workflow scaffolded at step 9 fires on draft open and the user gets first-commit signal before the PR flips to ready. Title: chore(scaffold): bootstrap project skeleton. Body lists the surfaces that landed (backend stack, frontend stack, compose services, e2e smoke, CI pipeline), a one-line confirmation that docker compose up reached 200 on every framework-metadata endpoint locally, and the seeded design tokens (frontend/src/styles/tokens.css, compiled from the locked docs/design-system/tokens.md).
gh pr create \
--draft \
--title "chore(scaffold): bootstrap project skeleton" \
--body "$(cat <<'EOF'
## Summary
- Backend: <stack>
- Frontend: <stack>
- Compose services: <list>
- E2E: Playwright smoke spec
- CI: `.github/workflows/pr-validation.yml` (per-stack checks + diff-scoped mutation → docker build → e2e)
- Design tokens: seeded `frontend/src/styles/tokens.css` (compiled from locked `docs/design-system/tokens.md`)
## Boot check
Locally verified `docker compose up` reaches 200 on backend framework-metadata and frontend `/`.
## Test plan
- [ ] `docker compose up --build` brings the stack up
- [ ] Backend framework-metadata endpoint returns 200
- [ ] Frontend `/` returns 200
- [ ] `cd e2e && npm test` passes against the running stack
- [ ] `pr-validation` workflow run is green on this draft PR
EOF
)"Report the PR URL and stop.
Iron rules
- Greenfield only. If any scaffold surface (
backend/,frontend/, compose file,e2e/) already exists, STOP. This skill does not partial-fill. - No defaulted URIs, service names, ports, or framework choices. Stack variants and topology come from
docs/architecture-decision-record/. If the ADR doesn't say, STOP and surface — never guess. A declared stack WITHOUT a template is not a guess — it takes the skeleton path; a missing declaration is what stops the run. - The stack manifest is derived, never decided.
docs/stack.yamlmirrors the ADR for machine consumption (pattern selection, surface classification, hooks). Its owner is theadrwriter scope ofworkflow-writer-publish-architecture(published at ADR lock, updated when a later ADR changes the stack); scaffold only asserts it exists and falls back to distilling it for lock-ins that predate the convention — never introducing a choice the ADR didn't make. - Templates are a baseline to tailor — for configuration, never for application code. Project configuration (manifests, lint/type/format rule sets, framework-specific lint whitelists, version/runtime pins, surface wiring) IS adapted to the ADR-declared stack and the surfaces that land — a template is a starting point, not a verbatim drop. Application code is still never authored: no routes beyond what the template ships (none), no components/pages beyond the placeholder, no middleware, settings logic, auth, migrations, or router — those are the engineer lane. Tailoring may hold or raise a gate, never loosen it below the template baseline; if a baseline gate cannot hold for the declared stack, STOP and surface rather than weaken it (the same anti-masking rule that governs the boot check).
- One commit per surface, in the order
stack-manifest→backend→frontend→compose→e2e→ci→design-tokens. Subject ischore(scaffold): <surface> — <short detail>in Conventional Commits format. Never bundle, never reorder, never usefeat:. - The boot check is mandatory and non-negotiable. Compose must bring the stack up locally before e2e lands; if it doesn't, STOP and surface — do not mutate templates to mask the failure.
- CI is scaffold-time validation only. The pipeline produced at step 9 runs lint/type/format/test, builds images locally, and runs e2e against compose. It MUST NOT push images, assume an OIDC role, reference a registry, or deploy. Deploy pipelines, environment gates, and tag-driven promotion are the
sreagent's lane — surface and STOP if the user asks scaffold to add any of those. - CI checks are single-sourced; both githooks are mandatory. Each per-stack check job runs
bash scripts/ci-checks.sh, and the committed.githooks/pre-push(wired withgit config core.hooksPath .githooks) runs that same script for every touched stack — the plugin's engineer pre-push gate delegates to it too. Never inline the check commands into the workflow — that reintroduces the drift this exists to kill. The committed.githooks/pre-commitrunsgitleaks protect --stagedso secrets are stopped before they enter a commit (push-time scans are backstops). Both hooks must be materialized and wired at step 9; record the one-timegit config core.hooksPath .githooksin the README so every clone enables them. - The design system is consumed, not generated. Scaffold never invokes a UI/UX skill and never authors
docs/design-system/. The system is locked upstream bydesign-leadand committed bydesign-writerduring/deep-dive-feature(the## Design tastesection ofCLAUDE.mdis written there too). At step 10 scaffold assertsdocs/design-system/tokens.mdandsurfaces.mdexist and fails loudly if either is absent — it does not invent tokens or fall back to generating a design system. Step 11 only seeds the lockedtokens.mdintofrontend/src/styles/tokens.cssand imports it at boot. - The skill ends with a draft PR. Push the branch and open a draft PR via
gh pr create --draftso the scaffold-time CI fires on first commit. Do not merge; do not flip the PR to ready; do not switch back tomain; do not delete the branch.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

