Ship a change: edit until tests pass, review, approve once

The implement step repeats until your test command exits 0, so a program decides it is done, not the model. The diff then goes to two reviewers in fresh contexts, a gate holds back anything with an open blocking finding, and nothing is pushed before you approve.

8 steps in 7 stages · 7 subagents · a kit of 12 files

Free. Built in your browser; nothing is uploaded. No API key, no account.

How it runs

Steps in the same stage start at the same time. Each subagent gets only what its incoming edges carry, and a step in a fresh context never sees the reasoning of the steps before it. A gate decides whether the work passes, and a failed gate re-runs the work it checks.

  1. Stage 1
    • Plan · Planner

      sonnet · Read, Grep, Glob

  2. Stage 2
    • IMPLEMENT (loops on tests) · Worker

      sonnet · Read, Grep, Glob, Edit, Write, Bash · repeats until npm test passes

  3. Stage 3
    • Collect diff · Command

      runs git diff --stat && git diff

  4. Stage 42 in parallel
    • REVIEW: Correctness · Worker

      haiku · Read, Grep, Glob · fresh context

    • REVIEW: Security · Worker

      haiku · Read, Grep, Glob · fresh context

  5. Stage 5
    • GATE (Fresh Context) · Checker

      opus · Read, Grep, Glob · fresh context

      Gate: No blocking finding is left open, and every finding cites a line of the diff.

  6. Stage 6
    • Approve pull request · Your OK

      asks you

  7. Stage 7
    • Open pull request · Helper

      haiku · Bash · irreversible

Use it when

  • You hand Claude Code a feature or fix and want it finished, tested and reviewed.
  • You want the pull request opened for you, but only after a yes from you.
  • Agents keep saying done while tests still fail.

Change these first

  • Change the loop's check from npm test to your own test command.
  • Narrow the publish step's Bash to the git and gh commands you allow.

Need a workflow built for your team? Fixed-price packages

What you get

An orchestrating SKILL.md, one Claude Code subagent per step with its own tools and model, and the same skill as a Cursor rule. Your agent runs it with its own subagents; nothing on this site calls a model.

ship-a-change-skill-kit.zip12 files
  • .claude/skills/ship-a-change/SKILL.mdorchestrator
  • .claude/skills/ship-a-change/graph.skill.mdgraph source
  • .claude/agents/ship-a-change-plan.mdsubagent
  • .claude/agents/ship-a-change-implement.mdsubagent
  • .claude/agents/ship-a-change-review-correctness.mdsubagent
  • .claude/agents/ship-a-change-review-security.mdsubagent
  • .skill-graph/.gitignoresupport
  • .cursor/rules/ship-a-change.mdcCursor rule
  • README.mdreadme
  • + 3 more subagents
.claude/skills/ship-a-change/SKILL.md
---
name: ship-a-change
description: "Implements a change in a loop on the test suite, reviews the diff in parallel, gates it in a fresh context, and opens a pull request after one approval."
---

# ship-a-change

Implements a change in a loop on the test suite, reviews the diff in parallel, gates it in a fresh context, and opens a pull request after one approval.

This skill is a graph: each step has its own prompt and context, and only the payloads named below move between steps.

## Plan

Run the stages in order. Every model step runs in its own subagent; do not do a step's work yourself. Only command steps and approvals are yours to run. Steps in the same stage do not depend on each other: start them together, in one message with several subagent calls.

The input (`goal`) is the user's goal: their request, word for word, handed on under `### goal`. Ask for it if the user has not given one.

### Before stage 1 · lessons

- Read `.skill-graph/ship-a-change/EXPERIENCE.md` if it exists (there is none before the first run). Each lesson starts with `- [L<n>] <step id>:`.
- When you hand a step its task, add the lessons for its id, verbatim, under `### Lessons from earlier runs`. Note which lessons each step got.
- While the run goes, keep a failure log: every check or command that exited non-zero (the command and its last 20 lines of output), every `GATE: FAIL` line, and every retry. Also note which steps passed their check or gate on the first try.

### Stage 1 · 1 step

- **PLAN** (`plan`) → subagent `ship-a-change-plan`
  - Hand it: the user's goal; its lessons from earlier runs, if any.
  - Expect: `change_plan` (markdown).

### Stage 2 · 1 step

- **IMPLEMENT (loops on tests)** (`implement`) → subagent `ship-a-change-implement` · loop until `npm test` exits 0, at most 3 iterations
  - Hand it: the output of PLAN (`plan`); its lessons from earlier runs, if any.
  - Loop, before iteration 1: read `.skill-graph/ship-a-change/implement.loop.md` if it exists (it keeps notes from earlier runs), and append a heading `# Run <date>: <the first line of the user's goal>` for this run (create the file and folder if needed). If the file is over 200 lines, delete the oldest `# Run` sections first.
  - Loop, each iteration: hand it the same inputs plus `### Loop` with "iteration <n> of 3", the whole ledger and, from iteration 2, the last 40 lines of the check's output.
  - After each iteration: append its `## Loop note` section to `.skill-graph/ship-a-change/implement.loop.md` under `## Iteration <n>`, with the check's exit code.
  - The loop ends when `npm test` (run with Bash after each iteration) exits 0. Otherwise start the next iteration.
  - If iteration 3 ends without that, stop the run and show the user the ledger for this run and the last answer.
  - Its output is the last iteration's answer, without its `## Loop note` section.
  - Add every iteration that did not end the loop to the failure log, with what stopped it.

… 70 more lines in the kit

Or let Claude adapt it

Add Skill Graph to Claude Code as a connector, then ask. Claude loads this starter, changes it for your project, checks it and hands you the kit.

Set up the connector

Ask Claude

Use Skill Graph: get the ship-a-change template, adapt it to this project, validate it until it has no errors, and compile it for Claude Code.

The graph file

The whole workflow is one Markdown file, graph.skill.md: the steps and edges in the frontmatter, one prompt per step below it. The guide explains every field.

graph.skill.md · 148 lines
---
name: ship-a-change
description: Implements a change in a loop on the test suite, reviews the diff in parallel, gates it in a fresh context, and opens a pull request after one approval.
spec: skill-graph/1
experience:
  max_lessons: 20
topology:
  nodes:
    - id: goal
      type: input
      label: CHANGE REQUEST
    - id: plan
      type: orchestrator
      label: PLAN
      model: sonnet
      tools: [Read, Grep, Glob]
    - id: implement
      type: worker
      label: IMPLEMENT (loops on tests)
      model: sonnet
      tools: [Read, Grep, Glob, Edit, Write, Bash]
      check: npm test
      loop:
        until: check
        max_iterations: 3
      risk: wide
    - id: diff
      type: code
      label: COLLECT DIFF
      run: git diff --stat && git diff
    - id: review_correctness
      type: worker
      label: "REVIEW: Correctness"
      isolated_context: true
      model: haiku
      tools: [Read, Grep, Glob]
    - id: review_security
      type: worker
      label: "REVIEW: Security"
      isolated_context: true
      model: haiku
      tools: [Read, Grep, Glob]
    - id: gate
      type: verifier
      label: GATE (Fresh Context)
      isolated_context: true
      model: opus
      tools: [Read, Grep, Glob]
      gate: No blocking finding is left open, and every finding cites a line of the diff.
      on_fail: retry
      max_retries: 2
      retry_target: implement
    - id: approve
      type: approval
      label: APPROVE PULL REQUEST
    - id: publish
      type: agent
      label: OPEN PULL REQUEST
      model: haiku
      tools: [Bash]
      risk: irreversible
      on_fail: stop
  edges:
    - from: goal
      to: plan
    - from: plan
      to: implement
      contract: change_plan
    - from: implement
      to: diff
    - from: diff
      to:
        - review_correctness
        - review_security
        - gate
      contract: diff_text
    - from:
        - review_correctness
        - review_security
      to: gate
      contract: review_findings
    - from: gate
      to:
        - approve
        - publish
      contract: verdict
    - from: approve
      to: publish
contracts:
  change_plan:
    format: markdown
    description: The files to change, what changes in each, and the tests that prove it.
  diff_text:
    format: text
    description: The output of git diff, unchanged.
  review_findings:
    format: markdown
    description: A numbered list; each finding cites a file and line of the diff and says blocking or minor.
  verdict:
    format: markdown
    description: PASS or FAIL, the findings kept with their evidence, and a three-line summary of the change.
---

# Node Prompts & Edge Contracts

## @node: plan
Read the code this request touches and write a short plan: the files to change, what changes in each, and the tests to add or update.

The request:
{{goal}}

## @node: implement
Implement this plan. Change only the files it names; add or update the tests it lists.

{{plan.output}}

Return a short summary of what you changed.

## @node: review_correctness
Review ONLY correctness: logic errors, missed edge cases, broken contracts and tests that do not test the change.

{{diff.output}}

## @node: review_security
Review ONLY security: injection, missing authorization, secrets, unsafe input handling.

{{diff.output}}

## @node: gate
You see only the diff and the two reviews, not how the change was made. Keep the findings that the diff supports, drop the rest, and decide whether anything blocking is left.

Diff:
{{diff.output}}

Reviews:
{{review_correctness.output}}

{{review_security.output}}

## @node: approve
Show the verdict and the diff summary, then ask: open a pull request with this change?

## @node: publish
The user approved: {{approve.output}}

Commit the change on a new branch, push it, and open a pull request. Use the summary in this verdict as its description:
{{gate.output}}