Skip to content
Back to skills

Ship

ASecurity

Commit and push the current snapshot, creating a branch in a detached, task-owned worktree when needed; open a ready PR and merge when clean. Use when the user asks to ship, publish, or hand off local changes. Matching beta and docs paths publish automatically after merge; other production promotion is manual.

  • 6,969 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added May 27, 2026
data-aigobashreactgitapi

Works with

  • claude code
  • cursor
  • terminal
  • cli
  • api

Security analysis

A100/100

Scanned September 30, 2026

npx -y skills add BuilderIO/agent-native --skill ship --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Ship?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Ship
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/builderio-ship/badge)](https://www.skillsdirectory.com/skills/builderio-ship)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: ship
description: >-
  Commit and push the current snapshot, creating a branch in a detached,
  task-owned worktree when needed; open a ready PR and merge when clean. Use
  when the user asks to ship, publish, or hand off local changes.
  Matching beta and docs paths publish automatically after merge; other
  production promotion is manual.
user-invocable: true
scope: dev
metadata:
  internal: true
---

# Ship

Use /ship only when the user asks to ship, publish, or hand off the current
work. It means: publish the requested current-branch snapshot, open a ready
PR, and monitor it through merge unless the user explicitly asks to leave the
PR open. A merged shipment also leaves the worktree ready for the next task.

## Contract

- Ship all nonignored changes belonging to the requested work on the current
  branch. The checkpoint helper excludes learnings.md, bridge/**, and data/**.
- A ship request authorizes publishing a new PR. Pushing to someone else's PR
  needs explicit current authorization for that exact PR; links and inherited
  ship authority don't count. It permits a normal fast-forward push, not a
  merge. Merge with separate current authorization; otherwise use
  `ship_mode=ready-only` and leave the PR open. Before every push, resolve the
  active GitHub login with `gh api user --jq .login`, include `author` in the
  live PR query, and compare `author.login` with that login. Verify the head
  repository, branch, head OID, and base; recheck the head.
- Preserve unrelated or incomplete concurrent work. Never reset, clean, stash,
  overwrite, rebase, or force-push it.
- `/ship` starts in `ship_mode=merge-authorized` for a new PR or a PR authored
  by the current user. For an existing PR authored by someone else, an exact
  current-request authorization to push is push-only: use
  `ship_mode=ready-only` and leave the PR open. Use `merge-authorized` for
  that PR only when the same request separately authorizes merging that exact
  PR. A general ship request or earlier merge authorization does not change
  this. Otherwise, merge once the gates below pass unless the user explicitly
  says to leave the PR open. If they opt out, switch to `ship_mode=ready-only`;
  keep fixing CI and review feedback until the PR is ready, then leave it open
  and do not rotate the branch.
- Before the guarded merge, persist its exact verified PR head OID as
  `ship_merge_head_oid` in the active goal or task transcript. Continue in the
  foreground through post-merge disposition. Carry the immutable value through
  verification; never replace it with a live PR head read after merge, because
  the source branch may advance or be deleted.
- `/ship` uses the current suitable branch when attached. In a dedicated
  task-owned worktree, creating or switching to a needed task branch is already
  authorized; Steve's explicit request to ship or open a PR from a detached
  worktree is standing authorization, so do not ask again. Before branch
  movement, classify all staged, unstaged, and untracked paths; a switch carries
  the whole index and worktree, so proceed only when every dirty path belongs to
  this task. Otherwise preserve the checkout and report exact paths without
  asking again. Base new shipments on fresh `origin/main`; existing PR updates
  use the fetched live PR head as `new-branch` describes. Never move or rewrite
  a branch used by another worktree or a platform-assigned branch. After
  `origin/main` ancestry is verified, rotate to a fresh task branch in the
  task-owned worktree without asking when `/ship` safety checks pass. If
  unpublished commits or dirty publishable paths remain, retain the source
  branch and report them. In a shared checkout, keep its branch unchanged. If
  it cannot safely serve as the PR source, `/ship` authorizes a managed
  task-owned worktree and branch without asking. Follow `new-branch` for the
  base: fresh `origin/main` for a new PR, the fetched live PR head for an
  existing PR update. Carry only this task's changes. If they cannot be
  isolated safely, preserve all state and report exact paths or commits without
  asking for branch or worktree permission.
- In Codex, inspect the task goal with `get_goal` at the start. If none exists,
  create one with `create_goal` whose objective, under normal `/ship`
  authorization, says to continue until the PR is merged, `origin/main` ancestry
  is verified, and the task-owned worktree is rotated to a fresh branch when
  the safety checks pass. Retain the source branch and report any unpushed
  commits or dirty publishable paths. In a shared checkout, keep the source
  branch; if it cannot safely source the PR, follow `new-branch` to isolate
  this shipment with the correct base without asking. Preserve
  platform-assigned branches while checking and fixing CI/review feedback and
  using the guarded squash-admin merge. If the user explicitly opts out of
  merging, make the goal match that endpoint. Reuse an existing goal only when
  it covers this shipment; never replace an unrelated goal. For
  `ship_mode=ready-only`, set the endpoint to an open PR with green required
  checks, addressed review feedback with no new actionable item at final
  revalidation, `MERGEABLE`, a clean worktree, and no unpushed commits.
  Complete the ship goal only after its stated endpoint is reached.
  The goal records the objective; `/babysit-pr` owns the checks. `/ship` stays
  foreground-only and creates no watcher or lease.
- In Claude Code, use its native session goal for the same endpoint. `/goal` is
  a session command, not an agent tool, so the user must submit it as a separate
  message before invoking `/ship`; loading the skill cannot set it. Submit this
  condition in a standalone `/goal` message: `Run /ship through the guarded admin merge, verify
  origin/main contains the merge commit, then rotate this task-owned worktree
  to a fresh branch when no unpushed commits or dirty publishable paths remain.
  Do this without asking for confirmation. Keep the source branch and report
  any remaining commits or paths. In a shared checkout, keep the source branch;
  if it cannot safely source the PR, follow `new-branch` to create a managed
  task-owned worktree from the correct base and carry only this task's changes
  without asking. Keep platform-assigned Builder.io and Fusion branches unchanged. Keep checking
  and fixing CI and review feedback until then.` Do not replace an
  unrelated active goal; Claude Code permits one per session. If `/ship` was
  already invoked without one, keep shipping in the
  foreground; the missing native goal does not block the authorized merge or
  completion. Do not claim that a native goal is active.
  If the user explicitly opts out of merge, replace that goal with the
  `ready-only` endpoint above; leave the PR open and do not rotate.
  The goal evaluator reads the transcript, so report the live PR state, merge
  SHA, ancestry proof, and branch disposition as they happen. If Claude clears,
  pauses, or completes the goal before the actual endpoint, state that it is
  inactive and continue the shipment in the foreground. If the session ends
  first, give the user the same condition to submit as `/goal` in the next
  session; do not claim the goal is active or ask the user to interrupt an
  in-progress shipment to restore it.
- If the user asks not to create scheduled tasks, keep ship and babysitting in
  the foreground; do not create a separate recurring automation.
- For a linked GitHub issue, a verified source fix in the merged shipping
  snapshot is enough to close it. Start an authorized issue comment by thanking
  the reporter for opening it, then link the fix and close immediately; do not
  leave it open waiting for publication, beta, or live proof, and never say
  "leaving open until published." Keep it open only while accepted scope is
  still unfixed, the source fix is not merged, or reporter information is
  required. Ask a targeted question only if the invoking workflow authorizes an issue
  comment, and begin it by thanking the reporter for opening the issue.
- Use the current worktree. If it is detached, create a named task branch only
  when publishing this work requires one, as described in the preflight gate
  below. Do not create a branch just for tidiness or attach or move another
  worktree.
- Never add Co-Authored-By, codex, [codex], or agent labels to commits, branch
  names, PR titles, or PR bodies.

## Flow

1. Preflight the worktree and ownership.
2. Run focused validation and publish the first coherent snapshot.
3. Open or update the ready PR immediately.
4. Run `/babysit-pr <number>` in this foreground task with the inherited
   `ship_mode`. The standalone 30-minute stop never ends a `/ship` lifecycle.
5. In `merge-authorized` mode, merge only after the live gates hold for 10
   minutes. In `ready-only` mode, stop at the verified ready-PR gate and leave
   the PR open.
6. After a merge, verify it reached `origin/main`, then finish branch
   disposition. In a task-owned worktree, rotate to a fresh task branch without
   asking if `/ship` safety checks pass; in a shared checkout, keep the source
   branch and follow `new-branch` to isolate if it cannot safely source the PR.
   `ready-only`
   shipments do not rotate.
7. Report source checks, PR, merge or intentional open state, branch
   disposition, and deployment boundaries separately.

## Existing PR backlog

When the user asks to ship a backlog, inspect every relevant open PR directly
with fresh `gh pr view` and `gh pr checks` state. Do not create a second
reminder or leave a scheduler repeating an unchanged status. For each PR:

- If required CI is failing, open the failing run logs, fix only an actionable
  repo-owned failure, publish one coherent update, and recheck the same head.
- In `merge-authorized` mode, if CI is green, the PR is mergeable, and review
  items are addressed, use the authorized admin merge after the unchanged
  10-minute soak. Capture the final live `headRefOid` immediately before
  merging, retain that OID for branch disposition, and bind the operation to it:
  `gh pr merge <number> --squash --admin --match-head-commit <verified-head-oid>`.
  If the command rejects because the head changed, restart the soak.
- In `ready-only` mode, keep fixing CI and review feedback until the ready-PR
  gate in `/babysit-pr` holds; then leave the PR open without merging or rotating.
- If an external dependency is unchanged, record the exact blocker once and
  keep the foreground task quiet until a meaningful state change. Do not send
  repeated "continue" prompts that restate CI status.

The scheduler is a trigger, not the work. The original task that received the
ship request owns its endpoint; it must not stop at a progress report while an
actionable PR state is available. In `merge-authorized` mode, that endpoint is
merge, `origin/main` proof, and branch disposition; once the gates hold, the
owning task captures the final live `headRefOid` and performs the guarded admin
merge without waiting for the user or a separate watcher. In `ready-only` mode,
the endpoint is the verified ready-PR gate with the PR intentionally left open.
Under `merge-authorized`, `reviewDecision: REVIEW_REQUIRED` is not a user
handoff: once required checks are green, the live PR is `MERGEABLE`, and every
review item has a verified fix, reply, or terminal disposition, the owning task
must perform the guarded admin merge after the unchanged soak. Never ask the
user to click Merge for that routine authorized step.

## 1. Preflight

Start by refreshing the remote and reading the actual checkout:

```bash
if ! git fetch origin --quiet; then
  echo "Cannot refresh origin refs; stop before checking unpublished commits." >&2
  exit 1
fi
git status --short
git diff --stat
git log --oneline -5
git rev-list --count HEAD..origin/main
```

The all-origin fetch refreshes both `origin/main` and the current branch's
tracking ref before comparing unpublished work. Inspect the current branch's
unpushed commits with the remote-aware fallback:

```bash
if git show-ref --verify --quiet "refs/remotes/origin/$(git branch --show-current)"; then
  git log --oneline "origin/$(git branch --show-current)"..HEAD -- \
    ':(exclude)learnings.md' ':(exclude)bridge/**' ':(exclude)data/**'
else
  git log --oneline HEAD --not --remotes=origin -- \
    ':(exclude)learnings.md' ':(exclude)bridge/**' ':(exclude)data/**'
fi
```

The behind count is information, not a reason to update the branch. Merge
freshly fetched `origin/main` only when GitHub reports the PR `CONFLICTING`.
Pending checks, a behind count, or a timer never justify a main update.

If `git branch --show-current` is empty, inspect `git worktree list
--porcelain` and existing `changes-*` refs. In a dedicated task-owned worktree,
do not ask permission to create a shipping branch: fetch `origin/main`, save
`detached_head=$(git rev-parse HEAD)`, and choose an unused name using
`/new-branch`'s naming rules. Before any branch creation or switch, record
`git status --short --untracked-files=all` and classify every staged, unstaged,
and untracked path. A switch carries the whole index and worktree, so proceed
only when every dirty path belongs to this task. If any path is unrelated or
incomplete, preserve the detached checkout and report the exact paths without
asking again. If `origin/main` is an ancestor of
`detached_head`, create the branch at that saved commit so no detached commits
are lost. If `detached_head` is an ancestor of `origin/main`, create from the
fresh `origin/main` and carry or reapply the task's dirty changes; never stash,
discard, or overwrite them. If histories diverge, create from the saved
`detached_head` and reconcile fresh `origin/main` on that task branch. A name
already in use belongs to its existing task; pick another. In a shared
checkout, keep its branch unchanged. When `/ship` cannot safely publish from
that checkout, follow `new-branch` to isolate this shipment without asking.
Use fresh `origin/main` for a new PR and the live PR head for an existing PR
update. Never move or rewrite a branch checked out in another worktree.

Before publishing, classify every dirty path and unpushed commit. If any is
unrelated or incomplete concurrent work, preserve it and stop the publishing
step with a concrete report. Do not hide it in a stash or make a guessed
commit.

## 2. Validate and publish

Run the smallest relevant formatter, tests, typecheck, and guards for the
changed area. Finish the current implementation and batch all currently known
CI and review fixes into one coherent snapshot before publishing. Do not
publish per file, delegated task, feedback item, checkpoint, timer, or queued
check: every new head restarts affected CI and the merge soak. Only the
foreground ship owner publishes; delegates return their changes to that owner.
A slow or contaminated local check is not permission to publish an incomplete
snapshot; record the exact result and let the current PR checks finish.

After the ownership check, use `ship:push` for a new PR or when an existing
PR's head repository is `origin` and its `headRefName` matches the local branch.
For any other existing PR target, follow `babysit-pr`'s verified head remote/ref
procedure.

```bash
corepack pnpm ship:push -m "fix: deduplicate chat start checkpoints"
```

Replace the example with a subject naming the actual behavior changed. The
helper refuses an omitted or generic subject. Confirm the push landed on the
current branch and read the remote head back. Publish again only after a new
actionable CI/review fix or conflict has been resolved and all currently known
fixes are batched. A clean tree, a behind count, queued checks, or a babysit
timer never creates a publish commit.

## 3. Open or update the PR

Open or update one ready PR for the current branch immediately after the first
push. Use a factual title and body. Do not create a second PR from a worktree.
Do not tag, assign, mention, or leave proactive comments on the PR unless the
user explicitly requested that communication. A factual reply needed to
document a review fix or terminal disposition is allowed when the babysit
gate requires it.

Keep these claims separate in the PR and final report:

- source and focused tests;
- CI and review state;
- merged commit and origin/main ancestry;
- beta, docs, or production deployment state.

## 4. Babysit

Run /babysit-pr <number> immediately after PR creation in this foreground
task. Follow that skill for local-change ownership checks, review handling,
conflict recovery, and cadence. `/ship` never creates a watcher or acquires a
lease; keep this task active through its authorized endpoint.

Under `/ship` with `ship_mode=merge-authorized`, `/babysit-pr` is a blocking
subworkflow, not a terminal handoff. Do not return "All clear" or stop this
foreground task while the PR is open. A green, review-clean, mergeable
unchanged head that passes the 10-minute gate is an immediate guarded-merge
trigger. After merge, continue in this foreground task through `origin/main`
verification and branch disposition before completing the ship goal.

With `ship_mode=ready-only`, continue fixing CI and review feedback until the
PR is open, required checks are green, all review items are addressed, GitHub
reports `MERGEABLE`, no new actionable feedback arrived since the final review
scan, the worktree is clean, and no commits are unpushed. Then leave the PR
open and return to the parent `/ship` goal without merging or rotating. This is
the no-merge endpoint, not the standalone 30-minute quiet stop.

If a live PR is CONFLICTING, let babysit-pr recover it only after:

- the local tree and publishable-path unpublished-commit check are clean;
- the local HEAD exactly matches the live PR headRefOid;
- origin/main was freshly fetched.

Merge freshly fetched `origin/main` only to resolve the confirmed conflict.
Resolve and test it, push, and restart the soak. Never update from main merely
because the PR is behind, checks are pending, or mergeability is UNKNOWN.

### Feedback handoff

If /review-latest-feedback was used, carry its start cursor, grouped reports,
evidence links, and disposition table into the ship ledger and PR recap.
Follow review-latest-feedback for ownership, claims, reporter replies, and the
exact disposition vocabulary; follow babysit-pr for review comments and merge
blocking. Shipping does not independently change Slack reactions. Keep the
feedback workflow's `👀` claim in place; add `✅` only for verified fixes, and
never remove reactions. Newer thread evidence controls the current disposition.
Do not send Slack replies or reactions as a routine ship step unless that
workflow was explicitly requested or already owns the action.
Start any such Slack feedback reply by thanking the person for sharing the
issue, then give the status or ask the needed question. This does not widen the
existing write authorization.

Close linked GitHub issues as soon as their accepted fix is verified in the
merged snapshot. The publication and runtime follow-ups belong in the ship
ledger; they do not delay issue closure. If an issue was already fixed in the
merged snapshot and the issue comments document that fix, close it during the
same ledger pass and thank the reporter. If more information is needed, ask
one targeted question and leave the issue open.

Leave bot-authored PRs, including Dependabot, untouched when reviewing a queue.

## 5. Merge gate

Merge only when all of these are true at the same time and remain true for 10
continuous minutes on the unchanged live PR head:

- working tree is clean and there are no unpushed commits;
- required GitHub Actions checks are green;
- every human or bot review item has a verified fix/reply or a valid terminal
  disposition;
- GitHub reports the PR mergeable;
- no new actionable feedback arrived during the soak.

Immediately before merging, revalidate the full gate for the still-open PR:
working tree clean, no unpushed commits, required checks green, every review
item addressed, mergeability still `MERGEABLE`, and no new actionable feedback
since the soak began. Capture the live `headRefOid` from that same final check
and use it for the merge guard. If any gate changed, restart the soak.

Then use the explicit squash-admin merge:

```bash
gh pr merge <number> --squash --admin --match-head-commit <verified-head-oid>
```

Capture `<verified-head-oid>` only after the full final gate check immediately
before this command. This admin merge is the normal `/ship` completion step
once the gates hold; do not wait for an additional approval or enable
auto-merge. If the head-match guard rejects the merge, restart the soak for the
new head.

Never enable auto-merge. If a gate fails, fix the actionable cause, publish one
coherent update to the same PR, and restart the soak. A queued, skipped,
cancelled, superseded, provider, or missing-secret job is not automatically a
repo defect; classify it before changing code.

## 6. Branch disposition after merge

After the merge, verify that `origin/main` contains the merge commit. In a
task-owned worktree, rotate to a fresh branch using `/new-branch`'s dedicated
post-merge path without asking when there are no unpushed commits or dirty
publishable paths. Keep the source branch and report any remaining work when
those checks fail. In a shared checkout, keep the source branch and do not
rotate it or ask for branch permission. Platform-managed Builder.io and Fusion
checkouts stay on their assigned branches. Only then mark the ship goal
complete.

## Deployment boundary

Merges trigger the prebuilt beta publisher on every push to `main`. The docs
production workflow runs only when its path filters match. Other production
promotion is manual. Do not wait for Netlify Git-connected builds, clear a
Netlify lock by hand, or claim beta or production is live from a green PR. Use
/ship-and-monitor when the user asks for post-merge beta, docs, release-tail,
or manual-production proof.

## Final report

Include the ready PR URL, merged commit, branch disposition, focused/local
checks, required CI state, and any deployment result. In the feedback
dispositions,
name each linked issue that was thanked and closed and each issue left open
with its precise blocker. Say explicitly when deployment was not part of this
run.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…