#+TITLE: Spec-Create Workflow #+AUTHOR: Craig Jennings & Claude #+DATE: 2026-06-09 * Overview This workflow produces a *spec* — a short design document written before non-trivial code, whose real product is the thinking it forces, not the artifact. A spec exists to solve a problem on paper, where iterating costs minutes, before solving it in code, where iterating costs days. The guiding principle, drawn from how Google, Oxide, Amazon, Basecamp, and the ADR tradition actually write these: /the most important person to convince is the author/. If the design looks weak on the page, the code will be worse. Writing the spec *is* the design work. It is the front of a trio: - =spec-create.org= (this one) — author writes the spec. - =spec-review.org= — a reviewer gates the spec for implementation-readiness and writes =-review.org=. - =spec-response.org= — the author folds the review back in. The spec this workflow produces has to *pass spec-review's gate* — that gate is the definition of done. So the structure below is built to answer the reviewer's questions up front. Keep it lightweight anyway: a short required spine plus a *readiness-dimensions menu* where each item is either answered or explicitly marked "N/A because…". The best spec is the shortest one that still lets an engineer build it, test it, and ship behavior that matches the user's mental model. * When to Use This Workflow Trigger phrases: "let's write a spec", "spec this out", "create a spec for X", "I want a spec-create workflow" (meta — that creates/edits this file; see protocols.org terminology). ** Phase 0 — The when-to-spec gate (do this first, bail cheaply) A spec is overhead. Only write one when the work clears the proportionality bar. Write a spec when *two or more* hold: - More than 6 hours of work. - The design is uncertain, ambiguous, or contentious. - There are *real trade-offs* — more than one viable approach with different consequences. (Malte Ubl's test: if there are no trade-offs to weigh, skip the spec and write the code.) - The change is cross-cutting or hard to reverse later. If the bar isn't met, say so and stop: "this is below the spec bar — just do it." Don't spec a one-liner; the writing cost would exceed the thinking benefit. * The Workflow Mark anything unknown as an open decision rather than stalling on it. ** Phase 1 — Frame the problem (problem first, always) Before any design, write the problem from the *caller's or user's* point of view. A concrete problem story is the baseline every later design decision is judged against. Capture, in this order: 1. *Summary* — 2-3 sentences a reader can triage in 30 seconds: what this is and why it exists. 2. *Problem / Context* — the actual problem, concretely. What's wrong now, what forces are at play. 3. *Goals and Non-Goals* — bullets. The *non-goals do most of the scoping work* — state plainly what this will not do. If you can't articulate the boundary, you're not ready to design. 4. *Scope tiers* — separate what's in v1 from what's out-of-scope and what's deferred to vNext. The reviewer gates on this separation; vNext items get logged to =todo.org= at hand-off (Phase 6). ** Phase 2 — Design, alternatives, decisions 1. *Design* — overview first, then detail. Write the reasoning as *prose, not bullet dumps* — prose exposes weak logic that bullets let you hide. Use bullets only for genuinely enumerable lists. When the thing has an interface, use the *two-altitude* split (Rust RFC): explain it once for a user/caller, once for an implementer. 2. *Alternatives considered* — the load-bearing section authors skip and reviewers need most. For each option, force a why-not with the MADR grammar: "Good, because… / Bad, because… / Neutral, because…". Even one rejected option, with the reason, beats presenting one path as inevitable. 3. *Decisions* — capture each real choice as an org =TODO= task carrying an inline mini-ADR (Nygard's spine): - The heading is =** TODO =. It flips to =DONE= when the decision-maker agrees with the call; until then it stays =TODO=. - =Context:= the forces motivating the choice - =Decision:= the call, stated actively ("We will…") - =Consequences:= what gets easier *and* what gets harder (both halves — a decision with only upsides is under-examined) An *open* decision is a =TODO= task with an *owner* and a *by-when*; agreeing flips it to =DONE=. If the decision-maker doesn't agree, it stays =TODO= and the back-and-forth continues under a =*** Discussion= child header — never overwrite the decision body to win an argument. Put a =[/]= statistics cookie on the =* Decisions= heading so the resolved tally is visible at a glance. To revisit a =DONE= decision: reopen it to =TODO= (new dispute in its =*** Discussion= thread, prior text preserved) when the same decision is being re-argued; flip it to =SUPERSEDED= with a link to the replacing decision when a fresh decision takes its place; flip it to =CANCELLED= with a one-line reason when scope changes make it moot. All three keep the original body intact — never silently rewrite a resolved decision. =SUPERSEDED= and =CANCELLED= are done-class (the =#+TODO:= header in the template defines them), so they count as resolved in the =[/]= cookie and don't block the gate. Keep decisions inline here; promote to a standalone numbered ADR only when a decision outlives or spans beyond this one spec. (The per-decision =TODO/DONE= is distinct from the spec-wide =Status= in the metadata header — see the implementation-ready gate in Phase 6.) ** Phase 3 — Make it buildable This is where the spec earns a "Ready" from review: an engineer must be able to build it in steps, know when it's done, and never have to invent product behavior mid-implementation. 1. *Implementation phases* — decompose the work into phases each small enough to finish in one focused session and each leaving the tree in a working (not half-broken) state. =spec-review= lifts this section straight into =todo.org= tasks, so a spec that can't be phased fails the gate — the absence is itself a finding. 2. *Acceptance criteria* — the observable conditions that mean the feature works, written as checkable items. The review's test-surface task mirrors these. 3. *Readiness dimensions* — walk this menu and, for each, either define the behavior or write "N/A because…". The escape hatch keeps a simple spec short; the prompt keeps a hidden decision from slipping into implementation: - *Data model & ownership* — what's user-authored / generated / cached / remote; who owns each editable region; what persists vs refreshes. - *Errors, empty states & failure* — actionable messages naming the operation, object, and next step; partial-failure and conflict behavior; no silent data loss. - *Security & privacy* — credentials, sensitive data, redaction in logs. - *Observability* — how the user/operator sees progress and failures and isolates a problem from a bug report; long-op progress/cancel. - *Performance & scale* — expected counts, likely bottlenecks, long-running ops tested with fakes rather than flaky live dependencies. - *Reuse & lost opportunities* — what the platform/framework already provides; preserved, wrapped, or intentionally replaced. - *Architecture fit* — named integration points; weak points and their mitigations (concurrency, lifecycle, failure isolation). - *Config surface* — public knobs named, with defaults and safety notes. - *Documentation plan* — README / user / developer / migration docs, or why none are needed. - *Dev tooling* — Makefile/script targets for setup, test, lint, coverage, cleanup, slow/manual verification. - *Rollout, compatibility & rollback* — migration, opt-out/revert, and dry-run/backup for anything that changes persisted data, public APIs, or external/shared state. - *External APIs & deps* — assumed fields/mutations/enums verified against current schema/docs/live responses, or listed as research prerequisites. ** Phase 4 — Risks and the terseness pass 1. *Risks, rabbit holes, and drawbacks* — name the known technical unknowns and how you'll dodge them (Shape Up's rabbit holes), plus the costs of the chosen path. 2. *Cut it.* "Remove every word that can be removed" — expect a ~30% cut from the first draft with no information loss. Push heavy detail, data, and long calculations to an appendix so the core argument stays readable in one sitting. Tone is conversational and human, not formal — walls of text go unread. Run =/voice general= (or =/voice prose= if it's prose-heavy) for this pass. ** Phase 5 — Wire it up (conventions) - *Filename + location:* =docs/-spec.org=. Org-mode. The slug names the *problem/feature*, not a date. Must end in =-spec.org=. - *Metadata header:* a small table at the top — Status, Owner, Reviewer(s), Date, Related (link to the task/ticket). - *Review-and-iteration-history stub:* add a =Review and iteration history= section at the bottom and seed it with the author's first entry. =spec-review= and =spec-response= append provenance entries here, so the heading shape is a contract: =YYYY-MM-DD Day @ HH:MM:SS -ZZZZ — Contributor — Role=, body fields What / Why / Artifacts. - *Cross-link both ways:* the spec links its task; the task links the spec (replace the task's inline plan with a terse description + a =file:= link to the spec). ** Phase 6 — Hand-off readiness Self-assess against =spec-review='s rubric before handing off, so the review starts from a clean spec instead of catching basics: - *Decisions:* no decision is still =TODO= (the =[/]= cookie reads complete), or the author *consciously accepts* the risk of building with one open (recorded). =SUPERSEDED= and =CANCELLED= count as resolved. *Implementation-ready gate:* the spec Status cannot move past =draft= to an implementation-ready state while any decision is still =TODO=. - *APIs:* every external API assumption is verified or listed as a research prerequisite — otherwise the honest verdict is =Needs research=. - *Self-rubric:* Ready / Ready with caveats / Not ready / Needs research. If it isn't at least =Ready with caveats=, keep drafting. - *Defer:* log open decisions and vNext items to =todo.org= (v1 work =[#B]=, vNext/someday =[#D]=) — don't leave them only in the spec. Then it's ready for =spec-review.org=. Snapshot-vs-living rule: keep the spec living for small in-flight corrections; on a *material* design pivot, write a new =-spec.org= referencing the old rather than letting one doc accrete contradictions. The drift to avoid is the code silently becoming the only real spec. * The Template #+begin_src org ,#+TITLE: — Spec ,#+AUTHOR: ,#+DATE: ,#+TODO: TODO | DONE SUPERSEDED CANCELLED ,* Metadata | Status | draft | |----------+---------------| | Owner | | |----------+---------------| | Reviewer | | |----------+---------------| | Related | [[file:...][task / ticket]] | |----------+---------------| ,* Summary <2-3 sentences: what this is and why it exists.> ,* Problem / Context ,* Goals and Non-Goals ,** Goals - ,** Non-Goals - ,** Scope tiers - v1: - Out of scope: - vNext: ,* Design ,* Alternatives Considered ,**