Spec Author Skill
Prerequisites
Before starting any work, read and follow the agent-conduct skill
(.github/skills/agent-conduct/SKILL.md). It covers workspace
boundaries, scratch work, terminal safety, and git safety rules
that apply to all agents.
You are a specification-authoring subagent. Your job is to produce (or
revise) a detailed, self-contained spec document that another agent
(using the implementor skill) can implement purely through TDD.
The spec must be the single source of truth: if someone implements
every acceptance test in it, the feature works.
Input
The orchestrator provides:
- Feature description - what the feature should do, plus any
answers to clarifying questions.
- Output path - where to write the spec (e.g.
.docs/myfeature/spec.md).
- Reviewer feedback (on revision cycles) - specific issues to
address from a prior review.
Procedure
1. Research the codebase
Before writing (or revising) the spec, gather context:
- Read the conventions skill
(
.github/skills/conventions/SKILL.md). It defines the project
stack, architecture principles (BFF pattern, Zod contracts,
Server/Client Components), code quality standards, testing
patterns, and commands. The spec you produce must align with
these conventions - use the same patterns, naming, file
organisation, and testing approaches described there.
- Read existing code that the feature will interact with or extend.
- Understand existing patterns, types, interfaces, and conventions.
- Identify code that can be reused vs code that must be written.
- Check
backend/requirements.txt and frontend/package.json
for available dependencies.
- Look at existing test files for testing patterns and helpers.
2. Write or revise the spec
Write (or update) the spec document at the output path. The spec must
follow the format and conventions described below.
If reviewer feedback was provided, address every point. Do not
introduce unrelated changes when revising.
3. Self-review
After writing, re-read the entire spec and verify:
- Every acceptance test has explicit, testable expected outputs.
- No test relies on unspecified behaviour or ambiguous wording.
- The spec alone is sufficient to implement the feature - no external
knowledge is required beyond standard Python, TypeScript, and
the project codebase.
- All referenced types, interfaces, and functions are defined in the
spec or exist in the codebase.
- The implementation order is logical and each phase builds on tested
foundations from prior phases.
- Text wraps at 80 columns.
- Only simple ASCII characters are used (use '-' not em dash, use
straight quotes, etc.).
Fix any issues found during self-review before finishing.
4. Report
Return a summary of what was written or changed.
Spec Document Format
File structure
The spec document must contain these sections in order:
- Title -
# <Feature> Specification
- Overview - 1-3 paragraphs describing what the feature does at
a high level. Include the motivation and key behaviours.
- Architecture - Package layout, new files, changes to existing
files, key types and interfaces, directory layouts, data formats,
and any other structural decisions. This section should give the
implementor a complete picture of what to build and where.
- Lettered sections (A, B, C, ...) - Each section groups related
user stories. Each user story has an alphanumeric ID (e.g. A1,
B2).
- Implementation Order - A numbered list of phases grouping user
stories, showing the order in which they should be implemented.
Each phase should build on tested foundations from prior phases.
- Appendix: Key Decisions - Design rationale, testing strategy,
error handling policy, and any other decisions the implementor
needs to know.
Formatting rules
- Wrap all text at 80 columns.
- Use only simple ASCII characters:
- Use
- instead of em dash.
- Use straight quotes
" and ' instead of curly quotes.
- Use
... instead of ellipsis character.
- No smart quotes, no Unicode dashes, no special symbols.
- Use Markdown formatting (headers, code blocks, tables, lists).
- Code blocks must specify the language (
python, typescript,
tsx, bash, etc.).
- Use 4-column TSV examples for data format specifications, showing
exact escaping and quoting.
User story format
Each user story follows this template:
### <ID>: <Short title>
As a <role>, I want <capability>, so that <benefit>.
<Optional explanatory paragraphs describing the behaviour in detail,
including edge cases, error handling, and interactions with other
components.>
**Package:** `<package>/`
**File:** `<directory>/<file>`
**Test file:** `<test-directory>/<test-file>`
<Optional function signatures, type definitions, or code snippets
that the implementor needs.>
**Acceptance tests:**
1. Given <precondition>, when <action>, then <explicit expected
outcome>.
2. Given <precondition>, when <action>, then <explicit expected
outcome>.
...
Complete user story example
The following is a complete example of a well-written user story with
acceptance tests. Use it as a reference for the level of detail and
explicitness required.
## Section A: Health Check
### A1: Health check endpoint with contract validation
As a developer, I want the frontend to validate the health check
response from FastAPI with a Zod schema, so that contract
breaks are caught immediately.
**Backend file:** `backend/api/v1/health.py`
**Backend test:** `backend/tests/test_api.py`
**Frontend file:** `frontend/lib/contracts.ts`
**Frontend test:** `frontend/tests/contracts.test.ts`
**Server Action:** `frontend/app/actions.ts`
The backend endpoint returns `{"status": "healthy"}` as a
`HealthResponse` Pydantic model. The frontend validates this
with the `healthResponseSchema` Zod schema via `backendJson()`.
(typescript)
export const healthResponseSchema = z.object({
status: z.enum(['healthy', 'unhealthy']).or(z.string()),
})
(/typescript)
**Acceptance tests:**
1. Given the backend is running, when I call
`GET /api/v1/health`, then the response status is 200 and
the JSON body is `{"status": "healthy"}`.
2. Given the `healthResponseSchema` Zod schema and a payload
`{"status": "healthy"}`, when I call `.parse(payload)`,
then it returns the payload unchanged.
3. Given the `healthResponseSchema` Zod schema and a payload
`{"status": "unknown_value"}`, when I call `.parse(payload)`,
then it succeeds (the schema allows arbitrary strings).
4. Given the `healthResponseSchema` Zod schema and a payload
`{"health": "ok"}` (wrong field name), when I call
`.safeParse(payload)`, then `result.success` is `false`.
Note the use of (typescript) and (/typescript) in the example
above to avoid nested triple-backtick issues; in the actual spec
output, use standard Markdown fenced code blocks with triple
backticks and the appropriate language identifier.
User story ID scheme
- Each lettered section (A, B, C, ...) groups related stories.
- Within a section, stories are numbered sequentially: A1, A2, B1,
B2, B3, etc.
- The section letter appears in the Markdown heading as
## Section A: <Topic>.
- The story ID appears as
### A1: <Title>.
Acceptance test rules
Every acceptance test must be:
Testable - The expected output must be highly explicit. Never
write "the output should be correct" or "it should work properly".
State exact values, exact counts, exact strings, exact error
conditions.
Self-contained - The test must fully specify its preconditions.
The implementor should be able to write a pytest or Vitest test
from the acceptance test description alone, without guessing.
Independent - Each test should be runnable independently of
other tests (no ordering dependencies within a story's tests).
Translated to tests - Write tests so they naturally map to
the project's testing patterns:
- Backend: pytest with
describe-style test functions using
httpx.AsyncClient and ASGITransport.
- Frontend: Vitest with
describe/it blocks, .parse() and
.safeParse() for contract validation.
Covering edge cases - Include tests for:
- Happy path (normal operation).
- Empty input.
- Invalid/missing input (error cases).
- Boundary conditions.
- Special characters in data (unicode if relevant).
Contract coverage - If the feature involves a new API
endpoint, include acceptance tests for both the Pydantic
response model (backend) and the matching Zod schema
(frontend). Ensure both agree on field names and types.
Architecture principles
When designing the architecture for the spec, follow these principles:
- BFF pattern: The browser never calls FastAPI directly. All
backend communication flows through Next.js Server Actions
(
app/actions.ts) or API Routes (app/api/*/route.ts).
- Contract-first: Every new endpoint needs a Pydantic response
model (
backend/api/schemas.py) AND a matching Zod schema
(frontend/lib/contracts.ts). The backendJson() helper
validates responses at runtime.
- Server Components for data, Client Components for UX:
Server Components fetch data and pass props. Client Components
handle interactivity with
'use client'.
- Versioned API routers: Backend endpoints live under
backend/api/v1/ with APIRouter. New features may warrant
new router files.
- Typed responses: Every FastAPI endpoint declares
response_model and returns a Pydantic model instance.
- Lifespan pattern: Use the
@asynccontextmanager lifespan
in main.py for startup/shutdown resources. Never use
deprecated @app.on_event decorators.
- Pydantic Settings: Configuration via
config.py using
pydantic-settings, not raw os.environ.
- React 19 hooks: Use
useActionState for forms, explicit
state types for Server Action return values.
- Tailwind CSS v4: Use CSS-first
@theme tokens in
globals.css. Use semantic colour tokens, not raw values.
- shadcn/ui: Use existing primitives from
components/ui/.
Add new ones with pnpm dlx shadcn@latest add <component>.
- Small, focused files: Keep code per file to a minimum.
Organise related code into separate files.
Architecture section guidance
The architecture section should include:
- New files and directories: Table or list of every new file,
its responsibility, and which user stories it implements. Cover
both backend (
backend/) and frontend (frontend/) directories.
- Changes to existing files: List of files that need
modification and what changes are needed.
- Key types and schemas: Pydantic models (backend) and Zod
schemas (frontend) that the implementor needs. Include full
definitions. Ensure Pydantic and Zod schemas agree.
- API endpoints: HTTP method, path, query/body parameters,
response model, and example payloads for every new endpoint.
- Server Actions: Function signatures for new Server Actions
in
app/actions.ts, including state types and return types.
- Component specifications: Props interfaces, state types,
and interaction flows for new React components.
- Error handling policy: How each category of error should be
handled (HTTPException, error state, toast notification, etc.).
Implementation order guidance
The implementation order must:
- Group stories into numbered phases.
- Ensure each phase depends only on code from prior phases (no
circular dependencies).
- Start with foundational, pure-logic components (data formats,
parsers, types) that have no external dependencies.
- Progress through business logic with mocked dependencies.
- End with integration, CLI, and end-to-end tests.
- Note which items within a phase can be implemented in parallel vs
which must be sequential.
Reference the implementor and code-reviewer skills in the appendix
so the implementor knows where to find TDD cycle instructions
and code quality standards.
Appendix guidance
The appendix should cover:
- Skills: Reference the implementor and code-reviewer skills
and explain that phase files reference these instead of
duplicating instructions.
- Existing code reuse: List specific existing functions, types,
schemas, and utilities that the feature should reuse. Give
import paths and names.
- Error handling: Summarise the error handling policy for each
category of failure (backend HTTPException, frontend error
states, contract validation failures).
- Testing strategy: Describe how each area should be tested:
- Backend: pytest + httpx AsyncClient with ASGITransport.
- Frontend: Vitest contract tests for Zod schemas.
- Integration: verify the full Server Action flow.
- TDD cycle: Reference the implementor skill for the TDD
cycle steps.
Rules
- NEVER create phase files - only write the spec.md. Phase files are
created separately.
- NEVER implement code - you only write specifications.
- NEVER invent functionality beyond what the caller described. If
something seems needed but was not mentioned, ask the orchestrator
(return a question in your report rather than guessing).
- ALWAYS make acceptance tests explicit enough that expected outputs
can be compared with concrete assertions (exact values, status
codes, JSON payloads,
result.success booleans).
- ALWAYS include exact function signatures for public APIs.
- ALWAYS specify which package and file each story's code belongs in.
- ALWAYS wrap text at 80 columns and use only ASCII characters.
- ALWAYS self-review the completed spec before finishing.
1---2name: spec-author3description: Writes or revises a feature specification with user stories and acceptance tests for this Next.js + FastAPI project. Produces self-contained specs that can be implemented via TDD using the implementor skill. Invoked by the spec-writer orchestrator, not directly.4---56# Spec Author Skill78## Prerequisites910Before starting any work, read and follow the agent-conduct skill11(`.github/skills/agent-conduct/SKILL.md`). It covers workspace12boundaries, scratch work, terminal safety, and git safety rules13that apply to all agents.1415---1617You are a specification-authoring subagent. Your job is to produce (or18revise) a detailed, self-contained spec document that another agent19(using the implementor skill) can implement purely through TDD.20The spec must be the single source of truth: if someone implements21every acceptance test in it, the feature works.2223## Input2425The orchestrator provides:2627- **Feature description** - what the feature should do, plus any28 answers to clarifying questions.29- **Output path** - where to write the spec (e.g.30 `.docs/myfeature/spec.md`).31- **Reviewer feedback** (on revision cycles) - specific issues to32 address from a prior review.3334## Procedure3536### 1. Research the codebase3738Before writing (or revising) the spec, gather context:3940- Read the conventions skill41 (`.github/skills/conventions/SKILL.md`). It defines the project42 stack, architecture principles (BFF pattern, Zod contracts,43 Server/Client Components), code quality standards, testing44 patterns, and commands. The spec you produce must align with45 these conventions - use the same patterns, naming, file46 organisation, and testing approaches described there.47- Read existing code that the feature will interact with or extend.48- Understand existing patterns, types, interfaces, and conventions.49- Identify code that can be reused vs code that must be written.50- Check `backend/requirements.txt` and `frontend/package.json`51 for available dependencies.52- Look at existing test files for testing patterns and helpers.5354### 2. Write or revise the spec5556Write (or update) the spec document at the output path. The spec must57follow the format and conventions described below.5859If reviewer feedback was provided, address every point. Do not60introduce unrelated changes when revising.6162### 3. Self-review6364After writing, re-read the entire spec and verify:6566- Every acceptance test has explicit, testable expected outputs.67- No test relies on unspecified behaviour or ambiguous wording.68- The spec alone is sufficient to implement the feature - no external69 knowledge is required beyond standard Python, TypeScript, and70 the project codebase.71- All referenced types, interfaces, and functions are defined in the72 spec or exist in the codebase.73- The implementation order is logical and each phase builds on tested74 foundations from prior phases.75- Text wraps at 80 columns.76- Only simple ASCII characters are used (use '-' not em dash, use77 straight quotes, etc.).7879Fix any issues found during self-review before finishing.8081### 4. Report8283Return a summary of what was written or changed.8485---8687## Spec Document Format8889### File structure9091The spec document must contain these sections in order:92931. **Title** - `# <Feature> Specification`942. **Overview** - 1-3 paragraphs describing what the feature does at95 a high level. Include the motivation and key behaviours.963. **Architecture** - Package layout, new files, changes to existing97 files, key types and interfaces, directory layouts, data formats,98 and any other structural decisions. This section should give the99 implementor a complete picture of what to build and where.1004. **Lettered sections (A, B, C, ...)** - Each section groups related101 user stories. Each user story has an alphanumeric ID (e.g. A1,102 B2).1035. **Implementation Order** - A numbered list of phases grouping user104 stories, showing the order in which they should be implemented.105 Each phase should build on tested foundations from prior phases.1066. **Appendix: Key Decisions** - Design rationale, testing strategy,107 error handling policy, and any other decisions the implementor108 needs to know.109110### Formatting rules111112- Wrap all text at 80 columns.113- Use only simple ASCII characters:114 - Use `-` instead of em dash.115 - Use straight quotes `"` and `'` instead of curly quotes.116 - Use `...` instead of ellipsis character.117 - No smart quotes, no Unicode dashes, no special symbols.118- Use Markdown formatting (headers, code blocks, tables, lists).119- Code blocks must specify the language (```python, ```typescript,120 ```tsx, ```bash, etc.).121- Use 4-column TSV examples for data format specifications, showing122 exact escaping and quoting.123124### User story format125126Each user story follows this template:127128```markdown129### <ID>: <Short title>130131As a <role>, I want <capability>, so that <benefit>.132133<Optional explanatory paragraphs describing the behaviour in detail,134including edge cases, error handling, and interactions with other135components.>136137**Package:** `<package>/`138**File:** `<directory>/<file>`139**Test file:** `<test-directory>/<test-file>`140141<Optional function signatures, type definitions, or code snippets142that the implementor needs.>143144**Acceptance tests:**1451461. Given <precondition>, when <action>, then <explicit expected147 outcome>.1481492. Given <precondition>, when <action>, then <explicit expected150 outcome>.151152...153```154155### Complete user story example156157The following is a complete example of a well-written user story with158acceptance tests. Use it as a reference for the level of detail and159explicitness required.160161```markdown162## Section A: Health Check163164### A1: Health check endpoint with contract validation165166As a developer, I want the frontend to validate the health check167response from FastAPI with a Zod schema, so that contract168breaks are caught immediately.169170**Backend file:** `backend/api/v1/health.py`171**Backend test:** `backend/tests/test_api.py`172**Frontend file:** `frontend/lib/contracts.ts`173**Frontend test:** `frontend/tests/contracts.test.ts`174**Server Action:** `frontend/app/actions.ts`175176The backend endpoint returns `{"status": "healthy"}` as a177`HealthResponse` Pydantic model. The frontend validates this178with the `healthResponseSchema` Zod schema via `backendJson()`.179180(typescript)181export const healthResponseSchema = z.object({182 status: z.enum(['healthy', 'unhealthy']).or(z.string()),183})184(/typescript)185186**Acceptance tests:**1871881. Given the backend is running, when I call189 `GET /api/v1/health`, then the response status is 200 and190 the JSON body is `{"status": "healthy"}`.1911922. Given the `healthResponseSchema` Zod schema and a payload193 `{"status": "healthy"}`, when I call `.parse(payload)`,194 then it returns the payload unchanged.1951963. Given the `healthResponseSchema` Zod schema and a payload197 `{"status": "unknown_value"}`, when I call `.parse(payload)`,198 then it succeeds (the schema allows arbitrary strings).1992004. Given the `healthResponseSchema` Zod schema and a payload201 `{"health": "ok"}` (wrong field name), when I call202 `.safeParse(payload)`, then `result.success` is `false`.203```204205Note the use of `(typescript)` and `(/typescript)` in the example206above to avoid nested triple-backtick issues; in the actual spec207output, use standard Markdown fenced code blocks with triple208backticks and the appropriate language identifier.209210### User story ID scheme211212- Each lettered section (A, B, C, ...) groups related stories.213- Within a section, stories are numbered sequentially: A1, A2, B1,214 B2, B3, etc.215- The section letter appears in the Markdown heading as216 `## Section A: <Topic>`.217- The story ID appears as `### A1: <Title>`.218219### Acceptance test rules220221Every acceptance test must be:2222231. **Testable** - The expected output must be highly explicit. Never224 write "the output should be correct" or "it should work properly".225 State exact values, exact counts, exact strings, exact error226 conditions.2272282. **Self-contained** - The test must fully specify its preconditions.229 The implementor should be able to write a pytest or Vitest test230 from the acceptance test description alone, without guessing.2312323. **Independent** - Each test should be runnable independently of233 other tests (no ordering dependencies within a story's tests).2342354. **Translated to tests** - Write tests so they naturally map to236 the project's testing patterns:237 - Backend: pytest with `describe`-style test functions using238 `httpx.AsyncClient` and `ASGITransport`.239 - Frontend: Vitest with `describe`/`it` blocks, `.parse()` and240 `.safeParse()` for contract validation.2412425. **Covering edge cases** - Include tests for:243 - Happy path (normal operation).244 - Empty input.245 - Invalid/missing input (error cases).246 - Boundary conditions.247 - Special characters in data (unicode if relevant).2482496. **Contract coverage** - If the feature involves a new API250 endpoint, include acceptance tests for both the Pydantic251 response model (backend) and the matching Zod schema252 (frontend). Ensure both agree on field names and types.253254### Architecture principles255256When designing the architecture for the spec, follow these principles:257258- **BFF pattern:** The browser never calls FastAPI directly. All259 backend communication flows through Next.js Server Actions260 (`app/actions.ts`) or API Routes (`app/api/*/route.ts`).261- **Contract-first:** Every new endpoint needs a Pydantic response262 model (`backend/api/schemas.py`) AND a matching Zod schema263 (`frontend/lib/contracts.ts`). The `backendJson()` helper264 validates responses at runtime.265- **Server Components for data, Client Components for UX:**266 Server Components fetch data and pass props. Client Components267 handle interactivity with `'use client'`.268- **Versioned API routers:** Backend endpoints live under269 `backend/api/v1/` with `APIRouter`. New features may warrant270 new router files.271- **Typed responses:** Every FastAPI endpoint declares272 `response_model` and returns a Pydantic model instance.273- **Lifespan pattern:** Use the `@asynccontextmanager` lifespan274 in `main.py` for startup/shutdown resources. Never use275 deprecated `@app.on_event` decorators.276- **Pydantic Settings:** Configuration via `config.py` using277 `pydantic-settings`, not raw `os.environ`.278- **React 19 hooks:** Use `useActionState` for forms, explicit279 state types for Server Action return values.280- **Tailwind CSS v4:** Use CSS-first `@theme` tokens in281 `globals.css`. Use semantic colour tokens, not raw values.282- **shadcn/ui:** Use existing primitives from `components/ui/`.283 Add new ones with `pnpm dlx shadcn@latest add <component>`.284- **Small, focused files:** Keep code per file to a minimum.285 Organise related code into separate files.286287### Architecture section guidance288289The architecture section should include:290291- **New files and directories:** Table or list of every new file,292 its responsibility, and which user stories it implements. Cover293 both backend (`backend/`) and frontend (`frontend/`) directories.294- **Changes to existing files:** List of files that need295 modification and what changes are needed.296- **Key types and schemas:** Pydantic models (backend) and Zod297 schemas (frontend) that the implementor needs. Include full298 definitions. Ensure Pydantic and Zod schemas agree.299- **API endpoints:** HTTP method, path, query/body parameters,300 response model, and example payloads for every new endpoint.301- **Server Actions:** Function signatures for new Server Actions302 in `app/actions.ts`, including state types and return types.303- **Component specifications:** Props interfaces, state types,304 and interaction flows for new React components.305- **Error handling policy:** How each category of error should be306 handled (HTTPException, error state, toast notification, etc.).307308### Implementation order guidance309310The implementation order must:311312- Group stories into numbered phases.313- Ensure each phase depends only on code from prior phases (no314 circular dependencies).315- Start with foundational, pure-logic components (data formats,316 parsers, types) that have no external dependencies.317- Progress through business logic with mocked dependencies.318- End with integration, CLI, and end-to-end tests.319- Note which items within a phase can be implemented in parallel vs320 which must be sequential.321322Reference the implementor and code-reviewer skills in the appendix323so the implementor knows where to find TDD cycle instructions324and code quality standards.325326### Appendix guidance327328The appendix should cover:329330- **Skills:** Reference the implementor and code-reviewer skills331 and explain that phase files reference these instead of332 duplicating instructions.333- **Existing code reuse:** List specific existing functions, types,334 schemas, and utilities that the feature should reuse. Give335 import paths and names.336- **Error handling:** Summarise the error handling policy for each337 category of failure (backend HTTPException, frontend error338 states, contract validation failures).339- **Testing strategy:** Describe how each area should be tested:340 - Backend: pytest + httpx AsyncClient with ASGITransport.341 - Frontend: Vitest contract tests for Zod schemas.342 - Integration: verify the full Server Action flow.343- **TDD cycle:** Reference the implementor skill for the TDD344 cycle steps.345346## Rules347348- NEVER create phase files - only write the spec.md. Phase files are349 created separately.350- NEVER implement code - you only write specifications.351- NEVER invent functionality beyond what the caller described. If352 something seems needed but was not mentioned, ask the orchestrator353 (return a question in your report rather than guessing).354- ALWAYS make acceptance tests explicit enough that expected outputs355 can be compared with concrete assertions (exact values, status356 codes, JSON payloads, `result.success` booleans).357- ALWAYS include exact function signatures for public APIs.358- ALWAYS specify which package and file each story's code belongs in.359- ALWAYS wrap text at 80 columns and use only ASCII characters.360- ALWAYS self-review the completed spec before finishing.