LPM CLI

lpm publish

Publish a package to LPM.dev Registry, npm, GitHub Packages, or a custom registry.

lpm publish   # alias: lpm p

Packs the current directory and uploads it to a registry. By default, the target is LPM.dev Registry (where every package is private until you flip distribution to Pool or Marketplace). Publish elsewhere with --npm, --github, --gitlab, or --publish-registry.

lpm publish runs the same quality and security checks regardless of target — it scans for hardcoded secrets, computes a quality score, and refuses to publish if --min-score is not met.

Examples

lpm publish                                  # publish to LPM.dev Registry
lpm publish --dry-run                        # pack + check, don't upload
lpm publish --check                          # quality report only
lpm publish --npm                            # publish to registry.npmjs.org
lpm publish --github                         # publish to GitHub Packages
lpm publish --publish-registry https://r.example.com   # custom npm-compatible
lpm publish --provenance                     # require Sigstore provenance (CI)
lpm publish --npm --provenance               # npm-compatible publish provenance
lpm publish --npm --provenance-file bundle.sigstore
lpm publish --no-provenance                  # override provenance config
lpm publish --min-score 80                   # gate on quality score
lpm stage publish --tag next                 # stage a version on npm
lpm stage list @scope/pkg                    # list staged npm versions
lpm stage approve <stage-id> --otp 123456    # promote the staged version

What runs before upload

In order:

  1. Pack — assemble the tarball from files, main, bin, etc. Tarballs over 500 MB are rejected outright.
  2. Workspace protocol rewrite — in monorepos, workspace:* and catalog: specifiers in dependencies get replaced with their resolved versions before hashing. Registries can't resolve those protocols; the rewrite happens on the in-memory tarball so the on-disk package.json stays untouched.
  3. Secret scan — refuse to publish if known secret patterns are found in the pack contents (skip with --allow-secrets, not recommended).
  4. Quality score — compute readme/license/types/tests/maintenance signals. The publish path prints one compact score line and lists only failing checks. With --min-score N, abort if the score is below the threshold.
  5. Skills validation (LPM.dev Registry target only) — when the project ships .lpm/skills/, validate every skill file and run a security pattern check on the content; either failing aborts the publish.
  6. Confirm — interactive confirmation in a TTY. Skip with -y.
  7. Upload — push the tarball to each target registry with the appropriate auth.

Successful human output is a compact status stream:

✓ Secret scan passed
✓ Quality score: 91/100
› Uploading tarball to LPM.dev Registry
    target     @lpm.dev/owner.pkg@1.2.3
    visibility private
    dist-tag   latest
✓ Done · published @lpm.dev/owner.pkg@1.2.3 in 2.41s

If quality checks fail or are missing, only those rows are shown beneath the score. The full per-category breakdown lives in lpm quality.

--check is the local-validation surface — it runs the local pack + secret scan + quality scoring and stops. It never contacts a registry: no OIDC exchange, no skills-staleness lookup, no auth handshake. Use it as a fast pre-commit gate.

--dry-run runs everything --check does, plus an LPM.dev Registry preflight: OIDC exchange (when LPM.dev Registry is a target) and a skills-metadata lookup. It stops there. It does not prompt for confirmation, does not verify the resolved token can actually publish this package (no whoami / permission check), and does not contact --npm / --github / --gitlab targets. Use it to catch local issues plus LPM.dev Registry auth misconfiguration — it won't tell you whether the upload itself would land.

npm Trusted Publishing

lpm publish --npm and lpm stage publish automatically use npm Trusted Publishing when a supported CI OIDC token is available. LPM CLI exchanges the CI identity token with npm for a short-lived registry token, then uses that token only for the publish or stage-publish upload.

Supported inputs:

CI sourceConfigure
GitHub Actionspermissions: id-token: write; LPM CLI fetches the runtime token with audience npm:registry.npmjs.org
GitLab CI / CircleCI / other supported providersSet NPM_ID_TOKEN to an OIDC ID token minted with audience npm:registry.npmjs.org

Trusted Publishing is attempted only for npm's public registry (https://registry.npmjs.org; HTTP loopback is accepted for local test registries). Custom npm-compatible registries, GitHub Packages, GitLab Packages, and --publish-registry targets keep using token auth. If npm's OIDC exchange fails and a normal npm token is available, LPM CLI falls back to the token path; otherwise the OIDC error is surfaced.

OIDC is publish-only. lpm stage list, view, download, approve, and reject still require normal npm auth because npm limits Trusted Publishing authentication to publish operations.

npm staged publish

Full command reference: lpm stage.

lpm stage publish [--tag next] [--access public] [--provenance | --provenance-file <PATH> | --no-provenance] [-y]
lpm stage list [package]
lpm stage view <stage-id>
lpm stage download <stage-id>
lpm stage approve <stage-id> [--otp 123456]
lpm stage reject <stage-id> [--otp 123456]

lpm stage wraps npm staged publishing for the current project. It is npm-only in this release: there is no LPM.dev Registry, GitHub Packages, GitLab Packages, custom publish registry, workspace-recursive, or tarball/package-spec staging mode yet.

Stage publish reuses the normal npm publish preparation path: pack, workspace dependency rewrite, secret scan, quality gate, npm name/access/tag config, optional npm-name tarball rewrite, and optional --provenance / --provenance-file over the final tarball. The upload goes to npm's staging endpoint instead of the live publish endpoint, so the version is not installable until it is approved.

Auth for lpm stage publish against the default npm registry uses npm Trusted Publishing first when available, then the normal npm token sources:

Source order
npm Trusted Publishing (NPM_ID_TOKEN or GitHub Actions OIDC, audience npm:registry.npmjs.org)
NPM_TOKEN
token stored by lpm login --npm
locked .npmrc token

Publishing to staging does not prompt for OTP. npm defers proof-of-presence to lpm stage approve and lpm stage reject, where --otp or the usual npm web-auth retry flow is used. Those approval commands are token-authenticated; NPM_ID_TOKEN alone is not enough.

lpm stage publish validates npm's version/tag safety rules before the real upload: the package must already exist on npm, an already-published version is blocked, prerelease versions require an explicit tag, and implicit latest is blocked when npm already has a higher stable version. --dry-run stays local-only and does not contact npm, so those remote version checks run only for a real stage publish.

Use --npm-registry <URL> to target a compatible npm staging registry. The global --registry flag still means LPM.dev Registry and is rejected on lpm stage commands with a message to use --npm-registry.

If lpm.json > publish.npm.registry points at a non-default staging registry, LPM CLI requires an exact registry-scoped token from lpm login --login-registry <URL> --token <T>. Generic NPM_TOKEN and tokens stored by lpm login --npm are only used for https://registry.npmjs.org.

Every lpm stage subcommand supports --json. JSON output uses LPM CLI envelopes with success, target: "npm", registry, auth on stage publish ("oidc" or "token"), stageId when a single staged package is involved, and data for the registry response.

Provenance

lpm publish --provenance
lpm publish --npm --provenance
lpm publish --npm --provenance-file ./pkg-1.2.3.sigstore
lpm publish --no-provenance

--provenance generates a Sigstore-signed attestation over the final tarball for each publish target. For LPM.dev Registry, the bundle is stored in package metadata. For npm-compatible targets (--npm, --github, --gitlab, or --publish-registry), LPM CLI also attaches npm's expected {name}-{version}.sigstore bundle in the publish payload.

Generated npm-compatible attestations use npm's current libnpmpublish SLSA statement shapes for GitHub Actions and GitLab CI, so the bundle matches the provenance contract npm-compatible registries and registry UIs expect.

Generated provenance requires an audience-sigstore OIDC token from a supported CI environment:

  • GitHub Actions — enable permissions: id-token: write on the job; the runtime mints the JWT.
  • GitLab CI — mint SIGSTORE_ID_TOKEN via the id_tokens block with aud: sigstore (the legacy LPM_GITLAB_OIDC_TOKEN env var is also accepted).

Other platforms aren't supported — Sigstore needs the OIDC issuer to sign. The flag fails loud (non-zero exit) if no usable token is found or if Sigstore signing/Rekor recording fails; it never silently falls back to publishing without provenance.

Generated npm-compatible provenance and provenance-file attachments require effective npm access to be public. LPM CLI's npm access default is public for scoped and unscoped packages. If you set publish.npm.access, publish.github.access, publish.gitlab.access, or --access restricted on stage publish, LPM CLI fails before npm auth, Sigstore signing, file validation, or upload.

--provenance-file <PATH> attaches a pre-generated Sigstore bundle to npm-compatible targets. The file is parsed, verified, and checked against the final tarball subject and SHA-512 digest before upload. It is not valid for LPM.dev Registry targets, so lpm publish --lpm --npm --provenance-file ... fails before validation or upload. --provenance, --provenance-file, and --no-provenance are mutually exclusive.

Provenance can also be enabled through npm-compatible config, in this order:

  1. CLI: --no-provenance, --provenance, --provenance-file <PATH>
  2. package.json > publishConfig.provenance
  3. Environment: NPM_CONFIG_PROVENANCE_FILE, NPM_CONFIG_PROVENANCE
  4. Project .npmrc: provenance=true or provenance-file=...
  5. Home .npmrc

provenance and provenance-file are mutually exclusive in env and .npmrc config. Use --no-provenance when a repo-level npm config enables provenance but a particular publish or staged publish should skip it.

Consumers can later verify provenance via the audit pipeline or registry UI.

Targets

lpm publish --lpm --npm                 # publish to both in one run
lpm publish --github --gitlab           # cross-publish to both git-host registries

Multiple target flags compose — lpm publish runs through them in order and reports per-target success / failure. Up to 5 target registries per invocation.

FlagRegistryRequirements
(default) / --lpmLPM.dev RegistryPackage name must be @lpm.dev/owner.pkg. Override with publish.lpm.name in lpm.json
--npmregistry.npmjs.org (or custom via publish.npm.registry)Override name with publish.npm.name; non-default registries require exact registry-scoped auth
--githubGitHub PackagesPackage name must be scoped (@owner/pkg). Falls back to publish.github.namepublish.npm.namepackage.json#name — any of them being a scoped name is enough
--gitlabGitLab Packagespublish.gitlab.projectId is required. Optional publish.gitlab.registry overrides the default https://gitlab.com instance
--publish-registry <URL>Any npm-compatible registryURL must be https://...

When no target flag is set on the CLI, the active set comes from lpm.json > publish.registries (default: ["lpm"]).

You must have auth for the chosen target — see Authentication for lpm login --npm, --github, --gitlab, or lpm login --login-registry <URL> for custom registries.

Custom publish registry URLs are HTTPS-only whether they come from --publish-registry or lpm.json > publish.registries. LPM CLI rejects http:// before dry-run planning or upload.

Repo-configured custom npm registries are routing data only. They do not redirect NPM_TOKEN, tokens stored by lpm login --npm, or locked default-npm .npmrc auth. Store a token for the exact registry URL with lpm login --login-registry <URL> --token <T>.

Authentication and OTP

Token resolution for npm-compatible targets:

TargetResolution order
npm (https://registry.npmjs.org)npm Trusted Publishing for publish --npm / stage publish -> NPM_TOKEN -> token stored by lpm login --npm -> locked .npmrc token
GitHub PackagesGITHUB_TOKEN → valid gh auth for github.com → LPM CLI-stored fallback token
GitLab.com PackagesGITLAB_TOKEN / CI_JOB_TOKEN → valid glab auth → LPM CLI-stored fallback token
Self-managed GitLabGITLAB_TOKEN / CI_JOB_TOKEN → LPM CLI-stored fallback token
Custom registriesExact LPM CLI-stored custom-registry token from lpm login --login-registry <URL> --token <T>

LPM CLI advertises npm web auth on npm-compatible publish requests (npm-auth-type: web, npm-command: publish). If npm returns a browser-based OTP challenge (authUrl + doneUrl), LPM CLI opens the browser flow, polls for completion, and retries with the returned npm-otp. Classic www-authenticate: OTP prompts still work in an interactive terminal; set lpm.json > publish.npm.otpRequired to prompt before the first publish attempt. Non-interactive publish should use an automation token.

Flags

FlagEffect
--dry-runPack and check, don't upload
--checkRun quality report only
-y, --yesSkip interactive confirmation
--provenanceRequire Sigstore provenance (CI with OIDC only)
--no-provenanceDisable provenance even when npm config enables it
--provenance-file <PATH>Attach a pre-generated Sigstore bundle to npm-compatible targets
--min-score <N>Minimum quality score required (0–100)
--allow-secretsSkip pre-publish secret scanning (not recommended)
--npm / --lpm / --github / --gitlabTarget a specific registry
--publish-registry <URL>Custom npm-compatible registry (https:// only)
stage --npm-registry <URL>npm staging registry for lpm stage subcommands
stage publish --provenanceGenerate npm-compatible Sigstore provenance for a staged publish
stage publish --no-provenanceDisable staged-publish provenance even when npm config enables it
stage publish --provenance-file <PATH>Attach a pre-generated Sigstore bundle to a staged publish
stage --otp <CODE>One-time password for lpm stage approve / reject

Plus the global flags.

See also

  • Authentication — login, tokens, CI setup
  • lpm stage — npm staged publish command reference
  • Save policy — how versions get saved on the consumer side
  • lpm quality — preview the quality report
  • Pool — flipping a published package to pool distribution