agentsclimarketplace

Shipit

Skill bostonaholic/team/skills/shipit

Drive a feature from idea to PR with a team of Claude Code agents.

Install
npx -y skills add bostonaholic/team --skill shipit

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 8 stars8 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Land a reviewed pull request: discover the open PR for the current branch, push any unpushed commits, wait for CI to go green, then squash-merge it so the PR title (which may carry a version) lands as the commit subject. Handles a PR that has fallen behind its base (rebase + force-with-lease) and surfaces branch-protection rejections verbatim. Project-agnostic — it knows nothing about how any project versions itself. Use ONLY when the user explicitly says "ship it", "land the PR", "land this", or runs "/shipit"; never auto-fire it — it merges, which is irreversible.

SKILL.md

8.2 KB, as published. Nobody here has run it

shipit — land a reviewed PR

Follow skills/progress-tracking/SKILL.md: this procedure has more than two steps — seed one todo item per step below before starting and mark each complete as you go.

shipit lands a pull request that has already passed review: it pushes any unpushed local commits, waits for CI to go green, and squash-merges so the PR title lands as the commit subject on the base branch (if a project puts a version in the title, that version then shows up in git log). It finalizes an existing open PR — it never opens one. It is generic: it does no versioning, changelog editing, or release work. If a project assigns a version at land time, that happens in a separate project-specific step before /shipit (in this repo, the dev version-bump skill — see docs/versioning.md); shipit only cares that the branch is ready to land.

gh pr merge is irreversible, so this skill is user-invocable only (disable-model-invocation: true): a human runs it deliberately; the model never auto-fires it.

Input acquisition

shipit lands the open PR for the current branch. Discover it with gh pr view --json baseRefName,number,state,title and a base-branch fallback; never hardcode the base branch. The title is captured here because step 5 lands it as the squash commit subject. Run this in one bash call (an agent thread resets cwd between calls):

PR_JSON=$(gh pr view --json number,baseRefName,state,title 2>/dev/null)
BASE=$(printf '%s' "$PR_JSON" | jq -r .baseRefName 2>/dev/null)
[ -z "$BASE" ] || [ "$BASE" = "null" ] && BASE=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@^refs/remotes/origin/@@')
[ -z "$BASE" ] && BASE=main
echo "PR: $PR_JSON"
echo "BASE: $BASE"
  • No open PR for the current branch (gh pr view finds none): refuse with a clear message and stop. shipit finalizes an existing PR — it does not open one. Tell the user to open the PR first.
  • PR state is MERGED or CLOSED (read from the discovery JSON above): refuse up front with a clear message before doing any work — there is nothing to land.
  • An optional <pr-number> argument overrides the discovered PR.

Land sequence

The steps below are the scriptable core. The one interactive confirmation (the pre-merge confirm in step 4) wraps it: a non-interactive caller passes --yes to skip the prompt, leaving a pure push → wait → merge sequence.

1. Pre-flight merge-button check

Before relying on --squash, read the repo's merge strategy and report whether squash merges are enabled. This is a read-only check, not enforcement:

gh repo view --json mergeCommitAllowed,rebaseMergeAllowed,squashMergeAllowed

Stop and report only if squashMergeAllowed is false — squash-merge is how the PR title (and any version it carries) lands as the commit subject, and it keeps linear history (a squash commit is a normal commit, not a merge commit), so it is the only acceptable strategy here. If squash merging is available, proceed regardless of which other methods (mergeCommitAllowed, rebaseMergeAllowed) are enabled.

2. Push any unpushed local commits

The branch may carry commits made after the PR was opened (review fixups, a project-specific land-time commit). Push them so CI runs against what will land:

git push

If the local branch and remote have diverged because the branch was rebased locally, see the force-with-lease guidance in step 5 — never a bare --force.

3. Wait for CI

Poll the PR's checks with gh pr checks. The bound is mechanical, not prose: timeout enforces the total cap and --fail-fast exits the instant a check fails. Bounded, never infinite. Defaults (overridable so a future automation loop can tune them):

  • interval: poll every 30s (--interval 30)
  • total timeout: 30 min cap = 1800s (timeout 1800)
timeout 1800 gh pr checks <pr-number> --watch --fail-fast --interval 30
status=$?

--fail-fast returns non-zero the moment any check fails; timeout kills the watch and returns 124 when the 30-min cap is hit. Map the exit code to one of three outcomes:

  • status is 0 (all required checks passed) → continue to the merge. (Add --required to gate on required checks only; the default here gates on all checks so a failing optional check still halts the land — the conservative choice for an irreversible merge.)
  • status is non-zero and not 124 (a check failed) → stop before merge. Run gh pr checks <pr-number> to print the failing check, and report it by name. Leave the branch in place — the user fixes CI and re-runs /shipit. Do not merge.
  • status is 124 (the 30-min cap was hit and CI never went green) → stop and report "CI wait timed out"; do not merge.

Re-entry after a CI fix: when re-running /shipit after fixing CI, the commits are already on the branch — shipit simply pushes any new ones, waits again, and merges. It is safe to re-run.

4. Pre-merge confirmation

gh pr merge is irreversible. For a human operator, ask for an explicit confirmation before merging — "about to merge PR #N into <base> — proceed?" — and only merge on a yes. A non-interactive caller passes --yes to skip this prompt; the prompt wraps the scriptable core, it does not live inside it.

5. Rebase if behind the base, then merge

PR behind its base. Before merging, check whether the base branch advanced since CI last ran. If the PR is behind <base>, bring it up to date:

  1. Rebase the branch onto the latest <base>.
  2. git push --force-with-lease the rebased branch — the force is required because the rebase rewrote history; --force-with-lease refuses if the remote moved underneath you (never a bare --force).
  3. Re-run the CI wait (step 3) against the rebased tree before merging.

Merge with gh pr merge --squash (named explicitly — squash lands the PR title as the commit subject while keeping linear history, so it is the only acceptable merge strategy here). Build the subject explicitly from the PR title captured during discovery and append (#<number>) so every landed commit shows both the title (with any version it carries) and the PR number — exactly the git log shape the operator sees. Passing --subject is deliberate: it guarantees the PR title regardless of the repo's "default squash commit message" setting (an explicit --subject is not auto-suffixed with the PR number, so we add it ourselves):

TITLE=$(printf '%s' "$PR_JSON" | jq -r .title)
gh pr merge <pr-number> --squash --subject "$TITLE (#<pr-number>)"

The squash body defaults to the concatenated commit messages — leave it as-is unless the operator asks otherwise.

  • On a branch-protection rejection, surface GitHub's rejection message verbatim to the user; never force the merge.

Completion

Report the merge result (or the failing-check / timeout / branch-protection reason if it stopped short). If the project publishes a release on merge, that runs asynchronously after the merge — point the operator at gh run watch (or gh run list) so they can observe it rather than assuming it is already done.

shipit touches no tracker or board — it stays generic. If the PR links a ticket (e.g. Closes #<n>), the tracker closes that ticket when the merge lands, and any board automation moves it to its done state on its own; that is a property of the link the PR phase added, not an action shipit performs.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.