---
name: build-scaffold
description: "Use to generate the initial layout of a fresh codebase — triggered by phrases like 'start a new project', 'scaffold from scratch', 'set up the repo', 'bootstrap the codebase', 'create the project structure', 'scaffold the app'. Produces directory layout, build tooling, Docker config, and test infrastructure that match the approved architecture. Skip when the work is on an existing codebase — scaffolding overwrites layout decisions that established code already encodes."
---

# Build Scaffold

## Overview

Set up a new project from scratch with production-ready structure, build tooling, containerization, and test infrastructure.

**Core principle:** A project that builds and tests from the first commit is a project that stays healthy.

**Announce at start:** "I'm using the build-scaffold skill to set up the project structure."

## When to Use

- Greenfield projects (no existing code)
- `/greenfield` command (scaffold phase)
- When the user says "start a new project" or "set up from scratch"

**Not for:**
- Adding features to existing projects (use build-tdd)
- Restructuring existing projects (use /refactor command)

## Prerequisites

Before scaffolding, the project profile must exist (CLAUDE.md or equivalent specifying tech stack, frameworks, database). Architecture context is also required, sourced from whichever upstream phase applies to the work:

- **Prototype-driven flow** (default `/feature`, `/greenfield`): the codified architecture in `aiwiki/architecture/` and the slice graph in the work manifest, produced by the `harden` skill at Phase 5 (codify).
- **Non-prototype fallback flow** (libraries, internal tools where wireframe makes no sense): architecture artifacts from `plan-architecture` in `.forge/work/{type}/{name}/architecture/` and key decisions in `aiwiki/decisions/`.

If neither is available, stop and request — do not guess at technology choices.

## Step 0: Codex Delegate Check

Before running any scaffold steps, check if Codex should build the scaffold instead of Claude:

1. Run `codex --version`. If exit code is non-zero, Codex is unavailable — skip this step silently and proceed to Step 1. Never prompt the user about Codex when it isn't installed.
2. If Codex is available, read `codex.delegate` in `.forge/local.yaml`:
   - **`always`** or the user explicitly requested Codex as the builder → dispatch Codex with the architecture artifacts, project profile, and this skill's SKILL.md. Codex generates the complete scaffold. Skip to Step 7 (Verify) when Codex returns. Quality gate still applies.
   - **`ask`** or absent → prompt once per `protocols/codex.md`. Save the answer if the user picks "always" or "never".
   - **`never`** → proceed with Claude-driven scaffold below.

See the **Codex Integration** section at the end for the exact invocation command and context paths.

## The Scaffold Process

### Step 1: Read Project Profile

Read CLAUDE.md (or the architecture artifacts) for:

```
- Language / runtime (Node.js, Python, Go, Rust, Java, etc.)
- Framework (Express, FastAPI, Gin, Actix, Spring, etc.)
- Database (PostgreSQL, MySQL, MongoDB, SQLite, etc.)
- Frontend framework (React, Vue, Svelte, etc.) if applicable
- Package manager (npm, yarn, pnpm, pip, poetry, cargo, etc.)
- Testing framework (Jest, Vitest, pytest, go test, etc.)
- CI/CD target (GitHub Actions, GitLab CI, etc.)
```

**Do not assume defaults.** If the project profile does not specify a choice, ask the user. Every technology decision matters.

### Step 2: Generate Directory Structure

Follow conventions for the detected stack. General pattern:

```
project-root/
├── src/                          # Application source code
│   ├── [domain-grouped dirs]     # Organized by feature/domain, NOT by type
│   └── index.ts / main.py / main.go  # Entry point
├── tests/                        # Test files (mirror src/ structure)
│   ├── unit/
│   ├── integration/
│   └── e2e/
├── scripts/                      # Build, deploy, utility scripts
├── docs/                         # Project documentation
├── docker/                       # Docker-related files (if complex)
├── .github/ or .gitlab-ci/       # CI/CD configuration
└── [config files at root]        # package.json, pyproject.toml, etc.
```

**Stack-specific structures:**

#### Node.js / TypeScript
```
├── src/
│   ├── modules/                  # Feature modules
│   │   └── [feature]/
│   │       ├── [feature].controller.ts
│   │       ├── [feature].service.ts
│   │       ├── [feature].repository.ts
│   │       ├── [feature].types.ts
│   │       └── [feature].test.ts
│   ├── common/                   # Shared utilities
│   │   ├── middleware/
│   │   ├── errors/
│   │   └── utils/
│   ├── config/                   # Configuration loading
│   └── app.ts                    # Application setup
├── tests/
│   ├── integration/
│   └── e2e/
├── package.json
├── tsconfig.json
├── vitest.config.ts / jest.config.ts
└── eslint.config.js
```

#### Python
```
├── src/
│   └── [package_name]/
│       ├── __init__.py
│       ├── [module]/
│       │   ├── __init__.py
│       │   ├── routes.py
│       │   ├── service.py
│       │   ├── models.py
│       │   └── schemas.py
│       ├── core/
│       │   ├── config.py
│       │   └── dependencies.py
│       └── main.py
├── tests/
│   ├── unit/
│   ├── integration/
│   └── conftest.py
├── pyproject.toml
└── alembic/ (if using SQLAlchemy)
```

#### Go
```
├── cmd/
│   └── server/
│       └── main.go
├── internal/
│   ├── [domain]/
│   │   ├── handler.go
│   │   ├── service.go
│   │   ├── repository.go
│   │   └── models.go
│   ├── config/
│   └── middleware/
├── pkg/                          # Public packages (if any)
├── go.mod
├── go.sum
└── Makefile
```

**Adapt structure to the specific framework** (e.g., Next.js uses `app/` or `pages/`, Django uses `manage.py` and app directories).

### Step 3: Set Up Build Tooling

Create the appropriate package manifest for the detected stack. Adapt to the specific framework in use (Next.js, Django, FastAPI, etc.).

- **Node.js** (`package.json`): include scripts `dev`, `build`, `start`, `test`, `test:coverage`, `lint`, `lint:fix`, `typecheck`. Pin Node version in `engines`. Commit the lockfile.
- **Python** (`pyproject.toml`, PEP 621): configure `[tool.pytest.ini_options]`, `[tool.ruff]` (line-length 100), and `[tool.mypy]`. Pin Python version in `.python-version`. If the package manager produces a lockfile (`poetry.lock`, `uv.lock`, `Pipfile.lock`), commit it; plain pip has no standard lockfile.
- **Go** (`go.mod` + `Makefile`): Makefile targets `build`, `test`, `lint`, `run`. Pin Go version in `go.mod`. Commit `go.sum`.

**Key rule:** every script/target must work immediately after setup. If `npm test` fails on a fresh clone, the scaffold is broken.

### Step 3.5: Install CSS Framework (Frontend Projects Only)

If the project has a frontend and `DESIGN.md` exists at the project root (from the `plan-design-system` skill):

1. **Read `DESIGN.md`** at the project root for design tokens (colors, typography, spacing, component conventions)
2. **Install the chosen CSS framework** (Tailwind, CSS Modules, styled-components, etc.) as specified in the design tokens
3. **Configure the framework** — set up Tailwind config with the design token colors, or create CSS custom properties from the tokens
4. **Apply the base theme** — set the global background, text color, and font family from the design tokens
5. **Verify the build succeeds** with the CSS framework installed

If no `DESIGN.md` exists (e.g., backend-only project), skip this step.

### Step 4: Docker Setup

Create Docker environment for reproducible development.

**Dockerfile** — multi-stage production build:
- `builder` stage installs dependencies and runs build
- `runtime` stage copies build output via `COPY --from=builder`
- Pin base image to a specific version (NEVER `:latest`)
- `EXPOSE` the app port, `CMD` runs the start command

**docker-compose.yml** — include every service the approved architecture requires (app, db, cache, queue, etc.). Omit services the architecture doesn't use; if the architecture uses no external services, compose may be omitted or contain only the app.
- `app`: `build: .`, port from `${APP_PORT}`, env from `.env`, volumes for hot-reload. If a db service is present, add `depends_on: db: condition: service_healthy`
- `db` (only if the architecture uses a containerized database — skip for SQLite or externally managed databases): pinned image (e.g., `postgres:16-alpine`), named volume for persistence, healthcheck (e.g., `pg_isready`)
- Top-level `volumes` block for any named volumes declared above

**.dockerignore** — exclude `node_modules/` (or equivalent), `.git/`, `.env*`, `*.log`, `dist/`/`build/`, `coverage/`, `.forge/`.

**Key rules:**
- Multi-stage builds for production images
- Healthchecks on every service that others depend on
- Volumes for hot-reload in development, not production
- Pinned base image versions — no `latest` tag
- `.dockerignore` must be present

### Step 5: Environment Configuration

**`.env.example`** — document every environment variable the app reads. Group by purpose (Application, Database, Auth, External Services). Use safe placeholder values; never real secrets. Include a comment per variable explaining what it does. `.env` itself must be gitignored.

**`.gitignore`** — generate stack-idiomatic entries. Always include: `.env*` (except `.env.example`), `*.log`, coverage outputs, build artifacts, `.forge/`, `.worktrees/`, and the stack's dependency/cache dir (`node_modules/`, `__pycache__/`, `vendor/`, `target/`, etc.).

### Step 6: Initial Test Infrastructure

Set up the test runner and write the first test:

**Test runner configuration** — configure the project's test framework (Vitest/Jest for Node, pytest for Python, `go test` for Go, etc.) with:
- Coverage enabled (v8, c8, coverage.py, `-cover`)
- Coverage thresholds at **80% on statements, branches, functions, lines** (or the stack equivalent)
- Test directory matches the structure in Step 2

**Smoke test** — write one trivial test per stack's idiom (e.g., `expect(true).toBe(true)` for Vitest, `assert True` for pytest, a minimal `t.Run` for Go). Its only job is to prove the test runner works. MUST pass before proceeding to any implementation.

### Step 7: Verify Build and Tests

Run the full verification sequence:

```bash
# 1. Install dependencies
[package-manager] install

# 2. Build the project
[build-command]

# 3. Run linter
[lint-command]

# 4. Run tests
[test-command]

# 5. Docker build (if Docker is set up)
docker compose build

# 6. Docker up + health check (optional but recommended)
docker compose up -d
docker compose ps  # verify all services healthy
docker compose down
```

**All steps must pass.** If any step fails:
1. Fix the issue immediately
2. Re-run verification from the beginning
3. Do not proceed to build-tdd until everything passes

### Step 8: Initial Commit

Once everything passes:

```bash
git init
git add .
git commit -m "feat: initial project scaffold

- Project structure for [stack]
- Build tooling configured
- Docker environment set up
- Test infrastructure verified
- All tests passing"
```

## TDD Exemption

Scaffolding is explicitly exempt from the build-tdd "NO production code without a failing test" rule. Scaffold generates boilerplate infrastructure (directory structure, config files, Docker setup, build tooling) that is verified by the post-scaffold checklist below, not by TDD. The initial smoke test written during scaffolding proves the infrastructure works. Once scaffold is complete and handed off to build-tdd, normal TDD discipline applies to all subsequent code.

## Post-Scaffold Checklist

Before handing off to build-tdd, verify:

- [ ] Directory structure follows stack conventions
- [ ] Package manifest exists with all required scripts
- [ ] All scripts work (`dev`, `build`, `test`, `lint`)
- [ ] Docker builds successfully
- [ ] docker-compose starts all services with health checks
- [ ] `.env.example` has all required variables
- [ ] `.gitignore` covers all generated/sensitive files
- [ ] Test runner configured with coverage thresholds
- [ ] Smoke test passes
- [ ] Linter passes with zero warnings
- [ ] Initial commit made

**Cannot check all boxes? Fix before proceeding. The scaffold is the foundation.**

## Common Mistakes

| Mistake | Fix |
|---------|-----|
| Skipping Docker setup | Docker-first for reproducibility. Always set up. |
| Missing .env.example | Every env var must be documented. No guessing. |
| No test infrastructure | First test must pass before any implementation. |
| Using `latest` Docker tag | Pin specific versions for reproducibility. |
| Organizing by file type | Organize by feature/domain. Not controllers/, services/, models/. |
| Missing .gitignore entries | Generate comprehensive ignore file for the stack. |
| Scripts that do not work | Every script must work on fresh clone. Verify each one. |
| No linter configured | Linting catches issues early. Configure from day one. |

## I/O Contract

| Field | Value |
|---|---|
| **Requires** | Architecture context (codified `aiwiki/architecture/` + manifest slice graph from `harden`, OR `.forge/work/{type}/{name}/architecture/` from `plan-architecture`) + project profile (CLAUDE.md) |
| **Produces** | Project directory structure, `package.json` / `pyproject.toml` / `go.mod`, `Dockerfile`, `docker-compose.yml`, `.env.example`, `.gitignore`, test runner config, initial smoke test |
| **Feeds into** | `build-tdd` at Phase 6 (production-build) |
| **Updates manifest** | `artifacts.scaffold.locked_at` (scaffold complete) — slice work proceeds against the scaffolded structure |

## Codex Integration

**Mode:** Delegate | **Protocol:** `protocols/codex.md` | **Consent key:** `codex.delegate`

**When:** Step 0, if Codex is installed AND `codex.delegate` is `always` (or the user accepts the `ask` prompt).

**Context to pass:**
- Path to architecture (either `aiwiki/architecture/` from harden, or `.forge/work/{type}/{name}/architecture/` from plan-architecture)
- Slice graph from manifest (harden flow) or `tasks.md` (plan-task-decompose flow)
- Path to this skill: `skills/build-scaffold/SKILL.md`

**What Codex does:**
- Generate the project scaffold following the architecture spec
- Follow the methodology defined in this skill's SKILL.md (directory patterns in Step 2, adapt to the detected framework)

**Prompt focus:** "Generate the project scaffold following the architecture artifacts at [paths]. Follow the methodology in skills/build-scaffold/SKILL.md. Output the complete file tree with contents."

**Quality gate:** Scaffold output goes through standard verification (Step 7) — directory structure matches architecture, configuration files are valid, initial tests pass. Claude runs verification regardless of who built.

---

## Integration

**Called by:**
- `/greenfield` command (after architecture phase)

**Pairs with:**
- `harden` (prototype-driven flow: reads codified architecture + slice graph from `aiwiki/` and manifest)
- `plan-architecture` (non-prototype fallback flow: reads `.forge/work/.../architecture/`)
- `build-tdd` (hands off a working project ready for Phase 6 production-build)
- `deliver-onboarding` (scaffold creates the foundation that onboarding documents)
