lpm trust
Manage project lifecycle trust and release-age exclusions.
lpm trust diff [--assert-none] [--json]
lpm trust prune [--dry-run] [--yes] [--json]
lpm trust lifecycle-scope add <SCOPE> [--json]
lpm trust lifecycle-scope remove <SCOPE> [--json]
lpm trust lifecycle-scope list [--json]
lpm trust release-age-exclude add <SELECTOR> [--json]
lpm trust release-age-exclude remove <SELECTOR> [--json]
lpm trust release-age-exclude list [--json]lpm trust manages security decisions that belong to the current project. These decisions stay in package.json so that the project can share them.
For lifecycle scripts, lpm trust manages project scope trust. It also inspects and cleans trustedDependencies.
Use lpm approve-scripts for strict package approvals. These approvals include the version, integrity, script hash, and requested capabilities.
For the release-age gate, lpm trust manages minimumReleaseAgeExclude. These selectors exempt selected packages from the project cooldown.
Project trust only. Global lifecycle trust uses ~/.lpm/global/trusted-dependencies.json. Manage it with lpm approve-scripts --global.
User release-age exclusions use ~/.lpm/config.toml. Manage them with lpm config release-age-exclude.
Storage contract
LPM stores each exception or approval in one policy layer. A command does not copy a policy entry into another file.
| Decision | Command | Persistent location |
|---|---|---|
| Project release-age exclusion | lpm trust release-age-exclude | package.json > lpm > minimumReleaseAgeExclude |
| Project lifecycle scope | lpm trust lifecycle-scope | package.json > lpm > scripts > trustedScopes |
| Project package approval | lpm approve-scripts | package.json > lpm > trustedDependencies |
| User release-age exclusion | lpm config release-age-exclude | ~/.lpm/config.toml > minimum-release-age-exclude |
| Global-install package approval | lpm approve-scripts --global | ~/.lpm/global/trusted-dependencies.json |
| One-run release-age exclusion | lpm install --min-release-age-exclude | None |
lpm.lock never stores release-age exclusions, lifecycle scopes, or lifecycle approvals. lpm trust prune reads the lockfile only to find stale project approvals.
Each command writes one declared policy layer. It does not cascade through package.json, user configuration, global trust, or the lockfile.
Project commands use the package.json in the current directory. In a workspace member, the member manifest receives the policy entry.
The workspace root and sibling manifests stay unchanged. User and global commands continue to use their fixed locations under ~/.lpm.
List commands read only their declared layer. They do not show the effective merged release-age list.
During an install, release-age exclusions merge in this order: CLI entries, project entries, then user entries. Duplicate selectors collapse.
An exact-version selector matches only that version. A scope wildcard matches every package in that scope.
A lifecycle scope addition also requires local signed authorization under ~/.lpm/security. This authorization approves the write and is not another trust list.
Mutating policy commands use atomic file replacement. A duplicate addition does not rewrite a normalized destination file.
Subcommands
| Subcommand | What it does |
|---|---|
diff | Show how the current trustedDependencies differs from the last install's snapshot |
prune | Remove entries whose package is no longer in the resolved tree |
lifecycle-scope | Add, remove, or list project lifecycle scope trust |
release-age-exclude | Add, remove, or list project release-age exclusions |
Flag Reference
| Command | Flag | Effect |
|---|---|---|
lpm trust diff | --json | Emit the diff envelope instead of human output. Same as global --json for this command. |
lpm trust diff | --assert-none | Exit non-zero if any added, removed, or changed entries are present. |
lpm trust prune | -y, --yes | Skip the confirmation prompt. Required on non-TTY / CI when pruning would write. |
lpm trust prune | --dry-run | Preview stale entries without writing package.json. |
lpm trust prune | --json | Emit the prune envelope instead of human output. Same as global --json for this command. |
lpm trust lifecycle-scope | --json | Emit the lifecycle scope envelope instead of human output. |
lpm trust release-age-exclude | --json | Emit the release-age exclusion envelope instead of human output. |
lpm trust lifecycle-scope
lpm trust lifecycle-scope add '@company/*'
lpm trust lifecycle-scope remove '@company/*'
lpm trust lifecycle-scope listA lifecycle scope trusts every package in one npm scope. The trust applies to all package versions and script contents.
Use this command only when your organization controls the complete scope. Use lpm approve-scripts for one package.
The command accepts lowercase npm scope wildcards such as @company/*. It rejects package names, package versions, uppercase scopes, and nested patterns.
add writes package.json > lpm > scripts > trustedScopes. It preserves all other fields in package.json.
An addition widens the project security policy. In an interactive terminal, LPM CLI requests native user approval before it writes the scope.
For an agent or JSON command, create a signed project unlock before you add the scope:
lpm security unlock trust-scope-widen --project . --ttl 10m
lpm trust lifecycle-scope add '@company/*' --jsonThe unlock is local to the project and user. The project scope list remains in package.json for the team.
The signed authorization remains under ~/.lpm/security. LPM CLI does not write lifecycle scope trust to lpm.lock.
remove narrows the security policy and does not need an unlock. It removes the signed authorization for that scope.
It also revokes trust-scope-widen from each active temporary unlock for the project. Other scopes in the same unlock remain active.
As a result, a later add requires new authorization. Removal matches the complete scope selector.
list shows the configured project scopes. It does not show strict package approvals or global lifecycle trust.
The JSON envelope contains success, schema_version, command, scope, action, changed, normalized, count, and scopes. The add and remove actions also contain selector.
changed reports whether the requested scope changed. normalized reports whether the command repaired existing stored entries. count is the number of scopes.
lpm trust release-age-exclude
lpm trust release-age-exclude add react
lpm trust release-age-exclude add '@company/*'
lpm trust release-age-exclude add react@19.1.0
lpm trust release-age-exclude remove react@19.1.0
lpm trust release-age-exclude listThe command writes package.json > lpm > minimumReleaseAgeExclude. It preserves the other fields in package.json.
The command accepts these selector types:
| Selector | Effect |
|---|---|
react | Exclude all versions of react. |
@company/* | Exclude all packages in the @company scope. |
react@19.1.0 | Exclude only version 19.1.0 of react. |
Version selectors must contain one exact semantic version. Ranges such as react@^19 are invalid.
add is idempotent. If the selector exists in a normalized list, the command does not rewrite package.json.
If stored entries need normalization, the command repairs the list. It returns changed: false and normalized: true when the selector stays unchanged.
remove matches the complete selector. For example, removal of react@19.1.0 does not remove the react selector.
list shows only the project list. It does not include the user list or one-run CLI exclusions.
The JSON envelope contains success, schema_version, command, scope, action, changed, normalized, count, and exclusions. The add and remove actions also contain selector.
changed reports whether the requested selector changed. normalized reports whether the command repaired existing stored entries. count is the number of exclusions.
User release-age exclusions
Use lpm config to apply an exclusion to all installs for the current user:
lpm config release-age-exclude add '@company/*'
lpm config release-age-exclude remove '@company/*'
lpm config release-age-exclude listThe user command writes ~/.lpm/config.toml > minimum-release-age-exclude. Project and user lists merge during an install.
lpm trust diff
lpm trust diff
lpm trust diff --assert-none
lpm trust diff --json
lpm trust diff --assert-none --jsonRead-only. Compares the current package.json > lpm > trustedDependencies against the snapshot LPM CLI took on the last lpm install. Surfaces three classes of change:
- Additions — entries that weren't there last install. Potential silent PR poisoning vector ("someone added
evil-packageto the trust list — was that reviewed?") - Removals — entries that were there but are now gone. Usually intentional cleanup, but worth a glance.
- Same-key binding changes — same
name@versionkey, but a differentintegrityorscriptHash. Indicates the package contents changed without a version bump (re-publish, tampering).
The snapshot lives at <project>/.lpm/trust-snapshot.json, written by every successful lpm install. If the project has never been installed with LPM CLI, diff reports "no prior snapshot" and exits cleanly — there's no baseline to compare against yet.
trust diff is informational by default — it prints whatever it found. For a built-in CI gate, use --assert-none:
lpm trust diff --assert-noneThat exits non-zero when any added, removed, or changed entry is present.
If you still want machine-readable output for bots or logs, --json works with the same gate:
lpm trust diff --json --assert-noneThe JSON envelope: success, schema_version, command, assertion_failed, diff_count, snapshot_captured_at, current_binding_count, added[], removed[], changed[]. Each entry carries key (e.g., esbuild@0.25.1), previous, and current (the integrity / scriptHash before and after). When --assert-none fails in JSON mode, LPM CLI emits this same single diff envelope with success: false, error_code: "trust_diff_assert_none", and exits non-zero.
| Flag | Effect |
|---|---|
--json | Machine-readable output for CI gating via jq |
--assert-none | Exit non-zero if any diff entries are present |
lpm trust prune
lpm trust prune # interactive — prompts before writing
lpm trust prune --dry-run # preview, don't write
lpm trust prune -y # skip the prompt (required on non-TTY / CI)
lpm trust prune --jsonRemoves trustedDependencies entries whose package isn't in the resolved tree anymore. "No longer in the tree" means: lpm.lock has zero entries with this name (regardless of version). Per-version drift on a name that's still installed is not considered stale — that's drift, handled by the install-time gate, not by prune.
Entries become stale when:
- A dep was removed from
package.jsonbut its trust entry stayed - A dep was renamed (the old name's pin is now orphaned)
- A dep was moved (e.g., from
dependenciestooptionalDependenciesand never reinstalled)
lpm trust prune reads lpm.lock to determine what's installed. If the lockfile is missing, the command exits with no lpm.lock found — run \lpm install` before pruning trust entries` — refusing to prune from an empty installed-set (which would mark everything stale).
The interactive prompt confirms the removal list before writing. In CI / non-TTY contexts, -y is required — without it, prune errors with lpm trust prune needs a TTY for confirmation. Pass \--yes` to ...`.
--dry-run runs the analysis normally but doesn't touch package.json.
The JSON envelope: success, schema_version, command, dry_run, mutated (the actual final state — false on --dry-run or no-op), stale_count, stale[] (the keys removed).
| Flag | Effect |
|---|---|
-y, --yes | Skip the confirmation prompt (required on non-TTY) |
--dry-run | Preview without writing |
--json | Machine-readable output |
CI usage
- run: lpm install --offline
- run: lpm trust diff --assert-none
- run: lpm trust prune --dry-run --json # informational — would prune anything?trust diff --assert-none is the built-in drift gate: fail the build if trustedDependencies changed since the last reviewed install. Add --json if you also want structured output in CI logs.
prune --dry-run is for hygiene reports only — it always exits zero. Gate it the same way if you want to fail on stale entries:
lpm trust prune --dry-run --json | jq -e '.stale_count == 0'See also
lpm approve-scripts— add entries to the trust listlpm rebuild— runs dependency scripts for trusted packagespackage.json"lpm.scripts" — project lifecycle settingspackage.json"lpm.trustedDependencies" — the file formatpackage.json"lpm.minimumReleaseAgeExclude" — project release-age exclusionsconfig.toml— user release-age exclusions