shipRig
RigSmith's release tool — the Go successor to net-changesets. One uniform add changeset → version → publish workflow across .NET, Node, Go, and Rust, plus Tauri, Electron, and Velopack desktop apps.
shiprig init # release-init wizard: pipeline, forge, publish auth
shiprig add -p my/pkg --bump minor -m "Add a feature" # interactive without flags
shiprig status --verbose
shiprig version # bump + changelog, with dependency cascade
shiprig publish # registries (idempotent, confirm-gated on a TTY)
shiprig release # the configurable step pipeline
shiprig release --dry-build # build artifacts locally, publish nothing
shiprig release --rehearse # full local dry run — no commit, tag, or network
shiprig doctor # health-check changesets + release readiness
shiprig infoversion runs the shared engine in rigsmith/core: it parses changesets, cascades bumps to dependents, applies linked/fixed/lockstep grouping, stamps the new versions into each ecosystem's manifest, and writes CHANGELOG.md.
The full surface
The whole workflow is wired:
init,add(--since),status(--since,--output)version(normal / pre / snapshot, changelog enrichment +format:)pre— enter/exit prerelease modeconfig—show/get/set/path/editthe.changeset/config.jsoninfo,uipackages— show every discovered package and what the release does with each (its bump, or no change / private / ignored) and include/exclude them via a picker that persists the choice to the changesetignorelist;packages listprints and exits, andpackages list --jsonprints every package for a script (ecosystem, directory, version, next version and bump, private/ignored, and where its changelog goes)tag— create the git tags for the released versionspublish-plan— what a publish would release, aschangeset publish-plan: each package's registry is asked whether its version is already there (for npm:node.packageSource, else the package'spublishConfig.registry, else the scope routing in the nearest.npmrcup to the repository root, so a workspace that routes its scope to a private registry at the root is asked there, and published there, not npmjs.com; a registry given as a${VAR}that is unset or empty is an error — set it, or write the URL literally), and a package released by its git tag alone (a Go module, a desktop app, a private package withprivatePackages.tag) is listedtag-onlywhen its tag is missing, and so is a package already published whose tag never made it. A private NuGet feed that asks for credentials gets them, first found wins: credentials written into the source URL (https://user:token@…), else the resolveddotnet.auth, elseNUGET_API_KEY(never in place of adotnet.auththat can't be resolved); the account is the URL's user, elsedotnet.user, else a placeholder. They're sent only after it asks, and only to the source's own host and port over https (plain http only to a loopback host,localhost,127.0.0.0/8or::1, for a local test feed).--output <file>writes @changesets v3's plan JSON, chunked in dependency order, and--tagsets the npm dist-tag. A registry that can't be reached fails it rather than guessingpack --out-dir <dir>— build the package file for each release the plan would publish (npm pack,dotnet pack) into<dir>/packages/, and write<dir>/publish-plan.jsonrecording each file and its sha256 integrity, aschangeset packdoes;--from-publish-plan <file>packs a plan made earlier. This is the build half of a split release, where the job holding registry credentials never builds. Cargo can't publish a prebuilt crate, so a cargo release is refusedpublish— idempotent, confirm-gated on a TTY,--yesfor CI. It ships the versions already on disk and never versions, so it refuses while changeset files are waiting to bump them (a dry run warns instead): runshiprig versionand commit first, orshiprig releaseto do it all, or pass--allow-pendingto publish the versions on disk anyway. Commit-derived changes don't count, since a pipeline publishes before it tags. A NuGet version the feed already holds is reported as skipped, "already on" the feed, not as pushed. In pre mode npm packages go out under the prerelease tag (next, say) rather thanlatest, aschangeset publishdoes;--tag <name>picks another dist-tag outside pre mode.--from-pack-dir <dir>publishes exactly the filespackbuilt there, in the plan's order and under its npm dist-tag, building nothing, aschangeset publish --from-pack-dirdoes: each file's sha256 must still match whatpackrecorded and its package must be at the plan's version, or nothing is pushed. npm and NuGet publish a prebuilt file; cargo can't, so it's refusedtagandpublishspeak @changesets v3's output contract: with--output <file>or$CHANGESETS_OUTPUTset, each appends a{"type":"git-tag","tag":…,"packageName":…}line per tag it creates, skips a tag that already exists locally or on the remote, and pushes nothing. The caller owns the push, as withchangeset publish; this is how changesets/action and shiprig-action learn which tags to push and releaserelease— the configurable step pipeline with step filtering (--only/--skip/--from/--to),--channelsto build one target channel instead of the whole Velopack matrix,--dry-run,--dry-build,--local, and--rehearse(see local rehearsal)doctor— the changeset baseline (git/repo/config/workspace) plus a release section:ghauth and the publish/build tool each detected ecosystem needs
Beyond the basics, the release pipeline adds multi-forge releases (GitHub / GitLab / Gitea), OIDC trusted publishing + 1Password/secret-manager auth for npm / crates.io / NuGet, Tengo scripting (if gates, computed vars, script steps), a cross-platform portable shell, an issues step that comments on and closes resolved issues (GitHub today; GitLab/Gitea are planned), and code-signing for Tauri / Electron artifacts. See the release pipeline.
shipRig vs changeRig
changeRig is the changeset lifecycle on its own. shipRig is everything changeRig does plus tag, publish, pre, and release. They share the same add/status/version code, so the changeset half behaves identically.