agentleFS
napnap11napnap11/claude-skills/ship/SKILL.md

ship

Skill1 starsChanged 5 months agoMITView on GitHub

End-to-end ship automation: detect the git host, confirm a distribution pipeline exists, merge the base branch, run the tests, triage failures by ownership, run any required eval suites, apply a /pre-merge-review structural pass over the diff, commit in bisectable chunks, push, and open the PR/MR. Runs straight through by default — pausing only for test failures, merge conflicts, or findings that need a human call. Use when the user says "ship it", "ship this", "release", "/ship", "merge and push", "create the PR", "open a PR/MR", "land this branch", or wants the branch tested, committed, pushed, and turned into a PR/MR.

  • Reads credentials
  • Commits and pushes

194 other projects use a version of this, 1 of them edited.

Adopted by

Most recently taken up by

Used with

Projects with it also use ios-sync, open-gstack-browser and 10 more.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • Saqlain-811Skill

    ios-sync

    Regenerate the iOS debug bridge against the latest upstream gstack templates. (gstack)

    Also in 6 projects that use this

  • seek888Skill

    open-gstack-browser

    Launch GStack Browser — AI-controlled Chromium with the sidebar extension baked in. Opens a visible browser window where you can watch every action in real time. The sidebar shows a live activity feed and chat. Anti-bot stealth built in. Use when asked to "open gstack browser", "launch browser", "connect chrome", "open chrome", "real browser", "launch chrome", "side panel", or "control my browser". Voice triggers (speech-to-text aliases): "show me the browser".

    Also in 10 projects that use this

  • ayudaySkill

    setup-deploy

    Configure deployment settings for /land-and-deploy. Detects your deploy platform (Fly.io, Render, Vercel, Netlify, Heroku, GitHub Actions, custom), production URL, health check endpoints, and deploy status commands. Writes the configuration to CLAUDE.md so all future deploys are automatic. Use when: "setup deploy", "configure deployment", "set up land-and-deploy", "how do I deploy with gstack", "add deploy config".

    Also in 19 projects that use this

  • ShreyRaviSkill

    landing-report

    Read-only queue dashboard for workspace-aware ship. Shows which VERSION slots are currently claimed by open PRs, which sibling Conductor workspaces have WIP work likely to ship soon, and what slot /ship would pick next. No mutations — just a snapshot. Use when asked to "landing report", "what's in the queue", "show me open PRs", or "which version do I claim next". (gstack)

    Also in 9 projects that use this

  • zebbernSkill

    debug-fix

    Find and fix a bug or issue — from any source (GitHub issue, error message, user report, or observed behavior)

    Also in 4 projects that use this

  • ramybarsoumSkill

    document-release

    Post-ship documentation update. Reads all project docs, cross-references the diff, updates README/ARCHITECTURE/CONTRIBUTING/CLAUDE.md to match what shipped, polishes CHANGELOG voice, cleans up TODOS, and optionally bumps VERSION. Use when asked to "update the docs", "sync documentation", or "post-ship docs". Proactively suggest after a PR is merged or code is shipped.

    Also in 23 projects that use this

The file

Show its rules and text

We split this skill into the rules it gives an agent

41 rules. 0 are common, 30 are distinctive, and 11 are very specific to this project.

  • 0

    Common

    Most of the 180 edited versions we read keep these.

  • 30

    Distinctive

    This author's own choices. Worth a look.

  • 11

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Commit message approval (auto-commit)

    line 66
  2. Distinctive:

    Never skip a verification step just because a prior run did it.

    line 76
  3. Distinctive:

    Check the current branch. If it's the base branch or the repo's default branch, abort: "You're on the base branch.

    line 116
  4. Very specific:

    Run git status (never -uall).

    line 118
  5. Very specific:

    Run git diff <base>...HEAD --stat and git log <base>..HEAD --oneline to see what's shipping.

    line 120
  6. Very specific:

    If no /plan-review has run on this branch AND the diff is >200 lines:

    line 123
  7. Distinctive:

    If the diff introduces a new standalone artifact (CLI binary, library package, tool) — as opposed to a web service that already has …

    line 131
  8. Very specific:

    Check whether the diff adds a new cmd/ directory, main.go, bin/ entry point, or package manifest:

    line 133
  9. Distinctive:

    If a new artifact shows up, look for a release workflow:

    line 138
  10. Distinctive:

    If no release pipeline exists and a new artifact was added: Use AskUserQuestion:

    line 144
  11. Distinctive:

    If the project has more than one suite (e.g.

    line 189
  12. Distinctive:

    If anything fails: do NOT stop immediately — apply the Test Failure Ownership Triage below.

    line 199
  13. Distinctive:

    When tests fail, establish ownership before deciding to stop.

    line 205
  14. Distinctive:

    in-branch: if: the failing test file itself was modified on this branch, OR the test output references code changed on this branch, OR you …

    line 220
  15. Distinctive:

    pre-existing: if: neither the test file nor the code it tests was modified on this branch, AND the failure is unrelated to any branch …

    line 221
  16. Very specific:

    Commit the fix separately from the branch's main changes: git commit -m "fix: pre-existing test failure in <test-file>"

    line 295
  17. Distinctive:

    If these are different people, prefer the production-code author — they likely introduced the regression.

    line 304
  18. Distinctive:

    Create an issue assigned to that person:

    line 305
  19. Very specific:

    If --assignee/-a fails (user not in the org), create the issue without an assignee and note who should look at it in the body.

    line 320
  20. Very specific:

    If TODOS.md exists, add a P0 entry with the title, error output, and the branch it was noticed on.

    line 324
  21. Very specific:

    If TODOS.md doesn't exist, create it with a standard header and add the entry.

    line 325
  22. Distinctive:

    After triage: if any in-branch failures remain unfixed, STOP.

    line 332
  23. Distinctive:

    If a project config (e.g. CLAUDE.md) declares its own prompt-file patterns, use those.

    line 354
  24. Distinctive:

    If multiple suites need to run, run them sequentially (each needs a test lane).

    line 364
  25. Very specific:

    Run the pre-merge-review structural pass over the diff before landing, using the same specialist-lens approach as the /pre-merge-review …

    line 377
  26. Distinctive:

    If the pass applies auto-fixes: commit them:

    line 435
  27. Distinctive:

    If there are unstaged changes, they need to land in the commits.

    line 461
  28. Distinctive:

    Read the diff and group changes into logical commits.

    line 469
  29. Distinctive:

    If the whole diff is small (< 50 lines across < 4 files), a single commit is fine

    line 483
  30. Distinctive:

    If the repo squash-merges PRs (check the merge-commit history) or the user prefers one commit, a single commit is fine — match the repo's …

    line 484
  31. Distinctive:

    Before pushing, re-verify if code changed during Steps 4–6:

    line 511
  32. Distinctive:

    Test verification: if ANY code changed after Step 3's test run (pre-merge-review fixes, etc.), re-run the suite.

    line 513
  33. Distinctive:

    Build verification: if the project has a build step, run it.

    line 515
  34. Distinctive:

    If tests fail here: STOP. Do not push. Fix it and return to Step 3.

    line 523
  35. Very specific:

    If ALREADY_PUSHED, skip the push but continue to Step 8.

    line 538
  36. Very specific:

    If an open PR/MR already exists: update its body with gh pr edit --body "..." (GitHub) or glab mr update -d "..." (GitLab).

    line 562
  37. Distinctive:

    If no PR/MR exists: create one using the platform detected in Step 0.

    line 564
  38. Distinctive:

    Keep it under 70 characters

    line 614
  39. Distinctive:

    Never block on these — the PR/MR URL is the primary deliverable.

    line 630
  40. Distinctive:

    Never skip the pre-landing staff review: If it can't run, stop and report.

    line 637
  41. Distinctive:

    Never push without fresh verification evidence: If code changed after the Step 3 tests, re-run before pushing.

    line 643

“Common” is measured: kept by at least 6 in 10 of the 180 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Ship — Automated Release Workflow

You are running the ship workflow. It is non-interactive and fully automated. Don't ask for confirmation at any step unless a step explicitly calls for it. Run end to end and finish by printing the PR/MR URL.

Gather context first

This skill ships standalone, so it can't assume your project's conventions, house style, or preferences the way it could for its author. Before doing the main work:

  1. Auto-detect what you safely can from the repo — language/stack, base branch, build/test commands, existing config and docs. Never ask for something you can read for yourself.
  2. Ask, don't assume, for the rest. Where an input, convention, or preference would change the result and you can't reliably detect it, ask ONE concise AskUserQuestion (put a sensible default first, labelled Recommended) instead of guessing. The user has less context than this skill's author assumed — a wrong silent default is worse than a quick question. Don't ask about things you can detect, and don't ask more than you need.

For this skill, confirm up front (only the items you can't already detect) — batch them into a single question so the rest of the run stays non-interactive:

  • How far to go — the default is the full ship (merge base, test, commit, push, open the PR/MR). If the user might only want a dry run (verify + report, no push) or to stop right before opening the PR/MR, confirm the desired end state rather than pushing and opening by surprise.
  • Commit style — bisectable multi-commit split (the default below) vs a single squashed commit. Many repos squash-merge and would rather see one commit; confirm when the convention isn't obvious from the merge-commit history.
  • Commit-message / attribution convention — whether to append a co-author or attribution trailer at all, and what it should read. Don't hardcode an identity the user never asked for; match the repo's existing trailer style or ask.
  • Base branch — auto-detected in Step 0; confirm only when detection is genuinely ambiguous (no origin/HEAD, several plausible defaults).

How this runs

This skill lives in the main conversation, and that placement is load-bearing. The few interactive moments — the distribution-pipeline gate, pre-existing-failure triage, pre-merge-review ASK items — need the user to answer directly, and every git mutation (merge, commit, push, PR/MR create) reads and writes durable repo state. All of that stays in the main loop.

The workflow is mostly sequential and stateful: each step builds on the git state the prior step produced — merge the base, then test the merged tree, then commit, then push. That ordering can't be parallelized. The two places where parallel compute could help are purely read-only analysis bursts: classifying many failing tests (Step T1) and running multiple pre-merge-review specialist lenses over the diff (Step 4). Both default to running inline and sequentially in this context. Before spawning any subagent or Workflow, stop and ask the user, for example:

This branch has [N failing tests to triage / a large diff touching M specialist areas]. I can do it inline here (cheaper, slower) or fan out parallel subagents (faster, more tokens). Which do you want?

Spawn subagents/workflows only after an explicit yes. If the user declines or doesn't answer, do the whole job inline.

If you do fan out: Workflow agent() calls run in the background — they cannot call AskUserQuestion, cannot talk to the user, and cannot write files or mutate the repo. So every gate, approval, and question (distribution pipeline, pre-existing-failure triage, pre-merge-review ASK items) and every state mutation (merge, commit, push, issue creation, PR/MR create, TODOS.md edits) stays in the main loop. A Workflow only does headless read-only compute (classify failures, gather authorship metadata as text) and returns structured results; you present and act on them. Always set model: 'opus' on agent() calls so no lightweight tier leaks in, and pass everything in through args — Workflow scripts have no Date.now/Math.random/filesystem access, so timestamps, git commands, and file writes all happen in the main loop.

Arguments

Inspect $ARGUMENTS:

  • A base-branch override (e.g. --base develop, or a bare branch name) → use it as <base> instead of auto-detecting in Step 0.
  • A PR/commit ref or branch name → treat as the branch to ship if it isn't already checked out (otherwise ship the current branch).
  • A mode hint — "report only" / "dry run" → run the verification steps (0–4) and report without pushing or opening a PR/MR; "no merge" → skip the Step 2 base merge.
  • Empty → ship the current feature branch end to end.

Only stop for:

  • Being on the base branch (abort)
  • Merge conflicts that can't be auto-resolved (stop, show the conflicts)
  • In-branch test failures (pre-existing failures are triaged, not auto-blocking)
  • Eval suite failures (prompt/LLM changes only)
  • pre-merge-review ASK items that need user judgment
  • A missing distribution pipeline for a new artifact (ask)
  • PR/MR creation problems

Never stop for:

  • Uncommitted changes (always include them)
  • Commit message approval (auto-commit)
  • Multi-file changesets (auto-split into bisectable commits)
  • Auto-fixable review findings (fixed automatically)

Review readiness reminder: If the user skipped pre-flight review, they should ideally have run /plan-review (plan/architecture); this skill runs pre-merge-review on the diff before landing regardless. If neither has happened and the diff is large (>200 lines), suggest /plan-review first. Never block — ship runs its own pre-merge-review in Step 4.

Re-run behavior (idempotency): Re-running ship means "run the whole checklist again." Every verification step executes on every invocation. Only actions are idempotent:

  • Step 7: if already pushed, skip the push command
  • Step 8: if a PR/MR exists, update its body instead of creating a new one

Never skip a verification step just because a prior run did it.


Step 0: Detect platform and base branch

First, read the git host from the remote URL:

git remote get-url origin 2>/dev/null
  • URL contains github.com → GitHub
  • URL contains gitlab → GitLab
  • Otherwise, probe CLI availability:
    • gh auth status 2>/dev/null succeeds → GitHub (covers GitHub Enterprise)
    • glab auth status 2>/dev/null succeeds → GitLab (covers self-hosted)
    • Neither → unknown (use git-native commands only)

Now find the branch the PR/MR targets, or the repo's default branch if there's no PR/MR yet. That result is "the base branch" for every later step.

If GitHub:

  1. gh pr view --json baseRefName -q .baseRefName — use it if it succeeds
  2. gh repo view --json defaultBranchRef -q .defaultBranchRef.name — use it if it succeeds

If GitLab:

  1. glab mr view -F json 2>/dev/null and read target_branch
  2. glab repo view -F json 2>/dev/null and read default_branch

Git-native fallback (unknown platform or CLI failed):

  1. git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's|refs/remotes/origin/||'
  2. git rev-parse --verify origin/main 2>/dev/null → use main
  3. git rev-parse --verify origin/master 2>/dev/null → use master

If everything fails, default to main — but when detection was genuinely ambiguous (e.g. both origin/main and origin/master exist, or origin/HEAD is unset), confirm the base branch with the user before continuing rather than silently guessing. Print the detected platform and base branch, and substitute that branch name everywhere the steps below say <base>.


Step 1: Pre-flight

  1. Check the current branch. If it's the base branch or the repo's default branch, abort: "You're on the base branch. Ship from a feature branch."
  2. Run git status (never -uall). Uncommitted changes are always included — no need to ask.
  3. Run git diff <base>...HEAD --stat and git log <base>..HEAD --oneline to see what's shipping.
  4. Review readiness check (informational):
    • If no /plan-review has run on this branch AND the diff is >200 lines:

      "Note: this is a large diff ($LINES lines). Consider running the /plan-review skill first for architecture-level review before shipping."

    • This never blocks. Ship runs its own pre-merge-review in Step 4.

Step 1.5: Distribution Pipeline Check

If the diff introduces a new standalone artifact (CLI binary, library package, tool) — as opposed to a web service that already has deployment — confirm a distribution pipeline exists.

  1. Check whether the diff adds a new cmd/ directory, main.go, bin/ entry point, or package manifest:
    git diff origin/<base> --name-only | grep -E '(cmd/.*/main\.go|bin/|Cargo\.toml|setup\.py|package\.json)' | head -5
  2. If a new artifact shows up, look for a release workflow:
    ls .github/workflows/ 2>/dev/null | grep -iE 'release|publish|dist'
    grep -qE 'release|publish|deploy' .gitlab-ci.yml 2>/dev/null && echo "GITLAB_CI_RELEASE"
  3. If no release pipeline exists and a new artifact was added: Use AskUserQuestion:

    "This PR adds a new binary/tool but there's no CI/CD pipeline to build and publish it. Users won't be able to download the artifact after merge."

    • A) Add a release workflow now (GitHub Actions or GitLab CI, depending on platform)
    • B) Defer — add to TODOS.md
    • C) Not needed — this is internal/web-only, existing deployment covers it
  4. If a release pipeline exists: continue silently.
  5. If no new artifact is detected: skip silently.

Step 2: Merge the base branch (BEFORE tests)

Fetch and merge the base branch into the feature branch so tests run against the merged tree:

git fetch origin <base> && git merge origin/<base> --no-edit

On merge conflicts: try to auto-resolve the simple ones (VERSION files, CHANGELOG ordering, generated schema files). If conflicts are complex or ambiguous, STOP and show them.

If already up to date: continue silently.


Step 3: Run tests (on merged code)

Detect the test framework and run the right command. Common signals:

# Node
[ -f package.json ] && grep -q '"test"' package.json && echo "RUN: npm test"
# Ruby/Rails
[ -f Gemfile ] && [ -x bin/test-lane ] && echo "RUN: bin/test-lane"
[ -f Gemfile ] && [ -x bin/rails ] && echo "RUN: bin/rails test"
# Python
[ -f pytest.ini ] || [ -f pyproject.toml ] && echo "RUN: pytest"
# Go
[ -f go.mod ] && echo "RUN: go test ./..."
# Rust
[ -f Cargo.toml ] && echo "RUN: cargo test"
# PHP
[ -f phpunit.xml ] && echo "RUN: ./vendor/bin/phpunit"

If the project has more than one suite (e.g. Rails + Vitest), run them in parallel:

bin/test-lane 2>&1 | tee /tmp/ship_tests.txt &
npm run test 2>&1 | tee /tmp/ship_vitest.txt &
wait

If no test command is configured: note "No test suite configured" and continue. If everything passes: note the counts briefly and continue. If anything fails: do NOT stop immediately — apply the Test Failure Ownership Triage below.


Test Failure Ownership Triage

When tests fail, establish ownership before deciding to stop.

Step T1: Classify each failure

Each failing test is an independent, read-only judgment call: does this branch own the failure (in-branch) or did it arrive broken (pre-existing)? Gather the branch diff once, then classify each failing test against it. No part of this mutates the repo or asks the user — you produce verdicts and act on them in the main loop.

Gather the input first:

git diff origin/<base>...HEAD --name-only

Default (inline): Walk the failing tests one at a time in this context. For each, compare its test file, its source-file-under-test, and the first ~10 lines of error output against the changed-files list, then apply the rules below. This is the cheap path and the default.

Classification rules:

  • in-branch if: the failing test file itself was modified on this branch, OR the test output references code changed on this branch, OR you can trace the failure to a branch-diff change.
  • pre-existing if: neither the test file nor the code it tests was modified on this branch, AND the failure is unrelated to any branch change you can identify.
  • When ambiguous, default to in-branch with low confidence — it's safer to stop the developer than to let a broken test ship. Only call something pre-existing when you're confident. For a pre-existing verdict, capture the likely author (prefer the production-code author over the test-file author when they differ) and a suggested issue title, and quote the error excerpt verbatim.

Opt-in (parallel): If there are many failing tests and the user has opted into subagents (see How this runs — ask first), run one agent per failure as a dynamic Workflow. Pass the changed-files list plus each failing test's name, test-file path, source-file-under-test, and first ~10 lines of error output into the Workflow as args:

export const meta = {
  name: 'ship-failure-triage',
  description: 'Parallel ownership classification of failing tests — one agent per failure',
  phases: [{ title: 'Classify' }],
}
const TRIAGE_SCHEMA = {
  type: 'object',
  properties: {
    test: { type: 'string' },
    classification: { type: 'string' },                 // in-branch | pre-existing
    confidence: { type: 'string' },                     // high | low
    reasoning: { type: 'string' },
    likelyAuthor: { type: 'string' },                   // for pre-existing: who last touched the code
    issueTitle: { type: 'string' },                     // suggested title if filed
    errorExcerpt: { type: 'string' },                   // first ~10 lines, verbatim
  },
  required: ['test', 'classification', 'confidence', 'reasoning'],
}
const triage = await parallel(args.failures.map(f => () =>
  agent(
    `You are classifying ONE failing test for ship-ownership. Do NOT mutate the repo or talk to the user — ` +
    `return a verdict only; the main loop decides and acts.\n\n` +
    `BRANCH DIFF (files changed on this branch):\n${args.changedFiles}\n\n` +
    `FAILING TEST: ${f.name}\n` +
    `TEST FILE: ${f.testFile}\n` +
    `SOURCE UNDER TEST: ${f.sourceFile}\n` +
    `ERROR OUTPUT (first ~10 lines):\n${f.error}\n\n` +
    `Classify as "in-branch" if: the failing test file itself was modified on this branch, OR the test ` +
    `output references code changed on this branch, OR you can trace the failure to a branch-diff change. ` +
    `Classify as "pre-existing" if: neither the test file nor the code it tests was modified on this branch, ` +
    `AND the failure is unrelated to any branch change you can identify. ` +
    `When AMBIGUOUS, default to "in-branch" with confidence "low" — it is safer to stop the developer than ` +
    `to let a broken test ship. Only classify "pre-existing" when you are confident. ` +
    `For a pre-existing verdict, name the likely author (production-code author preferred over test-file ` +
    `author when they differ) and a suggested issue title. Quote the error excerpt verbatim.`,
    { label: `triage:${f.key}`, phase: 'Classify', model: 'opus', schema: TRIAGE_SCHEMA }
  )
))
return triage.filter(Boolean)

Pass args: { changedFiles, failures: [{ key, name, testFile, sourceFile, error }, ...] }. These verdicts are heuristic — the agents' judgment reading the diff and the test output. If the Workflow fails or times out, fall back to classifying each failure sequentially with the same in-branch / pre-existing rules.

Either way, route each verdict in the main loop: in-branch → Step T2; pre-existing → Step T3.

Step T2: Handle in-branch failures

STOP. These are the developer's failures. Show them and don't proceed. The developer fixes their own broken tests before shipping.

Step T3: Handle pre-existing failures

Use AskUserQuestion:

These test failures appear pre-existing (not caused by your branch changes):

[list each failure with file:line and a brief error description]

RECOMMENDATION: choose A — fix now while the context is fresh — OR choose B if this is a collaborative repo and someone else owns the code.

A) Investigate and fix now (root cause, minimal fix) B) File an issue assigned to whoever last touched the failing code C) Add as a P0 TODO — fix after this branch lands D) Skip — I know about this, ship anyway

Step T4: Execute the chosen action

If "Investigate and fix now":

  • Switch into investigation mode: root cause first, then minimal fix.
  • Commit the fix separately from the branch's main changes: git commit -m "fix: pre-existing test failure in <test-file>"
  • Continue with the workflow.

If "File an issue":

  • Find who likely broke it. Check BOTH the test file AND the production code it tests (the inline triage or the Workflow already surfaced likelyAuthor; confirm it):
    git log --format="%an (%ae)" -1 -- <failing-test-file>
    git log --format="%an (%ae)" -1 -- <source-file-under-test>
    If these are different people, prefer the production-code author — they likely introduced the regression.
  • Create an issue assigned to that person:
    • If GitHub:
      gh issue create \
        --title "Pre-existing test failure: <test-name>" \
        --body "Found failing on branch <current-branch>. Failure is pre-existing.\n\n**Error:**\n\`\`\`\n<first 10 lines>\n\`\`\`\n\n**Last modified by:** <author>" \
        --assignee "<github-username>"
    • If GitLab:
      glab issue create \
        -t "Pre-existing test failure: <test-name>" \
        -d "Found failing on branch <current-branch>. Failure is pre-existing.\n\n**Error:**\n\`\`\`\n<first 10 lines>\n\`\`\`\n\n**Last modified by:** <author>" \
        -a "<gitlab-username>"
  • If --assignee/-a fails (user not in the org), create the issue without an assignee and note who should look at it in the body.
  • Continue with the workflow.

If "Add as a P0 TODO":

  • If TODOS.md exists, add a P0 entry with the title, error output, and the branch it was noticed on.
  • If TODOS.md doesn't exist, create it with a standard header and add the entry.
  • Continue with the workflow.

If "Skip":

  • Continue with the workflow.
  • Note in the output: "Pre-existing test failure skipped: <test-name>"

After triage: if any in-branch failures remain unfixed, STOP. If every failure was pre-existing and handled, continue to Step 3.25.


Step 3.25: Eval Suites (conditional)

Evals are mandatory when prompt/LLM-related files change. Skip this step entirely if no prompt files are in the diff.

1. Check whether the diff touches prompt-related files:

git diff origin/<base> --name-only

Match against common prompt/LLM patterns:

  • **/*prompt*, **/*_prompt_builder.*
  • **/*_generation_service.*, **/*_writer_service.*
  • **/*_evaluator.*, **/*_scorer.*, **/*_classifier*
  • **/system_prompts/*, **/prompts/*.txt, **/prompts/*.md
  • test/evals/**, evals/** (eval-infrastructure changes affect all suites)
  • Files importing OpenAI/Anthropic SDKs alongside prompt strings

If a project config (e.g. CLAUDE.md) declares its own prompt-file patterns, use those.

If nothing matches: print "No prompt-related files changed — skipping evals." Continue.

2. Identify the affected eval suites:

Each eval runner usually declares which source files affect it (e.g. a PROMPT_SOURCE_FILES constant). Grep for those references to find the matching suites. If you're unsure which suites are affected, run ALL suites that could plausibly be impacted — over-testing beats missing a regression.

3. Run the affected suites at the highest-fidelity tier. Ship is a pre-merge gate, so use the project's "full" or "production" eval tier (e.g. EVAL_JUDGE_TIER=full).

If multiple suites need to run, run them sequentially (each needs a test lane). If the first suite fails, stop immediately — don't burn API cost on the rest.

4. Check results:

  • If any eval fails: show the failures and the cost summary. STOP.
  • If all pass: note the pass counts and cost. Continue.

5. Save the eval output — it goes into the PR body in Step 8.


Step 4: Staff Review (pre-landing)

Run the pre-merge-review structural pass over the diff before landing, using the same specialist-lens approach as the /pre-merge-review skill — so the pre-landing gate happens without leaving the ship flow. pre-merge-review is a sibling skill, not a subagent; do NOT spawn it via the Agent tool.

  1. Select specialists by what the diff touches (security, performance, testing, maintainability, data-migration, api-contract, design); skip the pass entirely if the diff is < 50 lines. (Use the same selection logic the /pre-merge-review skill applies.)
  2. Run the specialist lenses.
    • Default (inline): work through the selected lenses one at a time in this context. For each lens, run git diff origin/<base>, review against that lens's checklist (the same checklists the /pre-merge-review skill uses), and collect findings. This is the cheap default.
    • Opt-in (parallel): if the diff is large and touches many areas and the user has opted into subagents (see How this runs — ask first), launch the specialist panel as a Workflow, one agent() per lens. Pass args: { base, stack, testFw, specialists: [{ key, domain, checklist }, ...] }, where each checklist is the verbatim checklist for that lens from the /pre-merge-review skill:
export const meta = {
  name: 'ship-specialists',
  description: 'Parallel specialist review army over the branch diff — one lens per agent',
  phases: [{ title: 'Specialist' }],
}
const FINDING_SCHEMA = {
  type: 'object',
  properties: {
    specialist: { type: 'string' },
    findings: {
      type: 'array',
      items: {
        type: 'object',
        properties: {
          severity: { type: 'string' },
          confidence: { type: 'number' },
          path: { type: 'string' },
          line: { type: 'number' },
          category: { type: 'string' },
          summary: { type: 'string' },
          fix: { type: 'string' },
          fingerprint: { type: 'string' },
          evidence: { type: 'string' },
          test_stub: { type: 'string' },
        },
        required: ['severity', 'confidence', 'path', 'category', 'summary'],
      },
    },
  },
  required: ['specialist', 'findings'],
}
const reviews = await parallel(args.specialists.map(s => () =>
  agent(
    `You are a specialist code reviewer for ${s.domain} on a ${args.stack} project.\n\n` +
    `Run \`git diff origin/${args.base}\` to get the full diff. Review against the checklist below.\n\n` +
    `For each finding return: severity (CRITICAL|INFORMATIONAL), confidence (1-10), path, line (optional), ` +
    `category, summary, fix, fingerprint (path:line:category), specialist ("${s.domain}"); optionally evidence ` +
    `and a test_stub (minimal ${args.testFw} skeleton if a test would catch it). Before flagging a commented ` +
    `line, walk up to the nearest block boundary; if the enclosing function is itself commented, it is dead — ` +
    `do not file it. If no findings, return an empty array. Findings only, no preamble.\n\n` +
    `CHECKLIST:\n${s.checklist}`,
    { label: `specialist:${s.key}`, phase: 'Specialist', model: 'opus', schema: FINDING_SCHEMA }
  )
))
return reviews.filter(Boolean)
  1. Merge + fix-first (main loop): dedupe by fingerprint; classify each finding AUTO-FIX (mechanical → fix directly) vs ASK (security / race / design / >20-line / behavior-changing → user decision); any test_stub finding reclassifies to ASK. (Use the same classification table the /pre-merge-review skill defines.) Then:

If the pass applies auto-fixes: commit them:

git add <fixed-files> && git commit -m "fix: pre-landing review fixes"

If ASK items remain: present them in ONE AskUserQuestion with per-item options (A) Fix, (B) Skip. Apply approved fixes and commit.

If fixes were applied: re-run tests (Step 3) to confirm the fixes didn't break anything. This is an IRON LAW — no completion claims without fresh verification.

If no issues are found: continue.

Output summary: Pre-Landing Review: N issues — M auto-fixed, K asked (J fixed, L skipped) Or: Pre-Landing Review: No issues found.

Save this summary — it goes into the PR body in Step 8.


Step 5: Stage all changes

Stage every uncommitted change (code that hasn't been committed yet):

git status --porcelain

If there are unstaged changes, they need to land in the commits.


Step 6: Commit (bisectable chunks)

Goal: small, logical commits that work well with git bisect and help future readers see what changed.

  1. Read the diff and group changes into logical commits. Each commit = one coherent change (not one file, but one logical unit).
  2. Commit ordering (earlier commits first):
    • Infrastructure: migrations, config changes, new dependencies, route additions
    • Core logic: models, services, utilities, hooks, API functions (with their tests)
    • Components & views: controllers, views, UI components, pages (with their tests)
    • Final: any remaining changes + VERSION/CHANGELOG/TODOS metadata
  3. Splitting rules:
    • A component and its test go in the same commit
    • A service/hook/model and its test go in the same commit
    • A controller + its views + its test go in the same commit
    • Migrations are their own commit (or grouped with the model they support)
    • Config/route changes group with the feature they enable
    • If the whole diff is small (< 50 lines across < 4 files), a single commit is fine
    • If the repo squash-merges PRs (check the merge-commit history) or the user prefers one commit, a single commit is fine — match the repo's convention rather than forcing a bisectable split
  4. Each commit must stand on its own — no broken imports, no references to code that doesn't exist yet. Order commits so dependencies come first.
  5. Compose each commit message:
    • First line: <type>: <summary> (type = feat/fix/chore/refactor/docs/test)
    • Body: brief description
    • Append an attribution / co-author trailer only if the repo's history already uses one or the user asked for it — match the existing style; the identity below is an example, not a default to hardcode. If only the final commit carries the trailer:
git commit -m "$(cat <<'EOF'
<type>: <summary>

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
EOF
)"
  1. Always stage specific files by name — never git add -A or git add ., which can sweep in sensitive files.
  2. Never commit .env files, credentials, or secrets.

Step 6.5: Verification Gate

IRON LAW: NO COMPLETION CLAIMS WITHOUT FRESH VERIFICATION EVIDENCE.

Before pushing, re-verify if code changed during Steps 4–6:

  1. Test verification: if ANY code changed after Step 3's test run (pre-merge-review fixes, etc.), re-run the suite. Paste the fresh output. Stale output is not acceptable.
  2. Build verification: if the project has a build step, run it. Paste the output.
  3. Rationalization prevention:
    • "Should work now" → RUN IT.
    • "I'm confident" → confidence is not evidence.
    • "I already tested earlier" → code changed since then. Test again.
    • "It's a trivial change" → trivial changes break production.

If tests fail here: STOP. Do not push. Fix it and return to Step 3.


Step 7: Push

Idempotency check: is the branch already pushed and up to date?

git fetch origin <branch-name> 2>/dev/null
LOCAL=$(git rev-parse HEAD)
REMOTE=$(git rev-parse origin/<branch-name> 2>/dev/null || echo "none")
[ "$LOCAL" = "$REMOTE" ] && echo "ALREADY_PUSHED" || echo "PUSH_NEEDED"

If ALREADY_PUSHED, skip the push but continue to Step 8. Otherwise push with upstream tracking:

git push -u origin <branch-name>

Never force push. Plain git push only.


Step 8: Create PR/MR

Idempotency check: does a PR/MR already exist for this branch?

If GitHub:

gh pr view --json url,number,state -q 'if .state == "OPEN" then "PR #\(.number): \(.url)" else "NO_PR" end' 2>/dev/null || echo "NO_PR"

If GitLab:

glab mr view -F json 2>/dev/null | jq -r 'if .state == "opened" then "MR_EXISTS" else "NO_MR" end' 2>/dev/null || echo "NO_MR"

If an open PR/MR already exists: update its body with gh pr edit --body "..." (GitHub) or glab mr update -d "..." (GitLab). Always regenerate the body from scratch using this run's fresh results — never reuse a stale body from a prior run.

If no PR/MR exists: create one using the platform detected in Step 0.

PR/MR Body Template

## Summary
<Run `git log <base>..HEAD --oneline` to enumerate every commit. Group the commits
into logical sections (e.g., "**Feature**", "**Refactor**", "**Infrastructure**").
Every substantive commit must appear in at least one section. If a commit's work
isn't reflected in the summary, you missed it.>

## Pre-Landing Review
<findings from Step 4 pre-merge-review, or "No issues found.">

## Eval Results
<If evals ran: suite names, pass/fail counts, cost summary. If skipped: "No prompt-related files changed — evals skipped.">

## Test plan
- [x] All tests pass (<counts>)
- [x] Pre-landing pre-merge-review completed
- [x] Base branch merged, tests re-run on merged state

Generated with Claude Code

Create the PR/MR

If GitHub:

gh pr create --base <base> --title "<type>: <summary>" --body "$(cat <<'EOF'
<PR body from above>
EOF
)"

If GitLab:

glab mr create -b <base> -t "<type>: <summary>" -d "$(cat <<'EOF'
<MR body from above>
EOF
)"

If neither CLI is available: Print the branch name and remote URL, and tell the user to open the PR/MR manually in the web UI. Do not stop — the code is pushed and ready.

PR title rules

  • Keep it under 70 characters
  • Conventional commit format: feat:, fix:, chore:, refactor:, docs:, test:
  • Summarize the user- or developer-facing change, not the file list

Output the PR/MR URL — it should be the last thing the user sees.


Next Steps — Review Chaining

Once the PR/MR is up, recommend the natural follow-ups:

  • /file-followup-issues — file GitHub issues for every unresolved review finding (SHOULD FIX / FOLLOW-UP / deferred MUST FIX) recorded in REVIEWED.md, SCOPE_REVIEW_*.md, PLAN_REVIEW_*.md, PR-comment.md, or pre-merge-review notes, now that the branch has landed.
  • /qa — if the branch shipped user-facing changes and no QA pass has run yet.
  • /doc-sync — confirm docs match what shipped (new features, APIs, or significant behavior changes).

Never block on these — the PR/MR URL is the primary deliverable.


Important Rules

  1. Never skip tests. In-branch failures stop the ship. Pre-existing failures go through triage.
  2. Never skip the pre-landing staff review. If it can't run, stop and report.
  3. Never force push. Plain git push only.
  4. Never ask for trivial confirmations (e.g. "ready to push?", "create PR?"). DO stop for: pre-merge-review ASK items, test failures, merge conflicts, a missing distribution pipeline.
  5. Split commits for bisectability — each commit = one logical change.
  6. Always stage specific files — never git add -A or git add ..
  7. Never commit .env files, credentials, or secrets.
  8. Never push without fresh verification evidence. If code changed after the Step 3 tests, re-run before pushing.
  9. Suggest /plan-review for large diffs (>200 lines) with no prior review — but never block. Ship runs pre-merge-review regardless.
  10. Interactive work and state mutations stay in the main loop; only opt-in read-only compute fans out to a Workflow. Never put a gate, an AskUserQuestion ceremony, or any git/file mutation inside a Workflow agent() — background agents can't talk to the user or write the repo.
  11. The goal: user says "ship it", the next thing they see is the PR/MR URL.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.