DOCS · CORE CONCEPTS
Specs and citations
What a spec contains, what a citation promises, and the four verdicts that make the promise checkable.
On this page
A spec is only worth a gate if a reviewer can check it faster than they could write it. Citations are what make that true — and a citation is only worth having if someone can verify it.
The three sections
Requirements — EARS-shaped, therefore testable
Acceptance criteria written as when ‹trigger›, the system shall ‹response›. The shape is not ceremony: a "shall" statement is exactly what a test asserts, so a requirement that cannot be written this way is usually a requirement nobody has pinned down yet.
Design — every claim cited or flagged
The approach, the affected modules, the trade-offs. Each claim points at a passage in your knowledge base, or carries
UNVERIFIED. There is no third option where the agent asserts something unattributable.Tasks — each one pull request
An ordered list, implemented in order, one commit per task. The final task of every spec is always the same: file the as-built record into
knowledge/specs/.
What a citation is
A citation is a CITE-AS string that identifies a specific passage — a document, and a section within it. It is produced by retrieval, not composed by the model afterwards, which is the property that makes it followable: the agent cites what it was actually shown.
Jobs are claimed with FOR UPDATE SKIP LOCKED so two runners
polling the same queue cannot take the same row.
— per knowledge/architecture.md#runner-job-queueThe four verdicts
Verification returns one of four answers, and the distinctions between them are the whole point.
| Verdict | Means | What you should do |
|---|---|---|
supported | The passage exists and says what the claim says it says. | Nothing. This is the normal case. |
unsupported | Checked, and wrong — no such document, or no such section. | Treat the claim as unfounded. Something in the draft is confused. |
unknown | The corpus could not answer: the document never reached the prompt, holds no indexed content, or was cut for budget. | Look yourself. This is a gap in retrieval, not evidence of anything. |
stale | The passage is real, but it describes code that changed since the doc was last touched. | Read the code. The doc, the claim, or both, need updating. |
"I found no evidence" and "no evidence exists" are different answers, and only one of them is safe to write into a spec.
The same four verdicts come out of verify_citation over MCP — from the same function. A citation that is supported inside a spec and unsupported when anyone checks it would make the verdict worthless.
UNVERIFIED is a feature
When the agent cannot ground a claim, it marks it and moves on. That marker is the most valuable line in the spec: it is the agent telling you precisely where it would have had to guess.
- Read every one before approving. Each is a decision being handed to you.
- Answer it in the knowledge base, not just in the spec — otherwise the next spec asks again.
- Never treat the marker as a formality to clear. A team that learns to skim past
UNVERIFIEDhas converted an honest signal into decoration.
Versions are append-only
Approving pins the approval to that exact version. A revision creates v2; v1 keeps its stamp exactly as recorded, and approved → draft is refused. There is no edit-in-place, so "what was approved" is always answerable — which is the property an audit actually needs.
How the spec is drafted
Three bounded retrieval stages feed the SpecAgent, and each is described in full in The retrieval engine:
- Reciprocal Rank Fusion over vector similarity (pgvector) and Postgres full-text search — headings outrank body text, and one document cannot take every slot.
- A one-hop expansion across resolved links in the document graph, edge-kind weighted and hub-gated, with every added chunk carrying the edge that pulled it in.
- Up to two code snippets — the actual source of symbols the seed documents reference, read from the repository at retrieval time and citable as
path#Class.method.