# Ship

> Automates the full code release pipeline — branch, commit, push, PR, wait for CI, merge, version bump, release, cleanup. Use when the user wants to release code changes, says "ship it", or asks to create a release.

- Skill: `majiayu000/ship-20` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds add majiayu000/ship-20`
- Raw SKILL.md: https://api.skillmd.com/api/skills/majiayu000/ship-20/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: majiayu000 (https://skillmd.com/u/majiayu000)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/majiayu000/ship-20

---


## Your Task

Automate the complete release pipeline for this plugin using the conventional commit message provided.

**Input**: `$ARGUMENTS`

This is a conventional commit message (e.g., `feat: streaming URL management tools`).

---

# Ship — Automated Code Release Pipeline

You automate the entire release workflow from uncommitted changes on `main` to a published GitHub Release with version bump.

**Pipeline**:
```
[uncommitted changes on main]
  → create feature branch
  → commit with conventional commit message
  → push + create PR
  → poll CI checks until all pass (or fail)
  → merge PR
  → pull main
  → determine version bump from commit prefix
  → update plugin.json + marketplace.json + CHANGELOG + README badges
  → commit "chore: release 0.x.0"
  → push to main (triggers auto-release.yml → GitHub Release)
  → delete local feature branch
```

---

## Step 0: Parse Input

Extract from `$ARGUMENTS`:

1. **Full commit message** — the entire string (e.g., `feat: streaming URL management tools`)
2. **Prefix** — the conventional commit type before the colon: `feat:`, `fix:`, `feat!:`, `docs:`, `chore:`
3. **Description** — everything after the prefix (e.g., `streaming URL management tools`)
4. **Branch name** — derived from the message: lowercase, spaces to hyphens, prefix becomes the branch prefix
   - `feat: streaming URL management tools` → `feat/streaming-url-management-tools`
   - `fix: correct audio path` → `fix/correct-audio-path`
   - `feat!: breaking change` → `feat/breaking-change`
   - `docs: update README` → `docs/update-readme`
   - `chore: cleanup` → `chore/cleanup`
5. **Version bump type**:
   - `feat:` → MINOR (0.57.0 → 0.58.0)
   - `fix:` → PATCH (0.57.0 → 0.57.1)
   - `feat!:` → MAJOR (0.57.0 → 1.0.0)
   - `docs:` or `chore:` → **none** (skip version bump and release steps)

If `$ARGUMENTS` is empty or doesn't match a conventional commit pattern, **stop** and ask the user for a commit message.

---

## Step 1: Pre-flight Checks

Run these checks. If ANY fail, **stop immediately** with a clear error message.

1. **On main branch?**
   ```bash
   git branch --show-current
   ```
   Must be `main`. If not: "Switch to main first: `git checkout main && git pull`"

2. **Uncommitted changes exist?**
   ```bash
   git status --porcelain
   ```
   Must have output. If empty: "No changes to ship. Make some changes first."

3. **GitHub CLI authenticated?**
   ```bash
   gh auth status
   ```
   Must succeed. If not: "Run `gh auth login` first."

4. **Read current version** from `.claude-plugin/plugin.json`:
   ```bash
   jq -r '.version' .claude-plugin/plugin.json
   ```
   Store as `CURRENT_VERSION`.

Report: "Pre-flight passed. Current version: {CURRENT_VERSION}. Shipping: {commit message}"

---

## Step 2: Branch + Commit + Push

1. **Create feature branch**:
   ```bash
   git checkout -b {branch-name}
   ```

2. **Stage files** — use `git status` to identify changed files. Stage them by name. **Never** stage `.env`, `credentials`, or secret files. Prefer specific filenames over `git add -A`.

3. **Commit** with the conventional commit message + co-author:
   ```bash
   git commit -m "$(cat <<'EOF'
   {full commit message}

   Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
   EOF
   )"
   ```

4. **Push**:
   ```bash
   git push -u origin {branch-name}
   ```

---

## Step 3: Create PR

Create a pull request using the commit message as the title:

```bash
gh pr create --title "{full commit message}" --body "$(cat <<'EOF'
## Summary
{1-3 bullet points summarizing what changed}

## Test plan
- [ ] CI checks pass (automated)
- [ ] Version sync validates (automated)

🤖 Generated with [Claude Code](https://claude.com/claude-code)
EOF
)"
```

Capture the PR number from the output for subsequent steps.

---

## Step 4: Wait for CI Checks

Poll CI using `gh pr checks` with the `--watch` flag:

```bash
gh pr checks {pr-number} --watch --fail-level all
```

This blocks until all checks complete. Use a 10-minute timeout.

**If any check fails**:
- Report which check(s) failed
- Print the failing check URL(s) if available
- **Stop the pipeline** — leave the PR open for the user to investigate
- Say: "CI failed. Fix the issues, push to the branch, and re-run `/bitwize-music:ship` or merge manually."
- **Do NOT proceed to merge.**

**If all checks pass**: Report "All CI checks passed." and continue.

---

## Step 5: Merge PR

1. **Merge the PR** (merge commit, delete remote branch):
   ```bash
   gh pr merge {pr-number} --merge --delete-branch
   ```

2. **Switch back to main and pull**:
   ```bash
   git checkout main && git pull origin main
   ```

---

## Step 6: Version Bump

**Skip this entire step if the prefix is `docs:` or `chore:`.**

### 6a: Calculate new version

From `CURRENT_VERSION` and the bump type:
- MINOR: increment middle number, reset patch to 0 (e.g., 0.57.0 → 0.58.0)
- PATCH: increment last number (e.g., 0.57.0 → 0.57.1)
- MAJOR: increment first number, reset others to 0 (e.g., 0.57.0 → 1.0.0)

Store as `NEW_VERSION`.

### 6b: Update `.claude-plugin/plugin.json`

Change `"version": "{CURRENT_VERSION}"` → `"version": "{NEW_VERSION}"`

### 6c: Update `.claude-plugin/marketplace.json`

Change `"version": "{CURRENT_VERSION}"` → `"version": "{NEW_VERSION}"`

### 6d: Update `CHANGELOG.md`

1. Find the current `## [Unreleased]` section content
2. Insert a new versioned section between `[Unreleased]` and the previous version:
   - Empty `## [Unreleased]` section at top
   - Then `## [{NEW_VERSION}] - {YYYY-MM-DD}` with the content that was under Unreleased
3. The date is today's date

### 6e: Update README.md badges

Update these badge lines:
- Version badge: `![Version](https://img.shields.io/badge/version-{NEW_VERSION}-blue)`
- Skills count badge: count directories in `skills/*/` and update `![Skills](https://img.shields.io/badge/skills-{COUNT}-green)`
- Test count badge: run `pytest --co -q 2>/dev/null | tail -1` to get the count, update `![Tests](https://img.shields.io/badge/tests-{COUNT}-brightgreen)`

### 6f: Update README "What's New" table (for `feat:` and `feat!:` only)

If the commit is a `feat:` or `feat!:`:
- Read the CHANGELOG entry for this version
- Add a row to the "What's New" table in README.md at the top (below the header row)
- Format: `| **{MINOR_VERSION}** | {brief highlight} |`
- Example: `| **0.58** | Ship skill for automated code release pipeline |`

### 6g: Update README skill count text

If a new skill was added, update the "collection of **N specialized skills**" text in README.md to match the badge count.

---

## Step 7: Release Commit + Push

**Skip if `docs:` or `chore:` prefix (no version bump happened).**

1. **Stage the version files**:
   ```bash
   git add .claude-plugin/plugin.json .claude-plugin/marketplace.json CHANGELOG.md README.md
   ```

2. **Commit**:
   ```bash
   git commit -m "$(cat <<'EOF'
   chore: release {NEW_VERSION}

   Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
   EOF
   )"
   ```

3. **Push to main** — this triggers `auto-release.yml` which creates the GitHub Release:
   ```bash
   git push origin main
   ```

---

## Step 8: Cleanup

1. **Delete local feature branch** (it was already deleted from remote by `--delete-branch`):
   ```bash
   git branch -d {branch-name}
   ```

2. **Report success**:
   ```
   Ship complete!

   Commit: {full commit message}
   Version: {CURRENT_VERSION} → {NEW_VERSION}
   PR: {PR URL}
   Release: auto-release.yml will create GitHub Release for v{NEW_VERSION}

   Branch {branch-name} cleaned up (local + remote).
   ```

   For `docs:`/`chore:` (no version bump):
   ```
   Ship complete!

   Commit: {full commit message}
   Version: unchanged ({CURRENT_VERSION})
   PR: {PR URL}

   No version bump for {prefix} commits.
   Branch {branch-name} cleaned up (local + remote).
   ```

---

## Error Handling

| Scenario | Action |
|----------|--------|
| Not on `main` | Stop. Tell user to `git checkout main && git pull`. |
| No uncommitted changes | Stop. "Nothing to ship." |
| `gh` not authenticated | Stop. Suggest `gh auth login`. |
| CI check fails | Stop. Report failure details. Leave PR open. |
| Merge conflict | Stop. Report conflict. Let user resolve. |
| Push rejected | Stop. Report error. Suggest `git pull --rebase`. |
| Invalid commit message | Stop. Show expected format with examples. |

**Never force-push. Never skip CI. Never auto-close a failed PR.**

---

## Remember

1. **Parse the commit message first** — everything flows from the prefix
2. **Pre-flight is non-negotiable** — stop if any check fails
3. **Stage files by name** — never `git add -A` or `git add .`
4. **CI must pass** — never merge with failing checks
5. **Version bump follows conventional commits** — `feat:` = MINOR, `fix:` = PATCH, `feat!:` = MAJOR
6. **Both JSON files must match** — plugin.json and marketplace.json versions stay in sync
7. **CHANGELOG gets the content** — move Unreleased to versioned section
8. **Badges must match** — version, skills count, test count in README
9. **`chore: release` commit triggers auto-release.yml** — which creates the GitHub Release
10. **Clean up branches** — delete local and remote after merge

**Your deliverable**: Changes shipped from uncommitted code to published GitHub Release in one automated pipeline.

