Project Structure
Everything durable lives under specs/; the queue and conversation live in the GitHub issue. Nothing else is permanent.
project/
├── specs/
│ ├── product.md # mental models + flows
│ ├── glossary.md # ubiquitous language (optional, recommended)
│ ├── decisions/ # NNNN-<slug>.md decision records
│ ├── queues/ # <name>.md local fallback, only when gh is unavailable
│ └── <feature>/
│ └── spec.md # load-bearing contract
├── .agents/skills/ # generated skills (canonical)
└── .claude/skills/ # symlinks for Claude Code (only with --tools claude)
specs/product.md — what we are
Mental models, what the project is and isn't, 2–3 representative flows. Human + agent maintained. Every plan/build/review session reads it first.
specs/glossary.md — shared words
Curated ubiquitous language — only terms that are shared, stable, and ambiguous enough to matter. litespec-plan reads it and nudges when a new term appears; other skills consult it without enforcement. Missing file degrades gracefully. See Glossary. One line per term:
- **Widget**: a customer-visible unit of work in the dashboard. Not a database row. Not a UI component.
specs/decisions/NNNN-<slug>.md — durable rulings
Standing architectural reasoning that spans files — why not the obvious road. Created with touch + validate; no CLI. Never deleted after a feature ships; supersede instead.
---
spine: true
---
# Title
## Status
proposed | accepted | superseded
## Context
## Decision
## Consequences
spine: true marks load-bearing decisions that view stars. The bar is high: real contention (someone argued the other road, or observably will) plus no better home (a line comment fits a one-line change; decisions hold reasoning with no single line to attach to). Context records what was measured; Consequences state what would justify revisiting.
specs/<feature>/spec.md — load-bearing contracts
One file per load-bearing feature. Edited in place — no staging, no approved layer, no lifecycle markers. Only promises that break things when wrong earn a spec.
# <feature>
## Requirements
### Requirement: <name>
Body must contain SHALL or MUST.
#### Scenario: <short name>
- **WHEN** <condition>
- **THEN** <outcome>
Small fixes edit it directly; litespec-plan drafts it in clear mode for new features.
specs/queues/<name>.md — offline fallback only
A 1:1 mirror of the GH issue body (Base:/Branch: + proposal + design + queue), written only when gh is unavailable. <name> is the change name from plan[clear]. When gh works, the issue is the queue and this directory stays empty. Local receipts append as Evidence: blocks under their unit; routing metadata appends after all units in separate commits.
.agents/skills/ and .claude/skills/
Canonical generated skills — one SKILL.md plus references/ per skill, regenerated by litespec update from internal/skill/templates/:
.agents/skills/
├── litespec-plan/ # fuzzy/clear + grilling, codebase-design, domain-modeling
├── litespec-build/ # one unit + review-fixing
└── litespec-review/ # adversarial review
--tools claude symlinks these into .claude/skills/ because Claude Code doesn't read .agents/. Project-specific skills (like the-drill) live beside them as tracked files — never generated, never overwritten, ignored by stale-skill detection.
The two lanes on this structure
- Small fix: read product + relevant spec + decisions/glossary, edit code and spec in place, stop. No issue, no branch.
- New feature:
plan[clear]recordsBase:+Branch:and createslitespec/<change-name>— all branch work belongs to the issue.buildimplements one unit at a time there;reviewscreens every local path before reading it. The issue closes only when every unit checkbox is checked, every rebuild request is resolved, review returnsPASS, and the issue'sBranch:is merged (decision 0008) — merge first, then close.