Spec
Upstream planning-discipline — brainstorm a feature into spec.md + plan.md under .agent/plans/<slug>/, then route to plan approval. Enforced by the spec-gate tool boundary, not prompt coercion. NOT for trivial/test/doc-only edits (the gate scopes those out), and NOT for executing an already-approved plan (that is /supervise).From its SKILL.md
npx -y skills add joymin5655/Agent --skill specAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
8.4 KB, as published. Nobody here has run it
/spec
Goal
Turn a fuzzy request into two committed artifacts — a spec (what/why) and a
plan (how, in waves) — before any implementation edit, then hand the plan to
the user for approval. Approval is what unlocks editing: plan-gate.py writes the
plan-approval flag, and spec-gate.py (a PreToolUse gate) stops asking once that
flag exists.
This skill supplies the methodology; the enforcement is a tool boundary. You
cannot prompt your way past spec-gate — you produce the artifacts and get the
plan approved, or you flip the mode. That separation is the point.
Steps
1. Brainstorm
Explore the request before committing to a shape:
a. Restate the request in one sentence and name the success criterion. b. Surface the 2-3 plausible approaches and the tradeoff between them; pick one and say why. If the request is ambiguous, ask — don't guess. c. List what's explicitly out of scope (prevents scope creep later).
--interview — opt-in deep-interview submode
The default brainstorm is a single pass. /spec <slug> --interview replaces
step 1b's one-shot "ask if ambiguous" with a structured question loop for
requests fuzzy enough that a wrong guess commits the whole spec to the wrong
shape. It is opt-in by design: simple requests keep the single pass, and the
enforcement story is untouched — the spec-gate tool boundary neither knows nor
cares which submode produced the artifacts.
- Unknowns table. List every unknown in the request; mark each decision-changing (Y/N) — would different answers produce different specs? N-unknowns are implementation details; leave them to the plan.
- Batch-question the Y rows only — at most 4 questions per round, each naming the options and your recommended default.
- Re-score after the answers. Answers resolve rows and surface new unknowns; add those to the table and mark them Y/N. This is the decision-tree pruning: each round should shrink the Y set.
- Terminate on either condition (whichever comes first):
- the table has zero open decision-changing unknowns, or
- 3 rounds have run.
Unresolved rows carry into
spec.mdunder## Open questions— named and deferred beats silently guessed.
The interview's Q/A trail is recorded in spec.md under ## Interview log
(one line per question: the question, the answer, the decision it settled),
so the spec shows why it has its shape, not just the shape.
--score-candidates — opt-in candidate-scoring submode
Step 1b picks an approach in prose. When the harder question is which problem
or approach to commit to — a wide field where the pick should be earned, not
asserted — /spec <slug> --score-candidates replaces 1b's one-line "pick one
and say why" with an explicit numeric pass. Like --interview, it is opt-in and
touches only the brainstorm; the spec-gate boundary is indifferent to it.
- List the candidates. Enumerate the plausible problems/approaches — the field before pruning (the reference workflow scored 18, kept 3). A field of one means you don't need this submode.
- Name the dimensions. 3–5 criteria that actually discriminate (e.g.
impact, effort, risk, fit). Reuse the repo's scoring idiom — each
dimension scored 0–5, aggregated per candidate — rather than coining a new
scale (
docs/scoring-convention.md,core/infra/supervisor-goal-audit.sh). - Score and rank. Build a candidates × dimensions table, aggregate, and take the top-K (usually K=1, sometimes a short list the plan sequences). The score ranks; it never gates — a low-scoring candidate is dropped by judgment, not auto-rejected by a threshold.
- Record the winner and the cut. The chosen candidate becomes step 1b's pick; the runners-up and why they lost are the audit trail.
The scoring table is recorded in spec.md under ## Candidate scoring, so the
spec shows the field it chose from, not just the choice.
2. Write spec.md
Pick a short kebab-case <slug> and write .agent/plans/<slug>/spec.md:
# <slug> — spec
## Problem
<the one-sentence problem + why it matters>
## Success criteria
- <falsifiable, checkable outcomes>
## Approach
<the chosen approach + the tradeoff rejected>
## Out of scope
- <explicitly deferred>
## Candidate scoring <!-- --score-candidates runs only -->
| candidate | <dim1> | <dim2> | <dim3> | total | verdict |
|---|---|---|---|---|---|
| <winner> | 5 | 4 | 5 | 14 | chosen |
| <runner-up> | 3 | 5 | 2 | 10 | cut: <why> |
## Interview log <!-- --interview runs only -->
- Q: <question> → A: <answer> → settled: <the decision it fixed>
## Open questions <!-- --interview runs only -->
- <unresolved decision-changing unknown, carried, with its default>
The trailing sections are submode-specific — ## Candidate scoring on
--score-candidates runs, ## Interview log / ## Open questions on
--interview runs; a single-pass spec omits them.
3. Write plan.md
Write .agent/plans/<slug>/plan.md as ordered waves — the shape /supervise
consumes:
# <slug> — plan
## Wave 1: <name>
- <step> → verify: <check>
## Wave 2: <name>
- <step> → verify: <check>
Every step names its verification. A plan whose steps aren't checkable isn't done.
Default each → verify: to an executable check — a command whose exit code
decides (bash core/tests/<battery>.sh, grep -q <artifact>); prose
verification is allowed only with a stated reason why no command can check it.
4. Route to approval
Present the plan to the user and exit plan mode (ExitPlanMode). User approval
is what triggers plan-gate.py to write /tmp/agent-plan-approved. From that
point spec-gate allows edits for the rest of the session (the flag is the dedup —
approve once, not per-edit). SessionStart/Stop clear the flag, so each new session
starts unapproved.
This skill is complete when spec.md and plan.md both exist under
.agent/plans/<slug>/ and the plan has been routed through ExitPlanMode —
approval itself is the user's move, not yours.
Enforcement — the tool boundary, not prompt coercion
core/hooks/spec-gate.py runs on every Write|Edit|MultiEdit. When no plan is
approved this session and the target is substantive impl code (matches the scope
regex, not a test/type/config/doc/meta file, not a risk area), it acts:
AGENT_SPEC_GATE_MODE | Behavior |
|---|---|
off | Gate disabled — no-op. |
dryrun (default) | Logs the verdict to .agent/logs/spec-gate.jsonl; advisory only, never stops an edit. |
block | Emits permissionDecision: "ask" — surfaces the missing plan; the user approves to proceed or dispatches this skill. |
Deny vs ask. The gate uses ask, not deny. A planning-discipline gate is
reversible — the edit isn't destructive and the escape is trivial — so ask (the
harness default for reversible gates) is more defensible than a hard deny, and it
de-risks a false positive by leaving the user in control.
Escapes
Two, both named in the gate's own reason message:
- Approve a plan via ExitPlanMode (this skill's normal path) → the flag is written and edits are allowed for the session.
- Set
AGENT_SPEC_GATE_MODE=off→ disable the gate entirely.
Hard rules
- Spec and plan before impl. The artifacts come first; editing is what they unlock.
- Never hand-write the approval flag. It's written by
plan-gate.pyon real approval — forging it defeats the gate. - The scope is substantive impl code only. Tests, types, config, docs, and
.agent/meta are out of scope by design; risk-area paths defer to their own hooks. Don't widen the gate to nag on trivial edits.