# Spec Author

> Write an executable specification under docs/graph/specs/ that turns a clear goal into testable contracts. Use whenever a feature, endpoint, job, significant function, or AI interaction needs a contract that the tester can encode and the implementer can satisfy. Coordinates product (§3, §9), architect (§4, §6, §7), and tester (§10 testability review) into a single signed-off document. Specs are the source of truth for behavior; do not write code without one.

- Skill: `llopresto87/spec-author` (Agent Skill)
- Install (CLI): `npx skillmds@latest add llopresto87/spec-author`
- Raw SKILL.md: https://api.skillmd.com/api/skills/llopresto87/spec-author/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: llopresto87 (https://skillmd.com/u/llopresto87)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/llopresto87/spec-author

---


# spec-author

This skill is the discipline of writing a spec that another agent can
turn into failing tests and another into passing code. It is invoked
from `docs/graph/protocols/specify.md`.

A spec is **executable** when every functional contract maps to at
least one test in the suite and the test name names the contract.
Specs that read like marketing or like implementations are not specs.

## When to apply this skill

- `brainstorm` has converged and the next step is to formalize the
  behavior.
- An existing feature's contract is changing.
- A bug investigation revealed a contract that was implicit and is
  now being made explicit.
- An ADR introduces a new system behavior that needs a spec.

## How to write each section

### §1 Summary

One paragraph. What this spec covers and why. No marketing, no
philosophy. Pretend you're explaining to the next agent on the team
in two sentences what they're about to implement.

### §2 Scope

Two bullet lists: "in scope" and "out of scope". The out-of-scope
bullets are equally important. Reading the spec a year later, the
out-of-scope list is what tells the next agent "no, we considered
that and excluded it deliberately."

### §3 User-facing behavior (product)

Describe what the user experiences. Use the user's vocabulary, not
the system's. If the spec is for an internal API or a job, the
"user" might be another service or a developer — name them and
describe their experience.

### §4 Functional contracts (architect)

The heart of the spec. Each contract is one Given/When/Then, single-
outcome, observable from outside.

**Naming.** Use `UPPER_SNAKE_CASE` slugs that read as sentences.
Tester turns these into test names.

```
### Contract: SUBMIT_VALID_FORM_RETURNS_2XX
### Contract: SUBMIT_FORM_SCHEMA_INVALID
### Contract: SUBMIT_FORM_PERSISTS_RECORD
### Contract: GET_SUBMITTED_RECORD_RETURNS_BY_ID
```

(The `### ` heading form is load-bearing: `spec-lint.py` only counts
`### Contract: SLUG` headings as live contracts — a bare `Contract:` line
is invisible to coverage.)

**One outcome per contract.** "Returns 201 *and* sends an email" is
two contracts: one for the response, one for the side effect.

**Observable from outside.** If the test has to inspect a private
field, the contract is wrong. Move the observation to a public
surface (a returned value, a queried record, an emitted event).

### §5 Non-functional requirements

Only the constraints that bind this behavior — the template carries
the category list and the bind-only rule at point of use.

### §6 Data shapes (architect)

Schemas for inputs, outputs, persisted state. Use a language-
agnostic notation (YAML-like) by default; cross-link to native
schema files when they exist.

Required fields, types, allowed values, max sizes. These become
test fixtures and validation rules.

### §7 Failure modes (architect, with security)

For each contract, the named ways it can fail and what happens.
This is what separates a spec from a description.

```
Failure: SUBMIT_FORM_SCHEMA_INVALID
- Trigger: payload violates §6 schema
- Response: 422 with field-level error in body
- Side effects: audit log entry; nothing persisted
- Recovery: client may resubmit with corrections
```

Security adds adversarial cases here: prompt injection, tool
hijacking, data exfiltration when AI is involved.

### §8 Examples

Concrete input/output pairs. Three minimum: one happy, one edge,
one failure. Examples are the seed for test fixtures — make them
real values, not `<placeholders>`.

### §9 Acceptance criteria (product)

Measurable conditions for "done". Each criterion maps to one or
more contracts in §4 and to one or more tests in §10.

Acceptance criteria include the non-functional ones (latency,
accessibility). Don't let non-functional become "we'll do that
later" — write them down so the tester can encode them.

### §10 Test mapping (tester)

A table mapping each contract and each acceptance criterion to the
tests that cover them. Update as tests are written. Status values:
`pending` (no test yet), `red` (test exists, fails), `green` (test
exists, passes), `skipped` (with reason).

### §11 Open questions

Every "we'll decide later" with a named resolution path. A spec
with open questions stays in `draft`.

## The sign-off rule

A spec is not promoted from `draft` to `active` until:
- **product ✓** confirms §3 and §9 reflect the user outcome.
- **architect ✓** confirms §4, §6, §7 are coherent.
- **tester ✓** confirms every contract in §4 is testable (the
  testability review).
- **security ✓** if the spec touches auth, secrets, payments,
  uploads, external integrations, or AI behaviors that act on
  data.

Sign-off goes in §0 (Metadata) — and the spec stays `draft`. Sign-off
says the contract is authoritative; `active` says it is under test. The
status moves in the change that lands the spec's first RED tests
(`test-first`'s COMMIT; `verify.status-evidence` owns the moment), and to
`implemented` when every contract is green. A live status over an empty
assertion set is a false green, which is why a signed draft is never
promoted early to "get the gate going".

Before a spec is signed, its prose passes `docs/graph/skills/humanizer.md`
in file mode and `python3 docs/graph/prose-lint.py --file <spec> --against HEAD`
reports no strong tell and no dropped contract slug, number, or code span.

The sign-offs are judgment; the shape and the coverage are mechanical.
`python3 docs/graph/spec-lint.py` (the §3.1 gate in
`docs/graph/protocols/verify.md`) checks every spec's shape — unique
slugs, a §10 row per contract, §9 criteria that map to real slugs, sign-offs
present on anything past `draft` — and, for live specs, that every slug
appears in at least one test. A draft is shape-checked and not counted for
coverage, so a spec in authoring never reports uncovered.

## Spec drift management

When the code and the spec disagree, do not silently sync the spec
to the code. Decide:
- **Code is right, spec is wrong:** edit the spec deliberately,
  add a §12 changelog entry, get re-sign-off.
- **Spec is right, code is wrong:** file a bug, add a regression
  test, fix the code.
- **Both partially right:** the brainstorm needs to revisit the
  contract; back up to `brainstorm` or `specify` and write a new
  version.

## Anti-patterns

- **Spec as marketing.** "The system seamlessly empowers users…"
  Cut that. Contracts.
- **Spec as implementation.** "Stores the record in Postgres."
  Wrong layer; that goes in grill.md §8.
- **No failure modes section.** Happy-path-only specs are half
  specs.
- **No examples.** Examples turn abstract contracts into
  concrete tests.
- **One giant contract that says everything.** Many small,
  single-outcome contracts that compose.
- **Skipped sign-offs.** A spec without all three sign-offs is
  unsigned; nobody plans against it.
- **Promoted at sign-off.** `active` with no test is a red gate until
  RED lands and a false green after someone silences it. Promote with
  the RED.

## Reference files

- `docs/graph/templates/spec.template.md` — the template.
- `docs/graph/protocols/specify.md` — the protocol.
- `docs/graph/protocols/test-first.md` — what happens next.
- `docs/graph/agents/01-architect.md`, `docs/graph/agents/04-tester.md`,
  `docs/graph/agents/08-product.md` — the three co-authors.

