Docs Guides
Release
This document tells how the packages of the monorepo go to npm. The first release needs a one-time bootstrap. Each later release starts from GitHub Actions.
The packages#
- The npm scope of the packages is
@procedures. The npm name can differ from the folder (the root README has the table). Until 2026-10-12 the scope was@mark1russell7.scripts/lib/old-names.mjsmaps each old name to its new name. - The 30 public packages have one version together. The
fixedgroup of.changeset/config.jsonnames each one. site,documentationand the repository tool (packages/cli) are private. They are not published.- The MCP server of
packages/impl-mcp-devis published as@procedures/mcp-dev-tools, with the binmcp-dev-tools. - Three packages use general packages from other repositories:
client-cueuses@mark1russell7/cue,client-splayuses@mark1russell7/splay, andclient-sqliteuses@mark1russell7/docker-sqlite.
The package check#
node scripts/check-packages.mjs examines the packages as a user gets them from npm. Start pnpm build first. For each public package, the script does these steps:
- It packs the package with pnpm. pnpm writes the versions of the
workspace:*dependencies. - It reads the packed
package.json. Aworkspace:or git specifier is an error. The metadata,LICENSEandREADME.mdmust be in the tarball. - It examines the tarball with
publint --strict, and withattwand its ESM-only profile. - It installs all the tarballs into an empty project.
- It imports each package root, runs a program with the client, and starts each bin with
--help.
The option --allow-git-deps accepts the github: dependencies of the general packages. CI uses it until the general packages are on npm. The release workflow does not use it, because npm 12 does not install git dependencies by default.
The one-time bootstrap#
npm trusts a workflow only for a package that exists. Thus the first version of each package comes from a computer, as a staged publish. The registry keeps a staged version until the owner approves it with 2FA.
1. Publish the general packages#
Each general repository has the file docs/release.md. Publish them in this order:
@mark1russell7/cue1.0.0. Its branchnpm-releasehas the release changes. Merge the branch after the publish, because its presets write^1.0.0.@mark1russell7/splay0.1.0.@mark1russell7/docker-sqlite0.1.0.
Then switch the monorepo to the npm versions, and examine the packages:
node scripts/use-npm-general-packages.mjs
pnpm build
node scripts/check-packages.mjs
The script examines that each version is on npm. Then it changes the specifiers, removes the git build approvals of pnpm-workspace.yaml, and starts pnpm install. Commit the result.
2. Stage the packages of the monorepo#
npm login
node scripts/npm-bootstrap.mjs --dry-run
node scripts/npm-bootstrap.mjs
The script packs each public package with pnpm and stages it with npm stage publish. It skips a version that is on npm or staged. It refuses a package with a git dependency.
To publish without the approval step, publish directly. Start this command in a terminal. npm opens the browser for the 2FA. The command stops at the first failure. Start it again: it skips the versions on npm. Step 3 is then not necessary:
node scripts/npm-bootstrap.mjs --publish
npm limits the number of new packages of one account. Then each new package fails with HTTP 429 ("rate limited exceeded"), for the staged and the direct publish. On 2026-10-12, this occurred after 25 new packages. Wait for the limit to reset, or ask npm support for a higher limit.
3. Approve the staged versions#
Start this command in a terminal. For each staged version of the packages, it starts npm stage approve <id>, and npm opens the browser for the 2FA:
node scripts/npm-bootstrap.mjs --approve
You can also approve each staged version on npmjs.com.
4. Connect each package to the release workflow#
node scripts/npm-bootstrap.mjs --trust
The script starts npm trust github <package> --file release.yml --repo mark1russell7/client --env npm --allow-publish for each package, in the terminal, so npm can open the browser for the 2FA. It skips a package that trusts the workflow already, and a package that is not on npm. You can start it again at any time.
5. Set the repository and the packages#
- Each run in the GitHub environment
npmwaits for the approval of the owner. The environment exists already. - In the settings of the repository, turn on
Allow GitHub Actions to create and approve pull requests. The release workflow opens the version pull request. - After the first release from the workflow, set "Require two-factor authentication and disallow tokens" for each package on npmjs.com.
6. Point the old packages to the new names#
22 packages went to npm as @mark1russell7/* 0.1.0 before the scope change. After the @procedures packages are on npm, start this command in a terminal. For each old package on npm, it starts npm deprecate with the new name, and npm opens the browser for the 2FA:
node scripts/npm-bootstrap.mjs --deprecate-old --dry-run
node scripts/npm-bootstrap.mjs --deprecate-old
A user who installs an old package sees "Moved to @procedures/<name>". The old versions stay on npm, so nothing breaks. The command does not deprecate an old package before its new package is on npm. Start it again after the last publish.
A release#
- For each change that users see, add a changeset: start
pnpm changesetand answer the questions. Commit the file. - On GitHub, open Actions, select "Release", and start the workflow. Approve the
npmenvironment. - The workflow opens the pull request "Version the packages". It sets the new version and writes the change logs. Merge it.
- Start the workflow again. It does the checks and the strict package check. Then it publishes each version that is not on npm, with provenance.
A new public package#
- Make it with
lib new, asclient/CLAUDE.mdtells. - Give it the metadata of the other packages:
description,keywords,homepage,bugs,repositorywithdirectory,license,author,filesandpublishConfig. - Copy
LICENSEinto its folder, and addCHANGELOG.md. - Add its name to the
fixedgroup of.changeset/config.json. The package check fails without it. - Before its first release, stage it with
node scripts/npm-bootstrap.mjs --only <name>, and connect it with--trust.