tiny-spec-create · git:20260904.276fd34 · 2026-09-04 · sha256 b0ea6789529f80be
tiny-spec-create git:20260904.276fd34A
Immutable. This exact content is served forever at /api/v1/blob/b0ea6789529f80be.
---
name: tiny-spec-create
description: Start or update a spec — capture intent and requirements into .spec/<slug>/SPEC.md, optionally bound to a ticket (or ad-hoc). On first run, scaffolds .spec/ and seeds the shared constitution (constitution.md). If a BREAKDOWN.md (from tiny-spec-scope) is present, seeds the spec from a chosen story instead of a full interview. Re-run to update an existing spec in place.
---
# tiny-spec-create
Captures **what** the user wants and **why**, as testable `REQ-N` requirements.
This is the front door of the per-ticket flow. A spec can be bound to a ticket or worked
**ad-hoc** — both are first-class.
The suite works **one spec at a time**, namespaced per spec. Artifacts live under
`.spec/` in the **project root** (the user's cwd) — never in this skill's directory. Two
are **project-wide** and shared at the `.spec/` root (`constitution.md`, `memory.md`);
the per-spec ones (`SPEC.md`, `PLAN.md`, `tasks.md`, `decisions.md`) live under
`.spec/<slug>/`. The `SPEC.md` and `constitution.md` skeletons are inline below — write
them from there, no files to read.
## Pick your mode first — before doing anything else
**Decide which mode you are in before you ask a single question, create a directory, or
touch git** — each mode forbids side effects the others require, so getting here late
means the damage is already done.
Check in this order; the first match wins:
| # | If | Mode | Go to |
|---|----|------|-------|
| 1 | `.spec/` exists but `.spec/constitution.md` does **not** | **reseed** | [Reseed a missing constitution](#reseed-a-missing-constitution) — repair only, then stop |
| 2 | `.spec/` does not exist | **fresh** (first run) | Seeded mode if `BREAKDOWN.md` exists, else Pick the slug → First run — scaffold → Write `SPEC.md` |
| 3 | the active spec's `SPEC.md` already exists | **update** | [Update mode](#update-mode-re-run-on-an-existing-spec) — edit in place, never overwrite |
| 4 | otherwise (new spec in an existing `.spec/`) | **fresh** (new spec) | Seeded mode if `BREAKDOWN.md` exists, else Pick the slug → Write `SPEC.md` |
Rule 1 outranks everything, including **Seeded mode** — a missing constitution is a
repair, and repairs don't create work items. Rule 3 outranks rule 4 so that a re-run on
existing work can never overwrite it.
To evaluate rules 3 and 4 you need the **active spec dir**. Resolve it **read-only**
first (see *Pick the slug* for the shared resolution order). Only *create* a dir once
you know you're in a fresh mode.
**If the user (or `tiny-spec-run`) says this is new work, skip the sole-dir fallback**
and go to rule 4. That fallback exists to find the ticket you're already on; letting it
match when someone asked for a *new* spec quietly retargets the run onto an old ticket
and marks its downstream artifacts stale for no reason.
## Reseed a missing constitution
Check this **before** anything else. The constitution is project-wide, so it can go
missing — deleted, or never committed — while a perfectly good `.spec/<slug>/` sits next
to it. Then it is unrecoverable: the scaffold below never fires, `tiny-spec-plan` only
*hardens* an existing one, and `tiny-spec-build` would inject nothing.
**If this repo already contains real source code, hand off to `tiny-spec-adopt`** — it
derives the constitution from the code itself, which beats anything reconstructible from
here. Say so and stop; that skill also handles the staleness propagation below.
Otherwise (little or no code yet), do **only** this:
1. Resolve the active spec dir **read-only** — you may need its `SPEC.md`. There may be
none; that's fine.
2. Write `.spec/constitution.md` using the skeleton in **First run — scaffold** below,
filled in from whatever already exists, in this order of preference: a `BREAKDOWN.md`
`## Decisions` block at the project root if there is one (Stack + Code-lives →
**Style** and **Layout**; verification hints → **Verification commands**;
cross-cutting → **Guiding invariants**), then the active `SPEC.md`, then the codebase
itself. A *declared* source beats inference. Ask the user only what you genuinely
cannot infer.
3. **Flag downstream work as unverified — across every spec, not just the active one.**
The constitution is project-wide, so *any* `[x]` task in *any* `.spec/*/` was built
and reviewed against a document that did not exist. For each spec dir whose
`tasks.md` has checked tasks, set it `status: stale` and log a `decisions.md` entry
in that spec (`type: change`) saying the constitution was reseeded and the completed
tasks were never checked against it.
4. Report what you seeded, say plainly that it was **inferred and needs review** (it
gets injected whole into every executor and reviewer, so a wrong Verification
commands block silently corrupts every future gate), note that `SPEC.md`/`PLAN.md`
and the branch were left untouched, and point the user at `tiny-spec-plan` to harden
it. Then stop.
Do **not** run the interview, create a spec dir, switch branches, or touch `SPEC.md`.
This is a repair, not a new spec.
## Seeded mode (`BREAKDOWN.md` present)
**Fresh modes only** — reseed (rule 1) and update (rule 3) both outrank this.
Before interviewing, check for **`BREAKDOWN.md`** at the project root (written by
`tiny-spec-scope`). If it exists and the user is creating one of its stories, **seed from
it instead of running the full interview** — confirm, don't re-ask:
1. **Pick the story.** Ask which story (or infer from the user's request); match it to
its `## Feature:` → `Story:` entry by slug or title.
2. **Slug + binding.** Use the story's **slug** for `.spec/<slug>/`. Take the ticket
provider from the Decisions **Platform** and the **id** from the story's tracker
parent or the user (ask for the id if the placeholder is still blank; omit the
`ticket:` block entirely if the platform is ad-hoc).
3. **Requirements.** Promote the story's **`AC:` lines into `REQ-N`** — verbatim where
already atomic; split any that hide two capabilities behind an "and".
4. **Constitution (first run only).** Seed `constitution.md` from the **`## Decisions`**
block instead of interviewing stack/layout: Stack + Code-lives → **Style** and
**Layout**; any verification hints → **Verification commands**; cross-cutting
concerns → **Guiding invariants**. If `constitution.md` already exists, reuse it.
5. **Designs.** If the story carries `design:` paths, note them and point the user at
**`tiny-spec-design`** — that skill reads the files and writes this spec's `D<n>`
entries against a token system. Don't describe the screens here.
6. Confirm the captured `REQ-N` with the user, then write `SPEC.md` as below.
Only the **project-wide** questions collapse — still confirm this story's binding and
requirements. If there is **no `BREAKDOWN.md`**, or no entry matches, run the **full
interview** below unchanged.
**Exception — a story run.** If the caller says this is a **story run** and names the
story's slug (`tiny-spec-run` does, in build-through mode), skip step 6's confirmation
and write `SPEC.md` straight out. The `AC:` lines *are* the approval: the user reviewed
them when they wrote or accepted `BREAKDOWN.md`, and re-confirming them once per story is
asking the same question twice — across a seven-story run it is the difference between
walking away and being interrupted seven times. Report the captured `REQ-N` instead of
asking about them.
This waives **only** that confirmation. Everything that is a genuine question still stops
the run: a story whose `AC:` lines contradict each other or the Decisions block, an `AC:`
you cannot turn into a testable `REQ-N`, a missing ticket id the platform needs, a design
export the story names that isn't on disk. Those are not ceremony — they are the human
input the run is supposed to stop for. Never guess past one because a run is in progress.
## Pick the slug (resolve the active dir)
**Fresh modes only** — in reseed or update mode the active dir already exists and you
resolve it read-only, as above. Do not run this section.
**If a spec dir already resolves for the current branch, reuse it — don't invent a new
slug.** Asking for a slug when `.spec/PROJ-123/` already matches the branch is how you
end up with both `PROJ-123/` and `dark-mode/` matching `feature/PROJ-123-dark-mode`,
which makes the ticket permanently ambiguous for every downstream skill.
Each spec lives in its own directory `.spec/<slug>/`. At the start of the interview,
establish the slug. There are two paths — both are first-class:
- **Bound to a ticket.** Ask for the **provider** (`jira | github | ado | monday`),
**id**, **url**, and optionally the current **status**. Derive the slug from the
platform key: verbatim when filesystem-safe (`PROJ-123`); otherwise normalize —
GitHub `#42`→`gh-42`, Monday item→`monday-<id>`, ADO `AB#77`→`ado-77`.
- **Ad-hoc (no ticket).** Perfectly supported — just confirm there's no ticket and use a
short kebab-case slug of the feature name (e.g. `dark-mode`, `perf-pass`). The SPEC
omits the `ticket:` frontmatter block, and commits drop the `Refs:` footer (everything
else — namespacing, the constitution, the build loop — is identical). You can bind a
ticket later by adding the block to `SPEC.md`.
Create `.spec/<slug>/`.
**One branch per spec — how the active spec is resolved.** Work lives on a branch named
after the slug (e.g. `PROJ-123` or `feature/PROJ-123-dark-mode`); downstream skills
resolve the active spec from the branch name, so several can be in flight on separate
branches at once. If the user isn't already on such a branch, create one (e.g.
`git switch -c <slug>`) so the new spec resolves by branch match.
## First run — scaffold
If `.spec/` does not exist:
**If this repo already contains real source code, run `tiny-spec-adopt` first.** It
derives the constitution from the actual lint/test/build commands, layout, and
conventions — an interviewed constitution on an existing codebase is how you get a gate
that names commands the project doesn't have. Come back here for the spec itself.
Otherwise:
1. Create `.spec/` and the active spec dir `.spec/<slug>/` (on the spec's branch — see
above).
2. **Short interview** (keep it short — earned ceremony):
- the ticket binding (above);
- the intent in one paragraph;
- the language/stack and where code lives;
- the must-have requirements (the capabilities, not the design).
3. Seed the **shared constitution** at `.spec/constitution.md` (the **root**, not the
spec dir — it is project-wide), filling in what the interview or a `BREAKDOWN.md`
`## Decisions` block already told you (Style, Layout, Verification commands at
minimum). Leave the rest for `tiny-spec-plan` to harden — but never leave a section
empty of intent. If `constitution.md` already exists (a prior spec created it),
**reuse it** — do not overwrite the project's constitution. Write it with this
structure (drop the indentation when you write the file):
```markdown
# Constitution
> This is the strongest, most persistent document in the project. It is
> **project-wide** — it lives at the `.spec/` root and anchors *every* spec, not
> any one of them. Every task is implemented and reviewed against it. Keep it true;
> keep it lean. Project-specific richness belongs here — not scattered across tasks.
## Style
<Formatting, naming, language idioms. The defaults a reader should assume.>
## Engineering standards
<Error handling, logging, testing approach, dependency policy, what "tested" means here.>
## Guiding invariants
<The non-negotiables. "Never X." "Always Y." The rules a reviewer can fail a task on.>
## Glossary
<Domain term — one-line definition. Keep the team speaking one language.>
## Layout
<Where things live. Directory map. Where new code of each kind goes.>
## Definition of Done
<The bar a task must clear to be checked off: e.g. code + tests + docs updated,
gate green, no TODOs left, matches the invariants above.>
## Verification commands
<The exact gate. The reviewer runs these. Omit any stage this project doesn't have.
- install: `...`
- lint: `...`
- test: `...`
- build: `...`
- run: `...`
>
```
**A `## Design system` section is `tiny-spec-design`'s** — leave it absent here. A
dead design heading on a CLI or library is worse than none: it gets injected into
every executor and reviewer prompt for the life of the project.
## Write `SPEC.md`
Write `.spec/<slug>/SPEC.md` with the structure below, filling it in:
```markdown
---
status: current
updated: <ISO date>
# Ticket binding (reference-only). Omit this whole block if there is no ticket.
ticket:
provider: jira | github | ado | monday
id: <PROJ-123 | #42 | AB#77 | item id>
url: <link to the ticket>
status: <optional manual mirror of the platform status, e.g. In Progress>
---
# <Project / feature name>
<!-- optional: omit if N/A -->
## Context
<Why now — the background, the problem, what prompted this. No solution detail.>
## Intent
<One paragraph: what this is and why it exists. The "what" and "why", never the "how".>
## Requirements
<Each REQ is one user-observable, testable capability. No implementation detail.
If a line hides two capabilities behind an "and", split it.>
- REQ-1 — <capability>
- REQ-2 — <capability>
- REQ-3 — <capability>
<!-- optional: omit if N/A -->
## Non-goals
<What this explicitly does NOT cover — scope boundaries that prevent creep.>
<!-- optional: omit if N/A -->
## Success criteria
<How we'll know the whole spec succeeded, beyond the per-requirement acceptance —
e.g. a metric, an end-to-end scenario, a stakeholder sign-off.>
<!-- optional: omit if N/A -->
## Open questions
<Unresolved questions that may change requirements. Resolve before/while planning.>
<!-- optional: omit if N/A -->
## Links
<Ticket, related specs, design docs, prior art.>
```
- the **ticket binding** frontmatter block (or omit it if there's no ticket);
- a one-paragraph **intent**;
- a `## Requirements` list — each `REQ-N` a single **user-observable, testable**
capability with **no implementation detail** ("the CLI accepts a `--json` flag and
prints valid JSON", not "add a json module");
- the optional sections (`Context`, `Non-goals`, `Success criteria`, `Open questions`,
`Links`) where they add value — omit any that don't apply.
Number requirements `REQ-1, REQ-2, …`. Keep each atomic — if a line has an "and" that
hides two capabilities, split it.
**If this spec has a visual surface**, run **`tiny-spec-design`** afterwards. It adds a
`## Design` section — one `D<n>` per screen, written against a project-wide token system
— and arms the visual gate. Don't write screen descriptions here; a description not
anchored to tokens is how per-screen drift starts.
## Update mode (re-run on an existing spec)
When the active spec's `SPEC.md` already exists and the user wants a change to
requirements (resolve the active dir by branch match):
1. Edit `.spec/<active>/SPEC.md` in place — add/alter/remove `REQ-N`, preserving existing
ids where the requirement still exists.
2. Flip downstream **stale**: set `PLAN.md` and `tasks.md` frontmatter to `status: stale`
(if they exist).
3. Log it: append a `decisions.md` entry to `.spec/<active>/decisions.md`, using the
fixed skeleton (`type: change`, the affected `REQ-N`). Create the file if absent:
```
## D-NNN — <short title>
- type: change
- date: <ISO date>
- affects: REQ-N
- note: <what changed + why>
```
4. **Completed-work guardrail.** If a changed `REQ-N` is delivered by a task already
`[x]` in `tasks.md` (follow its `req:` field), **uncheck it** and name the unchecked
ids in the same `decisions.md` entry. `tiny-spec-build` resumes from the checkbox
state, so a task left `[x]` is a task it will never revisit — never assume built work
survived a requirement change.
5. Set `SPEC.md` `status: current` and bump `updated`. **Do this even if it was already
`current`.** `SPEC.md` is the root of the chain and no other skill in the suite writes
that flag, so a hand-edited `stale` SPEC is otherwise unclearable and the chain jams
at the root.
If the spec has a `## Design` section and the change touches a screen, hand off to
**`tiny-spec-design`** — it owns those entries and their staleness hashes.
Tell the user which downstream docs went stale and to re-run `tiny-spec-plan` to
reconcile.
> **New spec?** To start a different piece of work, re-run this skill on a new branch —
> it creates a new `.spec/<slug>/` that resolves by branch match. The shared
> `constitution.md` and `memory.md` carry over; the previous spec's artifacts stay
> untouched on disk.
## When done
Report the requirements captured and point the user at `tiny-spec-plan` (or
`tiny-spec-design` first, if this spec has screens to anchor).