npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

npm-trust

v0.11.0

Published

Bulk-configure npm OIDC Trusted Publishing for all packages in a scope

Readme


Built for LLM consumption. Every entry point is shaped for an agent to drive end to end:

  • Filesystem auto-detection (--auto) that removes the "what packages live here?" guesswork — works for pnpm/npm/yarn workspaces and single-package repos, picks up scope from package names automatically.
  • --only-new for incremental setup so the agent doesn't waste calls re-checking packages that are already trust-configured.
  • --doctor for a structured environment + per-package health report (JSON via --json); a Claude skill or other tooling can branch on the report's issue codes.
  • A typed programmatic API alongside the CLI (discoverFromCwd, checkPackageStatuses, findUnconfiguredPackages, configureTrust, …) so an agent can choose between spawning the binary or importing the library — same primitives, same data shapes.
  • Deterministic output: every package status comes back as one of configured | already | not_published | auth_failed | error, so an agent can branch on the result without parsing prose.
  • For an interactive guided wizard with AskUserQuestion gates, install the gagle/solo-npm marketplace plugin and invoke /solo-npm:trust — that skill orchestrates this CLI.

The problem

npm OIDC Trusted Publishing lets GitHub Actions publish packages without secrets or expiring tokens. But it requires per-package configuration on npmjs.com. If you maintain an npm org with 10, 50, or 100+ packages, setting up each one manually through the web UI is tedious and error-prone.

The solution

npm-trust bulk-configures OIDC Trusted Publishing for every package in your npm scope from a single command. It auto-discovers all published packages in your org, handles npm 2FA authentication once, and configures the rest automatically.

Use cases

Pick the section that matches your situation. Each one shows the command to run and what to expect.

1. First-time setup for an org

You've published a batch of packages under your npm scope and need to enable OIDC trust for all of them in one go.

npx npm-trust --scope @myorg --repo myorg/release-pipeline --workflow release.yml

The CLI auto-discovers every published package in the scope, configures each one, and reports a summary at the end. The first package triggers a browser auth flow; on the npm site, choose "skip 2FA for the next 5 minutes" so the rest finish without further prompts.

2. Adding new packages to an existing trusted setup

You already configured OIDC for your org's packages and just published one or more new ones. Combine --scope with --only-new to filter automatically — the CLI runs npm trust list and npm view per package and configures only the ones missing trust or not yet published.

npx npm-trust --scope @myorg --repo myorg/release-pipeline --workflow release.yml --only-new

--only-new works with any source (--scope, --packages, or --auto).

3. A single-package project

You maintain a standalone npm package (no monorepo, no scope-wide setup). Run from the repo root and let --auto read ./package.json:

cd ~/projects/my-package
npx npm-trust --auto --repo me/my-repo --workflow release.yml

If you'd rather be explicit:

npx npm-trust --packages my-package --repo me/my-repo --workflow release.yml

4. A monorepo (pnpm / npm / yarn workspaces, with or without NX)

You maintain a monorepo with multiple publishable packages — for example packages/foo, packages/bar, apps/something. Run from the repo root with --auto:

cd ~/projects/my-monorepo
npx npm-trust --auto --repo myorg/repo --workflow release.yml

Detection priority: pnpm-workspace.yamlpackage.json#workspaces → single ./package.json. Packages marked private: true are skipped.

If every published package shares the same scope, --scope @myorg is also a one-liner. For ad-hoc lists, --packages still works.

5. Auditing — checking what's already trusted

To inspect current trust status without making changes:

npx npm-trust --scope @myorg --list

To preview what configure would do:

npx npm-trust --scope @myorg --repo myorg/repo --workflow release.yml --dry-run

What happens during execution

  1. The CLI discovers all packages in your npm scope (or uses the list you provide).
  2. For each package, it runs npm trust github to configure OIDC trust.
  3. If npm requires 2FA, the CLI pauses and opens a browser-based authentication prompt. You authenticate once — npm caches the session for ~5 minutes, long enough to configure the remaining packages.
  4. Packages already configured are silently skipped. Unpublished packages are reported so you know to publish them first.
  5. At the end, a summary shows how many were configured, already set, or failed.

Requirements

  • Node.js >= 24.0.0
  • npm >= 11.5.1 (for npm trust support)
  • 2FA enabled on your npm account
  • Write access to the packages you're configuring

Options

| Flag | Description | | --------------------- | ------------------------------------------------------------------------------------------ | | --scope <scope> | npm org scope (e.g. @myorg) — auto-discovers all published packages | | --packages <pkg...> | explicit package names (alternative to --scope) | | --auto | detect packages from the current directory (workspaces or single package.json) | | --repo <owner/repo> | GitHub repository | | --workflow <file> | GitHub Actions workflow filename (e.g. release.yml) | | --list | list current trust status instead of configuring | | --only-new | filter the resolved package list to those without OIDC trust yet, or not yet published | | --doctor | print a structured health report (environment, repo, packages); exit 1 on fail issues | | --validate-only | fast read-only pre-flight (workflow + repo + auth, no per-package npm calls) | | --verify-provenance | bulk-query provenance attestations for the discovered/named packages | | --emit-workflow | print the canonical OIDC release.yml template to stdout | | --with-prepare-dist | modifier for --emit-workflow; emits the variant that wires in gagle/prepare-dist@v1 | | --capabilities | emit a CapabilitiesReport JSON describing the CLI surface (for tool-discovery) | | --json | emit machine-readable JSON (works with --doctor, --list, --validate-only, --verify-provenance, --capabilities, and configure) | | --dry-run | show what would be done without making changes | | --help | show help message |

Downstream consumers should pin to the public CLI contract documented in docs/cli-api.md — exit codes, JSON schemas, and migration notes.

Example output

Discovering packages in scope @myorg...
Found 12 packages

Configuring OIDC trusted publishing for 12 packages in @myorg
Repo: owner/repo | Workflow: release.yml

@myorg/core                    ✓ configured
@myorg/cli                     ✓ configured
@myorg/utils                   ✓ already configured
@myorg/new-pkg                 ✗ not published yet

Done: 2 configured, 9 already set, 1 failed

Failed packages (publish first, then re-run):
  - @myorg/new-pkg

Programmatic usage

npm-trust is published as a dual CLI + library. The same package exposes a typed public API for use inside other tools, scripts, or CIs.

import {
  checkPackageStatuses,
  configureTrust,
  discoverFromCwd,
  discoverPackages,
  findUnconfiguredPackages,
  listTrust,
  runCli,
} from "npm-trust";

discoverPackages(scope)

Discovers all published packages in an npm scope by paginating the public registry search API.

| Parameter | Type | Description | | --------- | -------- | ---------------------------------------------------------------------- | | scope | string | The npm scope (with or without leading @, e.g. @myorg or myorg). |

Returns: Promise<Array<string>> — sorted package names in the scope.

Throws if the registry response is malformed, the registry URL is invalid, or the request times out (15 s).

const packages = await discoverPackages("@myorg");

discoverFromCwd(cwd)

Detects packages from a directory's filesystem layout: pnpm-workspace.yamlpackage.json#workspaces → single ./package.json. Packages marked private: true are skipped.

| Parameter | Type | Description | | --------- | -------- | -------------------------------------------------------- | | cwd | string | Absolute path to the directory to inspect (often process.cwd()). |

Returns: Promise<DiscoveredWorkspace | null>

interface DiscoveredWorkspace {
  readonly source: "pnpm-workspace" | "npm-workspace" | "single-package";
  readonly packages: ReadonlyArray<string>;
}
const detected = await discoverFromCwd(process.cwd());
if (detected !== null) {
  console.log(`Found ${detected.packages.length} packages in ${detected.source}`);
}

checkPackageStatuses(packages) and findUnconfiguredPackages(packages)

Both call three npm commands per package — npm trust list <pkg> (existing trust record), npm view <pkg> name (publication), and npm view <pkg> dist.attestations.url (SLSA provenance attestation).

checkPackageStatuses returns the full status of every package — useful for orchestration code (e.g. a wizard) that needs to differentiate "unpublished" from "missing trust" from "trusted via the npm web UI":

interface PackageStatus {
  readonly pkg: string;
  readonly trustConfigured: boolean;
  readonly published: boolean;
  readonly hasProvenance: boolean;
}

hasProvenance cross-checks the registry for a SLSA provenance attestation on the latest version. It catches the common case where Trusted Publishing was set up via npm's web UI rather than the CLI — npm trust list returns empty in that scenario, but the package's publishes are still going through OIDC.

findUnconfiguredPackages is a convenience filter over the same data. A package is kept (i.e. flagged as needing work) only when it lacks both an explicit trust record and a provenance attestation, or isn't yet published. Concretely: kept if !((trustConfigured || hasProvenance) && published).

const statuses = checkPackageStatuses(["@myorg/foo", "@myorg/new"]);
const unconfigured = findUnconfiguredPackages(["@myorg/foo", "@myorg/new"]);

configureTrust(options)

Runs npm trust github <pkg> --repo <r> --file <w> --yes for every package and aggregates the results.

| Option | Type | Default | Description | | -------------- | -------------------------- | ------------------ | ------------------------------------------------------------------------ | | packages | ReadonlyArray<string> | (required) | Package names to configure. | | repo | string | (required) | GitHub owner/repo. | | workflow | string | (required) | GitHub Actions workflow file (*.yml / *.yaml). | | dryRun | boolean | false | Print what would happen without invoking npm. | | logger | Logger | console | { log, error } — supply a capturing logger to suppress stdout. |

2FA: npm trust uses web-based 2FA only — there is no OTP/TOTP flag to pass programmatically. The first call opens a browser auth flow; on the npm site, enable the "skip 2FA for the next 5 minutes" option to let bulk calls proceed without re-authenticating. configureTrust falls back to an interactive prompt automatically when run from a TTY; in non-TTY contexts (CI without an OIDC issuer) it returns auth_failed immediately.

Returns: TrustSummary

interface TrustSummary {
  readonly configured: number;
  readonly already: number;
  readonly failed: number;
  readonly failedPackages: ReadonlyArray<string>;
}
const summary = configureTrust({
  packages: ["@myorg/foo", "@myorg/bar"],
  repo: "owner/repo",
  workflow: "release.yml",
});

if (summary.failed > 0) {
  console.error("Failed:", summary.failedPackages);
  process.exit(1);
}

listTrust(options)

Runs npm trust list <pkg> for each package and prints the current trust configuration.

| Option | Type | Default | Description | | ---------- | ----------------------- | ---------- | ------------------------------------------ | | packages | ReadonlyArray<string> | (required) | Package names to query. | | logger | Logger | console | { log, error } — destination for output. |

Returns: void.

listTrust({ packages: await discoverPackages("@myorg") });

runCli(argv, logger?)

The same entry point used by the bin script. Useful for embedding the full CLI behaviour inside larger tools without spawning a child process. Returns the exit code instead of calling process.exit.

| Parameter | Type | Default | Description | | --------- | ---------------------------- | --------- | ----------------------------------------------------------------- | | argv | ReadonlyArray<string> | (required) | The argument list, equivalent to process.argv.slice(2). | | logger | Logger | console | { log, error } — supply a capturing logger to suppress output. |

Returns: Promise<number> — process exit code.

const code = await runCli(["--scope", "@myorg", "--list"]);
process.exit(code);

Health check (--doctor)

--doctor produces a single structured report covering everything an agent or human needs before running a trust setup: Node + npm versions, npm auth, the detected workspace, the GitHub remote, candidate workflow files, and per- package trust + provenance state. Plus a list of issues with stable codes.

npx npm-trust --doctor                # human-readable, color when stdout is a TTY
npx npm-trust --doctor --json         # machine-parseable JSON for agents and CI

Exit code is 0 when no fail-severity issues exist, 1 otherwise. Warnings don't fail the gate. Stable issue codes (for agents to branch on):

| Code | When | |---|---| | NODE_TOO_OLD (fail) | Node < 24 | | NPM_TOO_OLD / NPM_UNREACHABLE | npm < 11.5.1 or not on PATH | | AUTH_NOT_LOGGED_IN | npm whoami failed | | AUTH_REGISTRY_UNUSUAL | registry isn't https://registry.npmjs.org | | WORKSPACE_NOT_DETECTED / WORKSPACE_EMPTY | no signals or all packages private | | REPO_NO_REMOTE / REPO_REMOTE_NOT_GITHUB | no origin or non-GitHub origin | | WORKFLOWS_NONE / WORKFLOWS_AMBIGUOUS / WORKFLOW_NOT_FOUND | publish workflow problems | | PACKAGE_NOT_PUBLISHED | package not yet on the registry | | PACKAGE_TRUST_DISCREPANCY | npm trust list empty but registry has SLSA provenance for the package | | REGISTRY_UNREACHABLE | sentinel registry call failed | | DOCTOR_FLAG_IGNORED | --auto / --scope / --packages was supplied alongside --doctor and ignored |

The JSON shape is DoctorReport from the public types. schemaVersion is versioned; consumers should switch on it before reading other fields.

Use from a Claude Code agent

The CLI is callable directly from any agent that can spawn shell commands — npx npm-trust --auto --repo <owner/repo> --workflow release.yml, etc. For an interactive guided wizard with AskUserQuestion gates, install the gagle/solo-npm marketplace plugin:

/plugin marketplace add gagle/solo-npm
/plugin install solo-npm@gllamas-skills

Then invoke /solo-npm:trust for the OIDC trust wizard (which calls this CLI under the hood). Or /solo-npm:init for the full bootstrap umbrella that scaffolds release.yml + publishConfig + .nvmrc + consumer wrappers and then chains into trust.

Release workflow for solo AI devs

npm-trust is the OIDC-trust primitive in an opinionated release workflow built for solo developers (or small groups of LLM agents) shipping AI-generated code. The full lifecycle — bootstrap, release, verify, status, audit, deps — lives in the gagle/solo-npm marketplace plugin as seven Claude Code skills. solo-npm's /solo-npm:trust skill is what calls this CLI.

/plugin marketplace add gagle/solo-npm
/plugin install solo-npm@gllamas-skills

First publish (chicken-and-egg)

OIDC trusted publishing requires the package to already exist on the npm registry before trust can be configured (npm needs the package record to attach trust to). That creates a chicken-and-egg: you can't publish via OIDC + provenance until trust is set up, but trust can't be set up until the package exists.

The bootstrap path:

  1. Develop the MVP locally; bump package.json#version to the initial release (e.g., 0.1.0).
  2. Classic publish, locally, ONE time:
    npm login                           # web 2FA, browser flow
    npm publish --access public         # without --provenance
    The package now exists on npm.
  3. Configure OIDC trust via this CLI:
    pnpm exec npm-trust --auto --repo <owner/repo> --workflow release.yml
    Or invoke /solo-npm:trust in Claude Code for the full guided flow (auth gate, dry-run, configure, verify).
  4. Set package.json#publishConfig:
    "publishConfig": {
      "access": "public",
      "provenance": true
    }
  5. From here, every subsequent release uses the tag-triggered CI workflow — no more classic publishes. CI handles the publish via OIDC + provenance.

Step 2 is the only place a human is at the keyboard for the bootstrap beyond the single AskUserQuestion approval in /solo-npm:release. Everything else is agent-driven once trust is configured.

Environment variables

| Variable | Default | Description | | ------------------------- | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | NPM_TRUST_NPM | <dirname(process.execPath)>/npm | Override the path to the npm binary. Used in tests; rarely needed in production. | | NPM_TRUST_REGISTRY | https://registry.npmjs.org | Override the registry used for package discovery. Must be https://..., or http://localhost / http://127.0.0.1 for local mirrors and tests. |