# Squid Sdk Release

> Cut a new squid-sdk release — verify Rush change files, run the bump/release/github-release workflows in order, watch them, and (for minor/major bumps) standardize the auto-generated GitHub release notes. Use when the user asks to "release", "publish", "ship", or "cut the next release" of squid-sdk.

- Skill: `subsquid/squid-sdk-release` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add subsquid/squid-sdk-release`
- Raw SKILL.md: https://api.skillmd.com/api/skills/subsquid/squid-sdk-release/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: subsquid (https://skillmd.com/u/subsquid)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/subsquid/squid-sdk-release

---


# squid-sdk release

End-to-end release procedure for the squid-sdk Rush monorepo. Unlike a single-version repo, squid-sdk publishes ~109 packages with **independent per-package versions**, driven by three manual `workflow_dispatch` workflows. GitHub releases are date-tagged (`YYYY-MM-DD`), not version-tagged. Most of the heavy lifting is automated — your job is to trigger the workflows in the right order, surface failures clearly, and (optionally) wrap the auto-generated release notes for minor/major bumps.

## Mental model

| Stage | Workflow | What it does |
|---|---|---|
| 1. Bump | `bump.yml` | `rush change --verify` then `rush version --bump` against `release/arrowsquid`, merges versions + CHANGELOGs back into the current branch |
| 2. Publish to npm | `release.yml` (`mode=release`) | From `release/arrowsquid`, builds and publishes via OIDC trusted publishing (`NPM_CONFIG_PROVENANCE=true`) |
| 3. GitHub release | `github-release.yml` | Diffs `**/CHANGELOG.md` since the previous date tag, aggregates per-package sections + contributors, creates `YYYY-MM-DD` tag and release |

Per-package change tracking lives in `common/changes/@subsquid/<pkg>/<branch>_<timestamp>.json`. Each PR that touches a published package should add a change file via `rush change` — no change file means CI's verify step fails.

## How `release/arrowsquid` is maintained (and what silently doesn't reach it)

Releases publish from `release/arrowsquid` (`release.yml` `mode=release` always checks it out, ignoring the caller branch — line 29), but **no workflow has an explicit step that pushes to `release/arrowsquid`.** Grep the workflows and you won't find one. The branch is advanced purely as a *side effect* of `rush version --bump` in step 1: rush internally branches `version/bump-*` **from master**, commits the version + CHANGELOG bumps, then `git merge`s that branch into `release/arrowsquid` and pushes it. (The `merge back` step afterwards brings the same bumps into master.)

**The trap:** that sync fires *only when there is a real version bump to apply*. A change that produces no bump never reaches `release/arrowsquid`, so the next release publishes a **stale tree**. This includes:
- `rush.json` / version-policy edits (e.g. moving a package to the `docker` policy so it stops publishing to npm),
- workflow / CI / other config changes,
- any batch where every pending change file is `type: none`.

Hence, the scripts provide a leaky abstraction: running `bump` then `release` on `master` will publish the changes in `master`, but if anything breaks in between these two and you fix the release machinery, the `release` workflow won't pick it up.

Consequences and remedies:
- **Editing the release machinery on `master` does not take effect on the next release** until `release/arrowsquid` catches up. This is the easy way to "fix" a release bug on master, run a release, and watch nothing change.
- A config-only fix lands on `release/arrowsquid` only when it **rides along with the next real (non-`none`) bump** (which re-branches from master and sweeps the whole tree in), **or** when you sync the branch directly:
  ```sh
  # release/arrowsquid is normally a strict ancestor of master, so this fast-forwards it:
  git push origin master:release/arrowsquid
  ```
- **Before cutting a release after any machinery/config change, verify the branch actually contains it:**
  ```sh
  git fetch origin master release/arrowsquid
  git log --oneline origin/release/arrowsquid..origin/master   # commits on master not yet on the release branch
  ```

## Preconditions

Confirm before starting:
- Working tree is clean.
- You're on the feature branch where the release will be cut from (typically `master`); the merged PRs since the last release are the contents of this release.
- Every published package modified since the last release has a corresponding change file. Run locally:
  ```sh
  node common/scripts/install-run-rush.js change --verify --target-branch origin/release/arrowsquid
  ```
  If this fails, ask the user to author missing change files with `rush change` (or open a PR that does).
- `gh auth status` passes and the user has `Actions: write` on `subsquid/squid-sdk`.

## Steps

### 1. Bump versions (`bump.yml`)

```sh
BRANCH=$(git rev-parse --abbrev-ref HEAD)
gh workflow run bump.yml --ref "$BRANCH" -R subsquid/squid-sdk
gh run watch --workflow=bump.yml --exit-status -R subsquid/squid-sdk
```

This pushes version bumps and CHANGELOG.md updates to both `release/arrowsquid` and the current branch. Pull locally afterwards: `git pull`.

If the merge-back step fails, the current branch diverged from `release/arrowsquid` in a non-trivial way — surface it and let the user resolve. Do not force.

### 2. Publish to npm (`release.yml`, mode=release)

```sh
gh workflow run release.yml -f mode=release -R subsquid/squid-sdk
RUN_ID=$(gh run list --workflow=release.yml --limit 1 --json databaseId --jq '.[0].databaseId' -R subsquid/squid-sdk)
gh run watch "$RUN_ID" --exit-status -R subsquid/squid-sdk
```

This always runs from `release/arrowsquid` regardless of caller branch (see `release.yml` line 29). The publish step uses **OIDC trusted publishing** — no NPM_TOKEN.

If a single package fails to publish, the tree is now half-published. **Do not retry blindly.** Check what landed:

```sh
npm view @subsquid/<failed-pkg> versions --json | tail -5
```

Common cause: the failing package's trusted publisher is not configured on npmjs.com. Surface the error verbatim to the user and stop — do not proceed to step 3 until npm and the local CHANGELOG state agree.

### 3. Cut the GitHub release (`github-release.yml`)

```sh
gh workflow run github-release.yml -R subsquid/squid-sdk
gh run watch --workflow=github-release.yml --exit-status -R subsquid/squid-sdk
```

The `.github/actions/publish-releases` action will:
- find the previous `YYYY-MM-DD[.N]` tag,
- diff `**/CHANGELOG.md` since that tag,
- emit `### @subsquid/<pkg> <ver>` sections in the order Git returned the changed paths,
- append a Contributors footer (resolved from commit emails to GitHub logins),
- create a `YYYY-MM-DD` tag (or `YYYY-MM-DD.N` if today already has one),
- publish a release with those notes.

If no CHANGELOG.md diff exists, the action exits cleanly without creating a release — usually a sign that step 1 was skipped or every change was `type: none`.

Print the release URL when done:
```sh
TAG=$(gh release list --limit 1 --json tagName --jq '.[0].tagName' -R subsquid/squid-sdk)
echo "https://github.com/subsquid/squid-sdk/releases/tag/$TAG"
```

### 4. (Optional) Standardize release notes

Only for releases that contain at least one **minor or major** bump. Patch-only releases keep the bare auto-generated body — they're not worth a headline.

Rules in [release-notes-template.md](release-notes-template.md). The wrap-around prepends a `## <Headline>` and 1–3 sentence lead and appends a compare link; the per-package `### @subsquid/...` blocks are kept verbatim.

To rewrite:

```sh
TAG=2026-04-15  # or whatever date tag was created
PREV=$(gh api repos/subsquid/squid-sdk/releases --jq '.[1].tag_name')
# headline + lead come from the user-visible diff; don't restate every package bullet
gh release edit "$TAG" -R subsquid/squid-sdk --notes "$(cat <<EOF
## <Headline>

<1-3 sentence lead.>

$(gh release view "$TAG" -R subsquid/squid-sdk --json body --jq .body)

**Full Changelog**: https://github.com/subsquid/squid-sdk/compare/${PREV}...${TAG}
EOF
)"
```

Pick the headline from the largest user-visible change in the aggregated body. **Don't restate every package's bullets.** The per-package sections are already there — the headline is editorial framing, not a summary.

## Prerelease path

For prereleases (e.g. previewing changes from a feature branch under a non-`latest` dist-tag):

```sh
gh workflow run release.yml -f mode=prerelease --ref <feature-branch> -R subsquid/squid-sdk
```

This runs from the caller branch (not `release/arrowsquid`), uses `rush publish --apply --partial-prerelease --tag <branch>` with a commit-hash suffix, and does **not** cut a GitHub release. Skip `bump.yml` and `github-release.yml` for prereleases.

## Failure modes

- **`rush change --verify` fails in CI**: a published package was modified without an accompanying change file. The user must run `rush change` for each missing package and push the JSON files in `common/changes/@subsquid/<pkg>/`.
- **`bump.yml` merge-back fails**: branch diverged from `release/arrowsquid` non-trivially. Resolve by hand; do not force-push.
- **Partial npm publish**: stop and surface. Re-running `release.yml` will skip already-published versions (Rush checks the registry), but if the cause was a misconfigured trusted publisher, the same package fails again. Fix the npmjs.com config first.
- **Date tag collision**: the action automatically suffixes `.2`, `.3`, … (`createDateTag()` in `index.js`). Nothing to do.
- **No CHANGELOG diff after running `bump.yml`**: every change file was `type: none` (e.g. doc/test-only changes). Action exits cleanly without a release. Confirm this is intended.
- **`github-release.yml` fails to resolve a contributor login**: not fatal — the action just skips that author. Check logs if a known contributor is missing.

## Quick reference

```sh
# Verify change files locally
node common/scripts/install-run-rush.js change --verify --target-branch origin/release/arrowsquid

# Three workflow triggers
gh workflow run bump.yml --ref "$(git rev-parse --abbrev-ref HEAD)" -R subsquid/squid-sdk
gh workflow run release.yml -f mode=release -R subsquid/squid-sdk
gh workflow run github-release.yml -R subsquid/squid-sdk

# Watch the latest run of a workflow
gh run watch --workflow=<file>.yml --exit-status -R subsquid/squid-sdk

# Inspect what was published
gh release view --web -R subsquid/squid-sdk
```

