Releasing MCO
July 29, 2026 · View on GitHub
MCO is published through npm only. Do not publish to PyPI. The normal path is a
GitHub Release from the matching version tag; the publish workflow gates and
publishes that exact tag. The manual path remains available when GitHub Actions
cannot publish because NPM_TOKEN is missing or npm requires web-based 2FA.
Preview package (CI artifact)
Pull requests run the Preview package GitHub Actions workflow
(.github/workflows/preview-package.yml). It builds and uploads an installable
npm tarball as a workflow artifact. It does not publish to the npm registry.
- Open the PR Checks tab → Preview package → Artifacts
- Download
mco-preview-package-<run_id>and extract the.tgzinside - Install locally (Python 3.10+ required on PATH):
tmp=$(mktemp -d)
npm install /path/to/tt-a1i-mco-X.Y.Z.tgz --prefix "$tmp" --no-audit --no-fund
"$tmp/node_modules/.bin/mco" --help
For same-repository pull requests, a separate job with only pull-requests: write
permission makes a best-effort PR comment with the install hint. A denied comment
never blocks the preview build. That job never checks out or executes PR code.
Fork PRs receive the same instructions through the workflow summary without
granting untrusted code a write-capable token.
1. Prepare the release PR
Start from the current remote main branch, not from a stale local main.
git fetch origin main --tags
git switch -c release/vX.Y.Z origin/main
Update the version in all package metadata:
package.jsonpyproject.tomlruntime/__init__.py
Add a CHANGELOG.md entry for the release date and version.
Run the release gate before opening the PR:
PYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover -s tests -p 'test_*.py'
npm pack --dry-run
Commit, push, open the PR, wait for GitHub checks, then merge it.
2. Tag the merged commit
After the release PR is merged, verify the remote main branch has the intended version.
git fetch origin main --tags
git show --no-patch --oneline origin/main
git show origin/main:package.json | node -e "let s='';process.stdin.on('data',d=>s+=d).on('end',()=>console.log(JSON.parse(s).version))"
Create and push the tag from origin/main.
git tag -a vX.Y.Z origin/main -m "vX.Y.Z"
git push origin vX.Y.Z
The release workflow accepts only a tag matching v<package.json version> and
requires a dated changelog heading. The same guard can be checked locally:
GITHUB_REF=refs/tags/vX.Y.Z python3 scripts/check_release_ref.py
If the tag already exists, do not recreate it. Verify it instead:
git ls-remote --tags origin refs/tags/vX.Y.Z
3. Publish through a GitHub Release
Create the release as a Draft, inspect its tag and notes, then publish it. The
Publish npm workflow runs the full gate, publishes the package, waits for npm
latest to match, and performs a clean registry install smoke.
gh release create vX.Y.Z --draft --title "vX.Y.Z" --notes-file docs/releases/vX.Y.Z.md
gh release edit vX.Y.Z --draft=false
Watch the workflow through completion. If npm publish succeeds but a later
verification step fails, choose Re-run failed jobs on that same workflow run.
The preflight skips npm publish only after the registry confirms the exact
version, then continues with the latest and clean-install checks.
If the package was not published or the retry still fails, return the GitHub Release to Draft while investigating so GitHub and npm do not continue advertising different latest versions.
4. Manual fallback: publish npm from a clean tag checkout
Check the currently published version first.
npm view @tt-a1i/mco version dist-tags --json
Publish from a clean temporary clone of the tag, not from a dirty working tree.
tmp=$(mktemp -d /tmp/mco-publish.XXXXXX)
git clone --depth 1 --branch vX.Y.Z https://github.com/mco-org/mco.git "$tmp"
cd "$tmp"
node -p "require('./package.json').version"
npm pack --dry-run
Then publish from a real terminal/TTY:
npm publish --access public --auth-type=web
5. npm web auth and 2FA
The repository NPM_TOKEN must identify an npm account or granular automation
token with write access to @tt-a1i/mco. The publish workflow runs npm whoami
before npm publish; if that check fails, replace the secret before retrying.
An existing package may return E404 Not Found when the token is valid but lacks
scope or package permission, so also verify the token owner appears here:
npm view @tt-a1i/mco maintainers --json
Publishing the prepared Draft GitHub Release triggers the npm workflow. If the registry confirms the package was not published and that workflow fails, return the release to Draft before using this manual fallback.
Use a real TTY for npm web-auth publish prompts. Do not pipe npm publish
through tee, and do not run it through a non-interactive command runner for the
final publish step. In non-TTY mode npm may print
https://www.npmjs.com/auth/cli/*** with the auth id redacted; that URL is not
usable and cannot be recovered from the npm debug log because the log is redacted
too.
If npm reports E401 Unauthorized, log in first:
npm login --auth-type=web
npm whoami
If npm reports EOTP during npm publish, rerun publish in a TTY:
npm publish --access public --auth-type=web
Expected TTY prompt:
Authenticate your account at:
https://www.npmjs.com/auth/cli/<auth-id>
Press ENTER to open in the browser...
Open the URL, finish the browser confirmation, then let the same publish command continue. A successful publish ends with:
+ @tt-a1i/mco@X.Y.Z
If publish returns E404 Not Found with do not have permission, first check
whether the shell is actually logged in as a maintainer:
npm whoami
npm view @tt-a1i/mco maintainers --json
In the observed failure case, E404 followed a stale or missing npm session; a
fresh npm login --auth-type=web fixed it.
The working manual sequence for the v0.10.6 release was:
cd "$tmp"
npm whoami
npm publish --access public --auth-type=web
If npm publish asks for web auth, keep that same command running, open the
printed https://www.npmjs.com/auth/cli/<auth-id> URL, complete the browser
confirmation, and return to the terminal. Do not start a second non-TTY publish
attempt while the first publish is waiting.
6. Verify the published package
Confirm the registry state:
npm view @tt-a1i/mco version dist-tags --json
Run a clean install smoke:
tmp=$(mktemp -d /tmp/mco-npm-test.XXXXXX)
npm install @tt-a1i/mco@X.Y.Z --prefix "$tmp"
"$tmp/node_modules/.bin/mco" --help
The release is complete only after npm shows latest pointing at the new
version and the clean install smoke succeeds.