Skip to main content
ClaudeWave
Skill6 repo starsupdated today

release

The `release` skill provides the npm tag-and-publish mechanics for PipRail's SDK and MCP packages. Use it after running the `deploy` skill's initial phases or to independently release either `@piprail/sdk` or `@piprail/mcp` via signed git tags that trigger CI workflows, ensuring SemVer compliance, changelog updates, and the correct build order where the SDK publishes before the MCP.

Install in Claude Code
Copy
git clone --depth 1 https://github.com/piprail/piprail /tmp/release && cp -r /tmp/release/.claude/skills/release ~/.claude/skills/release
Then start a new Claude Code session; the skill loads automatically.

SKILL.md

# Releasing PipRail (`@piprail/sdk` · `@piprail/mcp`)

> **Shipping a real change? Start with the [`deploy`](../deploy/SKILL.md) skill** — the master
> runbook that also covers the doc/`llms.txt` surface sweep, the site/docs deploys, and the external
> repos. **This file is the focused npm tag-and-publish mechanics** that `deploy` Phases 5–8 use.

Publishing is **tag-driven CI**, not a manual `npm publish`. You bump versions,
push a signed tag, and a GitHub Action builds + publishes with the repo's
`NPM_TOKEN`. The **site** is separate: it auto-deploys to Netlify on every push
to `main` — no tag, no action needed.

> One package per tag. `sdk-v*` publishes `@piprail/sdk`; `mcp-v*` publishes
> `@piprail/mcp`. They are independent — release only what changed.

---

## The iron rules

1. **Never `npm publish` by hand.** Only a pushed `sdk-v*` / `mcp-v*` tag publishes
   (workflows `release.yml` / `mcp-release.yml`). Hand-publishing bypasses the gate
   and the lockstep build order.
2. **The gate must be green first.** `prepublishOnly` re-runs build + test + typecheck
   (SDK also `typecheck:test`) in CI, so a red gate *fails the release*. Note it does
   **not** re-run the lazy-chunk grep — that tripwire only runs in your local gate, so
   never skip it. Catch everything locally first (see the `verify-gate` skill).
3. **SemVer + Keep a Changelog.** Patch = fixes, minor = additive/opt-in (defaults
   never change), major = a breaking change. Every release gets a `CHANGELOG.md` entry.
4. **Build the SDK before the MCP.** `@piprail/mcp` imports the SDK's built `dist`.
   `mcp-release.yml` already does `build -w @piprail/sdk` *before* `build -w @piprail/mcp` —
   don't reorder it. If you release both, **release the SDK first** so the MCP resolves
   the published SDK.
5. **Tags are signed.** `git tag -s` (so GitHub shows "Verified").

---

## Procedure

### 0. Decide the package + the version
Pick the new SemVer number. Confirm what actually changed since the last tag
(`git log <last-tag>..HEAD -- sdk/` or `-- mcp/`).

### 1. Run the verification gate (must be green)
See the **`verify-gate`** skill. In short, from the repo root:
```bash
npm run typecheck                       # sdk + mcp type-check
npm run typecheck:test -w @piprail/sdk  # src + tests together
npm run test:sdk                        # (and test:mcp if releasing the MCP)
npm run build:sdk                       # (and build:mcp)
grep -E "from ?['\"]@(solana|ton|stellar)" sdk/dist/index.js   # → expect NO matches
```

### 2. Bump the version in **every** file (don't miss one)
- **SDK release** — `sdk/package.json` (`version`) **and** `sdk/CHANGELOG.md` (new
  dated entry, newest first; add the version-footer link).
- **MCP release** — `mcp/package.json` (`version`) **and** `mcp/CHANGELOG.md` **and**
  `mcp/server.json` (`version`, and the `packages[0].version` — the MCP registry reads
  these) **and** `mcp/src/version.ts` (the `VERSION` constant — reported to clients over MCP
  and in the startup banner). **All four must match** — the `version.test.ts` guard fails the
  gate if they drift (0.2.0 shipped a stale `VERSION` because this file was missed; don't repeat it).

### 3. Commit on `main`
```bash
git commit -am "release: @piprail/sdk vX.Y.Z"   # or @piprail/mcp
git push origin main
```

### 4. Tag + push (this is what publishes)
```bash
git tag -s sdk-vX.Y.Z -m "@piprail/sdk vX.Y.Z"   # or  mcp-vX.Y.Z
git push origin sdk-vX.Y.Z
```
The matching workflow runs the gate (`prepublishOnly`) and publishes to npm.

### 5. Confirm it published
Watch the Action (`gh run watch` / the Actions tab — it shows as **sdk-release** / **mcp-release**, the workflow `name:`). Then verify npm shows the new
version: `npm view @piprail/sdk version`. If the Action failed at the build step for
the MCP, it's almost always the **SDK-not-built-first** gotcha (rule 4).

### 6. Create the GitHub Release from the tag
```bash
gh release create sdk-vX.Y.Z --verify-tag --title "@piprail/sdk vX.Y.Z — <headline>" \
  --latest --notes "<summary; link to the CHANGELOG>"
```
Mark the newest **SDK** release `--latest`; MCP releases use `--latest=false`.

### 7. MCP only — the registry
After `mcp-vX.Y.Z` publishes to npm, refresh the MCP registry (interactive, owner-only):
```bash
cd mcp && mcp-publisher login github && mcp-publisher publish   # reads ./server.json
```
The `io.github.piprail/*` namespace is authorized by piprail-org membership.

---

## Don'ts
- Don't bump `package.json` but forget `CHANGELOG.md` (or, for MCP, `server.json`).
- Don't tag before the version bump is committed — the tag must point at the bump.
- Don't ship with a red gate; don't reorder the SDK→MCP build; don't hand-publish.