---
name: aide-create
description: >-
  Create a spec — a title and a description — as the 4-file spec
  structure (description, analysis, solution, status).
  Use when: creating a new spec, starting new work that needs
  documentation.
  Do NOT use for: analysis (use aide-analyze), implementation (use aide-implement),
  code review.
argument-hint: "\"<title>\" <description> | TODO-<name> <description>"
effort: medium
---

Create a spec: a title and a description, as the 4-file structure.

**Input:** $ARGUMENTS (all arguments after the command)

## Smart detection

Parse `$ARGUMENTS`:

**A quoted title, then the description:** the argument starts with a
double quote; what is inside the quotes is the title, and everything
after the closing quote is the description. The title is never made up
by this skill — an argument that does not start with a quote is a
missing title: ask for it before anything is created.
- Example: `/aide-create "Move the forms off Redux Form" The forms still use Redux Form, which is unmaintained. Move them to React Hook Form, one form at a time, keeping the validation rules.`

**A title may begin with an issue key** (`[A-Z][A-Z0-9]*-[0-9]+`, e.g.
`PROJ-7890`). The key becomes part of the folder name, and the spec can
then be referred to by that key in every later command. Nothing is
fetched from anywhere: the description is what the arguments say.

**A named folder:** if the first word starts with `TODO-`, the name after
it is the folder name and the rest is the description. This is the form
the dashboard's queue uses, stating the title on a line of its own.
- Example: `/aide-create TODO-redux-form-migration Move all forms`

**Error handling:** If the argument is missing or has an invalid format, show:

```text
Missing argument

Usage:
/aide-create "<title>" <description>
/aide-create TODO-<name> <description>       # the queue's form: a folder name, the title stated separately

Examples:
/aide-create "Dark mode" Add a dark theme that follows the system setting, with a manual override in Settings.
/aide-create "Move the forms off Redux Form" The forms still use Redux Form, which is unmaintained. Move them to React Hook Form, one form at a time, keeping the validation rules.
```

---

## Workflow

The steps below are this skill's own, inside the queue's `create` step.
Mark each one in the log, so a reader can follow the run: when it
starts, write one line `--- Step N of X: <title> — started`, and when
it ends, one line `--- Step N of X: <title> — done`. A step that ends
the run early says `— stopped: <why>` in place of `— done`, and one that does not apply to this run `— skipped: <why>`.

Step 7, the merge into the default branch, is Aide's, after this
session: Aide writes its marks, and the create is finished only when it is
done.

### Step 1 of 7: Find the specs root

First write `--- Step 1 of 7: Find the specs root — started`, and when this step ends, `--- Step 1 of 7: Find the specs root — done`.


- Before anything else, run `date +%s` and keep the printed number as
  this phase's start time — Step 5 uses it, for an interactive run only,
  to record how long this phase actually took.
- Read `AIDE_SPECS_PATH` from `.aide/config` in the project root
  (helper: `aide_specs_root` in `_aide-spec-lib.sh` does the whole lookup)
- If the key is set: use that path as the specs root
- Otherwise: use `specs/` in the project root
- `git pull --ff-only` the specs root before Step 2 reads it — Step 2's
  number and Step 5's commit both work from whatever is on disk right
  now, not from whatever it was when this session last looked.

### Step 2 of 7: Find the next available number

First write `--- Step 2 of 7: Find the next available number — started`, and when this step ends, `--- Step 2 of 7: Find the next available number — done`.


**Headless, with a literal folder name stated:** skip this step entirely
— see "A headless run states its own folder name" below Step 4.

- Find the highest number from the `NN-slug` format in the specs root
  AND in `<specs-root>/archive/` — archived specs keep their number,
  and a number must never be reused
- Next number = highest + 1 (or 01 if none exist), leading zero: `01`, `02`, ...
- Helper: `aide_next_spec_number <specs-root>` in `_aide-spec-lib.sh`
  does exactly this — use it, and never sort folder names as text:
  `ls | sort` puts `99-…` above `431-…`, and `aide-create-spec` refuses
  a number that is not above every number already there

### Step 3 of 7: Generate a slug from the title

First write `--- Step 3 of 7: Generate a slug from the title — started`, and when this step ends, `--- Step 3 of 7: Generate a slug from the title — done`.


**Headless, with a literal folder name stated:** skip this step
entirely, for the same reason as Step 2.

- Lowercase, spaces → hyphens
- Transliterate non-ASCII letters to their ASCII equivalents
- Remove special characters and double hyphens
- Result: `NN-slug` (e.g. `65-clean-up-console-log`)
- The deterministic no-AI create path uses `aide_slug_from_title` in
  `_aide-spec-lib.sh` for exactly this rule — read it there if this
  description and that function ever need to be checked against each other.

### Step 4 of 7: Create the directory and 5 files

First write `--- Step 4 of 7: Create the directory and 5 files — started`, and when this step ends, `--- Step 4 of 7: Create the directory and 5 files — done`.


**A headless run states its own folder name.** A prompt that says
"create the spec folder under exactly this name — `<name>` — do not
choose a number or a slug (skip Steps 2 and 3 of the skill)" means
exactly that: Steps 2 and 3 above are skipped, and the call below passes
`--folder-name "<name>"` instead of `--number`/`--slug`. The folder's
real number and slug are not decided in this session at all — a landing
step assigns both later, under the specs repo's own lock, which is the
one place two creates running at once cannot both miss.
Everything else in this step — the description, `--depends-on`, the
acceptance flag — works exactly the same either way.


A bare interactive `/aide-create`, typed in a session with no such line
in the prompt, runs Steps 2-4 exactly as below, unchanged.

**Before composing the description below:** if the incoming
description already contains a `## Acceptance criteria` section whose
lines already match `^- \*\*AC-\d+:\*\*` (spec-structure rule §
1-description), pass it through into `--description` exactly as
given — do not reformulate it, renumber it, or append a second
Acceptance criteria section. Only a description with no such matching
section reaches the step below.

Otherwise, attempt to formulate the user's loose description as a
`## Acceptance criteria` section with `AC-n` SHALL statements (format:
spec-structure rule § 1-description) — every line exactly
`- **AC-n:** ...`, bold included. If the description is too thin for
confident SHALL statements, ask the user for the necessary
clarifications now, before creating the spec — never write an
Acceptance criteria section you had to guess at.

`aide-create-spec` rewrites an Acceptance-criteria line with missing or
misplaced bold (`- AC-1:`, `- **AC-1**:`) to `- **AC-1:**`, and refuses
only a line it cannot rewrite. If it refuses for that reason, fix the
offending line's formatting and call it again — never work around the
refusal by dropping the line instead.

Call the script — never the Write tool — so file creation stays on a
Bash-only path (this is what lets a Write/Edit permission rule be
scoped to the specs-repo path later, with no legitimate case left to
break):

```bash
aide-create-spec \
  --specs-root "<specs-root>" \
  --number "<NN>" \
  --slug "<slug>" \
  --title "<title>" \
  --description "$(cat <<'AIDE_DESC'
<the description text, verbatim>
AIDE_DESC
)" \
  --depends-on "<value>"   # omit this flag entirely when the prompt states none
  --acceptance-not-required   # the default — see "Acceptance" below
```

Headless, with a literal folder name stated (Steps 2-3 skipped): the
same call, with `--folder-name "<name>"` in place of `--number`/`--slug`:

```bash
aide-create-spec \
  --specs-root "<specs-root>" \
  --folder-name "<name>" \
  --title "<title>" \
  --description "$(cat <<'AIDE_DESC'
<the description text, verbatim>
AIDE_DESC
)" \
  --depends-on "<value>"   # omit this flag entirely when the prompt states none
  --acceptance-not-required   # the default — see "Acceptance" below
```

**Depends on:** if the prompt states a Depends-on value (the "New spec"
form on the dashboard passes one as
`Use exactly this Depends-on value in Tracking info: <value>`), pass it
via `--depends-on`, using the value EXACTLY as stated, comma-separated.
The script writes it into `1-description.md`'s Tracking info as a
`Depends on:` line directly after `Created`, one backticked identifier
per entry:

```markdown
- **Depends on:** `105`, `92-a-spec-can-depend`
```

When the prompt states no such value, omit the `--depends-on` flag
entirely. Never infer a dependency from the description.

**Acceptance:** the prompt decides when it says so, and it says so both
ways.

- "Record this spec's Tracking info with an explicit
  acceptance-not-required line (Step 4)" — pass the flag.
- "Acceptance ticking IS required for this spec" — do NOT pass the
  flag, and write no acceptance line into Tracking info.

Neither stated (a bare `/aide-create` typed in a session): pass the flag
by default, and omit it when the user creating the spec has said they
want acceptance ticking required.

The default is what the New-spec form's own unticked box used to be
overruled by, so a spec whose author asked for the ticking was created
without it. An instruction always outranks the default.

**A collision you can see is a question to ask, not a dependency to
guess.** Before creating the spec, check whether an open spec already
changes the same files, pages or behaviour. Where one does, ask the user
about the dependency and create the spec with `--depends-on` set the
moment they say yes. Raising it afterwards leaves them to hold one spec
back by hand, which is what the field exists to avoid.

The script creates `<specs-root>/NN-slug/` (or, with `--folder-name`,
`<specs-root>/<name>/` — literally, no number or slug computed) and its
5 files, refuses (non-zero exit, `terminalReason: "refused"`) rather
than overwriting an existing folder at that path, and prints one JSON
line: `{"ok":true,"exitCode":0,"specFolder":"NN-slug","files":[...]}`.
Read `specFolder` and `files` from that line for Steps 5 and 6 below —
do not assume the 5 filenames.

Markdown validation uses `markdownlint-cli2` only when it is installed locally.
Rely on the automatic hook where present; otherwise check for the executable
with `command -v markdownlint-cli2` before running it. If it is unavailable,
report that validation was skipped and continue. Validation must not invoke `npx`
or another package-download fallback. This validation stays a Bash invocation
in the skill, not moved into the script — it already carries none of the
permission-layer ambiguity this change removes, and folding it in would add an
external-tool dependency to a script whose only other dependencies are `bash`
and `jq`, for no reduction in that ambiguity.

### Step 5 of 7: Stage in git

First write `--- Step 5 of 7: Stage in git — started`, and when this step ends, `--- Step 5 of 7: Stage in git — done`.


Working interactively, before staging, run:

```bash
aide-create-spec --stamp-outcome --specs-root "<specs-root>" \
  --folder "<specFolder>" --start-epoch "<the number from Step 1>" \
  --model "<tool> <model>"    # omit --model entirely on the same
                               # certainty rule as the commit message
                               # suffix below
```

so `1-description.md`'s own Tracking info carries this phase's `Model`
and `Time spent` the same way the other three phases' files already do
— before the file is staged, so the stamp lands in the same
commit as the rest of the spec. A headless run skips this: `aide-run-spec`
already performs the equivalent stamp itself once the whole run ends,
and running it here too would just be overwritten by that later,
authoritative write.

`git add <specs-root>/<specFolder>/*.md`, using the `specFolder` the
script's JSON reported — the specs root is a working directory the
skill can operate in, whether or not it sits inside the project root.

A headless run gets its commit for free — this session does not run
`git commit` or `git push` itself, headless or not, whatever the
paragraph below says about the interactive case. Working interactively,
commit and push RIGHT AWAY, with this message so the step is recognised
the same way:

```text
Run /aide-create for <spec-folder> (model: <tool> <model>)
```

Do not ask first: the user's request to create the spec was the
approval, and a follow-up question here is how a finished folder sits
staged-but-uncommitted for hours while everyone believes it was queued.
Commit only once the 5 files have actually been
created — nothing to stage means nothing to commit. If origin has moved,
`git pull --rebase` and push again; a push that still fails is reported
out loud, never left silent.

`aide-run-spec` writes `Workflow steps completed:` from the spec's own
commits — leave that line exactly as you found it in the template. The
same script writes this phase's `Model`/`Result`/`Time spent`/`Cost`
block into `1-description.md`'s own Tracking info — leave those lines
alone too, **for a headless run**; an interactive run wrote its own
`Model`/`Time spent` a few lines above, via `--stamp-outcome`, and those
stay exactly as that call left them. `create` is the one stage nobody picks a model for in advance: a spec
is already being written by the time it reaches a dashboard row, so its
model is only ever recorded after the fact, from whatever commit
created the folder.

Add the `(model: ...)` part only when you can name your own model with
certainty. A Claude Code session is told which model it is running in
its own context, so it can write `claude claude-opus-5`; an assistant
that cannot name itself offers the bare subject without the suffix and
never guesses. A user writing `1-description.md` by hand and
committing it under their own message leaves no such commit at all, and
no `Model (create)` line is written — an absence, never a guess.

### Step 6 of 7: Confirm

First write `--- Step 6 of 7: Confirm — started`, and when this step ends, `--- Step 6 of 7: Confirm — done`.

In a headless run nothing of this is on the default branch yet: the
create is finished only once Step 7, the merge into main, is done. So the
report's first line ends `— not finished, the merge into main is next
(Step 7)`, and the report never calls the create done or complete.


Show a summary and the next step, built from Step 4's `specFolder` and
`files` — not assumed. Never preview the composed description text
(Problem, or any Acceptance criteria section) in the chat; the file list
below is the whole summary. When an Acceptance criteria section was
written, say so explicitly and note that reading it through — and
editing it, in the dashboard or directly in the repo — is the user's
responsibility before `/aide-analyze` runs.

```text
Task created: 55-clean-up-console-log

Files created:
- specs/55-clean-up-console-log/0-README.md
- specs/55-clean-up-console-log/1-description.md (filled in)
- specs/55-clean-up-console-log/2-analysis.md (ready for analysis)
- specs/55-clean-up-console-log/3-solution.md (ready for solution)
- specs/55-clean-up-console-log/4-status.md (ready for status)

Next step: /aide-analyze 55
```

### Step 7 of 7: Merge into main

Aide writes `--- Step 7 of 7: Merge into main — started` itself, after this session, and ends it `— done` or `— stopped: <why>`.

Not this session's step, and it writes no mark for it. In a headless
run Aide merges what this session committed on the spec's branch into
the default branch once the session has ended, and the create is finished
when that merge is, not before. Working interactively there is no such
step: the steps above say what reaches the default branch.

IMPORTANT:
- Follow the workflows rules - Phase 1: Create document structure
- Follow the spec structure for the file layout
- Code blocks ALWAYS end with just ` ``` ` — NEVER ` ```text ` as the closing fence

---

## Next step

```text
/aide-analyze 55              # the spec's number
```
