Pair Workflow Implement Phase
ASecurityStage 3 (initial) of the delivery workflow — implementation of one refined story inside its persistent worktree: on a fresh card above the base, writing the story's tests and code together test-first (no up-front contract) and fixing what an informal, unrecorded self-review against the AC and the review rules finds; on a run already carrying a sealed `a0` contract, strictly above its RED snapshot, never touching a sealed test byte — following the project's implement process, verifying the tie...
- 2 stars
- 0 votes
- 0 copies
- 0 views
- Added November 7, 2026
Works with
Security analysis
100/100Pro scans all 8 files and shows the line behind each finding
npx -y skills add learnn-com/designn --skill pair-workflow-implement-phase --agent claude-codeAre you the author of Pair Workflow Implement Phase?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/learnn-com-pair-workflow-implement-phase)---
name: pair-workflow-implement-phase
description: "Stage 3 (initial) of the delivery workflow — implementation of one refined story inside its persistent worktree: on a fresh card above the base, writing the story's tests and code together test-first (no up-front contract) and fixing what an informal, unrecorded self-review against the AC and the review rules finds; on a run already carrying a sealed `a0` contract, strictly above its RED snapshot, never touching a sealed test byte — following the project's implement process, verifying the tier-resolved quality gate, recording decisions, writing the checkpoint, and then publishing exactly one review-ready PR through the project's publish-pr skill in the same execution. Resolves the durable cycle state first and redirects when another step is due. Never reviews, never merges. Dispatched by the batch engine (pair-implement-batch)."
version: 0.2.0
author: Foomakers
---
# /pair-workflow-implement-phase — Build the Story Test-First, Publish Its One PR
Turn one refined story into verified commits, then project them onto exactly one pull request. Two entries, one stage:
- **Fresh card** (no `$snapshot`, no `$contract` — ADR-024 amendment 2026-09-23, US-506): there is no up-front acceptance contract. You work above the base and write the story's tests and code **together, test-first, as practice** — one AC at a time, the test that proves it first, then the code that makes it pass. Independence moves to the final verifier, who names per AC the test that proves it.
- **Sealed `a0`** (`$snapshot` + `$contract` given — a run started before that amendment, or an `a0-rev<m>` revision on it): the contract is the specification. You may change implementation inside its scope; you may not change what it asserts.
The review and the fixes are other stages with other actors.
## Arguments
| Argument | Required | Description |
| ------------------ | -------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `$run`, `$story`, `$branch`, `$worktree`, `$base`, `$stacked`, `$entry`, `$policy`, `$inputs`, `$workflowVersion` | Yes | The cycle arguments, as every stage receives them. Handoffs live under `.pair/working/runs/$run/$story/` in the MAIN checkout. |
| `$phase` | Yes | `a0`, or `a0-rev<m>` when the final verifier found a genuine gap in a SEALED initial acceptance contract and the revised contract was sealed as a successor snapshot — implement again on the same branch, above that seal. |
| `$attempt` | Yes | `1` on the first implementation; `2` when the previous attempt published with a RED gate — same base (or same seal), fix the gate, never bypass it. |
| `$head` | Sealed `a0` only | 40-hex head the contract was prepared on; the snapshot sits directly on it. Absent on a fresh card: `inputHead` is the worktree's HEAD after Step 1. |
| `$snapshot` | Sealed `a0` only | 40-hex sha of the sealed RED snapshot commit — you re-discover it from Git, you never trust the prompt for its content. Absent ⇒ fresh card. |
| `$contract` | Sealed `a0` only | Absolute path of the sealed acceptance contract (main checkout's run directory). Absent ⇒ fresh card. |
| `$title` | Yes | Story title. |
| `$implementSkill` | Yes | The project's implement process skill (default `/pair-process-implement`). |
| `$verifyQuality` | Yes | The tier-resolved quality-gate skill (default `/pair-capability-verify-quality`). |
| `$recordDecision` | Yes | The decision-recording skill (default `/pair-capability-record-decision`). |
| `$checkpoint` | Yes | The checkpoint skill (default `/pair-capability-checkpoint`). |
| `$publishPr` | Yes | The project's PR-publishing skill (default `/pair-capability-publish-pr`). |
| `$notes` | No | Scope directive from the card; it overrides the issue body where they conflict. |
## Algorithm
**Headless execution (single owner: `.pair/knowledge/guidelines/technical-standards/ai-development/skill-conventions/headless-stage-execution.md`)** — this stage runs headless: never leave a command in the background and never end your turn while a command runs (a push with a pre-push gate, a quality gate): use the maximum tool timeout, poll to completion in the same turn, and ALWAYS end with the stage's structured result — on partial progress `{ status: "failed", reason: "incomplete", detail, branch, outputHead }`.
### Step 0: Resolve the durable state (mandatory)
```bash
SKILL_DIR="$(dirname "<absolute path of this SKILL.md>")"
MAIN="$(pwd)" # the main checkout — you have not cd'd yet
RUN_DIR="$MAIN/.pair/working/runs/$run/$story"
AC_HASH="$(node "$SKILL_DIR/scripts/cycle-state.mjs" ac-hash --story $story --dir "$RUN_DIR" | node -pe 'JSON.parse(require("fs").readFileSync(0,"utf8")).acHash')" # canonical card hash — the SAME input every stage resolves with
node "$SKILL_DIR/scripts/cycle-state.mjs" resolve --dir "$RUN_DIR" --workflowVersion $workflowVersion \
--policy '$policy' --entry $entry --story $story --inputs $inputs --acHash "$AC_HASH" --runsRoot "$MAIN/.pair/working/runs"
```
- `status: other-run` ⇒ return `{ status: "other-run", runId }`. `incompatible | invalid` ⇒ return `{ status: "redirect", next: { step: "blocked", reason: "failed-resume", detail: <reason> } }`.
- `next.step` is not `implement` ⇒ return `{ status: "redirect", next }` verbatim. Spend no judgment. When `next` names THIS dispatch (`implement`, `$phase`) you ARE the step: continue, never return a redirect to yourself — with one exception: `next` names this dispatch but carries a `contract` while the dispatch has no `$snapshot` (the coordinator's contract-less first guess on a run whose `a0` is already sealed, US-506) ⇒ return `{ status: "redirect", next }` verbatim, so the coordinator re-dispatches this step WITH the seal. Never take the fresh-card branch on a sealed run.
- Otherwise continue; `next.attempt` is your attempt number.
- A prior attempt may already have published a PR: `next` then says `verify`, and you return that — never a second PR.
### Step 1: Isolation and the contract (mandatory)
**Fresh card** (`$snapshot` and `$contract` absent): `next` from Step 0 carries no `contract` either, and `$RUN_DIR` holds no sealed `red-verify` handoff — if it does, the dispatch is inconsistent: return `status: failed`, `reason: seal-present-but-not-dispatched`. **Fresh-branch check (deterministic, before any work)** — "fresh" means no STALE history, judged on the commits the branch carries above `$base`, never on whether the branch descends from the CURRENT `$base` (main simply moves on: a branch forked from an older main is not stale). First refresh remote state — `git fetch --prune origin` — and confirm what really exists on the remote with `git ls-remote --heads origin <branch>`: a remote-tracking ref (`origin/<branch>`) that was deleted on the host lingers in the checkout until pruned, and judging that stale remote-tracking ref blocks a fresh card on history that no longer exists. Judge the branch that will actually be pushed — the local story branch — plus the remote branch ONLY if `ls-remote` shows it exists; a branch absent from `ls-remote` is not judged, whatever a local ref still says. When such a branch exists list `git log --format='%H%x09%s%x09%(trailers:key=Pair-RED-Snapshot,valueonly,separator=%x2C)' $base..<branch>` (when `$base` is not an ancestor of the branch, use `git merge-base` of the two as the lower bound, so only the branch's OWN commits are listed). A commit is the card's OWN when its subject starts with `[#<card>]` or `[US-<card>]` (the commit template's story reference). The branch is stale ONLY when it carries a FOREIGN commit (another story's history, e.g. pre-rewrite history) or a commit with a `Pair-RED-Snapshot` trailer while `$RUN_DIR` holds no sealed `red-verify`. An EMPTY `$base..<branch>` (no own work) is fresh and there is nothing to lose: reset it to `$base` yourself inside `$worktree` (`git -C $worktree reset --hard $base` on the story branch only, never the main checkout). The card's own commits above an older `$base` are NOT stale: that is a RESUME of the fresh path — keep them, inspect what is already done (`git log`, the diff, the checkpoint), continue implementing, verifying and publishing from there (do not rebase here; `publish-pr`'s base preparation handles a moved base), never redo or discard them. The same holds for UNCOMMITTED changes in the story worktree on this story branch: they are a previous attempt of THIS story interrupted mid-work (a Ctrl-C, a killed driver) — the card lock this run holds guarantees no other run owns them. Resume them: review the diff against the AC and the task list, keep what is right, finish, verify and commit it as the card's own work; never stash, reset or discard it, and never stop on it as foreign. Only a stale branch returns `{ status: "failed", reason: "branch-not-fresh", detail: <the foreign commit or snapshot trailer found, and the branch head>, next: { step: "blocked" } }` and tells the human what to do — archive the branch (rename it) or reset it to `$base` themselves, then re-run; never reset, delete, rebase or reuse a stale one yourself. A branch that does not exist yet passes. Then create or reuse the story worktree (`git worktree add $worktree -B $branch $base` on first setup, `git worktree add $worktree $branch` if the branch has commits, plain `cd` if the path exists); `inputHead` = `git -C $worktree rev-parse HEAD`. Never modify the main checkout's tree or switch its branch. Items 2 and 3 below do not apply; continue at Step 2.
**Sealed `a0`:**
1. Do ALL git and file work inside `$worktree`; never modify the main checkout's tree or switch its branch. `git -C $worktree rev-parse HEAD` must be `$snapshot` (or a descendant of it on this branch); otherwise return `status: failed` with `reason: head-not-snapshot` — never reset, stash or rebase.
2. Discover the contract from Git: the commit `$snapshot` carries `Pair-RED-Snapshot: pr=0; phase=$phase; base=$head; manifest=<path>` (`pr=0`: the initial chain is sealed before the PR exists and keeps that identity for its revisions); read the manifest and the sealed test blobs with `git show` / `git ls-tree`. Accept no digest or test path from the prompt. Missing, ambiguous or contradictory discovery ⇒ `status: failed`, `reason: snapshot-not-found`.
3. With `$stacked=true`: `$base` is another story's branch — its commits are already in your history and must NOT be reverted, duplicated or re-implemented.
### Step 2: Implement, test-first
0. **Activate the card first** (both entries, attempt 1 or resume — never skipped on the cycle path): `node "$SKILL_DIR/scripts/cycle-state.mjs" activate-card --dir "$RUN_DIR" --story $story --worktree $worktree` — writes the board state mapped to `In Progress` (`## State Mapping`) through the bound PM adapter and reads it back (a local tracker — `filesystem` — writes the card inside `$worktree` and commits it on the story branch); exit 1 (`confirmed: false`) warns with its `error` and continues. Assign when unassigned (`$implementSkill` Step 0.1b).
0b. **Progress list** (when the harness has a todo tool — Claude Code `TodoWrite`): one todo per card task (`T-1 <title>` …), then `Running checks`, then `Opening the PR`; exactly one `in_progress` at a time, updated as you move. `pair run` shows the in-progress item on the card's live line — a stale list misreports where the stage is.
1. Follow `$implementSkill` as the process of record — its task cycle, its TDD discipline, the task/commit templates. `$notes`, when present, is a SCOPE DIRECTIVE that overrides the issue body where they conflict.
- **Fresh card**: TDD as practice — tests and code evolve together, task by task, in the card's task order. For every acceptance criterion there is a test that would fail without the behavior it claims (run it before the code when you can; a bug-fix task gets its reproducing test first, always). No proof of test-first is recorded or required: what the verifier judges is the tests that exist at the head, per AC.
- **Sealed `a0`**: the sealed acceptance tests are the story's RED: make every `baseline: red` witness pass and keep every `baseline: pass` control passing; item 2 below applies.
2. (Sealed `a0` only.) Do NOT modify, format, rename, regenerate, delete or weaken any artifact the snapshot records; do NOT amend, rebase, reset or rewrite the snapshot commit. A test the contract does not cover that you need for your own task cycle may be added (it is listed in your handoff); a sealed one is untouchable — a gap in the contract is reported as `contractGaps` for the final verifier, never patched around.
3. **Finite-state completeness** (mandatory when the change parses, selects, snapshots or branches on a finite protocol/state domain): make the whole decision table pass — every supported state and its invalid/boundary pair, including the smallest interaction cross-product. Do not implement one newly discovered row at a time and wait for review to name the next ordinary variant.
4. **Empirical evidence**: before asserting a measured or factual claim in source comments, test names, ADR/ADL, PR body or a diagnostic, record claim | authoritative oracle | exact command/fixture/revision | observed output; absent evidence, remove or qualify the claim. **Authoritative boundary proof**: an external command, format or runtime claim is proven at its real producer/consumer in an isolated probe. **Lossless diagnostics**: an error that reports user input keeps actual, expected and candidate values distinguishable.
5. Commit only the files you changed — stage explicit paths, never `git add -A`. Commit after every task: an uncommitted worktree loses everything if the supervisor kills the agent. Never run a single command that can stay silent for more than ~2 minutes (a cold full-repo gate qualifies): scope it, narrate between steps. **Never leave a long command in the background and never end your turn while one runs** (a `git push` that triggers a pre-push gate, a full-repo gate): this agent runs headless — there is no further turn and no notification, so a turn that ends "waiting for completion" ends the stage with no PR and no handoff. Give such a command the maximum tool timeout, poll it to completion in the same turn (re-check its output file until it exits), and only then continue to the next step.
6. Run the tests you select by the changed producers and their consumers during iterations; record for each run `command`, `identity` (`node "$SKILL_DIR/scripts/cycle-state.mjs" test-identity --cwd $worktree --command "<cmd>"`) and `exitCode` — a result is reusable in a later step ONLY under the same identity.
### Step 3: Self-review, verify and record
**Changeset** (both entries, before the gates): Changeset: `.changeset/<story-id>.md` mirrors the PR description and states the bump (below 1.0 a breaking change is `minor`); write it, or refresh it when the description changed, and commit it with the change. A PR with no release-relevant change takes the `no-changeset` label instead.
0. **Informal self-review — fix, never record** (both entries, before the gates): re-read the card's acceptance criteria and the review rules your project's review would apply (`$implementSkill`'s quality standards, the code-review template's severities), walk your own diff against them, and FIX what you find — a missing test for an AC, a weak assertion, an edge case the AC names, a gate that would go red. Deliver only an artifact that holds up with its gates green. **Nothing of this self-review is recorded anywhere** — not in the handoff (`publish` refuses any `selfReview*` field: `self-review-not-recordable`), not in the PR body, not in a commit message, not in the checkpoint — so the independent verifier judges the result without your conclusions in front of it.
1. (Sealed `a0` only.) Remove the transient seal manifest (`.pair/red-snapshots/pr-*-a0*.json` — the initial chain is sealed under `pr=0`, it predates the PR) in your first commit above the snapshot: it is the seal's record and lives in Git history; the custody check expects it gone, and a manifest left in the tree fails the repository's format gate (canary run 11).
2. **Fresh worktree first**: a worktree this run created has no dependencies or build — run the adopted `worktree-setup-command` (`way-of-working.md`; absent ⇒ none) inside `$worktree` before any gate; a `worktree-setup-command` non-zero exit HALTs the stage — no gate runs on a broken setup (`status: failed`, `reason: worktree-setup-failed`); record `setup: <cmd> exit N` alongside the gates run; never symlink another checkout's `node_modules`/`dist`. Verify the gates with `$verifyQuality`: it resolves the story's `risk:*` tier and runs exactly the checks CI would run for that tier, plus the repository's own pre-push gate when one exists. Sealed `a0`: re-run every sealed witness command from the manifest — all green. A red gate is `gatesPassed: false` and `status: ok` only if the PR was still published; never bypass a hook (`--no-verify` on a push is forbidden — it hides exactly the gate this stage must prove) and never report green what you did not run.
3. Record any architectural or project decision with `$recordDecision`, never only in a commit message; on the sealed `a0` path the acceptance contract's `fixScope.allowedPaths` covers the story's implementation surface and `.pair/adoption/decision-log/` for that reason — a decision that does not fit is reported under `contractGaps`, never smuggled into the PR body.
### Step 4: Checkpoint, publish the PR, persist
1. Write the story checkpoint via `$checkpoint $mode=write`, then push the branch.
2. Publish the PR by invoking `$publishPr`. Do NOT hand-roll the PR: that skill owns the whole sequence — the tier-resolved gate, the PR body composed from `pr-template.md` with only the pertinent conditional sections, the story's classification tags, ready-for-review, the `pr-state:*` label, the PR-URL back-link on the story, the board state. If a PR already exists for the branch it is UPDATED, never duplicated. **One expected signal**: it emits `Review: review-dispatch-required` instead of nesting a review — correct; the coordinator dispatches the final verifier. Never dispatch or run a review yourself.
3. **External ACs**: an AC that needs live external verification this stage cannot perform (a real release, a third-party service) is listed by id as `external — pending live verification` in the PR body AND in the result's `summary` — never claimed done, never silently dropped.
4. **Text shape** of the PR body: schematic, one decision per line, no narration of the diff; everything a blind reviewer needs (rationale, decisions, ADR links) goes there — the reviewer cannot see the checkpoint.
5. Read back `prNumber`, `url` and the pushed head (`git rev-parse origin/$branch`, 40-hex). Publish the handoff (`skill: "implement-phase"`, `inputHead` (`$head` on the sealed path, the Step 1 HEAD on a fresh card), `snapshot` (sealed path only), `status: ok`, `gatesPassed`, `prNumber`, `url`, `outputHead`, `checkpointPath`, `tasks`, `testRuns: [{ command, identity, exitCode }]`, `addedTests`, `contractGaps` (sealed path only), `elapsedMs` — and NO self-review field) with `cycle-state.mjs publish … --workflowVersion $workflowVersion --attempt $attempt --pr <prNumber>`, plus `--predecessor a0-red-verify` on the sealed path only (a fresh card has no predecessor: `a0-implement-phase` is its first handoff) (the PR just created or updated — the envelope carries it even when the dispatch had none), run `resolve` again and return its `next` **verbatim** — copy the whole object the script printed; never retype, summarize or drop a field it carries because another field in your answer already seems to say the same thing (e.g. `contract`, next to a `contractHash` you also state). The orchestrator checks the object's shape, not your restatement of it; a hand-reconstructed `next` missing one field is refused as unusable.
**US-479 S12 — no production work without the complete seal (sealed `a0` path).** When the dispatch
names a contract, start only from a sealed contract whose applicable matrix rows are present and validated: if the seal is missing, partial, or its rows
were reduced after validation, stop and return the typed refusal instead of coding. You may never
edit, weaken or drop a sealed row — including a regression guard — to make your change pass.
## Output Format
You ALWAYS end with this structured result, even on partial progress: if you cannot finish (a gate or push that will not complete, a step that failed), return `{ status: "failed", reason: "incomplete", detail: <what is done — commits, pushed or not — and what remains>, branch, outputHead }` instead of ending in prose; the commits already on the branch are resumed by the next attempt.
`{ status: ok | failed, gatesPassed, branch, checkpointPath, prNumber, url, outputHead, summary, reason?, next }`. `gatesPassed: false` with `status: ok` means published but red: the cycle state routes ONE retry on the same base or seal (`$attempt=2`), then `failed-implement`.
## Notes
- Do NOT review. Do NOT merge. Never open a second PR for the same story.
- Read nothing under `.pair/working/` except the checkpoint and `$RUN_DIR`.
- Your handoff publish is observed by the host runtime (`cycle-runtime.mjs`, US-479 T-25) as a phase-level progress point, through `cycle-state.mjs` — never something you invoke yourself.
Files in this skill
- SKILL.md
- scripts/autonomy-policy.mjs
- scripts/host/adapter-kit.mjs
- scripts/host/azure-devops.mjs
- scripts/host/filesystem.mjs
- scripts/host/github.mjs
- scripts/host/index.mjs
- scripts/host/linear.mjs
Attribution
Comments
Loading comments…
Newsletter
Get the weekly list of safe new skills, and the ones we pulled.