| name | design-doc |
| description | Generate a detailed design document via `tx doc add design`. Covers architecture, interfaces, data model, invariants, failure modes, verification, and testing strategy. References plan via file path instead of embedding. Plan lives in ~/.codex/plans/<name>.md. Reads companion PRD automatically to map EARS requirements to invariants. Output lands in specs/design/<name>.md. |
| argument-hint | <feature-or-component-name> |
Generate Design Document
Create a comprehensive technical design document using the tx doc primitive. Design docs specify HOW the system implements requirements, with traceable invariants and a concrete testing strategy.
Design Doc + PRD are companions. A PRD defines WHAT and WHY. A design doc defines HOW. If a PRD exists for this feature, the design doc reads it automatically and maps every must-priority EARS requirement to an invariant + verification entry.
Naming Discipline
- tx assigns each doc an immutable
doc_id. Human name slugs only need to be unique within their doc kind.
- Use distinct companion names such as
<feature>-prd and <feature>-design.
- If a slug is already taken by another doc kind, rename the design doc rather than reusing the same name.
Migration Guidance
- When migrating existing markdown into tx-managed docs, preserve the source wording first, then normalize structure.
- If you extract sections programmatically, use a fence-aware parser. Headings inside fenced code blocks are content, not section boundaries.
Workflow State Machine
START
│
▼
┌─────────────────────────────────────────────────────┐
│ Step 0: PLAN GATE │
│ │
│ Is there an active plan in this conversation? │
│ │
│ ├─ YES → Save plan to `~/.codex/plans/<name>.md` if not │
│ │ already saved. Set `plan: ~/.codex/plans/<name>.md` │
│ │ in frontmatter. │
│ │ → Continue to Step 0.5 │
│ │ │
│ └─ NO → Tell the user to run `plan` first. │
│ If enough detail provided, generate plan, │
│ save to `~/.codex/plans/<name>.md`. │
│ → Continue to Step 0.5 │
└─────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────┐
│ Step 0.5: CHECK FOR COMPANION PRD │
│ │
│ Run: tx doc list --kind prd │
│ │
│ ├─ PRD exists for this feature? │
│ │ → tx doc show <prd-name> --md │
│ │ → Extract ALL EARS requirements │
│ │ → Each `must` EARS req MUST get an invariant │
│ │ and a verification entry in this design doc │
│ │ → Set `implements: <prd-name>` in frontmatter │
│ │ → Continue to Step 1 │
│ │ │
│ └─ No companion PRD? │
│ → Continue to Step 1 (design doc stands alone) │
│ → Suggest creating PRD after: `prd` <name> │
└─────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────┐
│ Step 1: SCAFFOLD via tx │
│ │
│ tx doc add design <name> --title "<title>" │
│ ├─ SUCCESS → Continue to Step 2 │
│ └─ FAIL (exists) → Edit existing doc │
└─────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────┐
│ Step 2: DEEP CONTEXT GATHERING │
│ │
│ Read: ARCHITECTURE.md, QUALITY.md, project instructions (for example `AGENTS.md`, if present), │
│ domain code, schema.ts, effect-schemas, │
│ API routes, workflows, activities, │
│ existing designs (tx doc list --kind design) │
│ → Continue to Step 3 │
└─────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────┐
│ Step 3: FILL DOCUMENT │
│ │
│ Write `# Plan` first (reference to plan file from │
│ Step 0). │
│ Then fill all sections from plan + PRD + codebase. │
│ │
│ MINIMUM THRESHOLDS: │
│ - Invariants: ≥ 5 │
│ - Failure modes: ≥ 3 │
│ - Verification entries: ≥ 5 │
│ - Integration test files: ≥ 2 (HARD REQUIREMENT) │
│ - Unit test files: ≥ 1 (recommended, not hard) │
│ - Sequence diagrams: ≥ 2 (happy + error) │
│ - Design decisions: ≥ 1 │
│ │
│ Integration tests are the primary verification │
│ mechanism. Unit tests complement but do not replace │
│ integration tests. │
│ │
│ RULE: No section may be left as a template/stub. │
│ │
│ COMPREHENSIVENESS: The design doc must cover EVERY │
│ item from the plan. Every implementation step, │
│ constraint, risk, and decision in the plan must │
│ appear in the design doc with full technical detail. │
│ The design doc is the single source of truth for HOW │
│ the feature is built — it should be detailed enough │
│ that an engineer can implement from it alone. │
└─────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────┐
│ Step 4: SELF-AUDIT │
│ │
│ Check: │
│ ├─ Every plan item captured in a section? │
│ ├─ Every PRD `must` EARS req has an invariant? │
│ ├─ Every invariant has a verification entry? │
│ ├─ Minimums met? │
│ ├─ No stubs/placeholders? │
│ ├─ All diagrams complete? │
│ └─ Plan file exists at frontmatter path and is │
│ consistent with doc sections? │
└─────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────┐
│ Step 5: VALIDATE │
│ │
│ tx spec lint │
│ ├─ PASS → Continue to Step 6 │
│ └─ WARN/FAIL → Fix, re-validate │
└─────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────┐
│ Step 5.5: SYNC PLAN FILE │
│ │
│ Read the plan file from frontmatter `plan:` path. │
│ Compare with what the doc now contains. │
│ UPDATE the plan file to incorporate: │
│ - Architecture decisions, component inventory │
│ - Interface contracts, data model details │
│ - Invariants, failure modes, error handling │
│ - Implementation sequence, testing strategy │
│ The plan file must reflect the FULL current state │
│ of the feature — not just the initial draft. │
│ This is a MANDATORY step, not optional. │
└─────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────┐
│ Step 6: DISCOVER + LINK + REPORT │
│ │
│ tx spec discover --doc <name> │
│ tx doc link <prd> <design> (if PRD exists) │
│ tx doc show <name> │
│ tx spec gaps --doc <name> │
│ Print summary │
└─────────────────────────────────────────────────────┘
│
▼
DONE
Step 0 — Plan Gate
The plan is the primary input. Check for plan content in the conversation:
- The plan is saved as a standalone file at
~/.codex/plans/<name>.md (relative to repo root).
- If a plan already exists in the conversation, write it to that file.
- If a plan file already exists at that path, read it instead.
- If no plan and vague request, ask user to run
plan first.
The doc's frontmatter gets plan: ~/.codex/plans/<name>.md and the # Plan section contains a reference link + brief summary, not the full verbatim content.
Step 0.5 — Check for Companion PRD
tx doc list --kind prd
If a PRD exists for this feature:
- Read it:
tx doc show <prd-name> --md
- Extract every EARS requirement
- Every
must-priority EARS requirement MUST become:
- An invariant in
invariants: YAML block
- A verification entry in
verification: YAML block
- Set
implements: <prd-name> in frontmatter
If no PRD exists, the design doc stands alone. Suggest creating one after.
Step 1 — Scaffold via tx
tx doc add design $ARGUMENTS --title "<Human-Readable Title>"
Creates specs/design/<name>.md. If exists, edit instead.
Step 2 — Deep Context Gathering
Read these files:
docs/ARCHITECTURE.md — architecture + DDD structure
docs/QUALITY.md — all invariants, governance rules
project instructions (for example AGENTS.md, if present) — stack, conventions
- Companion PRD (from Step 0.5)
- Domain code:
packages/core/src/domains/
- Database schema:
packages/infra/db/src/schema.ts
- Effect schemas:
packages/infra/db/src/effect-schemas/
- API routes:
apps/api/src/
- Workflows:
apps/worker/src/workflows.ts
- Activities:
apps/worker/src/activities.ts
- Existing designs:
tx doc list --kind design
Step 3 — Fill the Document
Required Frontmatter (already generated by tx)
---
kind: spec
spec_type: design
name: <name>
title: "<title>"
status: draft
version: 1
owners:
- <team-or-person>
summary: Technical approach for <title>
domain: <product-area>
tags:
- design
depends_on: []
supersedes: []
implements: <prd-name-or-null>
last_reviewed_at: <YYYY-MM-DD>
plan: ~/.codex/plans/<name>.md
---
Update owners, summary, domain, tags, depends_on, implements.
Body Structure — ALL sections MUST have real content
# Plan comes first (as a reference to the plan file). Then all technical sections. No section may be a stub.
If a companion PRD exists, every must EARS requirement maps to an invariant + verification entry.
# Plan
> Full plan: [~/.codex/plans/<name>.md](../~/.codex/plans/<name>.md)
<2-3 sentence summary of what the plan covers. The full plan lives in the file referenced above.>
# Summary
2-3 sentences on design approach and key technical decisions.
# Architecture
## System Context
Where this feature sits in the existing system. Reference `docs/ARCHITECTURE.md`.
## Component Diagram
┌──────────────────────────────────────────────────────┐
│ API Layer │
│ ┌──────────────────────────────────────────┐ │
│ │ apps/api [MOD] │ │
│ │ ├── routes/.ts [NEW] │ │
│ └──────────────────┬───────────────────────┘ │
└─────────────────────┼────────────────────────────────┘
▼
┌──────────────────────────────────────────────────────┐
│ Domain Layer │
│ ┌──────────────────────────────────────────┐ │
│ │ packages/core/src/domains// [NEW]│ │
│ │ ├── domain/ [NEW] │ │
│ │ ├── ports/ [NEW] │ │
│ │ ├── application/ [NEW] │ │
│ │ └── adapters/ [NEW] │ │
│ └──────────────────┬───────────────────────┘ │
└─────────────────────┼────────────────────────────────┘
▼
┌──────────────────────────────────────────────────────┐
│ Infrastructure Layer │
│ ┌─────────────┐ │
│ │ infra/db │ │
│ │ [MOD] │ │
│ └─────────────┘ │
└──────────────────────────────────────────────────────┘
Mark: `[NEW]`, `[MOD]`, or unmarked.
## Component Inventory
| Component | Package/App | Responsibility | New/Modified |
|-----------|-------------|---------------|--------------|
## Design Decisions
**MINIMUM: ≥ 1 decision with ADR-lite format.**
### Decision 1: <Title>
**Context:** Why needed.
**Options:**
| Option | Pros | Cons |
|--------|------|------|
**Decision:** Option X because <reasoning>.
**Consequences:** What follows.
# Interfaces
```yaml
interfaces:
- name: <InterfaceName>
type: http | queue | event | rpc | cron
definition: |
// TypeScript/Effect Schema definition
interfaces: is for runtime contracts and boundaries, not entities. Use:
http for routes and API endpoints
queue for async workflow, worker, or queue boundaries
event for published or consumed event contracts
rpc for Effect services, internal service boundaries, adapters, and request/response style contracts that are not public HTTP
cron for scheduled jobs
Entities, value objects, and aggregate state belong in # Data Model or domain sections, not interfaces:.
API Endpoints
| Method | Path | Request Schema | Response Schema | Auth | Permission |
|---|
Request/Response Schemas
import { Schema } from 'effect'
export const Create<X>Request = Schema.Struct({ })
export const Create<X>Response = Schema.Struct({ })
Error Responses
| Status | Error Code | Condition | Response Body |
|---|
| 400 | VALIDATION_ERROR | Invalid request body | { error, details } |
| 401 | UNAUTHORIZED | Missing/expired token | { error } |
| 403 | FORBIDDEN | Insufficient permissions | { error } |
| 404 | NOT_FOUND | Resource doesn't exist | { error } |
| 409 | CONFLICT | Duplicate / state conflict | { error, details } |
Port Contracts
export interface <Domain>Repository {
create(input: Create<X>Input): Effect.Effect<X, <Error>>
findById(id: string): Effect.Effect<X | null, <Error>>
findMany(filter: <Filter>): Effect.Effect<readonly X[], <Error>>
update(id: string, input: Update<X>Input): Effect.Effect<X, <Error>>
remove(id: string): Effect.Effect<void, <Error>>
}
Event Payloads (if applicable)
export interface <Domain><Verb>EventPayload { }
export const <Domain><Verb>EventPayloadSchema = Schema.Struct({ })
Data Model
New Tables
CREATE TABLE <table_name> (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX idx_<table>_<column> ON <table_name>(<column>);
Modified Tables
ALTER TABLE <existing_table> ADD COLUMN <column> <type>;
Effect Schemas
export const <Table>Schema = Schema.Struct({ })
Factories
export const create<Table>Factory = (overrides?: Partial<Table>): Table => ({ })
Entity Relationship Diagram
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ organizations │────<│ teams │────<│ <entity> │
│ │ 1:N │ │ 1:N │ │
└──────────────┘ └──────────────┘ └──────────────┘
Invariants
MINIMUM: ≥ 5 invariants. If companion PRD exists, every must EARS req MUST map to an invariant.
invariants:
- id: INV-<SCOPE>-001
statement: <what must be true>
enforcement: <lint script | test | pgTAP>
traces_to: REQ-<SCOPE>-001 # link to PRD requirement if applicable
Failure Modes
MINIMUM: ≥ 3 failure modes.
failure_modes:
- id: FM-<SCOPE>-001
trigger: <what causes failure>
impact: <user/system effect>
detection: <logs, metrics, alerts>
mitigation: <automatic response>
recovery: <human intervention>
Verification
MINIMUM: ≥ 5 entries. Every invariant MUST have a verification entry.
verification:
- invariant: INV-<SCOPE>-001
test_file: <path>
test_name: "description [INV-<SCOPE>-001]"
type: unit | integration | lint | pgtap
Sequence Diagrams
MINIMUM: ≥ 2 (happy path + at least one error path).
Happy Path:
Client API Core DB Worker
│ │ │ │ │
│ POST /api/<x> │ │ │ │
│─────────────────▶│ │ │ │
│ │ validate + auth │ │ │
│ │ create<X>(input) │ │ │
│ │────────────────────▶│ │ │
│ │ │ BEGIN TXN │ │
│ │ │───────────────────▶│ │
│ │ │ INSERT + event │ │
│ │ │───────────────────▶│ │
│ │ │ COMMIT │ │
│ │ │───────────────────▶│ │
│ │◀────────────────────│ │ │
│ 201 Created │ │ │ │
│◀─────────────────│ │ │ poll + dispatch │
│ │ │ │◀────────────────────│
Error Path:
Client API
│ POST /api/<x> │
│─────────────────▶│
│ │ <failure point>
│ <status code> │
│◀─────────────────│
Testing Strategy
Integration tests are the primary verification mechanism and a HARD REQUIREMENT. Unit tests are recommended but secondary.
The testing strategy must be comprehensive. Cover:
- requirement-to-test and invariant-to-test traceability
- happy paths and failure paths for every critical interface
- auth, permission, and validation behavior where applicable
- idempotency, retries, duplicate delivery, or concurrency/race conditions where relevant
- downstream dependency failures, timeouts, and degraded-mode behavior
- migration, backfill, and data-integrity checks when persistence changes
- exact test files, fixtures, and concrete assertions rather than vague “add tests” bullets
Integration Tests
HARD REQUIREMENT: ≥ 2 integration test files listed. Design docs MUST NOT be considered complete without integration tests.
| Test File | What It Covers | Invariants |
|---|
Integration Test Patterns
describe('<Domain> API', () => {
it('returns 401 for unauthenticated [INV-<SCOPE>-003]', async () => { })
it('creates resource with valid input', async () => { })
})
Unit Tests (recommended, not hard requirement)
| Test File | What It Covers | Invariants |
|---|
Unit Test Patterns
describe('<Entity>', () => {
it('creates valid entity [INV-<SCOPE>-001]', () => { })
it('rejects invalid input', () => { })
})
Database Contract Tests (pgTAP)
Test Annotation Convention
it('description [INV-<SCOPE>-001]', () => { ... })
Migration Strategy
Database Migration
File: packages/infra/db/migrations/NNNN_<description>.sql
Rollback Plan
Security Considerations
| Concern | Mitigation | Enforcement |
|---|
Cross-Cutting Concerns
Observability
Data Retention
Implementation Sequence
Phase 1: Domain Foundation
├── <specific file paths>
Phase 2: Infrastructure
├── <specific file paths>
Phase 3: Application Layer
├── <specific file paths>
Phase 4: API Layer
├── <specific file paths>
Phase 5: Worker (if domain events)
├── <specific file paths>
Phase 6: Quality Gates
├── pnpm lint && pnpm type-check && pnpm test && pnpm test:integration
├── tx spec discover --doc <name>
└── tx spec fci --doc <name>
Open Questions
## Step 4 — Self-Audit
Re-read the plan file and verify:
1. **Comprehensiveness check**: Read the plan file. For EVERY item (implementation steps, constraints, risks, decisions), confirm it has full technical detail in the design doc. The design doc must be detailed enough to implement from alone.
2. If PRD exists: every `must` EARS req has an invariant. Every invariant has a verification entry.
3. HARD: ≥2 integration test files (blocking requirement). SOFT: ≥1 unit test file (recommended).
4. Minimums met: ≥5 invariants, ≥3 failure modes, ≥5 verifications, ≥2 sequence diagrams, ≥1 decision.
5. Testing strategy is comprehensive: traceability, happy path, failure path, validation/auth, dependency failures, and data integrity are all covered where relevant.
5. No stubs, no empty tables, no "..." placeholders.
6. All diagrams complete.
7. Implementation sequence lists real file paths.
8. Verify plan file exists at the path in frontmatter and its content is consistent with the doc sections.
## Step 5 — Validate
```bash
tx spec lint
Treat schema and parser errors as blocking. Coverage-oriented warnings after generation, such as unlinked tasks or invariants without tests yet, should be surfaced separately from structural doc errors.
Step 5.5 — Sync Plan File (MANDATORY)
After filling and validating the doc, update the plan file at the plan: frontmatter path to reflect everything the design doc surfaced. The plan file must be the living source of truth — not a stale initial draft.
What to add to the plan file:
- Architecture decisions and their rationale
- Component inventory and file paths
- Interface contracts (HTTP routes, queues, events, and Effect service boundaries)
- Data model details (tables, indexes, constraints)
- Implementation sequence with specific file paths
- Invariants, failure modes, and error handling strategies
- Testing strategy and test file locations
Read the current plan file, merge in the new information, and write it back. Preserve the plan's structure but ensure it now covers the full technical design.
Step 6 — Discover, Link & Report
tx spec discover --doc <name>
tx doc link <prd> <design>
tx doc show <name>
tx spec gaps --doc <name>
After Generation
- Print output path (
specs/design/<name>.md).
- Summarize: component count, invariant count, failure mode count, verification count, test file count.
- If PRD exists, show EARS→invariant mapping coverage.
- List open questions.
- Run
tx spec lint.
- If the plan file is modified later, update the
# Plan summary and derived sections in this doc. If this doc's scope changes, update the plan file to stay consistent.