Publishing
Which items publish to npm and which only to GitHub Releases is in the Versioning and releases table.
Consumers install the Agent Skill as Get started shows. The CLI and core package READMEs give their own install commands.
Prerequisites
Section titled “Prerequisites”- npm account
bwilliamsonwith access to publish@merlon-docs/* - 2FA enabled on npm (auth-and-writes)
RELEASE_GITHUB_TOKEN, a secret of thereleaseenvironment, as Release token describespnpm installat repo root
Security reporting and bad-release handling: SECURITY.md and Security-incident triage.
First-time publish (chicken-and-egg)
Section titled “First-time publish (chicken-and-egg)”A package’s first npm publish runs from your machine with npm login, before Trusted Publishing can be configured for it. Routine releases run in CI.
Trusted Publishing
Section titled “Trusted Publishing”The release job in release.yml runs in the release environment. Repository settings lists its reviewers and deployment branches.
- Each package → Settings → Trusted Publisher → GitHub Actions
- Repository:
Merlon-Docs/merlon - Workflow filename:
release.yml
Tokens
Section titled “Tokens”The release job and the Dependabot changeset workflow each push with a fine-grained personal access token instead of the default GITHUB_TOKEN. The copy of a workflow that any pushed branch runs can read a repository secret. Only the jobs that run in an environment get that environment’s secrets, and the release environment’s deployment branches and reviewer keep other branches’ jobs out of it, as Repository settings lists.
Release token
Section titled “Release token”The release job pushes the release commit and tags and creates GitHub Releases with RELEASE_GITHUB_TOKEN.
- Create a fine-grained PAT as the maintainer (avoid classic
repounless necessary). - Repository access: this repo only. Give it Contents read/write (commits, tags, releases). Every fine-grained token also includes read-only Metadata access.
- Store it as
RELEASE_GITHUB_TOKENunder Settings → Environments →release→ Environment secrets.
Without it, the Release job fails before versioning (hard requirement).
Dependabot changeset token
Section titled “Dependabot changeset token”The Dependabot changeset workflow pushes its changeset commit to the pull request with DEPENDABOT_CHANGESET_TOKEN. A commit made with the default GITHUB_TOKEN would not start CI, and the required checks would stay pending.
- Create a fine-grained PAT with Contents: read and write on this repository only.
- Store it as the repository secret
DEPENDABOT_CHANGESET_TOKEN.
The GitHub Actions security checklist lists the exposure of this repository secret as an open risk.
Without the secret, the workflow logs a warning and doesn’t add a changeset. On a pull request that changes a package’s runtime dependencies, the Changeset check then fails.
Rotation
Section titled “Rotation”Rotation is advisory, because no workflow or check reads the tokens’ expiry dates. A maintainer rotates each token before the expiry date set on it, and when the maintainer who created it leaves. The new expiry date in the token’s settings is the record that a rotation happened. An expired token fails its run visibly: the Release job stops at its first call that uses the release token, and the Dependabot changeset run stops at its first API call.
Dry run and manual fallback
Section titled “Dry run and manual fallback”Routine releases run in CI, as Release schedule describes. The dry run prints each release command without running it, so it doesn’t change any file or push anything:
pnpm release:main --dry-runWith pending changesets, the dry run lists them and then exits 1 with “changeset version ran but no package versions changed”, because it skipped the version step. So it can’t preview a versioning release.
The manual fallback runs the release from a maintainer machine. pnpm release:main exits at once without RELEASE_GITHUB_TOKEN in the environment, and Trusted Publishing needs the OIDC token that only the release workflow gets. So export the token and sign in with npm login first. Run the fallback in a fresh clone of main, because the script points that clone’s origin at a URL that contains the token and sets its git identity to github-actions[bot]. The clone has no dependencies or synced Vale styles yet, and pnpm run check needs both:
pnpm install --frozen-lockfilepnpm vale:syncpnpm run checkpnpm release:mainWhen a CI run pushed the release commit to main and stopped before it published, main has no pending changesets left, and pnpm release:main only heals tags and GitHub Releases. Publish the missing versions from a checkout of main instead. When the run stopped at the dependency audit, first resolve the advisory, or confirm that it is dev-only as Classify impact first describes. The block’s pnpm audit --prod step then fails on any high advisory left in a published package’s dependencies. Give npm your 2FA code when it asks:
pnpm install --frozen-lockfilepnpm audit --prod --audit-level=highpnpm buildnpm loginpnpm exec changeset publish --no-git-tagchangeset publish publishes each public package whose version npm doesn’t have yet, and --no-git-tag leaves the tags to the Release run that the push of the release commit already started. That run waits for approval of the release environment. Leave it waiting until npm has the versions, then approve it, and it creates the missing tags and GitHub Releases. If that run is gone, start one from the Release workflow’s manual trigger.