speckit-companion-implement
Companion implement — execute tasks.md in dependency order, then mark complete
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Companion implement — execute tasks.md in dependency order, then mark complete
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
Perform a non-destructive cross-artifact consistency and quality analysis
Identify underspecified areas in the current feature spec by asking up
Mark the active spec completed — the Companion workflow's terminal step (writes status: completed)
Companion plan — implementation plan with research & design artifacts
Companion specify — spec.md with prioritized user stories
Companion tasks — user-story phased task list
| name | speckit-companion-implement |
| description | Companion implement — execute tasks.md in dependency order, then mark complete |
| compatibility | Requires spec-kit project structure with .specify/ directory |
| metadata | {"author":"github-spec-kit","source":"companion:commands/speckit.companion.implement.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.
Execute tasks.md phase by phase in dependency order. Each phase is laid out as ordered waves split by ⟶ Wait … join lines — a dependency map where tasks within a wave are independent and a ⟶ Wait marks where the next tasks depend on what came before. Build each task inline, in turn, stopping at each ⟶ Wait line until the wave above is done. (A host with subagents may parallelize a wave whose tasks are each heavy enough to be worth a separate worker, but inline is the default and usually faster for ordinary edits.) Each task's finish is logged as it completes; then mark the spec complete.
Read .specify/feature.json for the feature directory; load <feature_directory>/tasks.md, plan.md, and spec.md (and data-model.md / contracts/ if present). Then record the implement START so the step's duration begins now (the script stamps the real clock; do not hand-write implement timing):
python3 .specify/extensions/companion/scripts/write-context.py --feature-dir <feature_directory> --step implement --status implementing --kind start --by extension
Work tasks.md phase by phase, in dependency order: Setup, then Foundational (which blocks every story), then each user-story phase in priority order (P1 first), then Polish. tasks.md lays each phase out as ordered waves separated by **⟶ Wait …** join lines. The waves are a dependency map: tasks inside one wave are independent of each other (any order is safe), and a ⟶ Wait line marks where the next tasks depend on everything above it. Execute wave by wave, in order, and stop at each ⟶ Wait line until the wave above is done before starting the next. Halt on a failed task and report the cause.
Build a wave's tasks yourself, in turn — inline is the default. Implement each task in the wave directly (write its file), in any order within the wave since they're independent. As you finish each task, append its finish to the event log — that single append is the closing action of the task, done the moment its work is complete:
python3 .specify/extensions/companion/scripts/write-context.py --feature-dir <feature_directory> --task <TaskID> --kind complete --by ai --did "<one line>" --files "<files>" --append
--append is one no-read write, so it never stalls and never corrupts the shared context. Do not hand-edit the tasks.md checkbox — the materialize step below checks it off from your appended finish.
Task tool and a wave's tasks are each substantial enough that a separate worker would pay for its own startup, you may dispatch one subagent per task instead — each makes only its task's edits and appends its own finish. For the common case (small files, quick edits) this overhead does not pay off, so inline is both the default and usually the faster choice. Either way the result is identical.After each wave, reconcile and materialize, then cross the join line. Type-check/build the wave's files together and fix any seam drift. Then fold the wave with one call — it updates the panel and checks off the tasks.md boxes for every appended finish:
python3 .specify/extensions/companion/scripts/write-context.py --feature-dir <feature_directory> --materialize
tasks.md is owned only through this --materialize call (the script flips the boxes), so it never diverges from the journal. Now move past the ⟶ Wait line to the next wave.
On completion, validate the result against the spec's Functional Requirements and Success Criteria, and report a short summary of what was built and anything left undone.
Output: working changes per tasks.md, with completed tasks checked off.
5. Mark the spec complete. Once every task in tasks.md is checked off and the work validates, finish the lifecycle so the spec lands at completed instead of stopping at implemented. Run from the repository root (the feature directory resolves on its own):
python3 .specify/extensions/companion/scripts/write-context.py --mark-complete --by ai
This is the only sanctioned writer of completed: it closes the implement step and promotes an implemented spec — or an implementing one whose tasks are all checked — straight to completed, keeping currentStep at implement. Best-effort and idempotent: if python3 is unavailable, warn and skip without failing the host command; a spec already completed is left untouched. When the spec-kit workflow engine drives the run, its terminal mark-complete step calls the same path, so running it here too is harmless.
.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.