Spec-driven workflow
The principle
Non-trivial changes are specified before they are implemented. The agreed
.specs/<feature>.md file is the source of truth for the change. If reality
contradicts it mid-implementation, work stops and the spec is updated — the code does
not quietly diverge.
This is stated in CLAUDE.md / AGENTS.md as a standing decision. See
decision D10.
The five phases
┌──────────┐ ┌───────────────┐ ┌─────────────┐ ┌────────────────────────┐ ┌─────────────┐
──► │ planner │──► │ plan-reviewer │──► │ implementer │──► │ implementation-reviewer│──► │ docs-writer │
└──────────┘ └───────┬───────┘ └──────┬──────┘ └───────────┬────────────┘ └─────────────┘
writes critiques the executes in reviews the diff updates the
.specs/<f>.md spec BEFORE code small verified against the spec Antora docs
│ increments │ in docs/
│ │ │
└───────────────────┴─────────────────────┘
kick back on any contradiction
Phases auto-chain with checkpoints: each hands off to the next, but the implementer works incrementally and stops on any failing lint or test, or on any decision that contradicts the spec.
| Phase | Role | Stops and asks when |
|---|---|---|
1 |
Planner — produce or extend a spec with requirements, design and a file-level task list. |
The requirement is ambiguous, or the change needs a decision the user must make. |
2 |
Plan reviewer — critique the spec for correctness, scope, completeness and fit with existing Angular/NgRx patterns. Before any code. |
The plan invents architecture, or misses an existing pattern. |
3 |
Implementer — execute the approved spec one task at a time, verifying each step. |
Lint or a test fails non-trivially; the spec is wrong; a task needs an unspecced dependency; scope is growing. |
4 |
Implementation reviewer — review the diff against the spec and the correctness
properties. Verdict: |
Blocking findings route back to the implementer. |
5 |
Docs writer — update the Antora documentation component in |
The code contradicts the spec in a way that changes documented behaviour; a new
Antora module or |
Where the definitions live
| Tool | Definitions |
|---|---|
Claude Code |
|
Cursor |
|
Shared context |
|
Cursor additionally carries angular-architecture, change-plan-authoring,
change-plan-review and post-plan-code-review skills, which predate the five-phase
naming.
Operating principles
These shape how each phase works, not just what it produces. From CLAUDE.md,
after Andrej Karpathy:
- Keep the model on a tight leash
-
Many small, concrete, verifiable steps over one big speculative diff. Change one thing, prove it, move on.
- Optimise the generation→verification loop
-
Every change should be cheap to check — a small diff, a runnable test, a lint pass. If a human or a reviewer agent cannot verify a step quickly, the step is too big.
- Context is RAM
-
Pull in only the files that matter. Reference exact paths and symbols. Do not dump a whole module into context "just in case".
- Spec before code
-
Do not start editing until the plan exists and survives review.
- Never ship code you cannot explain
-
No "vibe" diffs. Every change is justified against the spec and covered by a test or a clear manual check.
- Match the codebase, do not impress it
-
Concrete and consistent beats clever.
- Keep the human at the decision points
-
Surface trade-offs and ambiguities; never silently choose on anything that changes scope or behaviour.
.specs/ formats
There are two reference formats and a third, longer planning format. All three are live; pick by size of change.
1. Requirements-and-tasks (for new work)
.specs/bank-name-swift-lookup.md:
# <Feature Name>
## Summary one paragraph: what and why
## Requirements numbered, testable
## Design the approach, existing patterns to follow, files involved
## Tasks - [ ] checkboxes, file-level, in order
The implementer checks off each task (- [x]) as it goes, so the spec doubles as
progress.
2. As-built record (for shipped work)
.specs/email-preference-management.md:
# <Feature Name>
## Overview what it is, where it lives in the UI
## Files Created each path with a one-line purpose
## Files Modified each path with what changed
## API Endpoints method, URL, request/response shape, auth note
## Component Behaviour loading, error and edge-case behaviour
Note how specific it is — down to
“supplierKey` visibility changed from private to `public” and
"401/403 → access denied message, 404 → not found message, 5xx/network → generic error
+ retry button". That level of detail is what makes the review phase cheap.
3. Plan documents (for large changes)
.specs/gar-2149-card-management-airwallex.plan.md and
.specs/airwallex_cardholder_registration_72c94cb6.plan.md use a fuller structure:
## Goals / non-goals / done
## Affected surfaces
## Documentation consulted
## Design
### API Migration Map
### Unified Card Model
### Provider Detection Flow
## Implementation sequence
### Phase 1: Model & Interfaces
### Phase 2: Feature Flag
### Phase 3: Service Layer
### Phase 4: NgRx Store (minimal additions)
### Phase 5: Component Updates
### Phase 6: Routing
### Phase 7: Module Registration
### Phase 8: Tests
## Files and resources
### New files / Modified files / Env vars
### New `USER_PERMISSION` values
### New `FEATURE_FLAG` key
## Risk and scale
## Testing and rollout
### Manual QA paths
Two things worth copying from that format:
-
Non-goals are stated explicitly, which is what keeps the implementer’s scope honest.
-
New
USER_PERMISSIONvalues, newFEATURE_FLAGkeys and new env vars get their own sections — exactly the items that also require a documentation catalogue update. See the blast-radius checklist below.
The result of that particular plan is documented in card programmes.
The documentation phase
Phase 5 is new relative to the original four-phase workflow, and exists because
docs/ is a structured Antora component rather than a README.
docs/ is an Antora documentation component named internal-admin, consumed by the
central Payability playbook via start_path: docs. Six modules: ROOT,
architecture, domains, platform, ops, reference. See
docs/README.adoc and the documentation map.
The docs-writer skill carries the AsciiDoc/Antora reference (resource-ID xrefs,
nav.adoc upkeep, the page template) and a blast-radius checklist. The short
version:
| If the change touched… | Update |
|---|---|
a route, guard or route |
|
an NgRx action, reducer or effect |
|
a service or endpoint |
|
|
|
|
|
|
|
|
|
a storage key, cookie or cache |
|
a new module or shared component |
|
a dependency or build config |
|
The docs-writer is documentation-only — it never edits src/. Where the code and a
page disagree, the code wins and the page is the bug.
Definition of done
A change is done when:
-
the spec’s acceptance criteria are met;
-
npm run lintandnpm run test-singlepass; -
new behaviour has a unit test (and a Cypress test if it is a user-facing flow — noting that the E2E suite is unmaintained, see testing);
-
the spec in
.specs/is updated to match what shipped; -
the Antora docs in
docs/are updated; -
.github/PULL_REQUEST_TEMPLATE.mdis filled in — including the "corresponding changes to the documentation have been added" checkbox; -
the diff is small enough to review in one sitting.
Using the phases
Invoke by name, or let the chain run:
"plan this" / "spec this ticket" / a Jira key with no code → planner
"review this plan" / "is this plan ready" → plan-reviewer
"implement this spec" / "build the approved plan" → implementer
"review this diff" / "is this ready to merge" → implementation-reviewer
"update the docs" / "document this change" → docs-writer
For a trivial fix — a typo, a one-line guard — the full chain is overkill. The bar is "non-trivial": anything that adds a file, changes behaviour, or touches an item in the blast-radius checklist.