Planning
The spec is the most important artifact in the scafld workflow. A bad spec produces bad work regardless of how capable the agent is.
Anatomy of a good spec
A spec answers five questions:
- What are we building? (objectives)
- Why are we building it? (summary, context)
- Where does it change? (scope, files_impacted, touchpoints)
- How do we know it works? (acceptance criteria)
- What must not break? (invariants, out_of_scope)
If any of these are vague, the spec isn't ready.
The planning loop
In planning mode, the agent reads the project-owned .scafld/prompts/plan.md template and runs a structured exploration cycle:
- THOUGHT -- interpret the request in repo terms, identify unknowns
- ACTION -- search the codebase, read files, check diffs
- OBSERVATION -- capture what was learned
- THOUGHT -- update the spec, ask clarifying questions
- REPEAT until all required fields are filled
The agent is in read-only mode during planning. It can explore anything but change nothing outside .scafld/specs/. If blocked by uncertainty, it leaves the spec as status: draft and records the unanswered question in the planning log or the latest harden round.
scafld plan <task-id> creates the draft. Run scafld harden <task-id> after
the draft is filled in to interrogate the contract before approval.
Task sizing
| Size | Scope | Phases | When to use |
|---|---|---|---|
micro | Single file, mechanical change | 1 | Rename, typo fix. Rarely needs a spec. |
small | 2-3 files, well-understood change | 1-2 | Add a utility, fix a bug. |
medium | Multiple files, some design decisions | 2-4 | New feature, refactor. |
large | Cross-cutting, architectural impact | 4+ | Migration, new subsystem. |
Writing objectives
Objectives are outcomes, not activities:
# Bad: describes activity
objectives:
- "Refactor the auth module"
# Good: describes outcomes
objectives:
- "Auth module uses stateless JWT instead of session cookies"
- "All auth endpoints return standard error envelope on failure"Each objective should be independently verifiable.
Defining scope
Scope is a contract. In-scope items will change. Out-of-scope items will not be touched. This is what makes adversarial review concrete instead of vibe-based.
scope:
in_scope:
- "JWT middleware in src/middleware/"
- "Login and refresh endpoints in src/routes/"
out_of_scope:
- "User model or database schema"
- "Frontend authentication flow"Phasing work
Each phase has its own acceptance criteria, so partial progress is measurable. Dependencies between phases enforce ordering.
## Phase 1: Token generation
Goal: JWT creation and signing.
Status: pending
Dependencies: none
Changes:
- `src/auth/token.ts` — sign and verify JWTs using RS256.
Acceptance:
- [ ] `ac1_1` test: Token round-trips correctly.
- Command: `npm test -- --grep 'token'`
- Expected kind: `exit_code_zero`
- Status: `pending`
## Phase 2: Auth middleware
Goal: Request validation pipeline.
Status: pending
Dependencies: phase1The planning log
Records decisions made during spec creation. Uses a structured format:
## Planning Log
- 2026-04-16T10:00:00Z - agent - Chose RS256 over HS256 for token signing.
- Notes: Asymmetric keys allow verification without exposing the signing key.Risk assessment
Risk level determines the default validation profile:
| Risk | Default profile | What it runs |
|---|---|---|
low | light | Compile check + acceptance criteria |
medium | standard | + full test suite, linter, typecheck, security scan |
high | strict | + per-phase boundary checks |
Common mistakes
Specs that are too vague. "Improve performance" with no metrics. If the agent can interpret the objective three different ways, the spec has failed.
Specs that are too prescriptive. Dictating exact implementations line by line defeats the purpose. Specify the contract, not the algorithm.
Skipping out_of_scope. Without explicit boundaries, the agent will "helpfully" refactor adjacent code.
Hardening
When a spec is finished but you want to stress-test it before approval, run scafld harden <task-id>. This enters HARDEN MODE: the agent interrogates the draft one question at a time, walking down the design tree and resolving upstream decisions before downstream ones. If a question can be answered by exploring the codebase, it should inspect the code instead of asking. When the contract is sharp enough to execute, run scafld harden <task-id> --mark-passed. The round is recorded in harden_rounds for audit.
Hardening is optional and operator-driven. scafld approve does not require it. Run it on high-risk or ambiguous specs; skip it on trivial or well-understood ones. See CLI reference for flags.
