Skip to content
Development
Skill

/ship

Open a PR and merge it in one step — combines `bin/pr.sh` create with `bin/wait-for-pr-checks.sh` polling and `gh pr merge`. Default mode enables GitHub's native auto-merge so the terminal returns immediately; `--client-side` polls in the foreground and merges when CI goes

From plugin
nyann
641 skills41 commands3 hooks
Install
$ npx -y skills add thettwe/nyann --skill ship --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/ship

Context preview

The summary Claude sees to decide when to auto-load this skill.

Open a PR and merge it in one step — combines `bin/pr.sh` create with `bin/wait-for-pr-checks.sh` polling and `gh pr merge`. Default mode enables GitHub's native auto-merge so the terminal returns immediately; `--client-side` polls in the foreground and merges when CI goes

SKILL.md

ship.SKILL.md
name: ship
description: >
  Open a PR and merge it in one step — combines `bin/pr.sh` create with
  `bin/wait-for-pr-checks.sh` polling and `gh pr merge`. Default mode
  enables GitHub's native auto-merge so the terminal returns
  immediately; `--client-side` polls in the foreground and merges when
  CI goes green.
  TRIGGER when the user says "ship this PR", "ship it", "open and merge",
  "PR and merge", "create PR and auto-merge it", "wait for CI then merge",
  "block until merged", "/nyann:ship".
  Do NOT trigger on "open a PR" alone (no merge intent) — that's the
  `pr` skill. Do NOT trigger on "merge this existing PR #N" — ship is
  PR-creation + merge, not standalone merge of an already-open PR.
  Do NOT trigger on "release X.Y.Z" — that's the `release` skill, which
  tags a merged commit rather than creating one.

ship

Wraps `bin/ship.sh`. The script composes `bin/pr.sh` (PR creation), `bin/wait-for-pr-checks.sh` (poll), and `gh pr merge` (merge) into a single ShipResult. The output schema is at `schemas/ship-result.schema.json`.

0. Drift check (quick, non-blocking)

Run `bash bin/session-check.sh --flow=ship`. If it produces output, surface the line to the user verbatim. Do not block the flow.

1. Pick the mode up front

Two modes, decided at invocation. They have very different terminal behavior, so confirm with the user when it isn't obvious which they want.

| Mode | Default | Terminal behavior | Use when | |---|---|---|---| | `auto-merge` | yes | returns ~instantly with `outcome:"queued"` | repo allows auto-merge, user wants to walk away | | `client-side` (`--client-side`) | opt-in | blocks until ship-or-fail | repo doesn't allow auto-merge, or user wants the wait surfaced |

If the user says "ship it and let me know when it's in" or "block until merged", use `--client-side`. If they say "queue it for merge" or "ship and I'll come back later", use the default.

When the user's intent doesn't clearly map to either mode, **you MUST call the `AskUserQuestion` tool** (not plain text):

{
  "questions": [
    {
      "question": "How should this PR be merged after CI passes?",
      "header": "Ship mode",
      "multiSelect": false,
      "options": [
        { "label": "Auto-merge (Recommended)", "description": "Returns immediately; GitHub merges when checks pass" },
        { "label": "Client-side", "description": "Blocks here until CI is green, then merges" }
      ]
    }
  ]
}

2. Pre-flight (same as `pr` skill)

  • `bin/ship.sh` runs the same gh guard as `bin/pr.sh`. Skip records

with reason `gh-not-installed` or `gh-not-authenticated` short-circuit before any PR is created. Relay these as-is.

  • The current branch must not be `main`/`master`. The underlying

`pr.sh` enforces this; if it dies, route the user to `/nyann:branch` first.

  • Synthesize the title + body the same way the `pr` skill does:

`bin/pr.sh --target <cwd> --context-only` first, then build a Conventional-Commits title and a Summary/Test-plan markdown body.

Pre-action guards

bash bin/pre-action-guard.sh --flow ship --target <cwd> [--profile <resolved-profile.json>]

By default ship runs the PR-flow guards (`branch-pushed`, `wip-commits`). A `guards.ship` array REPLACES that default set (subset semantics — it does not append) and may promote severities.

`coverage-delta` is an **opt-in** guard — off by default. Since `guards.ship` replaces the default set, enable it by re-listing the built-ins alongside it: `"guards":{"ship":[{"name":"branch-pushed"},{"name":"wip-commits"},{"name":"coverage-delta"}]}`. Naming only `coverage-delta` would silently drop them. It warns (advisory by default; promote to `confirm` via the profile) when the branch lowers test coverage versus the cached `.nyann/coverage-baseline.json`, tolerant up to `guards.coverage_delta_threshold` percentage points (default 0). It reuses an existing CI coverage artifact and **soft-skips** when none is present (it never runs the suite), so it's best paired with a profile/CI that already produces coverage. Refresh the baseline on the base branch / post-merge with `bash bin/guards/coverage-delta.sh --update-baseline`.

| Exit | Meaning | Action | |---|---|---| | 0 | Pass | Continue | | 3 | Critical guard failed | Refuse to ship. The user has to fix the underlying issue or pass `--skip-guards`. | | 4 | Confirm-severity guard failed | AskUserQuestion: "Proceed with ship?" — explicit confirm required. |

3. Confirm before shipping

Show the user the proposed title, body, and **mode** before invoking.

  • **Auto-merge**: "Ship it via auto-merge? (returns immediately;

GitHub merges when checks pass)"

  • **Client-side**: "Block here while CI runs and merge when green?

Default timeout is **30 minutes** (polling every **30 seconds**). Override with `--timeout` / `--interval` if your CI is slower."

Skip the confirmation only when the user said "just ship it" / "don't ask, ship it now".

4. Invoke

bin/ship.sh \
  --target <cwd> \
  --title "<conventional-title>" \
  --body  "<markdown-body>" \
  [--base <branch>] \
  [--draft] \
  [--client-side] \
  [--merge-strategy squash|rebase|merge] \
  [--timeout <sec>] [--interval <sec>] \
  [--allow-no-checks]

`--draft` opens as draft (auto-merge will wait for ready-for-review + checks; client-side mode merges as draft if you pass `--draft`, which is rarely what you want). `--merge-strategy` defaults to `squash`; respect the user's preference if they name a different one. `--timeout` and `--interval` are forwarded to the wait phase in client-side mode (defaults: 30 min / 30 s).

`--allow-no-checks` is a safety opt-out for client-side mode. By default, the script refuses to merge when the waiter reports `no-checks` — that outcome on a fresh PR almost always means "workflows haven't attached yet" rather than "this repo has no PR CI", so silently merging would defeat the gate. Pass `--allow-no-checks` only when you know the repo runs no PR-side che

Read more
Ships withnyann

ငြမ်း is Burmese for scaffolding. Nyann is the Claude Code plugin that picks expert git defaults for your stack — branching, working hooks (Husky / pre-commit.com / lefthook), commits, releases, CI, docs — then keeps the repo on those rails through every PR

Get the whole plugin

Other skills on nyann.