Claude
Skills
Sign in
Back

ship

Included with Lifetime
$97 forever

End-to-end branch delivery: commit (no AI attribution) → push → open a pull request → ensure a Board work item exists (create one per task, assigned to the configured user, if none) and link it → after merge, clean up branch and worktree. Auto-detects the platform from the remote — Azure Repos + Boards (azure-devops-node-api SDK; OAuth Bearer push fallback via `az`) or GitHub (Octokit; `gh` for auth). Scripts are TypeScript, run via `bun`. Use whenever asked to "ship", "ship it", "ship this branch", "open a PR", "push and open a PR", "raise a PR", "deliver this", "send this for review", or "create a PR and link the work item" — and when a direct push to main is blocked and the change needs to go through a PR instead.

Backend & APIsscriptsassets

What this skill does


# Ship

`ship` takes a finished branch the last mile: commit it cleanly, push it (working around Azure
DevOps auth when needed), open a pull request, link it to its work item, and — once it's merged —
tear down the branch and worktree. It auto-detects whether you're on **Azure Repos** or **GitHub**
and follows the matching path, so the same command works at Hypera and in a github.com repo.

It is deliberately narrow. It does *not* merge locally, run pipelines, or manage backlogs — it
hands a reviewable PR to the platform and cleans up after the merge.

## When to use this vs. neighbors

- **`ship`** — the PR-based delivery flow: push → PR → (merge happens via the platform) → cleanup.
- **`commit`** — just stage + commit + push the current branch, no PR.
- **`merge`** — merge a branch into `main` *locally* (fast-forward) and clean up. Use this when there's
  no PR gate; use `ship` when changes must go through review/policy.
- **`azure-devops`** — the deep REST/MCP toolbox (WIQL, batch updates, pipelines, comment threads).
  `ship` calls only the thin slice it needs; reach for `azure-devops` for anything richer.

## The flow

Run `bun scripts/ship-detect.ts` first — it prints the platform, the Azure org/project/repo (if
any), the branch, and an inferred work-item id. Everything below branches on that.

> **One-time setup:** the scripts depend on `azure-devops-node-api` and `@octokit/rest`. Run
> `bun install` in the skill dir (`~/.claude/skills/ship/`) once before first use.

### 0. Preflight
- Confirm there's something to deliver: `git status` and `git log --oneline @{u}.. 2>/dev/null`.
- Note the platform from `ship-detect.ts`. If it says `unknown` (e.g. a custom SSH host alias),
  set `SHIP_PLATFORM=azure` or `SHIP_PLATFORM=github` for the session.

### 1. Commit — as the author, never as the tool
Stage only files for this task and commit. **Never add AI attribution** — no
`Generated with Claude`, no `Co-Authored-By: Claude`. Commits are authored by the human; tooling
provenance does not belong in git history (this repo's `commit-msg` hook strips trailers as a
backstop, but don't rely on it — don't write them in the first place). If pre-commit hooks fail on
*unrelated* issues, `--no-verify` is acceptable; if they flag *your* change, fix it.

### 2. Branch posture
- **On a feature branch** → good, continue.
- **On `main`/`master`** → you can't open a PR from main into itself. Create a branch and move the
  commit onto it before pushing:
  ```bash
  git branch feature/<slug> && git reset --hard @{u} && git checkout feature/<slug>
  ```
  (Only do this when the commits aren't yet pushed to main. If unsure, stop and ask.)
- A **blocked direct push to main** (branch policy) is the signal to take the PR path — not to
  force-push or bypass the policy.

### 3. Push
```bash
bun scripts/ship-push.ts         # pushes current branch, sets upstream
```
On Azure DevOps, if the normal push fails on auth, this automatically mints an `az` OAuth token and
retries with a Bearer header — the fallback for when neither SSH nor an HTTPS credential helper is
available. See `references/azure-devops.md` for the mechanics.

### 4. Open the PR (+ ensure/link work item, + transition state)

> **Invariant — never ask the user for the work item id.** Resolving → verifying → (if missing)
> creating + assigning + linking the work item is *fully automatic*. A PR must never be surfaced
> as ready without a linked Board work item. If you're about to ask "what's the work-item id?",
> stop — that question is the exact failure this skill exists to prevent. The id comes from
> `--work-item`, the branch name, or a freshly created item; it never comes from a question.
>
> **Code review does not own the work item.** Because ship guarantees a linked item at PR-open,
> the review step — human reviewers or the `code-review` / `bmad-code-review` skills — must not
> re-prompt for or block on a work item. That concern is already satisfied upstream.

Draft a real description — copy `assets/pr-template.md` to a temp file, fill Summary / Changes /
Verification, and keep the `AB#<id>` line so the work item links.

```bash
bun scripts/ship-pr.ts --title "<title>" --body-file /tmp/pr-body.md \
  --work-item <id> --transition Resolved
```
- Platform is auto-detected; the script uses the **azure-devops-node-api** SDK (`createPullRequest`)
  or **Octokit** (`pulls.create`).
- **Azure never opens a PR without a linked Board work item.** The script resolves the id from
  `--work-item` (or the branch name), then **verifies it actually exists** via the SDK
  (`getWorkItem`). The branch-name parse is only a heuristic — a branch like `1234-foo` can carry a
  number that isn't a real item, which is why existence is checked, not assumed.
- **If no real work item is found, one is created per task and linked to the PR**, each **assigned
  to** `$SHIP_ADO_ASSIGNEE` (default `[email protected]`; override with `--assignee`).
  Pass `--task "<title>"` once per task (repeatable), or `--tasks-file <file>` (one title per line),
  to create one item each. With no `--task`, a single item is created from the PR `--title`. Type
  defaults to `Task` (`--work-item-type "User Story"|Bug`). Disable creation with
  `--no-create-work-item` to link only a pre-existing id.
  - The script prints `work_item_created=<id>` per created item and `work_items=<ids>` for the set —
    surface the new ids to the user (don't fabricate them; they come from the SDK response).
- `--transition` (Azure only) moves **each** linked/created item *after* the PR opens. State names
  are process-specific (Agile: Resolved; Scrum: Committed; Basic: Doing) — verify the valid next
  state first; see `references/azure-devops.md`. Omit `--transition` to leave the board untouched.
  (Created items start in the type's initial state, e.g. `New`/`To Do`.)
- The script prints `pr_url=…`; surface it to the user.

### 5. After merge — cleanup
Do this only once the PR is actually merged (don't delete a branch with an open PR). Mirror the
`merge` skill's cleanup, and **ask before deleting**:
- If the branch was developed in a **worktree**, `cd` to the main repo dir first, then
  `git worktree remove <path>` — you can't delete a branch from inside its own worktree.
- `git branch -d <branch>` (lowercase `-d` refuses unmerged branches — that refusal is the safety
  net; only escalate to `-D` if the user explicitly confirms).
- `git push origin --delete <branch>` (ignore failure if it was local-only).

## Bundled tools

| Script | Does |
|--------|------|
| `bun scripts/ship-detect.ts [remote]` | Print platform + Azure coordinates + branch + inferred work item |
| `bun scripts/ship-push.ts [-r remote] [-b branch]` | Push + set upstream; Azure OAuth Bearer fallback on auth failure |
| `bun scripts/ship-pr.ts --title … [opts]` | Open PR on the detected platform; ensure/create + link work item(s) (assigned to the configured user); optional Board transition |

Scripts are TypeScript run via `bun`; shared helpers live in `scripts/ship-lib.ts`. Run `bun install`
in the skill dir once (installs `azure-devops-node-api` + `@octokit/rest`). Git/push stays a
subprocess call (it's a git operation); only the ADO/GitHub REST surfaces use the SDKs. Platform
detail lives in `references/azure-devops.md` and `references/github.md` — read the one matching the
detected platform. The PR description starts from `assets/pr-template.md`.

## Safety

- **Ask before anything destructive or shared-visible** — deleting branches/worktrees, and opening a
  PR (it's visible to the team). Pushing a feature branch and creating a draft are low-risk; a
  ready PR and any branch deletion warrant a confirm.
- **Never force-push** to work around a rejected push. A rejection means diverged history or a
  policy — investigate, don't overwrite.
- **Tokens go in headers, are short-lived, and are never printed or put in URLs.**
- **No AI attribution** anywhere — commit message, PR title, or PR body.

Related in Backend & APIs