---
name: spec-structure
description: >-
  The 4-file spec structure (1-description, 2-analysis, 3-solution,
  4-status): what belongs in each file,
  the required sections, and the Tracking info fields.
  Use when: creating, analyzing, reviewing, implementing or archiving a
  spec; deciding which of the four files a piece of content belongs in.
  Do NOT use for: general documentation formatting (use the documentation
  skill), the workflow around the files (use the workflows skill).
effort: medium
---


# Spec structure

## Table of contents

- [Overview](#overview)
- [File structure](#file-structure)
  - [1-description](#1-description)
  - [2-analysis](#2-analysis)
  - [3-solution](#3-solution)
  - [4-status](#4-status)
    - [Workflow steps completed](#workflow-steps-completed)
- [Separation of content](#separation-of-content)
- [Templates](#templates)
- [See also](#see-also)

---

## Overview

4 standardized files per issue/plan:

```text
specs/<NN>-slug/          # flat structure
├── 1-description.md        # (an issue key in the title is part of the slug)
├── 2-analysis.md
├── 3-solution.md
└── 4-status.md
```

**Roles:**
1. **1-description.md** - Main entry point: The problem as reported
2. **2-analysis.md** - Detailed analysis: Mapping and findings
3. **3-solution.md** - Scope, behavior delta, acceptance criteria, risk and implementation plan with a TDD approach
4. **4-status.md** - Living document: Progress and status

`/aide-implement`'s VERIFY phase adds a fifth, non-markdown file next
to these four: `test-run.json`, written by `core/scripts/aide-record-test-run`
and read by `core/scripts/aide-archive-spec`'s test-record gate — never
written or read by a model. `aide-archive-spec`'s move step already
`git mv`s the whole folder, so it needs no special handling of its own.

---

## File structure

### 1-description

**Purpose:** Describe the problem as it was reported.

**Structure:**
```markdown
# [Title]

## Table of contents

- Metadata
- Description
- Problem

---

## Metadata

Number, created date, expected duration

---

## Description

**This field can be edited manually to add:**
- Extra context or clarifications
- Specific technical requirements
- Clarifications from meetings/discussions

---

## Problem

[The description as given]

---

## Acceptance criteria (optional)

- **AC-1:** The system SHALL ...
- **AC-2:** The system SHALL ...

```

**Key points:**
- Table of contents for quick navigation
- Metadata table
- The Description section is editable for manual additional information
- The Problem section is copied verbatim (do not rewrite)
- No code examples (they belong in 3-solution.md)
- Acceptance criteria here are the SHALL-statement source requirements
  (AC-n); the testable given/when/then scenarios that verify each one
  are part of the solution — 3-solution.md's own Acceptance criteria
  section
- No scope or estimate (they are commitments about the solution — 3-solution.md)
- Optionally a `Depends on:` line in Tracking info, naming the specs this
  one builds on (comma-separated; each identifier is either a bare number
  or a full `NN-slug` folder name — narrower than `/aide-analyze`'s
  resolver, which also takes `TODO-NN` and an issue key). `aide-run-spec`
  refuses to start while any named spec's `aide/<NN-slug>` branch on
  origin has commits not on the default branch — unmerged, not merely
  present — because a run cuts its branch from origin/main and would
  otherwise build on a main without that work
- The line holds back only the steps that BUILD on merged code —
  `implement`, `archive`. `analyze` and `create` write only the spec's
  own folder, so a whole chain of dependent specs can be analysed in
  parallel before it merges — the tradeoff being that the plan then
  describes the code WITHOUT it
- Queued through the dashboard, such a step WAITS rather than fails: it
  stays `queued`, starts itself once the dependency merges, and is
  cancellable. Run by hand, it still refuses immediately — there is no
  scheduler there to park it against
- Acceptance criteria is OPTIONAL: a flat bullet list, id in bold
  (`**AC-n:**`), one SHALL sentence per id — no table, no nested
  lists, so both the definition and any reference stay grep-able with a
  plain regex
- AC-n ids are additive only: once written, never renumbered or
  reused, even if later dropped — same philosophy as 4-status.md's
  `Workflow steps completed` line
- A held-back spec taking another round on its open checks (see
  4-status's own Acceptance criteria section below) numbers a new id
  after the highest one already written — the same additive rule,
  applied to a second round rather than to the first draft
- A description already carrying a matching `## Acceptance criteria`
  section is passed through unchanged — no rewriting, no second
  section appended. Only a description with no such section gets one
  authored from scratch. `aide-create-spec` writes an `AC-n:` bullet
  with missing or misplaced bold in the bold format, and refuses only
  a bullet it cannot rewrite that way
- `/aide-analyze` never retrofits an Acceptance criteria section into
  an existing `1-description.md` on its own initiative — only original
  authoring (via `/aide-create`) adds one

---

### 2-analysis

**Purpose:** Detailed technical analysis of the problem.

**Structure:**
```markdown
# [Title] - Analysis

## Table of contents

- Mapping
- Findings

---

## Mapping

**Last analyzed**: [date]

[How the analysis was performed - search terms, methods, tools used]

## Findings

**Affected files/components:**
1. `fil/path.tsx:123-145` - [description]
2. `fil/path2.tsx:67` - [description]

### Codebase analysis

[Detailed findings]

### Affected components

[Detailed description per file with specific line numbers]

### Test coverage

**Existing tests:** [list]
**Missing tests:** [gaps]
```

**Key points:**
- Focus on ANALYSIS (not solution)
- Include specific files with line numbers
- No implementation plan or solution proposals
- No complexity grade, estimate or risk analysis — those judge the
  solution we intend to build, and belong in 3-solution.md

---

### 3-solution

**Purpose:** Implementation plan with a TDD approach.

**Structure:**

````markdown
# [Title] - Solution

## Table of contents

- Scope
- Approaches
- Recommended: Approach A
- Recommended solution
- Behavior delta
- Acceptance criteria
- Risk analysis
- Implementation plan
- Testing
- References

---

## Scope

**Files to change:** [list, from the analysis]

### Complexity

[High/Medium/Low, with the factors that drove the classification]

### Estimate

- **Manual development:** [time]
- **AI-assisted development:** [time]

---

## Approaches

**Approach A: [Name] (recommended).** [one-line description]
- **Pros:** [list]
- **Cons:** [list]
- **Estimate:** [time]

**Approach B: [Name].** [one-line description]
- **Pros:** [list]
- **Cons:** [list]
- **Estimate:** [time]

### Recommended: Approach A

[Why this approach was chosen over the others, as plain text.]

---

## Recommended solution

### Before/After examples

**Before:**
```tsx
// fil/path.tsx:123
[old code]
```

**After:**
```tsx
// fil/path.tsx:123
[new code]
```

---

## Behavior delta

**Adds:** [new behavior] · **Modifies:** [before → after] · **Removes:** [behavior that goes away]

---

## Acceptance criteria

1. **Given** [precondition] **when** [action] **then** [expected outcome]

---

## Risk analysis

### [High/Medium/Low risk]

**[Risk 1]**
- **Consequence:** [description]
- **Probability:** [High/Medium/Low]
- **Mitigation:** [how to reduce]

---

## Implementation plan

### TDD approach (Red-Green-Verify)

### Phase 1: Write tests (RED)
- [ ] Task 1
- [ ] Task 2

### Phase 2: Implement the solution (GREEN)
- [ ] Task 1
- [ ] Task 2

### Phase 3: VERIFY
- [ ] Run the full test suite
- [ ] Check for regressions

---

## Testing

### Unit tests
[Testing strategy]

### Manual testing
[What is NOT covered by a test, and why — a note, not a checklist]

---

## References

- 1-description.md - Problem description
- 2-analysis.md - Analysis and findings
````

**Key points:**
- Scope, complexity, estimate and risk analysis live here: they judge
  the solution, not what the investigation found
- Approaches with pros/cons, each a bold-paragraph lead (not a
  heading) — `**Approach A: [Name] (recommended).**` followed by
  Pros/Cons/Estimate. The choice itself stands as its own heading,
  `### Recommended: Approach X`, directly under Approaches, with the
  reasoning as plain text below it and its own line in the table of
  contents — a reader who jumps straight to the heading, or only scans
  the ToC, must still find the pick. The RECOMMENDED one IS the spec —
  every section below it describes that approach and no other, and
  `/aide-implement` builds the plan it finds. Wanting a different one
  means saying so in `1-description.md` and analysing again
  (change an acceptance criterion, then `/aide-analyze` again)
- Before/After in SEPARATE code blocks (avoids redeclaration errors)
- Behavior delta: what the solution ADDS / MODIFIES / REMOVES relative to
  current behavior — not just which files change
- Acceptance criteria as given/when/then scenarios; the RED phase writes
  at least one failing test per criterion
- TDD approach with RED-GREEN-VERIFY phases
- Manual testing is a NOTE, not a checklist: it names what no test
  covers and why. Nothing under it is a task, and nothing under it
  blocks archiving — 4-status has no row for it

---

### 4-status

**Purpose:** Living document that is updated along the way.

**Structure:**
```markdown
# [Title] - Status

## Tracking info

- **Task:** `NN-slug/`
- **Workflow steps completed:** create, analyze   <!-- written by aide-run-spec -->
- **Total progress:** X% (Y of Z completed)
- **Estimate:** [time]
- **Last updated:** `YYYY-MM-DD`

## Table of contents

- Phase 1: Name
- Phase 2: Name
- Notation

---

## Phase 1: [Name]

| Task | Status | Notes |
|---------|--------|---------|
| Task 1 | ⬜ | [notes] |
| Task 2 | 🔄 | [notes] |
| Task 3 | ✅ | [notes] |

---

## Notation

| Symbol | Meaning |
|--------|-----------|
| ⬜ | Not started |
| 🔄 | In progress |
| ✅ | Completed |
| ❌ | Blocked |
| ⚠️ | Waiting |
| Not verified | Set aside for a check after deploy; counts as done (Acceptance rows only) |
| ❌ Failed | A check after deploy that did not hold; open, with a `Failed:` note (Acceptance rows only) |
```

**Key points:**
- Total progress at the top
- Organized in phases (matches 3-solution.md)
- Table format for clarity
- Updated continuously

#### Workflow steps completed

One line in Tracking info, saying how far a spec has got through the
workflow:

```markdown
- **Workflow steps completed:** create, analyze
```

The allowed values, in workflow order, are `create`, `analyze`, `implement`
and `archive`. A missing line means nothing is known to have completed;
an unknown value is ignored.

**Do not edit this line. It is written by `aide-run-spec`, from the
spec's own commits** — every step the runner finishes leaves a commit
whose subject names the step and how it ended, and the line is derived
from those commits at the end of every run, so the file agrees with git
rather than with whoever remembered to update it. A step run
interactively counts once committed under the same subject — the four
step skills offer exactly that commit, and ask first.

**The line is added to, never subtracted from.** A step it already
names stays even when no commit currently corroborates it — a copied
claim (a spec's four files copied from a sibling) stands the same way,
since the scan cannot tell it from a real one. A reopen that resets the
files is the only place a step comes off, by regenerating the file
without the line at all.

The dashboard reads the same commits, live, to mark a spec's phases
done — a `4-status.md` that disagrees with them is said out loud on the
row rather than believed.

#### Total progress

One line, near the top of the file, saying how many of the file's own
Phase-table rows are done:

```markdown
- **Total progress:** 50% (2 of 4 completed)
```

**Do not edit this line by hand. `aide-run-spec` recomputes it** at the
end of every step from the file's own `## Phase`/`## Fase` rows — a
well-formed three-column row counts as one task, done when its Status
cell reads `✅` or `Completed`; header rows, separators and free
commentary are skipped. A file whose Phase tables have no rows yet
(fresh from the template) is left alone: there is nothing yet to
derive.

#### Phase outcome record

Each of the four phases writes its own outcome into the Tracking info
of the file that is ITS OWN artifact — never into 4-status.md on
another phase's behalf:

| Phase     | Own file         | Date field enriched |
|-----------|------------------|---------------------|
| create    | 1-description.md | `Created:`          |
| analyze   | 2-analysis.md    | `Last analyzed:`    |
| implement | 3-solution.md    | `Last updated:`     |
| archive   | 4-status.md      | `Last updated:`     |

The record, beside the file's own existing date field — never a new
one, the date already exists, only the time of day is new
(`` `YYYY-MM-DD HH:MM UTC` ``):

```markdown
- **Repo:** `repo-name/branch @ sha`
- **Model:** claude claude-sonnet-5
- **Model id:** claude-sonnet-5
- **Result:** completed
- **Time spent:** 4m12s
- **Cost:** $0.1234
```

`Repo` is one line per repo root; it is absent for `create`, since
nothing has been analyzed against yet. `Result` is `completed`, or
`stopped (<reason>)` with a one-line error summary. `Model id` is the model
Claude Code's own log named for the run, so an alias shows what it ran on;
it is absent when the log names none. `Cost` is absent
for a tool that reports no cost (codex) — absence means unknown, never
zero.

**Do not edit these lines. `aide-run-spec` writes them**, never from a
model's own account of itself. Each run OVERWRITES its phase's own
block with the newest outcome — unlike `Workflow steps completed`,
nothing here is added to across runs.

**An absent `Model` line does not prove the phase ran without a
model** — only that no commit could be attributed to it, the ordinary
case for a file a user wrote and committed by hand under their own
message.

Specs archived before this record existed may still carry the older,
centralized `Model (create):`/`Model (analyze):`/`Model (implement):`
lines in their `4-status.md` — left exactly as they are, not migrated.

#### Acceptance criteria (optional)

When `1-description.md` has a `## Acceptance criteria` section,
`/aide-analyze` adds one more section to `4-status.md`, after the last
implementation phase and before `## Notation`, with exactly one row per
`AC-n` id from `1-description.md`, in ascending id order, carrying that
requirement's own SHALL text — never a scenario from `3-solution.md`'s
Acceptance criteria, which a user cannot judge and which can repeat
one id across several scenarios:

```markdown
## Acceptance criteria

| Task | Status | Notes |
|------|--------|-------|
| AC-1: <requirement text, verbatim from 1-description.md> | ⬜ | |
| AC-2: <requirement text, verbatim from 1-description.md> | ⬜ | |
```

Every row starts `⬜`, a `Not tested:` row too: a criterion no test
proves is one the user checks by hand. `Not verified` is a done mark like
`✅`: archiving does not wait for it, and the user can still tick it
later. Only the user writes it, when a check can only be made after
deploy — never a skill.

A `Not verified` row that was checked after the deploy and did not hold is
marked `❌ Failed`, with a Notes cell that starts `Failed:` and says what did
not hold. `❌ Failed` is not a done mark: archiving waits for it. Only the
user writes it (from the Specs list or the Status tab of an archived spec) —
never a skill. Reopening the spec puts the row back to `⬜` and keeps its
note, and a note starting `Failed:` on an open row counts as a changed
criterion for the rule that a new round needs one.

No Acceptance criteria section: `4-status.md` looks exactly as it does
today — no such section, no change to archiving.

**These rows start unticked, and no skill ever ticks one.** Unlike the
RED/GREEN/VERIFY rows above, an acceptance-criteria row names a
judgment only the user the spec is for can make — ticking it is the
same one-click Overview-tab action any other recognized row offers.
Placing the section after the last implementation phase means it only
becomes tickable once every earlier phase's own rows are done.

**`aide-archive-spec` refuses to archive while any of these rows is
still unticked**, with `terminalReason: "acceptance-criteria-unticked"`
— the one place a "must be ticked" gate exists in this file, scoped to
this section alone. A spec with no such section, or every row ticked,
archives exactly as it did before this section existed.

**A held-back spec may take another round on its open rows.**
`/aide-analyze` and `/aide-implement` may run again on a spec whose
archive is held back this way — a THIRD kind of restart, distinct
from a reopen that resets the files, which regenerates this table from
its template. A held-back round instead APPENDS: a ticked row's Status
and Notes cells are left exactly as they are; only an OPEN row's Notes
cell may gain text naming what the round still finds missing; and a
genuinely new `AC-n` id, numbered after the highest one already
written, may be appended as a new unticked row. The round may start
once at least one open row's own requirement text has changed since the
round that held it back, or a new `AC-n` id has been added — when none
has, the spec stays held back on Analyze and Implement alike, not only
on Archive.

**A reopened spec takes the same round.** `/aide-reopen` without a
reset (`aide-reopen-spec`) moves an archived or closed spec back into
the active list with `2-analysis.md`, `3-solution.md` and `4-status.md`
kept, and stamps a `**Round boundary:**` line after its
`**Archived:**` or `**Closed:**` line. A reopened spec has no open row
by construction, so the round it takes works on what changed since that
boundary instead: an `AC-n` id added to `1-description.md`, or an
existing criterion reworded whose row is still unticked. It follows the
rules above: ticked rows are left exactly as found, only `⬜` rows and
new ids are worked on, and with no new or changed criterion the spec
stays held back on Analyze and Implement. A spec reopened WITH a reset
starts from templates and is not in such a round.

---

## Separation of content

| Content                                                    | Location         |
|------------------------------------------------------------|------------------|
| Problem description                                        | 1-description.md |
| Acceptance criteria — source (AC-n, optional)              | 1-description.md |
| Metadata                                                   | 1-description.md |
| Mapping/findings                                           | 2-analysis.md    |
| Scope (files, estimate)                                    | 3-solution.md    |
| Complexity analysis                                        | 3-solution.md    |
| Risk analysis                                              | 3-solution.md    |
| Approaches                                                 | 3-solution.md    |
| Behavior delta                                             | 3-solution.md    |
| Acceptance criteria — testable scenarios                   | 3-solution.md    |
| Before/after examples                                      | 3-solution.md    |
| Implementation plan                                        | 3-solution.md    |
| Testing strategy                                           | 3-solution.md    |
| Progress                                                   | 4-status.md      |
| Acceptance criteria — tick checklist (AC-tagged, optional) | 4-status.md      |

---

## Templates

AI tools create documentation directly based on the structure described in this document.

The `/aide-create` command creates the 4-file structure with the correct placeholders.
The `/aide-analyze` command fills in the analysis, solution and status.

**Spec files are always produced by invoking the actual `/aide-*` skill
for that step — never by hand-writing or reimplementing the pattern
directly with Read/Write/Bash, even when the exact structure is already
known from a previous invocation in the same session.** A spec created
this way carries none of the commits, review or convention the skill
provides, and looks identical to one that did.

`aide-install-spec-hook <specs-repo> [...]` installs a best-effort `commit-msg` guard into a spec repo's common git
dir: a commit touching a spec's 4/5-file layout is rejected unless its message follows the
`Run /aide-<step> for <spec-folder>` convention. A hand-edit to an existing `1-description.md` is never gated. It only fires where it has
been installed; the rule above is the primary defence.

---

## See also

- The documentation skill - General documentation rules
- The markdown-linting skill - Markdown linting rules
