一键导入
finish
Use when implementation is complete and all tests pass. Verifies with fresh evidence, presents completion options (merge, PR, keep, discard), and cleans up.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Use when implementation is complete and all tests pass. Verifies with fresh evidence, presents completion options (merge, PR, keep, discard), and cleans up.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Use when creating or updating a pull request. Analyzes the full diff against the base branch, writes a concise title and structured body, and creates or updates the PR via gh.
Interactive, phone-drivable idea→spec loop. The operator hands the host agent a raw idea; the agent routes it to the right repo, runs the FULL DECIDE phase (explore [track] → complexity → prd [product track] → architecture-diagram → architecture-review → stories → conflict-check → plan, tier-aware) in that repo, opens a spec PR there, and nudges that repo's daemon. Runs independently of any build/execution loop. Use when capturing and routing new work, NOT when building inside one repo (that's plain conduct).
Use after stories are written and conflict-check has passed clean. Converts user stories into a step-by-step implementation plan with 2-5 minute task granularity.
Use after /finish to validate stories via curl (API) or browser (full-stack). Bugs found loop back through /tdd.
Use when executing an implementation plan with multiple tasks. Factory orchestration with three autonomy levels, quality gates, rework budgets, and audit trails.
Use when implementing any feature or bugfix. Five-step cycle: RED → DOMAIN → GREEN → DOMAIN → COMMIT. Enforces test-first development with domain integrity review at every phase boundary.
| name | finish |
| description | Use when implementation is complete and all tests pass. Verifies with fresh evidence, presents completion options (merge, PR, keep, discard), and cleans up. |
| enforcement | gating |
| phase | ship |
| standalone | true |
| requires | [] |
Ensures that completion claims are backed by fresh evidence — not cached results or assumptions. Presents structured options for integrating the work and handles cleanup.
GATE 0 — Refuse to finish a tree that is mid-rebase or mid-merge. This is the
FIRST thing you do, before the test suite or anything else. Run git status and
check for an in-progress rebase/merge:
git status reports rebase in progress / You are currently rebasing / You have unmerged paths, orgit rev-parse --git-path rebase-merge / rebase-apply directory exists, orgit diff --name-only --diff-filter=U is non-empty (unresolved conflicts).If ANY of these hold, STOP immediately: do NOT run the test suite, do NOT push,
do NOT create a PR, and do NOT write .pipeline/finish-choice. Finishing here would
push a detached, half-rebased branch (or grind for many minutes on a tree it can
never ship). This is not a finishable state — the rebase must be completed/
resolved first (the conductor's rebase step or /rebase does that). Report the
blocker plainly and end. Leaving no finish-choice lets the conductor re-evaluate
and HALT for resolution rather than ship broken work.
GATE: No completion claims without running verification commands NOW.
Do NOT trust:
Run these commands and read the full output:
All must pass before proceeding.
When the fresh suite fails — flake-check, then record the evidence:
.pipeline/test-failures.md (run evidence — overwrite any prior
one): one section per failing test file with the test names, a one-line
failure reason each, and your read on the cause — an implementation bug, or
tests lagging an intentional contract change (say which contract/commit).
This file is what the conductor hands /remediate to route the fix
autonomously; without it the daemon can only HALT blind..pipeline/finish-choice
(the missing marker is how the conductor knows finish refused).GATE: Prove remote staleness before force-pushing — never git pull after a sanctioned rebase.
The daemon's finish-time rebase (ADR-001/9.0) creates a common scenario: your branch
has been rebased on HEAD, but origin/<branch> still holds the pre-rebase commits.
This causes git status to report "diverged from / behind origin/" — a normal,
intended state, not a blocker.
Before pushing this state, you MUST prove that origin/<branch> is stale:
Fast path — merge-base proof: Run:
git merge-base --is-ancestor origin/<branch> ORIG_HEAD
If this exits 0 (true), origin/<branch> is an ancestor of your pre-rebase HEAD.
This proves the remote is behind and safe to overwrite.
Fallback — reflog proof: If merge-base is unavailable or fails, check the reflog:
git reflog | grep "rebase: finish"
If you see a "rebase: finish" entry, the daemon rebased this branch as part of completion. The pre-rebase state exists in ORIG_HEAD and the reflog. This proves staleness.
Once proof is obtained, reconcile with force-with-lease:
git push --force-with-lease origin <branch>
This is safe because --force-with-lease aborts if the remote has new commits you
don't know about — you've already verified it only has pre-rebase ones.
Explicitly forbidden — never do these:
git pull — pulls origin/<branch> and merges; creates conflicts or undoes the rebasegit fetch && git rebase origin/<branch> — same effect, undoing the rebasegit merge origin/<branch> — creates a merge commit that contradicts the rebaseAll three corrupt the finish-time rebase and break the feature's shipped state.
No new marker is introduced. The .pipeline/finish-choice semantics are unchanged
(still one of: pr, merge-local, keep, discard). This rule applies to all
completion paths: whether you merge locally, push a PR, or keep the branch, the
staleness proof and force-with-lease discipline must hold.
Failed Staleness Proof — Foreign Commits Detected
If the staleness proof fails — i.e., git merge-base --is-ancestor origin/<branch> ORIG_HEAD
exits non-zero AND no reflog "rebase: finish" entry exists — then another writer has pushed
real commits to origin/<branch> after your pre-rebase HEAD. This means origin/<branch>
is NOT an ancestor of your work; it has diverged.
GATE: STOP immediately — do NOT force-push. Even if --force-with-lease would
succeed (i.e., the remote head hasn't changed since the last fetch), a passing lease
does NOT authorize the push when the staleness proof failed. The proof's failure is
the blocking signal: real, authored work exists on the remote that you do not have.
Forcing would lose that work.
When this gate triggers:
--force, --force-with-lease, or push --set-upstream)origin/<branch>.pipeline/finish-choicegit log HEAD..origin/<branch> --oneline
This shows what work exists on the remote that you don't have.Failed Lease — Remote Changed After Last Fetch
If git push --force-with-lease exits non-zero, the remote has moved. This can happen
even if the staleness proof passed: the remote was behind at the time of the proof, but
a concurrent writer pushed new commits between your proof check and your push attempt.
GATE: STOP immediately — do NOT retry with --force. The lease failure is an
explicit signal that the remote state changed. Pushing with --force (without lease)
would overwrite the remote writer's work — the exact scenario force-with-lease is
designed to prevent.
When this gate triggers:
--force, not push --set-upstream).pipeline/finish-choiceBranch: <branch>
Expected remote head: <expected-oid>
Actual remote head: <actual-oid> (obtained from `git ls-remote origin <branch>`)
Cross-reference the completed work against the stories in .docs/stories/:
ADR compliance check:
.docs/decisions/ — all must be APPROVEDBefore presenting options, show the user what was built so they can review:
main, master, or develop)git diff --stat <base>..HEAD and git log --oneline <base>..HEADDo not skip this step. The user must have the opportunity to review before choosing.
After review, present these options to the user:
Feature implementation complete. All tests pass. Options:
1. Merge locally — Merge this branch into the base branch
2. Push & create PR — Push the branch and create a pull request
3. Keep as-is — Leave the branch for later; no merge or PR
4. Discard — Delete the branch and all changes (requires confirmation)
Wait for the user to choose. Do not assume.
Unattended/auto mode: If you are running in print mode (no user attached) or
--auto, do NOT prompt — decide deterministically and act (do not merely
describe the choice):
gh is authenticated → Option 2:
Push & PR (never merge). Before recording, verify using the §5 Option 2
STOP gate — if the push did not land or the PR does not exist, do NOT run
finish-record; halt for human review.gh unavailable/unauthenticated) → Option 3: Keep
as-is — leave the work committed on the branch.The final act in auto mode is always conduct-ts finish-record — it is the
single source of truth for the .pipeline/finish-choice marker and (for pr)
state.pr_url; do not hand-write these files yourself in auto mode. Use the
absolute pipeline directory supplied in the step's system prompt:
conduct-ts finish-record --choice pr --pr-url <PR_URL> --pipeline-dir /abs/path/to/.pipeline
gh unavailable/unauthenticated):
conduct-ts finish-record --choice keep --pipeline-dir /abs/path/to/.pipeline
finish-record itself re-verifies the PR exists and that HEAD was pushed
before writing anything — so it is safe to run as the terminal step even if
your own verification was imperfect; it fails closed (exit 1, nothing
written) rather than recording a false completion.
Refusal contract: any gate above (GATE 0, fresh-verification failures, push
staleness/lease failures, the §5 Option 2 STOP gate) that says STOP means do
NOT run conduct-ts finish-record in that pass — an absent finish-choice
marker IS the refusal signal the conductor watches for. Never write the marker
by hand to paper over a blocked gate.
The conductor's finish completion gate (artifacts.ts) requires a fresh
.pipeline/finish-choice (and, for pr, state.pr_url); without it the
feature is left "complete-but-unshipped" and the loop stalls.
Daemon mode — write markers to the worktree, before cleanup. When the daemon
runs finish, the feature's .pipeline lives in the worktree, but branch/PR/
worktree cleanup (the worktree-manager agent) cds into the main repo — so a
relative .pipeline/... write can land in the wrong repo and the gate (which
reads the worktree) never sees it. Write finish-choice and the pr_url in
conduct-state.json to the absolute worktree .pipeline path (the conductor
supplies it in the step's system prompt) and do so before any merge/cleanup
step — never from inside a cd'd main checkout. If a PR for the branch already
exists, reuse it (gh pr view --json url -q .url) rather than failing.
After executing any choice, record the outcome so the conductor's completion gate can verify the step actually did something:
pr or keep): the outcome MUST be recorded by running
conduct-ts finish-record --choice <pr|keep> [--pr-url <url>] --pipeline-dir /abs/path/to/.pipeline (see §4) — this is the final act, and it writes both
.pipeline/finish-choice and, for pr, state.pr_url atomically after
re-verifying the PR/push. Do NOT hand-write these files yourself when
running auto/unattended..pipeline/finish-choice as one of
the literal strings pr, merge-local, keep, or discard..pipeline/conduct-state.json as pr_url (the conductor will pick it up
from there; if the underlying /pr skill prints the URL to stdout the
conductor can also scrape it).Without one of these, the conductor will treat the step as failed and re-run it, even if the skill itself reports success.
Refusal contract: if any gate blocked before reaching this step (see the
refusal contract in §4), do NOT write finish-choice by hand and do NOT run
finish-record — the absent marker is itself the refusal signal the
conductor reads.
Option 1: Merge locally
conduct-ts shipped-record --slug <slug> --pr local (where <slug> is the
plan-file stem, .docs/plans/<slug>.md). It commits .docs/shipped/<slug>.md
on the branch so the merge lands the code and the shipped-fact atomically.
The command NEVER blocks the ship: on any failure it warns and exits 0 —
continue regardless.merge-local to .pipeline/finish-choiceOption 2: Push & PR
Run the /pr skill — it handles pre-push verification, title/body generation, push, and
PR creation
Engine Behavior — Halt-PR Rehabilitation: After the agent creates or updates the PR, the conductor automatically rehabilitates any reused halt PR:
needs-remediation label (if present)needs-remediation: prefix (if present)Closes reference to match the actual implementationThis automation runs before the completion gate checks the PR state
(adr-2026-07-03-halt-pr-rehabilitation-at-finish), so the finish gate only
succeeds if the PR's final title does NOT start with needs-remediation:.
Before writing finish-choice=pr and pr_url, verify both the PR and the push:
PR exists and has a non-empty URL:
gh pr view --json url -q .url
If this returns empty or fails, the PR does not exist or is inaccessible.
The branch was pushed (remote-tracking ref contains HEAD):
git merge-base --is-ancestor HEAD refs/remotes/origin/<branch>
If this exits non-zero, HEAD is not an ancestor of the remote tracking ref —
the push did not land, or the remote never updated locally (stale tracking ref).
If EITHER check fails, STOP immediately. Do NOT write finish-choice=pr or pr_url.
Explain what failed and what to do next:
gh pr view
works and the PR exists on GitHub. Then retry /finish."git push --force-with-lease origin <branch> to push the branch,
then retry /finish."In daemon mode: a missing finish-choice marker leaves the completion gate unsatisfied
(Story 1), routing to HALT for human review.
conduct-ts shipped-record --slug <slug> --pr <PR_URL> (where
<slug> is the plan-file stem, .docs/plans/<slug>.md), then git push so
the record commit rides the PR branch — the human merge lands the code and
the shipped-fact atomically. The command NEVER blocks the ship: on any
failure it warns and exits 0 — continue (dedup degrades to the local ledger)..pipeline/conduct-state.json (pr_url field)pr to .pipeline/finish-choiceOption 3: Keep as-is
keep to .pipeline/finish-choiceconduct-ts shipped-record for keep (or discard) — nothing
ships, so no .docs/shipped/ record may exist for the slugOption 4: Discard
discard to
.pipeline/finish-choiceAfter executing the chosen option:
worktree-manager agent with model="haiku" (see agents/worktree-manager.md):
/manual-test → /retrogit status first — confirmed NO rebase/merge in progress and no unmerged paths (else stopped without pushing/PR/finish-choice).pipeline/test-failures.md; NO finish-choice writtenconduct-ts finish-record --choice <c> [--pr-url <url>] — the
completion gate reads .pipeline/finish-choice AND the recorded PR URL; a choice of
pr without a recorded URL fails the gateneeds-remediation: and does not carry the needs-remediation label (engine
automatically removes/rewrites these after /pr completes; if title still contains
needs-remediation:, halt-PR rehabilitation failed — check conductor logs)refs/remotes/origin/<branch> contains HEAD)--force-with-lease (never pulled)--force, no pull, no finish-choice.pipeline/finish-choice written with the chosen outcomepr_url written to .pipeline/conduct-state.json