Natural-language requirements are ambiguous, untestable, and drift from implementation. The spec format solves this by defining a structured, machine-readable package that turns design intent into verifiable contracts. Every requirement maps to a test, every test maps to a task — nothing is specified without verification and nothing is built without a requirement.
A specification package ("spec") is the durable artifact that captures design
intent, acceptance criteria, verification contracts, and implementation plans
for one cohesive feature. Every spec lives in a numbered directory
({NN}_{snake_case_name}/) and contains four required artifacts plus one
optional artifact:
| Artifact | Format | Purpose |
|---|---|---|
prd.md |
Markdown + YAML frontmatter | Narrative intent — the "why" and "what." Human-authored. Contains a hashed ## Intent section that is protected after approval. |
requirements.json |
JSON (schema-validated) | What the system must do: EARS acceptance criteria, correctness properties, execution paths, and error handling. |
test_spec.json |
JSON (schema-validated) | How each requirement is verified: unit tests, property tests, edge-case tests, and smoke tests with computed coverage. |
tasks.json |
JSON (schema-validated) | What work to do, in what order: task groups, subtasks with a state machine, cross-spec dependencies, and requirement-to-test traceability. |
architecture.md |
Markdown (free-form) | Optional. Architectural context — modules, interfaces, data models, technology choices. No schema, not cross-validated. |
Key properties:
- EARS patterns. Requirements use the Easy Approach to Requirements Syntax — six
structured patterns (
ubiquitous,event_driven,complex_event,state_driven,unwanted,optional) that produce testable, unambiguous acceptance criteria from decomposed fields. - Two-layer validation. Schema validation (per-file, sub-millisecond) plus cross-file integrity checks (referential integrity of IDs, requirement-to-test coverage, glossary completeness) run on every mutation.
- Lifecycle. A spec progresses through
draft → active → sealed, with optionalsupersededandarchivedterminal states. The## Intentsection is hashed at thedraft → activetransition and protected thereafter. - Traceability. Bidirectional links connect every requirement through its test spec and task to an executable test, ensuring nothing is specified without verification and nothing is built without a requirement.
The full specification — field-level schemas, EARS pattern definitions, ID formats, validation rules, task state machine, and rendering — is at spec-format-v2.md. Version 1.3 is kept for reference at spec-format.md.
JSON Schemas for all artifacts are available in specification/schemas/
(prd-frontmatter.v2.json, requirements.v2.json, test_spec.v2.json,
tasks.v2.json, plus the v1 set). These schemas can be used for external
validation or code generation.
This repository holds the format, its reference library, the command that writes packages of it and the command that renders them:
| Path | What it is |
|---|---|
specification/ |
The format: the reference documents and the canonical JSON Schemas |
afspec/ |
The afspec Go library — load, validate, mutate, save and render spec packages. It embeds a copy of the v2 schemas in afspec/schemas/ |
envelope/ |
The JSON spec and specr write to stdout, as Go types for a program to decode it into; standard library only |
cmd/spec/, specgen/ |
The spec command and its generation pipeline, built on afspec and agentkit-go |
cmd/specr/ |
The specr command: a package rendered as Markdown, whole or scoped to one task |
See docs/architecture.md for how the pieces fit together.
The spec CLI turns a product idea into a complete, validated package in one
unattended run — there is no session state and no interactive refinement
loop. It takes exactly one positional input:
spec path/to/prd.md # a file's contents are the idea
spec https://github.com/org/repo/issues/42 # the issue and its comments are the idea
spec "add dark mode to the settings screen" # any other text is the idea
spec - # read the idea from stdinNobody is waiting to answer questions, so the run resolves every open
question itself, records each in a ## Design Decisions section of the PRD,
and reports the ones it is least sure of as open_questions in the result.
It then generates requirements.json, test_spec.json and tasks.json in
that order — each validated against the format's schema and its cross-file
rules before it is written — writes the package under .specs/{NN}_{name}/,
and activates it if it validates. A package that fails cross-file validation
is still written to disk, with the broken rules named in the result.
Output is one JSON object on stdout — spec id, artifacts written, requirement
and test counts, the validation report, derived traceability coverage, and
any open_questions — with progress on stderr. Exit codes: 0 a valid
package was written, 1 the run failed (the stage is named in the JSON),
2 a usage error.
| Flag | Effect |
|---|---|
--specs-dir |
Where NN_name packages live (default .specs/, or $AF_SPEC_DIR) |
--name |
Override the spec name the model chooses |
--architecture |
Also write the optional architecture.md |
--no-activate |
Leave a valid package in draft instead of activating it |
--comment |
Post the finished PRD back to the source issue |
--dry-run |
Write nothing to disk or to the forge; report what would be written |
--model, --effort |
A tier (SIMPLE, STANDARD, ADVANCED) or Claude model id, and its reasoning effort |
--phase-model |
Run one phase on another model and effort, e.g. tasks=claude-haiku-4-5:medium; a tier already runs the later phases lower |
--budget, --max-turns, --total-budget |
Per-phase and whole-run ceilings |
--preflight |
Run every check that would refuse the run, then stop before any model call |
--max-parallel |
How many packages of a split are generated at once (default 3) |
The model is Claude, reached through ANTHROPIC_API_KEY, Vertex AI or Amazon
Bedrock. Every flag, the envelope, the error categories and the warning codes
are in docs/cli.md; the environment variables in
docs/configuration.md.
A Go program that calls either command decodes its output with the
envelope package (envelope.DecodeSpec,
envelope.DecodeSpecr) instead of writing structs of its own.
Lifecycle management for an existing package — activating, sealing,
archiving, superseding, validating — has no CLI surface; it's library API in
afspec for an embedder to call. Rendering has one,
below.
The specr CLI renders an existing package as Markdown with afspec's render
functions, for an agent to read — called from a prompt, or from a skill's
instructions such as agent-fox's af-impl. It takes one reference to a
package (its directory, a file in it, or its number or name under the spec
root) and changes nothing:
specr .specs/16_indexed_code_search # the whole package
specr 16 --task 3 # scoped to task 3: what it owns in full, the rest by id
specr 16 --section tasks # only the named sections
specr 16 --max-tokens 8000 # drop detail until it fits
specr --schema # the flags and the output, as JSON SchemaLike spec, it writes one JSON object to stdout: the Markdown is
result.markdown, beside the spec's identity, the sections rendered, what a
budget dropped, and the plan's tasks with their states; next names the next
task not done. --markdown-file also writes the Markdown to a file. Exit
codes: 0 rendered, 1 the package could not be read, 2 a usage error.
Everything is in docs/specr.md; the decision is
ADR 05.
Build the spec and specr commands from a checkout:
git clone https://github.com/agent-fox-dev/spec && cd spec
make build # installs spec and specr into $GOBINmake build stamps both commands with git describe, the commit and the
build time (the variables in version.go), which --version
prints, e.g. spec v1.4.1 (commit 94f3890, built 2026-10-14T06:33:13Z).
go install …/cmd/spec@version (or …/cmd/specr@version) does not work yet: the module carries a
replace for agentkit-go until that module is tagged (see
ADR 01).
make build, make test and the other targets that compile first move the
agentkit-go pin in go.mod to the latest main (ADR 06);
AGENTKIT_UPDATE=0 make build skips that, e.g. offline.
go get github.com/agent-fox-dev/spec/afspecThe library and the command need Go 1.27 or later. The tests need no network and no API key: the command's tests run against a scripted model.
| Command | What it does |
|---|---|
make help |
List all targets |
make check |
make fmt, vet, lint and test |
make build |
Install the spec and specr commands, stamped with the version |
make test |
go test ./... -count=1 |
make test-fast |
The tests with -short |
make fmt |
gofmt -l -w . |
make vet |
go vet ./... |
make lint |
golangci-lint if installed (config in .golangci.yml) |
make coverage |
Test coverage per function |
make doc |
Write go doc -all for each package to docs/generated/ (committed) |
make update-agentkit |
Point go.mod at the latest agentkit-go main (the targets that compile run it first; AGENTKIT_UPDATE=0 skips it) |
make tidy |
go mod tidy |
make clean |
Remove build/ and the coverage profile |
make json-gen |
Regenerate the Go artifact types from afspec/schemas/ |
- Spec Format Reference v2 — field-level schemas, EARS patterns, validation rules, and rendering
- Spec Format Reference v1.3 — the superseded format
- afspec — the Go library's API
- Public Go API — the packages and where their reference lives
- Architecture and configuration
- The spec command — input, flags, the output envelope, errors and warnings
- The specr command — the forms of a render, the reference it takes, the output and
--schema - Configuration — environment variables and limits
- Architecture — repository layout, the schema copies, the command's packages and a run
- ADR 01 — why the command is built here, on the AgentKit driver
- ADR 06 — why every build moves to the latest agentkit-go