一键导入
specification-writing
Write technical specs that let agents implement autonomously. Use for "write a spec", "plan this feature", "create a planning doc".
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Write technical specs that let agents implement autonomously. Use for "write a spec", "plan this feature", "create a planning doc".
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
| name | specification-writing |
| description | Write technical specs that let agents implement autonomously. Use for "write a spec", "plan this feature", "create a planning doc". |
| metadata | {"author":"epicenter","version":"1.0"} |
Follow writing-voice for prose sections. Follow notebook-explanation for mental models, ownership diagrams, flow diagrams, and compressed rules.
A specification gives an agent or maintainer the context they need to implement a feature autonomously. The goal is not to describe everything exhaustively. The goal is to show enough evidence that the direction is credible and give the implementer a concrete launch point.
A spec is in-flight scaffolding, not the durable record. It plans work and holds research while the work is underway. It is not authoritative and does not outlive the work. Durable decisions live in docs/adr/, shared vocabulary in docs/CONTEXT.md, current state in docs/reference/ and the code. When a load-bearing decision crystallizes while you are writing the spec, record it as a Proposed ADR in docs/adr/ right then and reference it from the spec; do not leave it buried in the spec to be "harvested" later. When the work lands, the ADR flips to Accepted and the spec is deleted (see spec-execution). Git and docs/spec-history.md keep the history.
Note: This guide uses
[PLACEHOLDER]markers for content you must fill in. Code blocks show templates; replace all bracketed content with your feature's details.
Use this pattern when you need to:
Load these on demand based on the spec's decision surface:
Specs should:
A good spec is a launching pad, not a script to follow.
Before outlining sections, apply the one-sentence-test. If you can't name what this spec is about in one concrete sentence, the design is not coherent yet. That is the finding, and the spec is not ready.
The first screen of a spec must answer:
What is this?
Is it active, implemented, superseded, or historical?
What is the current shape?
What is the target shape?
What proves the change is done?
Large specs are allowed. Thoroughness is useful when the work is deep. The rule is not "split after N lines." The rule is: do not make one reader job fight another.
Split or add a short active slice when a document mixes:
When keeping everything in one file, add a "How to read this spec" block near the top:
Read first:
One Sentence
Current State
Target Shape
Implementation Plan
Verification
Read if changing the architecture:
Design Decisions
Rejected Alternatives
Edge Cases
Historical only:
Implementation Notes
Superseded Decisions
Execution Prompts
The reader should be able to get the current truth in one minute, the model in five minutes, and the execution path in fifteen minutes.
All implementation specs live in root /specs/. Do not create nested specs under apps/ or packages/.
Name new specs specs/YYYYMMDDThhmmss-feature-name.md: local timestamp, kebab-case feature name.
Prompt and handoff artifacts can live beside specs with explicit suffixes like .prompt.md, .handoff.md, or .execute.md. They should link back to the canonical spec and should not be treated as the current implementation plan unless the suffix says so.
Classify every material decision:
| Class | Resolved by | Rule |
|---|---|---|
| 1 | Evidence | Verify with source, test, or version check. |
| 2 | Design coherence | Apply the spec thesis consistently. |
| 3 | Taste under constraints | Pick deliberately and write the constraint. |
Before any "keep" decision, ask: "Would I add this if it did not already exist?"
Never let evidence questions hide behind design coherence. Verify before deleting old paths. For examples and failure modes, read references/decision-hygiene.md.
Most specs do not need a section for adjacent work. When adjacent work matters, write only what the implementer needs:
Deferred:
not required now, allowed later
Opportunistic:
not required, but acceptable to fix if discovered and grounded
A spec is an execution spine, not a file whitelist.
# [Feature Name]
**Date**: [YYYY-MM-DD]
**Status**: Draft | In Progress
**Owner**: [Name/team responsible for decisions]
**Branch**: [optional: branch name if work has started]
**Supersedes**: [optional: previous spec paths]
**Superseded by**: [optional: later spec path]
Every spec needs one concrete sentence before the overview. This is the maintainer's anchor.
## One Sentence
[One sentence naming the new shape and the boundary it changes.]
One paragraph max. Describe what the feature does. Don't sell it.
## Overview
[One to two sentences describing what this feature adds or changes and what it enables. Be specific about the capability, not vague about benefits.]
Structure as Current State, Problems, then Desired State.
## Motivation
### Current State
[Show actual code or configuration demonstrating how things work TODAY. Use real code blocks, not prose descriptions.]
This creates problems:
1. **[Problem Title]**: [Specific explanation of what breaks or is painful]
2. **[Problem Title]**: [Specific explanation of what breaks or is painful]
### Desired State
[Brief description of what the target looks like. Can include a code snippet showing the ideal API or structure.]
This is where specs shine. Document what you FOUND, not what you assumed.
## Research Findings
### [Topic Researched]
[Description of what you investigated and methodology]
| [Category] | [Dimension 1] | [Dimension 2] |
| ------------- | -------------- | ---------------- |
| [Project/Lib] | [What they do] | [Their approach] |
| [Project/Lib] | [What they do] | [Their approach] |
**Key finding**: [Your main discovery, for example that no standard exists, or that everyone does X]
**Implication**: [What this means for your design decisions]
Include:
Use a table for traceability. Every material decision should have a class and rationale.
A load-bearing decision (a Class 2 coherence or Class 3 taste choice about architecture, ownership, an API shape, or a rejected alternative worth not re-litigating) belongs in an ADR, not only in this table. Write it as a Proposed ADR in docs/adr/ as soon as it crystallizes and reference the ADR number in the table's rationale. The table then traces the spec's decisions to their durable home; the ADR survives after the spec is deleted.
## Design Decisions
| Decision | Class | Choice | Rationale |
| ------------------- | ----------- | ---------------- | ------------------------------- |
| [Decision point] | 1 evidence | [What you chose] | [Source, test, or version checked] |
| [Decision point] | 2 coherence | [What you chose] | [How this follows the thesis] |
| [Decision point] | 3 taste | [What you chose] | [Constraint and trade-off] |
| [Deferred decision] | Deferred | Deferred | [Why it is deferred and what would bring it back] |
Diagrams over prose. Prefer fenced text diagrams, file trees, route tables, and before/after blocks. Use simple ASCII diagrams by default because they are fast to write and easy to edit. Use box-drawing characters only when a polished diagram is worth the extra weight.
## Architecture
[Describe what the diagram shows]
[caller]
-> [boundary or route]
-> [policy or validation]
-> [storage or primitive]
For multi-step flows:
Step 1: [Step name]
[What happens in this step]
Step 2: [Step name]
[What happens in this step]
When the spec introduces a coherent set of new primitives (column types, action variants, error kinds, modifier methods, etc.), present them as a catalog: a compact code block that lists every primitive with a one-line annotation, followed by detail sections only for the ones that need elaboration.
Catalogs let a reader scan the entire surface in one glance before diving into any single primitive.
## The field.* catalog
```ts
field.string<TBrand?>(s?) // TEXT (TBrand for branded strings)
field.number(s?) // REAL
field.integer(s?) // INTEGER
field.boolean() // INTEGER 0/1
field.select([value]) // TEXT (single-element set)
field.select([...]) // TEXT + CHECK constraint
field.json<S extends TSchema>(schema) // TEXT JSON-encoded, schema required
nullable(inner) // Type.Union([inner, Type.Null()]) (standalone)
field.datetime(s?) // RFC 3339 string, branded DateTimeString
field.string<IanaTimeZone>() // IANA zone string, branded IanaTimeZone
```
Every primitive justified by N+ existing call sites in the audit.
### What was considered and rejected
| Candidate | Why rejected |
|---|---|
| `field.id()` | Subsumed by `field.string<IdBrand>()` + a co-located `generate*` factory |
| `field.array(of)` | Subsumed by `field.json(Type.Array(of))` |
| Declaring `_v` as a column | Library-managed; positional in `defineTable(v1, v2, ...)` |
A "rejected candidates" table is often as useful as the catalog itself: it shows the implementer what not to add, and why. The reader gains confidence that the surface is tight.
When the spec changes a consumer-facing API, show at least 2-3 real call sites translated, not invented examples. Real code surfaces semantic shifts the abstract proposal misses.
Find actual usages in the codebase first. Show the verbatim "Before" with file:line, then the "After" translation. Annotate any non-obvious mapping with a brief comment.
## Call sites: before and after
### honeycrisp notes table
**Before** (`apps/honeycrisp/src/lib/workspace.ts:78`):
```ts
const notesTable = defineTable(
type({ id: NoteId, title: 'string', _v: '1' }),
type({ id: NoteId, title: 'string', wordCount: 'number | undefined', _v: '2' }),
).migrate(...)
```
**After**:
```ts
const notesTable = defineTable(
{ id: field.string<NoteId>(), title: field.string() },
{
id: field.string<NoteId>(),
title: field.string(),
wordCount: nullable(field.number()),
},
).migrate(({ value, version }) => {
switch (version) {
case 1: return { ...value, wordCount: null };
case 2: return value;
}
});
```
**Semantic shift to flag**: rows previously stored with `wordCount` key absent will now read as `null` instead of `undefined`. Affects app code doing `if (row.wordCount === undefined)`. Also: `_v` no longer appears in the column record; it is library-managed and stripped from returned rows.
The "semantic shift to flag" callouts are critical: they're what the implementer needs to grep for and codemod across the codebase.
Break into phases. Use checkboxes for tracking. Phase 1 should be detailed; later phases can be rougher (the implementer will flesh them out).
## Implementation Plan
### Phase 1: [Phase Name]
- [ ] **1.1** [Specific, atomic task]
- [ ] **1.2** [Specific, atomic task]
- [ ] **1.3** [Specific, atomic task]
### Phase 2: [Phase Name]
- [ ] **2.1** [Higher-level task the implementer will break down]
- [ ] **2.2** [Higher-level task]
If the spec replaces an old code path with a new one, write separate phases:
1. Build the new path (waves 1 to N)
2. Stop importing the old path (one wave; old code stays on disk, unused)
3. Verify (typecheck, tests, smoke) (one wave; rollback is one revert)
4. Delete the old path (final cleanup wave)
Do not schedule deletion before verification passes. cohesive-clean-breaks owns the full Build, Prove, Remove rationale.
List scenarios that might break assumptions or need special handling.
## Edge Cases
### [Scenario Name]
1. [Initial condition]
2. [What happens]
3. [Expected outcome or "See Open Questions"]
### [Scenario Name]
1. [Initial condition]
2. [What happens]
3. [Expected outcome]
This section signals "you decide this" to the implementer. Include your recommendation but don't close the question.
## Open Questions
1. **[Question about an unresolved design decision]**
- Options: (a) [Option A], (b) [Option B], (c) [Option C]
- **Recommendation**: [Your suggestion and why, but explicitly leave it open]
2. **[Another unresolved question]**
- [Context about why this is uncertain]
- **Recommendation**: [Suggestion or "Defer until X"]
## Adjacent Work
- [Decision or feature]: [Why it is not required now, and what would bring it back.]
- [Issue or cleanup]: [Why it is not required, but may be fixed if discovered and grounded.]
Use this section only for Class 3 keeps. Each entry must name the constraint and a revisit trigger.
## Decisions Log
- Keep `[name]`: [constraint or trade-off].
Revisit when: [specific signal that would make the keep decision worth re-opening].
How do we know this is done? Checkboxes for verification.
## Success Criteria
- [ ] [Specific, verifiable outcome]
- [ ] [Specific, verifiable outcome]
- [ ] [Tests pass / build succeeds / docs updated]
Files that will be touched or consulted.
## References
- `[path/to/file.ts]` - [Why this file is relevant]
- `[path/to/pattern.ts]` - [Pattern to follow or reference]
When an agent reads your spec, they should:
The agent will then:
If your spec is too prescriptive, the agent will blindly follow it. If it's too vague, the agent will flounder. The sweet spot is: enough context to start, enough openness to own the implementation.
- [ ] Header (Date, Status, Owner)
- [ ] One Sentence
- [ ] First screen answers active status, current shape, target shape, and proof
- [ ] "How to read this spec" block when the file is long or partly historical
- [ ] Overview (1-2 sentences)
- [ ] Motivation
- [ ] Current State (with code)
- [ ] Problems (numbered)
- [ ] Desired State
- [ ] Research Findings
- [ ] Comparison tables
- [ ] Key findings
- [ ] Implications
- [ ] Design Decisions (table with rationale)
- [ ] Design decisions have classes
- [ ] Class 1 decisions were verified
- [ ] Class 3 keeps are logged with `Revisit when:`
- [ ] Adjacent work is included only when it clarifies implementation
- [ ] Catalogs (when introducing a primitive set: code block + rejected candidates table)
- [ ] Architecture (ASCII diagrams)
- [ ] Visual rhythm: prose is broken up with code, tables, trees, or diagrams where relationships matter
- [ ] Call Sites (before/after on 2-3 real usages with file:line)
- [ ] Implementation Plan (phased checkboxes)
- [ ] Edge Cases
- [ ] Open Questions (with recommendations)
- [ ] Success Criteria
- [ ] References
Not every spec needs every section. A small feature might skip Research Findings. A migration spec might focus heavily on Edge Cases. Use judgment.
Run a continuous collapse-and-simplify pass that surgically removes indirection failing to earn its boundary. Use when the user says 'collapse pass', 'simplify pass', 'reduce indirection', 'shrink the surface', 'find what to delete', when asking to audit a package for dead abstractions, when reviewing a pull request, branch, or recent merged change for simplification (isolated in a worktree), or when the goal is a sequence of small refactor commits that delete more than they add. Pairs with code-audit (smell catalog), refactoring (per-change mechanics), one-sentence-test (cohesion gate), cohesive-clean-breaks (deep redesigns), approachability-audit (first-read sanity), and post-implementation-review (second-read after each commit).
How a workspace-backed app under `apps/*` is composed: the isomorphic doc factory (`create<App>`), the environment factories (`open<App>Browser` / `open<App>Extension` / tauri), the `#platform/*` build-time platform DI for multi-platform (Tauri) apps, the `session` singleton, daemon/script placement under per-project `workspaces/<app>/`, and the file layout itself. Use when creating a new app, naming or placing the iso/browser/extension factory, wiring `#platform/*` subpath imports for a Tauri seam, choosing between auth-gated (Shape A) vs module-singleton (Shape B), placing the session singleton, or registering daemon/script bindings.
Query/RPC layer with TanStack Query, defineKeys, service composition, runtime DI. Use for createQuery, createMutation, queries/mutations, reactive data management.
TanStack AI patterns for @tanstack/ai, @tanstack/ai-svelte, chat state, streamed responses, UIMessage parts, tool calling, tool approvals, and provider model adapters. Use when working on AI chat, createChat, fetchServerSentEvents, UIMessage conversion, or TanStack AI tools.
Create a slash-command `/goal` for long-running Codex or Claude Code work when the user explicitly asks for a `/goal`, agent goal, or completion condition. Outputs one goal line with the objective, starting context, validation evidence, and stop condition.
List 3-5 comparable apps when planning a UX surface to test category fit and surface high-leverage refusals. Use for "what do other apps do", identity, sync state, local-first design.