agentsclimarketplace

Npm publishing best practices

Skill schalkneethling/claude-toolkit/skills/npm-publishing-best-practices

CLI for managing Agent commands, hooks, and skills across projects.

Install
npx -y skills add schalkneethling/claude-toolkit --skill npm-publishing-best-practices

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 3 stars3 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Audit and improve the security posture of npm package publishing: account security, npm trusted publishing strategy, GitHub repository hardening, token removal, release governance, dependency update policy, provenance, and supply-chain risk. Use when the user asks about npm publishing best practices, publishing security, OIDC/trusted publishing strategy, npm token hygiene, release automation posture, Changesets versus changelog strategies, publint, provenance, or auditing an existing publishing pipeline. For writing or debugging the concrete GitHub Actions publish workflow file, use the npm-trusted-publishing-github-workflow skill instead.

SKILL.md

17.4 KB, as published. Nobody here has run it

npm Package Publishing — Best Practices

Based on the e18e publishing guide. Reference it for the canonical source; this skill distils the actionable steps.

Agent Workflow

  1. Inspect the repository before recommending changes:
    • package.json
    • lockfiles and packageManager
    • .npmrc, .yarnrc.yml, .github/workflows/*
    • release tooling such as Changesets, changelogithub, semantic-release, or release-it
    • existing npm/GitHub tokens or NODE_AUTH_TOKEN usage in workflows
  2. Classify the request:
    • Audit: report risks by severity, with file and line references where possible.
    • Implementation: make scoped repository changes, then run relevant validation.
    • Strategy: explain tradeoffs and identify user-only settings.
  3. Separate agent-doable work from user-only UI work. Do not claim account, npmjs.com, or GitHub settings are configured unless verified by authenticated tool/API access.
  4. For concrete GitHub Actions publish workflow creation or CI failure debugging, hand off to the npm-trusted-publishing-github-workflow skill.

Freshness Rule

Before changing trusted publishing requirements, supported CI providers, npm CLI minimums, Node.js minimums, provenance behavior, or GitHub release/security settings, verify the current official npm and GitHub documentation when browsing is available. These requirements change over time.

Responsibility Split

Agent can usually:

  • Edit .github/workflows/*.
  • Add or update repository package-manager config such as .npmrc or .yarnrc.yml.
  • Remove NODE_AUTH_TOKEN usage from publish steps when trusted publishing is used. If private dependencies require registry auth during install, keep that token scoped to read-only install steps only.
  • Add Dependabot/Renovate config.
  • Run publint, workflow linting, tests, package builds, and other local validation.
  • Report exact user steps for npm/GitHub settings.

User or authenticated UI/API access required:

  • Enable npm/GitHub 2FA.
  • Configure npm trusted publisher settings on npmjs.com.
  • Set package publishing access to require 2FA and disallow tokens.
  • Enable GitHub repository/org Actions restrictions.
  • Configure branch/tag rulesets and immutable releases.
  • Remove repository/org secrets when the agent lacks GitHub settings access.

Non-Negotiables

  • Do not add NODE_AUTH_TOKEN to publish steps when trusted publishing is available. Use OIDC for publishing; if private dependencies require install auth, use a read-only token only for the install step.
  • Do not store npm publish tokens in GitHub Actions secrets for OIDC-capable publishing.
  • Do not run install lifecycle scripts in release workflows unless the user explicitly accepts the risk.
  • Do not show tag-pinned actions as compliant with SHA pinning; resolve all third-party and GitHub-owned actions to full commit SHAs. Tag-based refs such as @v6 or @v7 weaken supply-chain integrity and violate pinned-action policy.
  • Do not create or edit GitHub Actions workflows without explicit least-privilege permissions: for GITHUB_TOKEN. Set a restrictive top-level default such as contents: read, then grant elevated scopes only on the jobs that need them.
  • Do not use actions/checkout with default credential persistence. Always set persist-credentials: false; if a job must push to git, provide an explicit, narrowly scoped credential only for that push step.
  • Do not say npm/GitHub account settings are complete unless they were actually checked.
  • Do not use self-hosted runners for npm trusted publishing unless official npm docs currently support them.

Package manager note. The example install and configuration commands in this skill use npm to match the e18e source material, but should be adapted to whichever package manager the project already uses — pnpm, yarn, bun, etc. Adapt commands accordingly:

npmpnpmyarn
npm ci --ignore-scriptspnpm install --frozen-lockfile --ignore-scriptsyarn install --frozen-lockfile --ignore-scripts
npm i -g npmpnpm add -g pnpmyarn set version stable
ignore-scripts=true in .npmrcignore-scripts=true in .npmrcenableScripts: false in .yarnrc.yml

Detect the project's package manager by checking for a lockfile (pnpm-lock.yaml, yarn.lock, bun.lockb) or a packageManager field in package.json before generating any commands or workflow steps.

Section 2.2's trusted-publishing requirement is npm-specific: the publish step must run with a supported Node.js version and npm CLI version even when the rest of the workflow uses another package manager.

For pnpm projects on GitHub Actions, prefer the Marketplace action pnpm/setup to set up pnpm and the JavaScript runtime in one step. It installs pnpm from @pnpm/exe, can read devEngines.runtime from package.json, and replaces the separate pnpm/action-setup + actions/setup-node pattern. In release workflows, pin pnpm/setup to a full commit SHA, set install: false, and run the explicit hardened install command yourself so flags like --frozen-lockfile --ignore-scripts remain visible.


1 · Prerequisites

1.1 · Enforce 2FA everywhere

AccountLocationRecommended method
npmAccount → SecuritySecurity key (YubiKey, Touch ID, Windows Hello); fallback: authenticator app
GitHubSettings → Password and authenticationSame priority order

Use a password manager with generated passwords for both accounts.

1.2 · Harden GitHub Actions settings

Settings → Actions → General:

  • ✅ Require actions to be pinned to a full-length commit SHA
  • ✅ Require approval for first-time contributors
  • ✅ Set default workflow permissions to "Read repository contents and packages"

If the repository belongs to an organisation, apply these settings at org level for consistency across all repositories.

1.3 · Configure branch protection

Settings → Branches → create a ruleset for main:

  • ✅ Require a pull request before merging
  • ✅ Require at least 1 approval
  • ✅ Dismiss stale approvals when new commits are pushed
  • ✅ Require approval of the most recent reviewable push

1.4 · Remove legacy npm tokens

Settings → Secrets & Variables → Actions: remove any stored npm tokens. OIDC trusted publishing replaces them entirely — no long-lived secrets needed in the repository.


2 · Trusted Publishing (OIDC)

Trusted publishing means GitHub Actions authenticates directly with npm via OIDC — no npm token ever touches the repository.

2.1 · Configure on npmjs.com

  1. Open your package page → Settings tab → Trusted Publishing section.
  2. Add a trusted publisher:
    • Organisation / user: your GitHub org or username
    • Repository: the repository name
    • Workflow filename: e.g. publish.yml
  3. Check "Require two-factor authentication and disallow tokens" — this forces manual publishes to use 2FA as well.

For bulk configuration across many packages, use open-packages-on-npm to open each package in a new tab, then the npm-trusted-publisher userscript to configure them rapidly.

2.2 · npm CLI version requirement

The publish step must use npm CLI ≥ 11.5.1 for automatic OIDC trusted publishing. Node.js 22.14.0 or newer can use trusted publishing when the workflow installs npm CLI 11.5.1 or newer before publishing:

- run: npm i -g npm

3 · Standard Publish Workflow

Use the e18e setup-publish template as your base, or scaffold it with:

npx @e18e/setup-publish

3.1 · Job structure

The workflow must separate build from publish. This ensures publish permissions (the OIDC token) are never exposed to build-time code.

test  →  build  →  publish

3.2 · Non-negotiable workflow constraints

ConstraintWhy
All actions pinned to full-length commit SHAPrevents supply-chain attacks via mutable tags
Explicit least-privilege GITHUB_TOKEN permissionsAvoids inheriting broad repository defaults
actions/checkout uses persist-credentials: falseReduces token exposure to later workflow steps
npm ci --ignore-scripts (or --ignore-scripts flag)Prevents malicious lifecycle scripts running during install
Build and publish in separate jobsIsolates publish permissions from arbitrary build code

Always include a top-level permissions: block with the workflow-wide minimum, usually contents: read. Add job-level permissions only when a job requires more access; for npm trusted publishing, id-token: write belongs on the publish job only.

Every checkout step must disable persisted credentials:

- uses: actions/checkout@<full-length-commit-sha>
  with:
    persist-credentials: false

This is especially important for jobs that build packages or upload artifacts, because later steps should not inherit a repository token unless they explicitly need one.

3.3 · Suppress lifecycle scripts project-wide

Add to .npmrc in the repository:

ignore-scripts=true

Also apply globally on developer machines:

npm config set -g ignore-scripts true

3.4 · Creating a release

git tag v1.0.0
git push origin v1.0.0

Then in GitHub UI: Releases → Draft a new release → choose the tag → Generate release notesPublish release. This triggers the workflow.


4 · Alternative Workflow Strategies

4.1 · Changesets (recommended for teams)

Use the changesets template.

  • Merged PRs automatically update a release pull request
  • Changelog is generated by changesets and included in the release PR
  • Releasing = merging the generated release PR — no manual tagging

4.2 · changelogithub (changelog from commit messages)

Use the changelogithub template.

  • Tags are still pushed manually
  • GitHub release + changelog are created automatically on tag push
  • Package is published on tag push

5 · Ongoing Maintenance

5.1 · Keep dependencies updated

Set up Dependabot or Renovate to receive automated PRs for dependency updates, addressing security vulnerabilities promptly.

5.2 · Keep GitHub Actions updated

All third-party and GitHub-owned actions must be pinned to a full commit SHA, not a tag. Tag refs such as @v6 or @v7 are mutable and must not be committed to workflow files. To migrate existing workflows and keep them current:

npx actions-up

Run this periodically, or let Dependabot/Renovate manage action updates once SHAs are in place.

5.3 · Lint workflows for vulnerabilities

zizmor detects template injection vulnerabilities and excessive permission scopes in GitHub workflow files:

zizmor .github/workflows/publish.yml

Integrate this into CI or run it before merging workflow changes.

5.4 · Validate package.json and exports

publint checks for common publishing issues: missing files, incorrect exports fields, wrong main/module paths, and more.

npx publint

Review the full list of publint rules to understand what it checks. Run this locally before tagging a release.

5.5 · Visualise dependency changes

multiocular shows exactly what code changed between dependency versions, helping catch unexpected changes or potential security issues.


6 · Further Security Hardening

6.1 · Use a GitHub environment (important for shared repos)

Without a GitHub environment, any account with write access can trigger a publish by creating a branch and modifying the release workflow — bypassing code review entirely.

Settings → Environments:

  1. Create an environment named publish.
  2. Do not allow administrator bypass of protection rules.
  3. Limit deployment to explicit branch names only (e.g. main, v1). Do not use wildcards. Remove stale branches promptly.
  4. Update the publish job in publish.yml:
jobs:
  publish:
    environment: publish
  1. Update the npm trusted publisher settings on npmjs.com to include the environment name.

Optionally configure the publish environment to require manual approval before the job proceeds — providing a human gate even if malicious code reaches a release branch.

6.2 · Consider hardware security keys (optional)

Physical security keys (YubiKey, etc.) are significantly more resistant to phishing and credential theft than authenticator apps or SMS. They are worth recommending but should never be enforced — not everyone has access to one, and a good authenticator app is a perfectly reasonable alternative. Mention this as a suggestion, not a requirement.

6.3 · Protect all long-lived branches and tags

Apply branch protection rules not just to main but to all long-lived branches and to all tags.

6.4 · Enable immutable releases

Enable GitHub immutable releases to prevent modification or deletion of tags and releases after creation.


7 · Sole Maintainer Considerations

There is an open feature request to support 2FA for GitHub environment approvals. Until that lands, trusted publishing carries a risk for solo maintainers: a leaked GitHub token could be used to publish through the trusted workflow without a 2FA challenge.

Recommendation for sole maintainers: consider publishing locally with npm publish and 2FA-protected npm access until environment-level 2FA approval is supported. Continue to follow all other security recommendations in this document regardless.


Audit Output Format

For audits, lead with findings:

  • P0/P1/P2/P3 severity.
  • File and line when repo-local.
  • Risk.
  • Recommended fix.
  • Whether the agent can implement it now or the user must configure it externally.

Then include:

  • Validation run.
  • Remaining user-only checklist.
  • Suggested next change.

Quick Reference Checklist

Use this when setting up a new package or auditing an existing one.

Account security

  • npm 2FA enabled (security key preferred)
  • GitHub 2FA enabled (security key preferred)
  • Password manager in use

Repository settings

  • Actions pinned to full-length commit SHAs (enforced in settings)
  • First-time contributor approval required
  • Default workflow permissions set to read-only
  • main branch protected (PR + review required)
  • No npm tokens in repository secrets

Trusted publishing

  • OIDC trusted publisher configured on npmjs.com
  • "Require 2FA, disallow tokens" enabled on npm
  • Publish step uses npm CLI ≥ 11.5.1 and a Node.js version supported by official npm docs
  • GitHub environment (publish) configured with branch restrictions

Workflow hygiene

  • Build and publish are separate jobs
  • Workflows declare explicit least-privilege GITHUB_TOKEN permissions
  • Every actions/checkout step sets persist-credentials: false
  • npm ci --ignore-scripts used in all install steps
  • ignore-scripts=true in .npmrc
  • zizmor passes on all workflow files

Package quality

  • npx publint passes with no errors
  • Dependabot or Renovate configured
  • actions-up run to migrate to SHA-pinned actions

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.