Skip to content

/to-spec

Capture load-bearing technical decisions into a standalone `.task/spec/<slug>.md` — Decision/Rationale/Constrains sections cited via `Spec:`.

From plugin
78 skills8 agents
shell
$ npx -y skills add SpaiR/task-pipeline --skill to-spec --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.
  • You can call itInvoke it directly when you want it.
  • Slash command/to-spec
How auto-invocation works

Context preview

The summary Claude sees to decide when to auto-load this skill.

Capture load-bearing technical decisions into a standalone `.task/spec/<slug>.md` — Decision/Rationale/Constrains sections cited via `Spec:`.

SKILL.md

to-spec.SKILL.md
name: to-spec
description: 'Capture load-bearing technical decisions into a standalone `.task/spec/<slug>.md` — Decision/Rationale/Constrains sections cited via `Spec:`.'
disable-model-invocation: true
user-invocable: true

Fix **load-bearing technical decisions** — a protocol, a cross-cutting data shape, a "we picked X over Y because…" whose reasoning wouldn't survive re-derivation — into `.task/spec/<slug>.md`. Unlike `to-task` / `to-plan` / `to-roadmap`, a spec does not decompose work; it pins the decisions that work must honor. A task or roadmap references it via a `Spec: <slug>` header, and the executing session reads it as a fixed anchor (per the `## Execution` block). One spec may be cited by many tasks and roadmaps, and can be captured before any exist.

**Input:** `$ARGUMENTS` — a rough description of the decision area, or a reference back to a prior discussion in this conversation ("write a spec from what we settled").

**Format contract:** [docs/contract.md § Spec file format](../../docs/contract.md#spec-file-format-taskspecslugmd) is the single source of truth for the output structure. This file describes the authoring flow that produces it.

Instructions

Step 0: Config gate

Resolve the pipeline root first, then validate:

source "${CLAUDE_PLUGIN_ROOT}/skills/_lib/resolve-ws.sh"   # exports AI_DIR
bash "${CLAUDE_PLUGIN_ROOT}/skills/validate/validate.sh" all

**Every artifact path in this skill is under that resolved `$AI_DIR`, never the cwd** — `.task/spec/<slug>.md` below is shorthand for `$AI_DIR/spec/<slug>.md`. A cwd-relative write from a subdirectory or a linked worktree would create a second `.task/` that `validate.sh` (which resolves `$AI_DIR` itself) never sees.

  • **`config.md not found`** → `/task:to-spec` is intake-capable: run the inline setup gate exactly as `skills/to-task/SKILL.md` Step 0 does (detect stack → one `AskUserQuestion` confirmation, Accept / Edit / Decline chips → write `config.md` + `git config --local task.root` + exclude `.task`), then re-run `validate.sh all`. If config is now present → continue. If the user declined setup → report "`config.md` not written — nothing was created. If the detected language or testing policy looked wrong, re-run and pick **Edit** to change them before the write. → Next: `/task:to-spec`" and **stop**.
  • **Exit 1** (one or more *existing* artifacts fail validation) → surface the validator output, but **do not block**: those errors are pre-existing files, not the spec you're about to write (mirrors `to-task` Step 0 and `roadmap-to-workflow`, and `validate.sh` is advisory, never config-malformed — it doesn't inspect `config.md` content). Only a missing `config.md` (exit 2, handled above) hard-stops.

Preconditions

  • **No real decision to pin.** If the discussion settled no load-bearing technical decision — only behavioral outcomes, or details local to one task → **stop and suggest** `/task:to-task` or `/task:to-plan` instead. Say plainly that nothing was written, and carry **both** options in the footer with the reason: "Nothing here is a cross-task technical anchor — these are outcomes local to one task. Nothing was written. `→ Next: \`/task:to-plan\` to capture it with a plan, or \`/task:to-task\` for the what-and-why only.`"

(The slug-collision check runs at save time, once the slug is derived — see Step 4.)

Step 1: Load context

Read `.task/config/config.md` (Language, conventions), `CLAUDE.md` if present, and list `.task/spec/*` — match existing structural style and avoid duplicating a decision an existing spec already pins. List the `docs/` top level and skim entry points if any exist. Open source files only as far as needed to state a decision accurately — this is decision capture, not implementation.

Step 2: Cold start or harvest

**Branch first.** The file is written from decisions settled here — where they come from matters:

  • **Harvest** — the conversation, *before* this call, already settled concrete technical decisions. Tells: "write a spec from what we settled", or `$ARGUMENTS` reads as a handle for prior discussion. → Go to Step 2H.
  • **Cold start** — a rough decision area with no prior discussion. → Go to Step 2C.

On the fence, prefer harvest — a false positive costs one extra recap the user skims; a false negative silently drops reasoning.

Step 2H: Harvest — Decision Inventory

Comb the prior conversation and print, as message text in your reply (chat-only, never written to a file; heading skeleton English, prose in config language):

## Spec — Decision Inventory

{Writing this spec from our discussion — here is every technical decision
I captured with its load-bearing reasoning. Say so if a line is wrong.}

### Decisions locked so far
1. {decision at full specificity} — because {the load-bearing reason}
2. {...}

### Open forks (not yet decided)
- {unresolved technical question}

### Coverage caveat
{Only if part of the discussion is out of context. Omit otherwise.}

This inventory is a **recap** of decisions (with their reasoning) the user already reached in the discussion: print it, no confirmation chip. Then proceed — if open forks remain, resolve them first, then go to Step 3 (draft). If the recap misreads, drops, or misstates a decision or its rationale, the user says so in chat — correct it and reprint before drafting.

Step 2C: Cold start — decide the forks

For a decision area with no prior discussion, work each fork with the user before drafting. For each load-bearing choice, lay out the real options with a recommendation:

## Spec — Round 1

### Decision area as I understand it
{2–4 sentences.}

### Fork: {the choice to make}
**A) {option}** — {sketch}. Pros / Cons: {...}
**B) {alternative}** — {sketch}. Pros / Cons: {...}

### My recommendation
{a real opinion, not a hedge}

### What I need from you
{One focused question on the most load-bearing fork.}

Offer ≥2 options per fork (or justify why only one is viable). A r

Read more
Read it on GitHub ↗

Showing the first part of this file.

Ships withtask

Docs & guides → spair.github.io/task-pipeline A plan file is only as good as the argument that produced it. That second line is where projects quietly go wrong: the model agrees and starts building before the plan was ever argued.

Get the whole plugin, auto-invoked
Stats
7
Stars
0
Views
0
Forks
Active
Maintenance
Shell
Language
MIT
License
8h ago
Last commit
1mo ago
Created

Repo: SpaiR/task-pipeline