ship — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited ship (Agent Skill) and scored it 92/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 2 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 2 flagged
The text {match} tells the agent to skip the normal "ask the user first" gate. Used adversarially it removes the human-in-the-loop check before destructive or sensitive actions, turning a normally-gated agent into a fire-and-forget executor.
The text {match} tells the agent to skip the normal "ask the user first" gate. Used adversarially it removes the human-in-the-loop check before destructive or sensitive actions, turning a normally-gated agent into a fire-and-forget executor.
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
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.
Run bash bin/session-check.sh --flow=ship. If it produces output, surface the line to the user verbatim. Do not block the flow.
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" }
]
}
]
}pr skill)bin/ship.sh runs the same gh guard as bin/pr.sh. Skip recordswith reason gh-not-installed or gh-not-authenticated short-circuit before any PR is created. Relay these as-is.
main/master. The underlyingpr.sh enforces this; if it dies, route the user to /nyann:branch first.
pr skill does:bin/pr.sh --target <cwd> --context-only first, then build a Conventional-Commits title and a Summary/Test-plan markdown body.
bash bin/pre-action-guard.sh --flow ship --target <cwd> [--profile <resolved-profile.json>]Ship runs both the PR-flow guards (branch-pushed, wip-commits) and any profile-promoted guards under guards.ship.
| 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. |
Show the user the proposed title, body, and mode before invoking.
GitHub merges when checks pass)"
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".
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 checks (no GitHub Actions, no required reviews, etc.) and the empty state is intentional. Auto-merge mode doesn't need this flag — GitHub's server-side auto-merge already handles required-checks state correctly.
Branch on .outcome:
| Outcome | Mode | What happened | What the user should do |
|---|---|---|---|
queued | auto-merge | GitHub's auto-merge enabled; merge happens server-side when checks + reviews pass | trust it, walk away |
shipped | client-side | merge call succeeded after green CI | done; PR is merged + branch deleted |
ci-failed | client-side | one or more checks failed OR the PR had no checks attached without --allow-no-checks; loop bailed | inspect ci_failed_reason in the JSON; for the no-checks case re-run with --allow-no-checks if the empty state is intentional, otherwise wait for workflows to attach and retry |
ci-timeout | client-side | wait deadline hit, some still in_progress | retry with --timeout higher, or investigate runners |
merge-failed | either | auto-merge couldn't be enabled (e.g. branch protection) or gh pr merge failed | inspect merge_failed_reason; common causes: required reviews missing, branch protection forbids the strategy |
pr-failed | either | bin/pr.sh died before producing a URL | rerun /nyann:pr to surface the underlying error |
skipped | either | gh missing/unauthed; nothing was created | tell the user; can't proceed |
The script always exits 0. Branch on the .outcome field in the JSON to determine what happened.
merge-failed with reason like "auto-merge is not allowed" → suggestretrying with --client-side, which polls then calls gh pr merge directly (works even when server-side auto-merge is disabled).
merge-failed with reason like "required reviews" → relay verbatim;the user needs a reviewer to approve before merge can proceed.
ci-failed → don't suggest re-running ship; route the user to fixthe failing job first. Mention they can check it via gh pr checks <num> directly.
pr skill.wait-for-pr-checks skill.release skill — invoke after shipreports shipped or after the auto-merge actually lands.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.