speckit-companion-plan
Companion plan — implementation plan with research & design artifacts
Instalar com Codex ou Claude Copie este prompt, cole no Codex, Claude ou outro assistente e deixe que ele revise a página da skill e instale para você.
Menu
Companion plan — implementation plan with research & design artifacts
Instalar com Codex ou Claude Copie este prompt, cole no Codex, Claude ou outro assistente e deixe que ele revise a página da skill e instale para você.
Baseado na classificação ocupacional SOC
Perform a non-destructive cross-artifact consistency and quality analysis
Identify underspecified areas in the current feature spec by asking up
Companion implement — execute tasks.md in dependency order, then mark complete
Mark the active spec completed — the Companion workflow's terminal step (writes status: completed)
Companion specify — spec.md with prioritized user stories
Companion tasks — user-story phased task list
| name | speckit-companion-plan |
| description | Companion plan — implementation plan with research & design artifacts |
| compatibility | Requires spec-kit project structure with .specify/ directory |
| metadata | {"author":"github-spec-kit","source":"companion:commands/speckit.companion.plan.md"} |
$ARGUMENTS
Companion runs on top of stock spec-kit, so a project's installed spec-kit extensions (git, and any others registered in .specify/extensions.yml) must still fire on a Companion run exactly as they do on a stock /speckit.* run. This is separate from Companion's own node-hooks (.specify/companion.yml): both fire. Like the rest of the pipeline, checking these hooks must never fail the host command — if anything is missing or malformed, skip silently and continue.
Let <step> be this command's phase: specify, plan, tasks, or implement.
Before-hooks — run these now, before any of the work below.
.specify/extensions.yml exists in the project root. If it does not, skip silently — there are no hooks.hooks.before_<step>. If the YAML cannot be parsed, skip hook checking silently and continue normally.enabled is explicitly false. A hook with no enabled field is enabled by default.condition expression yourself: a hook with no condition (or a null/empty one) is executable; a hook with a non-empty condition is left to the HookExecutor — skip it here.optional flag:
optional: true):
## Extension Hooks
**Optional Pre-Hook**: {extension}
Command: `/{command}`
Description: {description}
Prompt: {prompt}
To execute: `/{command}`
optional: false):
## Extension Hooks
**Automatic Pre-Hook**: {extension}
Executing: `/{command}`
EXECUTE_COMMAND: {command}
Wait for the result of the hook command before proceeding to the Outline.
After-hooks — run these once this command's work is fully reported, before handing off.
.specify/extensions.yml; if absent or unparseable, skip silently. Look under hooks.after_<step>, applying the same enabled / condition filtering as above.optional: true):
## Extension Hooks
**Optional Hook**: {extension}
Command: `/{command}`
Description: {description}
Prompt: {prompt}
To execute: `/{command}`
optional: false):
## Extension Hooks
**Automatic Hook**: {extension}
Executing: `/{command}`
EXECUTE_COMMAND: {command}
For specify, branch creation is normally one of these before_specify hooks (the git extension); spec directory and file creation are always handled by the command body itself.
Produce an implementation plan and its design artifacts in phases: load context → write plan.md (Summary, Constitution Check, Project Structure) → Phase 0 research → Phase 1 design (data model, contracts).
Right-size this plan to the change. Before anything else, read the recorded size from the spec's context — .spec-context.json → the size field (treat a missing value as normal). That size sets the budget for the steps below; apply it to them, omitting anything it says to skip.
normal or oversized — produce the full plan and every design artifact exactly as the steps describe. No trimming.simple — a small change does not need the full ceremony. Produce a lean plan:
plan.md: keep the Summary only. Skip the Project Structure section (the task list already names every file) and skip the Constitution Check unless there is a real violation to flag.data-model.md — fold the one or two types into the plan's prose.plan.md (a few Decision/why lines), not a separate research.md, unless a decision genuinely needs its own page.contracts/ only if the feature exposes an interface a consumer or test codes against.This budget governs every step that follows. Where a later step would produce something the budget skips, omit it — do not produce it and then delete it.
Read .specify/feature.json for the feature directory; load <feature_directory>/spec.md and .specify/memory/constitution.md if present — the inputs the plan must satisfy. Then investigate the codebase to understand where this feature attaches: the patterns it must follow (state/store, routing, persistence, component and test conventions) and the exact files it will touch. Read inline by default. The exception worth parallelizing: a large or unfamiliar codebase with several independent areas to map — there, reading is genuinely heavy (each area means opening many files), so when your host has subagents, dispatch one read-only subagent per area in a single message, each returning a distilled finding (the pattern to copy, the concrete file paths, the conventions to match) rather than a dump of file contents. That is the case where a separate worker pays for its startup. For a small or familiar codebase, just read the areas yourself in turn — identical result, less overhead. Collect the findings as the research basis for the plan.
Create <feature_directory>/plan.md with these sections, in order (this is the full, normal/oversized shape — the size budget above governs: at simple size it keeps only the Summary and skips the rest unless genuinely needed). Lead each with prose; reserve inline code for real identifiers (paths, types, packages), not ordinary nouns — a sentence that is mostly code spans is a rewrite.
simple size per the budget — the task list already names every file.)Constitution Check — add a ## Constitution Check section to plan.md as a table: one row per constitution principle with a PASS / justified-violation assessment. This is a gate before Phase 0 research, re-checked after Phase 1 design. If a violation is genuinely necessary, justify it in a short Complexity Tracking table (violation | why needed | simpler alternative rejected). Omit Complexity Tracking when there are no violations; ERROR on an unjustified gate failure.
Phase 0 — Research (first). Write <feature_directory>/research.md before the Phase 1 docs, since they build on its decisions. (The size budget above governs: at simple size, fold the rationale into a short Key Decisions note in plan.md instead of a separate research.md.) For each genuine unknown the plan leaves open — a stack or dependency choice the codebase doesn't already settle, an integration, or a significant design choice — record a short entry as Decision (what you chose) / Rationale (why) / Alternatives considered (what else, and why not). Resolve every NEEDS CLARIFICATION here — this is where a maintainer sees why the design is shaped this way.
Phase 1 — Design & contracts. With research settled, generate the design artifacts the size budget keeps. They are independent documents that share no evolving state, so write them in any order. Inline (one after another) is the default — composing a short design doc is light work that doesn't pay back a separate worker's startup. Only when the documents are genuinely large and your host has subagents is it worth generating them concurrently (one subagent per document); the result is identical either way.
<feature_directory>/data-model.md — the entities this feature introduces or reshapes: fields, relationships, validation rules drawn from the requirements, and any state transitions.<feature_directory>/contracts/ — the interface the feature exposes (API / CLI / schema, or a UI contract listing routes and the identifiers a consumer/test codes against). Copy every identifier from the spec's Verbatim Constraints exactly — never rename, recase, pluralize, or invent an identifier the spec already pinned; those exact strings are the contract. Skip the directory only when the feature exposes no interface at all.
After the documents return, re-check the Constitution Check against the final design.Output: <feature_directory>/plan.md plus research.md, data-model.md, and contracts/ when applicable.
.spec-context.json honestThese rules apply to every Companion profile command. The extension records lifecycle timing with its own scripts wherever it can; these rules keep anything you append consistent with that and accurate for any dispatcher (terminal, IDE chat, or the GUI). The model is finish-only: each task and each substep records a single finish event, and its duration is the gap to the previous finish (or the step's start). Never a start+complete pair for a task or substep — a pair stamped at one instant is what produces 0s ticks and bursts.
Never hand-edit .spec-context.json. Record every finish by running the writer script, never by editing the JSON file yourself — a hand-authored edit is what corrupts the file (a duplicated status key). The script stamps the real clock, writes atomically, and is idempotent. The commands below are the only way you touch timing.
Self-close — but not specify or implement. When your own work for plan, tasks, clarify, or analyze ends, record the step finish (feature dir from .specify/feature.json):
python3 .specify/extensions/companion/scripts/write-context.py --feature-dir <feature_dir> --step <this step> --finish --by ai
--finish appends a single step-level complete and touches nothing else (it leaves status/currentStep to the lifecycle hooks). Do NOT self-close specify or implement: the extension closes those itself (specify from its own command, implement from the end-of-step hook), so an ai complete there would duplicate it.
Substeps — one finish each, via the script. For each substep boundary (plan: research, design; tasks: generate), the moment that substep ends, run:
python3 .specify/extensions/companion/scripts/write-context.py --feature-dir <feature_dir> --step <step> --substep <name> --finish --by ai
One call per substep, each stamped with its own real clock at the moment it finishes — never two substeps in one batch, never a separate start. The delta between consecutive finishes is each substep's duration.
Implement — finishing a task is logging it (finish-only). Recording a task's finish is the closing action of that task, done the instant its work is complete and before you start the next one — not a bookkeeping pass you batch at the end of a phase. The closing action is a single append (feature dir from .specify/feature.json):
python3 .specify/extensions/companion/scripts/write-context.py --feature-dir <feature_dir> --task <TaskID> --kind complete --by ai --did "<one-line summary of what this task did>" --files "<comma,separated,files,touched>" --append
--append writes one line to .spec-context.events.jsonl and does not read or rewrite the shared .spec-context.json, so it never hits the "read the file first" retry and parallel workers can each append their own finish at the same time without contending — the line carries its own real timestamp (date -u is stamped by the script). The --did/--files flags ride along so the Activity panel's Tasks card is populated from the script. Do NOT hand-edit the - [ ] checkbox in tasks.md — the script owns it: materialize flips it to - [x] from your appended finish, so a fanned-out subagent only appends and never touches the shared tasks.md. Do NOT hand-author per-task JSON and do NOT write a per-task start.
Then fold the appended lines into .spec-context.json — run this once per wave (after the wave reconciles) and again when the step ends:
python3 .specify/extensions/companion/scripts/write-context.py --feature-dir <feature_dir> --materialize
--materialize is the one read-modify-write: it folds the finishes into the panel and checks off the matching tasks.md boxes for every journaled task, idempotently (re-folding never double-counts), so running it per wave keeps the GUI current without re-serializing the work. The end-of-step hook is a backstop that materializes anything you didn't fold and fills any task you didn't journal. What's trustworthy here is the per-task summary (did/files) and the order tasks completed, plus the step-level start→complete span, which the scripts stamp exactly. The per-task timestamps are best-effort — a single agent logs a task right after building it, so they reflect when you recorded it, not a precisely measured duration; that's fine, the summaries are the point. Still, record each finish as you go, wave by wave rather than dumping every task at the very end — a per-wave cadence keeps the panel live and the ordering true.
Never write the next step's start. Only the next command appends the next step's start entry; writing it here makes the viewer render a phantom "Generating …".
This is one step in the Companion pipeline. How the run continues depends on the environment you are running in; do not invoke a separate headless/deterministic run command for the everyday flow.
speckit-extension/workflows/speckit-companion.workflow.yml) to learn which step comes next, then continue into it on your own — dispatch the next step's /speckit.companion.* command and keep going through the pipeline.gate (e.g. review-spec, review-plan), stop and wait for approval rather than running past it. Only continue once the gate is approved.mark-complete. Run it so the spec lands at status: completed. That step writes completed only through write-context.py --mark-complete, which refuses unless the spec is already implemented — never introduce a second completed-writer.before/after insertsThis command is assembled from ordered nodes. A project can attach its own work at the boundary before or after any node by declaring it in .specify/companion.yml. You are the runtime: read that file (if present) and run those hooks at the right moments. Like the rest of the pipeline, this must never fail the host command — degrade and continue.
Find the hooks for this command. Look up commands.<this-command>.hooks in .specify/companion.yml. It has two anchors, before and after, each keyed by a node id from this command's order. Run a node's before hooks immediately before that node's work, and its after hooks immediately after. When several hooks sit at one anchor, run them top to bottom, in declared order.
Hook types:
{ type: command, run: "<shell>" } — run the shell command with your terminal/Bash tool, then continue. If you have no terminal tool (some chat-only providers), do not pretend to: report the command you would have run and continue.{ type: prompt, text: "<instruction>" } — treat the text as an inline instruction and act on it before moving on.{ type: node, ref: <id> } — read .specify/companion/nodes/<id>.md and carry out its body as if it were part of this command.Background hooks. Any hook may add background: true. Kick it off and continue the pipeline immediately without waiting for it to finish — it must not hold the spec prisoner. Use it for slow, independent side-effects (a test run, a build, a notification): for a command, launch it detached (e.g. append & or use nohup … &); for a node/prompt, do its work without blocking the next step. Report its result whenever it lands, but never block on it. Do not mark a background hook on anything that writes .spec-context.json (the timing/capture calls): those are fast already and run a read-modify-write on the shared file, so two of them racing in the background can lose an update. Background is for side-effects, not bookkeeping.
Failure handling (never abort the host command):
.specify/companion.yml → there are no hooks; run the command exactly as written. Do not warn.type: node hook's ref file is missing → this is a real misconfiguration: report it clearly and stop before doing damage, rather than silently skipping.If a hook's own work fails (a command exits non-zero, a node can't complete), report it and — unless the failure clearly makes the rest unsafe — continue the pipeline. The host command's own output is never blocked by a hook.