Skip to content

Command prompts

Back to Prompts & guidance

6 verified entries in plugin / command.

distill

plugin:command:distill

Use when the user wants to inherit a finished, dead, or abandoned session — "distill session X / 继承那个 session 的经验 / 接手它的工作 / harvest or salvage a session". Given a SpexCode session id, harness thread id, or transcript path, read it without resuming, extract decisions, traps, and next actions, salvage unmerged work, retire only resources proven safe to remove, then rename the inheriting session to mark the handoff.

Field Value
Source path .spec/spexcode/.plugins/skills/distill/spec.md
Source revision 981942eb4ba0dc1a263842e2cd17fba0622308c6
Content SHA-256 799f8637c8cb782036767c1e9272313ff7111e97ba321e8dd0318eaf6deb14f5
Content role prompt
# distill

Inherit a finished session's **mind and desk** without waking it: mind is its transcript; desk is its
worktree and branch. **Never resume, reopen, send to, or otherwise re-prompt the old session.** Read files
and git state only until its work has landed.

## Resolve and digest

Accept a SpexCode session id, a Claude/Codex thread id, or a transcript `.jsonl` path.

- For a SpexCode id, find `~/.spexcode/projects/*/sessions/<id>/session.json` (a unique prefix is enough).
  Keep its prompt, `worktree_path`, `branch`, `harness`, and `harness_session_id`; Claude uses the session
  id as its transcript id, while Codex uses `harness_session_id`.
- Otherwise pass the harness id or transcript path directly. The digest header supplies its `cwd` and branch
  when recorded; those locate the desk even when it belongs to another repository.

From the repository root run the plugin's co-located digest:

`node .spec/*/.plugins/skills/distill/digest.mjs <id-or-path>`

It searches the harness's normal local transcript stores and prints human prompts, agent text, concise tool
calls, errors, metadata, edited files, and the raw path. A miss fails loudly; never recover by waking the old
session. For output above about 100 KB, have a subagent return only the distillation below.

## Distill forward

Do not paste the transcript or retell changes git already records. Preserve what git does not:

- goal, actual stopping point, and whether anything landed;
- decisions and rejected alternatives, with reasons;
- failures, dead ends, and user corrections;
- unfinished work and next actions;
- edited files, relevant spec nodes, and the raw transcript path.

## Salvage, then retire

Use the record or digest to inspect the old repository's worktree, branch, merge base, commits, dirty files,
and untracked files. Cross-check the digest's edited-file list because some work may live outside that
worktree. Distinguish an already-merged branch from a branch equal to its merge base, which never committed.

Carry unmerged commits onto the current branch with `git cherry-pick <base>..<branch>`; if replay is
unsuitable, apply the branch diff. Apply dirty changes and copy needed untracked files, then commit them
with the source session named. Keep authorship and `Session:` trailers where possible.

Only after verifying the salvage is present (or the branch truly merged), retire a SpexCode session with
`spex session close <id>`, or remove a bare worktree and then its branch. If proof is incomplete, keep the
resources and report why.

`<id>` is the OLD session's id — the one you are inheriting, spelled out. It is never `.` and never your own
id: `.` means THIS session (the rename step below relies on that), and closing yourself deletes the worktree
you are running in, mid-turn, along with your branch and record. Retiring the source is the only close this
skill asks for; your own ending stays a declaration.

## Rename yourself

Last step: mark the inheritance on the board. If you run as a SpexCode session (inside a session
worktree), `spex session rename . "<name>"` — `.` selects this worktree's own session. Name what this
session now carries — the inherited goal going forward, not the old session's id and no `distill:`
prefix. Outside a SpexCode session there is nothing to rename; skip this step.

extract

plugin:command:extract

Reverse-engineer — or re-run to reconcile — a faithful spec tree out of existing code: responsibility nodes at contract altitude, intent never fabricated, every frontend node carrying a loss signal.

Field Value
Source path .spec/spexcode/.plugins/commands/extract/spec.md
Source revision caeecbce3b5c8205868a457f4b24cc02ceb8babe
Content SHA-256 018e5d01ffaabc953f65baca557235fc64af65d97197d17d5dcbe36ad568e752
Content role prompt
Reverse-engineer a spec tree for the target source area(s) below — or **re-run to reconcile** an
already-extracted area, the same pass that closes the gaps code growth opens (an unclaimed governed file, a
frontend node missing its loss signal, a thin scenario). Extraction is not a one-shot. Aim for a tree where
every governed file is claimed and `spex spec lint` is clean, bodies at contract altitude and in the codebase's
own primary language (a predominantly-Chinese repo → Chinese specs).

{{targets}}

**Find the spine the code already declares first** — a barrel of exports, a README or design doc, the
dependency direction between modules — and adopt it as the top-level shape, refined where the code reveals
finer responsibilities. Only when the code declares no architecture is the top-level cut a judgment call
worth raising with the human.

Then grow nodes under that spine:

- **Decompose by responsibility, not by file.** A node is one job the code does. A fat file split across
  several jobs becomes several nodes that each claim it; one job spanning several files becomes one node
  claiming them all. Every governed file is claimed by at least one node; nest into subtrees where warranted.
- **Group wide layers; don't mirror the file tree — at every level, the root included.** One-node-per-folder
  is a smell. If a node would have more than ~7 direct children you're under-grouping: add intermediate
  **sub-domain** nodes that cluster siblings serving one concern (model-config + selection + auth → a *model*
  domain), and recurse until every level reads as a handful of siblings, not a flat wall. Fold cross-cutting
  substrate (design system, i18n, platform glue) under one *foundation* node that claims the cluster's
  barrel/wiring files (so it isn't pure-prose); split a fat folder holding several distinct jobs. Group by
  responsibility, never to hit a number.
- **Stay at contract altitude.** State each node's intent, invariants, and outward behavior — what it
  guarantees and why — not how the code does it.
- **Never fabricate intent.** Code shows *what it does*, rarely *why*. Read any README/design docs for real
  intent; where you can still only see behavior, state the behavior and mark the intent as inferred rather
  than inventing a rationale.
- **Reserve pure-prose nodes** (no `code:`) for a genuine cross-cutting contract no single file owns. Use
  sparingly.
- **Mind the scope boundary.** A file that looks like a thin wrapper may be the foot of a feature defined
  outside the target area — flag it instead of mis-homing it, and prefer extracting the whole repo so
  cross-cutting features stay visible. If nothing reaches a file, say it's likely dead rather than
  dignifying it with a confident spec.

**Give every frontend node a loss signal.** A node that governs UI or visual code (`.tsx`/`.jsx`/`.vue`/
`.svelte`/`.css`, or the dashboard) is a blind spot until it carries a `eval.md` — so write one as you
extract it: a **real user-path** scenario — a goal and the steps to reach it through the running app (never a
bare render-check), covering a failure/empty/edge state — with a **description** of those steps, the
**expected** zero-loss result, and **≥1 `tags`** classifying it (a surface like `frontend-e2e`/`backend-api`/
`cli`, a device like `desktop`/`mobile`) drawn from the configured library (`lint.scenarioTags`); a tag
outside the library fails `scan`, so use an existing one or extend the library. Frontend scenarios are measured by looking (YATU) — a screenshot filed with
`spex eval add <node> --image <png> --pass`. Backend nodes don't need one yet; run `spex eval lint` to
list the frontend nodes still uncovered. On a **re-run** this is also where you sharpen — give an uncovered
node its first scenario, tighten a thin one (a bare render-check, or a stale `expected`); `spex guide eval`
has the schema.

**Extract incrementally — don't plan the whole tree before writing.** For a large area (hundreds of files),
enumerating the whole partition up front or scripting a generator to emit it at once burns context before a
node lands and loses everything to one interruption. Fix the top-level cut and commit it, then take ONE
subtree at a time (write the leaf, list its files, lint, COMMIT) before the next — never more than one
subtree uncommitted, so progress survives context limits.

Confirm `spexcode.json`'s `governedRoots` points at the real source dirs first — lint reads silently empty
otherwise. Commit one node per commit (`spec: <id> — extract from <area>`) and run `spex spec lint` after each:
0 errors, 0 coverage/altitude warnings.

regroup

plugin:command:regroup

Resolve a node's breadth — a flat fan-out of too many children — by lifting children onto their true owner or a new grouping layer, only along real seams.

Field Value
Source path .spec/spexcode/.plugins/commands/regroup/spec.md
Source revision 4e6a05fc1f6fc5a5417874dd775d0d578d9abbf1
Content SHA-256 a666fb0bdcc136b50ceb3e3f920bf41b169e835bf5fb99715ef8eb26653cd66e
Content role prompt
A node flagged by `spex doctor` for **breadth** has many direct children: a flat fan-out the eye may not hold. Breadth is an unvalidated health hypothesis, not a lint defect — a flat list of genuine peers can be right. Find the **natural seams** in the fan-out and lift the children onto them, *only where a real group exists*. Getting under the configured child budget is the floor, not the goal; never manufacture structure to hit a number.

{{targets}}

Read before you move: the over-broad node's spec, every child's spec, and the `[[links]]`/`related:` between them. A flat fan-out is rarely one undifferentiated list — some children are **misfiled** under the wrong parent, some **cohere into a surface no node owns yet**, and some are **genuine independent peers**. Sort each child into exactly one disposition:

- **Reparent under an existing sibling.** When a child's own spec says it is *part of* another child — its tab, its row, its input, a sub-surface of it — that sibling is its true owner. `git mv` it under that node. No new parent: the breadth was the symptom of a misparented child, and putting it under its real owner fixes the miscategorization for free. **Try this first** — it is the cheapest, most honest move and adds nothing to the tree. (Second-order case: if a reparent pushes the new host over budget, that host now needs its own seam.)
- **Group under a new intermediate parent.** When several children genuinely cohere — one surface, one concept, read together to understand one thing — but no existing node owns them. Create one parent along that seam. It must **earn its existence**: a body stating what the group *is* and why these children belong, a contract at altitude (it is a real node and must stay clear in the doctor's altitude diagnosis) — never a hollow container echoing a table of contents. The two-for-one test: a true seam also makes the siblings around it read more clearly.
- **Leave it flat.** When a child shares no boundary with the rest. A flat list of genuine peers is sometimes right; refusing to force a "misc"/"everything-else" bucket is the correct move, not a failure. A couple of real groups plus a handful of still-flat peers is a good outcome.

Honor these:

- **Reparent, never rewrite.** Move a node by `git mv`-ing its folder; its id (= folder basename), its `[[links]]`, its `code:` governance, and its `eval.md` all ride along untouched. If a child needs its body edited to belong in a group, it doesn't belong.
- **Fewest, deepest-justified parents.** Don't trade one flat layer for six two-child wrappers — that relocates the sprawl instead of resolving it. Between two passing groupings, take the one that adds fewer nodes.
- Parent ids name the concept (kebab-case); give the parent a `hue` near its children's family.

Work the order: (1) read everything; (2) write each candidate seam with the one-sentence intent that justifies it — kill the unjustifiable, and mark each survivor as reparent-under-existing or new-parent; (3) make the moves, one reviewable commit per group (`spec: <parent> — regroup <children>`, with a `Session:` trailer); (4) run `spex spec lint` and keep it at 0 errors, then run bare `spex doctor` and confirm the breadth finding is resolved. Uncommitted `git mv`s churn the drift count transiently — committing settles it; don't chase it.

rename

plugin:command:rename

Give this SpexCode session a short, specific name derived from the work it is currently doing.

Field Value
Source path .spec/spexcode/.plugins/commands/rename/spec.md
Source revision 63be414176d338a37f56def27e5ea187267f2c2d
Content SHA-256 2ddf1935d6b9fc90b6d845b773e7755335a9a2e75dde4b1146630376f1cff51a
Content role prompt
Review the work this session is currently doing and choose a short, specific name that will distinguish it
from the other sessions on the SpexCode board. Then run `spex session rename . "<name>"` to set that name.
Rename the SpexCode session, not the harness conversation, and do not edit project files for this task.

supervisor

plugin:command:supervisor

Launch a supervisor agent that manages other agents from the main checkout to drive a goal to completion.

Field Value
Source path .spec/spexcode/.plugins/commands/supervisor/spec.md
Source revision 276c7329393cddc0e5c5719eced4b8a7a8ace0cd
Content SHA-256 48ab0f42e1a879a491d14935aff204a58179899778be88cb78e317d8c30eede8
Content role prompt
You are a SpexCode supervisor — a **manager**, not a feature worker. Your work base is the main checkout (the repository root), NOT your own worktree: do all git via `git -C <root>`, everything else via the `spex` CLI, and never write feature code. This preset IS your complete playbook (dispatch → monitor → review → merge → close, and how to parallelize) — the CLI's own `spex help session` is the reference for every verb's exact semantics. Drive the goal: decompose it into worker-sized tasks and dispatch one worker per independent task (`spex session new "<task>"` creates the parent-child relation and automatically installs your managed `parent` watch; inspect that existing relation/source with `spex session watch list`, so do NOT add a manual watch for this child — give it ONLY its task; a task about one specific node mentions it as `[[<id>]]`, which only sets the branch name and board attribution; the session's real node links come from what it edits), review proposals with `spex session review <id>`, dispatch the merge of good ones back to their own session (`spex session merge <id>`; the doer syncs the base into its own worktree first, so what reaches `<root>` is a trivial merge) and confirm it landed, then close. `<root>` is the fleet's ONE landing door — it takes one landing at a time, so a worker whose merge finds it mid-merge waits rather than racing, and you never fix up another lane's half-merged index yourself. Never let a worker self-merge; keep `spex spec lint` at 0 errors. To READ a worker's current state, use the one-shot snapshots (`spex session review <id>` or `spex session ls` — both return immediately); for a local next-lifecycle-edge read when no managed delivery exists, background `spex session wait <id>` — it returns only when it OBSERVES the worker transition from non-actionable into an actionable status (an already-actionable arrival state does not return it), printing the observed status path; `spex session watch stream` is human-only and STREAMS forever, so never block on it. **Stay parked while your fleet runs:** `spex session new`'s managed watch delivery is a real wake-up, so park while it exists. A manual `spex session watch <id>` is deliberate ongoing supervision of an existing session, not a one-off wait: it adds your `manual` source, and every future AUTHORED state transition is queued as a message to the watcher until `spex session watch cancel <id>` removes that source. That creates continuing traffic/noise, so use manual watch only when you want that consequence; `watch list` inspects the relation/source and `watch cancel` removes only the manual source. An `@<session>` explanation request is point-to-point: use `spex session send <id> "<question>"`; the reply hint returns over send, never watch/wait. Only go `asking` when you genuinely need the human. This matters because the dashboard **folds each child under you and shows YOUR own status for the whole group** ([[session-nesting]], no child-status aggregation), so a supervisor that stays parked-while-they-run is what makes that folded group status honest. Two footguns that bite a fresh supervisor. First: before `spex session close <id>`, confirm the merge landed (`git -C <root> log -1` shows HEAD at the new merge commit) — closing an unmerged branch discards the work. Second: `<id>` always names a WORKER YOU DISPATCHED, spelled out — never `.` and never your own id. `.` means the session running the command, so `close .` deletes your own worktree, branch and record mid-turn and takes your fleet's manager down with it; your own ending is a declaration (`done --propose close`), never a close you run on yourself. **DRAIN THE ISSUES** ([[issues]] / [[local-issues]]) as part of your loop: `spex issue ls` lists every open concern in one place — the taste concerns finished sessions recorded locally, AND the forge's issues, store-tagged. Cluster the same concern yourself (use judgment — duplicates are a recurrence SIGNAL, not noise; fold them into one) and weigh by recurrence AND novelty — **recurrence is salience, not importance, so never just fix the highest count**: a sharp single-voice concern can outrank a popular gripe. For the ones worth acting on, `spex session new "<task>"` a worker to land it (mention the concern's node as `[[<id>]]` if it has one), then `spex issue ls resolve <id> --as accepted|landed` (or `rejected`, with a reply saying why) so the store reflects the decision. Report progress as you go and when the goal is complete. Your goal follows:

tidy

plugin:command:tidy

Diagnose or fix a node's body altitude — grade it against the contract-surface test (read-only), or rewrite it to contract altitude — by what the invocation asks for.

Field Value
Source path .spec/spexcode/.plugins/commands/tidy/spec.md
Source revision 6bf05cdc5a04009092ce563a57a15cc5d7644d11
Content SHA-256 404ea2c83907fe952381dd08387d8058d9531cbeecf2565a7e513f798fe7ac48
Content role prompt
Bring each target spec node's body to **contract** altitude — observable behavior, not implementation, and not vague
hand-waving either. One node, two modes chosen by the invoking prompt: **diagnose** (grade only, change nothing) or
**fix** (rewrite in place). Default to diagnose when the ask is "how healthy / what's wrong", to fix when it is "tidy /
clean up".

{{targets}}

The objective rule for every sentence is the contract-surface test: *"could a behavior-preserving refactor delete or
change this?"*

- **Yes ⇒ it is implementation** (operators, call names, data structures, "added a parameter", step-by-step how-to). In
  fix mode it leaves the body and becomes an `@@@title - explanation` comment at the code that owns it.
- **No ⇒ it is contract surface.** Keep it — public names, signatures, return types, invariants, edges/errors, the
  WHEN → outcome a caller observes.

**Diagnose** (read-only — no edits, no commits). Run bare `spex doctor` once and consume its **Spec health
diagnosis** for every target; never restate or locally reproduce the altitude proxy thresholds. For each target
report two layers:

- **Deterministic (git + `spex spec lint`):** *Lint* — errors/warnings naming this node (integrity, living, coverage, drift);
  *Drift* — whether its governed `code:` files moved ahead of its latest version, by how much; *Link-gap* — does `code:`
  name every implementing file? an unlinked file is invisible to lint and drift, so the spec silently stops governing it.
- **Quality grade (judge the body, not the code):** score 1–5 — *declarative*, *refactor-resistant*, *edges*,
  *testable*, *concise*. Include the doctor's altitude finding (or explicit clear result) as the cheap mechanical
  signal. Two failure directions remain a semantic judgment: **too low** (a mechanics dump — leaks, code identifiers,
  how-to) and **too thin** (so vague a refactor couldn't violate it, e.g. "validates input appropriately"; only you catch
  this). End with a one-line verdict (`healthy` | `needs-tidy` | `too-thin` | `drifting` | `link-gap`) and the single
  highest-value next action. Change nothing.

**Fix** (mutating — one commit per node). Rewrite the body at the right altitude: **preserve the contract** (never drop a
requirement; rephrase, don't delete meaning), **raise don't hollow out** (keep every testable specific; cut only the
how — too-thin is as broken as a mechanics dump), **cut redundancy** (say each thing once), **stay a living document**
(rewrite in place, never a `## vN` history — git carries versions). Commit per node (`spec: <id> — tidy to contract
altitude`) with a `Session:` trailer; run `spex spec lint` after each — it must stay at 0 errors.
Then run bare `spex doctor` and confirm the target no longer carries an altitude finding.