/arc:release
Versioned package releases
—What it does
Release detects what changed since the last tag, proposes a semver bump per package with reasoning, then authors the release — changeset files, version bumps, CHANGELOG entries, and a migration note for any breaking change. Before publishing it builds and packs each package, installs the tarball into a throwaway project, and smoke-tests the real published shape: entry points import, "use client" directives survive bundling, runtime/animation libs are peerDependencies, the exports map resolves, and the files array does not drop needed dist. Publishing, tagging, and pushing are each gated behind an explicit choice.
—Why it exists
Publishing is where invisible mistakes ship: a dropped "use client" directive, a runtime lib bundled as a dependency, an exports map that resolves for import but not require, a files array that ships no dist. Version numbers also carry a promise — a breaking change published as a minor breaks installs silently. Release turns publishing from a hopeful `npm publish` into a verified, reasoned step.
—Design decisions
- —Semver is proposed with reasoning per package, confirmed in one question.
- —Every breaking change gets a migration note before it can publish.
- —Each package is packed and installed into a temp project before publishing.
- —Publishing, tagging, and pushing are always offered, never silent.
- —Commit owns simple unversioned publish; release owns version bumps and changelogs.
Source document
<arc_runtime> This workflow requires the full Arc bundle, not a prompts-only install.
Paths in this skill use these conventions:
agents/...,references/...,disciplines/...,templates/...,scripts/...,rules/...,skills/<name>/...are Arc-owned files at the plugin root. Resolve the plugin root from this skill's filesystem location — it's the directory containingagents/andskills/../...is local to this skill's directory..ruler/...,docs/...,src/..., or any project-relative path refers to the user's project repository. </arc_runtime>
<platform_context> Adapt the workflow to the current harness instead of assuming Claude-specific tool names.
- Use platform-native structured questions when available; otherwise ask one concise plain-text question at a time.
- Use the repo's detected package manager (
pnpm,npm,yarn,bun) consistently for every command below. </platform_context>
Release Workflow
Cut a versioned release of one or more npm packages. Owns semver bumps, changelogs, and multi-package releases. Commits, pushes, and simple unversioned publishing belong to /arc:commit.
Usage:
/arc:release- Detect, propose bumps, author, verify, then gate publish./arc:release dry-run- Run everything up to and includingpnpm packverification, but never publish.
$ARGUMENTS will be empty or "dry-run". Treat "dry-run" as a hard stop before any publish.
Boundary
- Never bump a version, publish, tag, or push without an explicit user choice at the gate.
- Never publish a
privatepackage or a version already on the registry. - Never use
--force,--no-verify, or delete published versions. - Do not invent changelog entries. Base them on actual commits and diffs.
Step 1: Detect Release State
Establish what is being released before proposing anything.
git describe --tags --abbrev=0 2>/dev/null || echo "(no tags)"
git log $(git describe --tags --abbrev=0 2>/dev/null)..HEAD --oneline 2>/dev/null || git log --oneline -20
Determine the repo shape:
- Single package: one
package.jsonat root, no workspace config. - Workspace/monorepo:
pnpm-workspace.yaml, orworkspacesin rootpackage.json.
For workspace repos, check for changesets:
test -f .changeset/config.json && echo "changesets present" || echo "no changesets"
- If changesets are present, read pending intents and status:
pnpm changeset status --since=$(git describe --tags --abbrev=0 2>/dev/null || echo HEAD~20) - If changesets are absent in a workspace repo, offer to scaffold on first run (
pnpm add -Dw @changesets/cli && pnpm changeset init) via one question before continuing. Do not scaffold silently.
Identify which publishable packages changed since their last release. Prefer changeset status; fall back to diffing since the last tag filtered by each package's directory:
git diff --name-only $(git describe --tags --abbrev=0 2>/dev/null || echo HEAD~20)..HEAD
A package is a release candidate only if its package.json has a name, a version, and is not "private": true. Ignore generated dirs (node_modules, dist, build, .next, .turbo, coverage).
Step 2: Propose Semver With Reasoning
For each changed package, inspect the diff and classify the change, then propose a bump with a one-line reason:
- major — removed or renamed an export, changed a signature, dropped a runtime, changed default behavior.
- minor — added a new export, prop, or option; backwards-compatible surface growth.
- patch — bug fix, internal change, docs, types-only fix with no surface change.
Confirm all packages in one structured question. List each package with its proposed bump; let the user override any of them.
AskUserQuestion:
question: "Proposed version bumps. Adjust any before I author the release."
header: "Bumps"
options:
- label: "Accept all"
description: "e.g. @scope/ui minor (new prop), @scope/core patch (internal fix)"
- label: "Override"
description: "Tell me which package should be major / minor / patch instead"
- label: "Stop"
description: "Cancel the release"
Step 3: Author The Release
Once bumps are confirmed:
- Changesets repo: write a changeset file per package under
.changeset/with the confirmed bump and a human summary, then run:
This applies bumps and regenerates eachpnpm changeset versionCHANGELOG.md. - Single package: bump the
versionfield manually to the confirmed level and prepend a dated entry toCHANGELOG.md(create it if absent), grouping changes as Added / Changed / Fixed / Breaking.
For any breaking change, write a short migration note — how to upgrade, before/after, and what to search-and-replace. Append it to MIGRATIONS.md at the package root (create if absent), keyed by the new version. Keep it to the minimum a consumer needs to update.
Step 4: Pre-Publish Verification
This step catches the failures a plain npm publish ships silently. Run it for every publishing package. Use the platform temp/scratch directory for the throwaway project.
For each package:
- Build: run the package's
buildscript if present. A failed build stops the release. - Pack: create the real tarball and inspect its contents.
pnpm pack tar -tf *.tgz - Install into a throwaway project: create a temp dir,
npm init -y, and install the tarball by path so you exercise the published shape, not the source. - Import-smoke each entry point: for every path in the
exportsmap (andmain/module/types), import it and confirm it resolves and loads without throwing.
Then check the traps that only appear in the packed output:
"use client"survives bundling: if any source file declares"use client", grep the packeddistfor the directive. If the bundler stripped it, the package is broken for RSC consumers — stop and report.- Runtime/animation libs are peerDependencies: libraries the consumer's app also renders with (React, React DOM, framer-motion, and similar runtime/animation libs) belong in
peerDependencies, notdependencies, to avoid duplicate copies. Flag any that are misplaced. - Exports map resolves both conditions: confirm both the
importandrequireconditions resolve for each export entry, and thattypespoints at real.d.tsfiles in the tarball. - Files array does not drop dist: confirm the
filesarray /.npmignoreactually includes the builtdist(and types) — the packed tarball listing from step 2 is the source of truth.
Report every finding. Any hard failure (build fail, stripped directive, missing dist, unresolved export) blocks publish until fixed.
If $ARGUMENTS is "dry-run", stop here and report the verification results. Do not proceed to publish.
Step 5: Publish
Gate publishing behind one explicit question:
AskUserQuestion:
question: "Verification passed for <packages>. How do you want to proceed?"
header: "Publish"
options:
- label: "Publish now"
description: "Publish each verified package to the registry"
- label: "Dry-run only"
description: "Run publish with --dry-run and report, but do not publish"
- label: "Stop"
description: "Leave the release authored but unpublished"
On Publish now, publish each verified package from its directory using the detected package manager. For changesets repos prefer pnpm changeset publish (it publishes only bumped packages and skips already-published versions). For single packages use npm publish, adding --access public for scoped public packages.
After a successful publish, offer to tag and push — never do it silently:
# offered, not automatic:
git tag <name>@<version> # or vX.Y.Z for single-package repos
git push --follow-tags
Step 6: Report
Tell the user:
- Which packages were released and at what versions, with the reason for each bump.
- Migration notes written, if any.
- Verification results per package (packed contents, entry-point smoke, the four traps).
- Publish status per package: published, dry-run, skipped (already on registry), or blocked.
- Tag/push status, or a reminder that tagging and pushing are still pending.