# ~/.lpm/config.toml (/docs/reference/config-toml)



`~/.lpm/config.toml` is the per-user CLI configuration file. It sets defaults that apply to every project on the machine, sitting **below** project-level config (`./lpm.toml`, `package.json > lpm`) and **above** built-in defaults in the precedence chain — except for `linker`, where the user-level value beats `package.json > lpm > linker`. For security-sensitive keys, this file is still a proposal layer: the effective machine floor can also be constrained by the signed approved-posture store and a managed policy. See [Precedence](#precedence) and [Security-sensitive keys are proposals](#security-sensitive-keys-are-proposals).

LPM CLI reads this file with a 16 MiB limit enforced before TOML parsing. A missing file keeps built-in defaults; an oversized file fails with its path and byte limit instead of being ignored or weakening the effective policy. See [local configuration size limits](/docs/project-setup#local-configuration-size-limits) for the complete scope and exclusions.

You can edit the file directly, or use [`lpm config`](/docs/infra/config) to manage it from the CLI:

```bash
lpm config set save-prefix '~'
lpm config get save-prefix
lpm config list
lpm config delete save-prefix
```

## Known keys [#known-keys]

```toml title="~/.lpm/config.toml"
# Save policy
save-prefix = "^"
save-exact  = false

# Lifecycle scripts
script-policy  = "deny"
triage-advisor = "none"

# Recently-published-package cooldown
minimum-release-age-secs = 86400
release-age-policy = "direct"
minimum-release-age-exclude = ["react", "@scope/pkg"]

# Workspace-root and dependency engine constraints
engine-strict = true

# Peer-dependency diagnostics
strict-peer-dependencies = false
auto-install-peers = true

# Package-published skills from @lpm.dev/* packages
auto-install-lpm-skills = true

# npm registry package signatures
signatures = false

# npm publisher/provenance trust downgrade policy
trust-policy = "off"

# Suspicious direct dependency name analysis
# Omit for the default enabled mode; set "on" to ignore the diagnostic env toggle.
typosquat-guard = "on"

# Reused v2 store object validation
integrity = "source"

# Workspace task fan-out for run/test/bench
workspace-concurrency = 4

# Run `lpm audit` after every successful install and print a one-line advisory
audit-after-install = false

# node_modules layout (overrides package.json > lpm > linker)
linker = "isolated"

# Lifecycle-script secret-file exemptions (paths the sandbox normally
# blocks but you want readable across every project on this machine)
script-read-allow = [".env", ".npmrc"]

# Canonical roots allowed to cover absolute sandboxWriteDirs entries
max-sandbox-write-roots = ["/Users/alice/shared-build-output"]

# Lifecycle-script sandbox
[sandbox]
mode = "default"
allow-degraded = false

# firewall.lpm.dev verdict checks for npm packages
[firewall]
mode = "enforce"

[firewall.npm.policies]
trusted_public_malicious_advisories = "block"
lpm_ai_confirmed_malware = "block"
lpm_ai_agent_control_surface = "warn"
critical_vulnerability = "warn"
static_only_suspicious = "warn"

# Local install policy extensions
[policy.extensions.local-feed]
command = ["/usr/local/bin/lpm-policy-feed", "--deny-list", "/etc/lpm/deny.json"]
mode = "enforce"
on-error = "block"
timeout-ms = 5000
events = ["package.candidate"]

# Provenance verification posture
[sigstore]
verify = "deny"
scope = "approved"
availability = "best-effort"

# Tunnel relay (override per-process with LPM_TUNNEL_RELAY)
[tunnel]
relay-url = "wss://relay.lpm.fyi/connect"
```

| Key                                                         | Type                                                  | Default                                                                      | Notes                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| ----------------------------------------------------------- | ----------------------------------------------------- | ---------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `save-prefix`                                               | `"^"` \| `"~"` \| `""`                                | `"^"`                                                                        | Prefix used when `lpm install <pkg>` writes to `package.json`. `*` is rejected.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `save-exact`                                                | bool                                                  | `false`                                                                      | Force exact saves regardless of `save-prefix`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `script-policy`                                             | `"deny"` \| `"allow"` \| `"triage"`                   | `"deny"`                                                                     | Lifecycle-script gate for `lpm install`, `lpm install -g`, and `lpm rebuild`. Machine-wide policy: applies to project and global installs alike.                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `triage-advisor`                                            | `"none"` \| `"claude-cli"` \| `"codex"` \| `"ollama"` | `"none"`                                                                     | Optional LLM advisor for the [triage gate](/docs/packages/security-audit#optional-llm-advisor). Only active when `script-policy = "triage"`. Approvals are ephemeral — never written to disk.                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `minimum-release-age-secs`                                  | u64                                                   | `86400` (24h)                                                                | Cooldown in seconds before a freshly published version becomes installable. On project installs, applies to direct/root dependencies; on direct package-selection commands (`lpm install -g`, `lpm dlx`, `lpm upgrade`, `lpm outdated`), applies to selected or reported package versions.                                                                                                                                                                                                                                                                                                                           |
| `release-age-policy`                                        | `"direct"` \| `"strict"`                              | `"direct"`                                                                   | Cooldown scope. `"direct"` checks direct/root dependencies only; `"strict"` also checks transitive dependencies and lockfile replays using persisted publish timestamps. Set with [`lpm config release-age-policy`](/docs/infra/config#setup-wizards).                                                                                                                                                                                                                                                                                                                                                               |
| `minimum-release-age-exclude`                               | string array                                          | `[]`                                                                         | Exact canonical package names exempted from the cooldown. Merged with CLI and package.json excludes. Globs, version selectors, and protocol specifiers are rejected.                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `sandbox.mode`                                              | `"default"` \| `"strict"` \| `"none"`                 | `"default"`                                                                  | Default lifecycle-script sandbox posture for this machine. Set with [`lpm config sandbox`](/docs/infra/config#setup-wizards).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `sandbox.allow-degraded`                                    | bool                                                  | `false`                                                                      | Allow degraded sandbox fallback for this machine when full containment is unavailable.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `sigstore.verify`                                           | `"deny"` \| `"warn"` \| `"off"`                       | `"deny"`                                                                     | Provenance verification posture used by installs and related flows. Set with [`lpm config sigstore`](/docs/infra/config#setup-wizards).                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `sigstore.scope`                                            | `"approved"` \| `"all"`                               | `"approved"`                                                                 | Which resolved packages enter the provenance verifier. `"approved"` verifies packages with a previously approved provenance identity; `"all"` checks every resolved package and records verified evidence in the lockfile. Set with `lpm config sigstore --set scope=all`.                                                                                                                                                                                                                                                                                                                                           |
| `sigstore.availability`                                     | `"best-effort"` \| `"strict"`                         | `"best-effort"`                                                              | What happens when an attestation is absent or temporarily unavailable. `"best-effort"` preserves the absence/unknown signal without blocking; `"strict"` fails the install. A supplied but invalid bundle is still governed by `sigstore.verify`. Set with `lpm config sigstore --set availability=strict`.                                                                                                                                                                                                                                                                                                          |
| `signatures`                                                | bool                                                  | `false`                                                                      | Verify npm registry package signatures during install and fail closed when a registry package cannot be verified. Set with [`lpm config signatures`](/docs/infra/config#setup-wizards). Per-process override: `LPM_VERIFY_REGISTRY_SIGNATURES`.                                                                                                                                                                                                                                                                                                                                                                      |
| `trust-policy`                                              | `"off"` \| `"no-downgrade"`                           | `"off"`                                                                      | When set to `"no-downgrade"`, resolution refuses weaker npm trusted-publisher/staged-publish evidence than an earlier release, and an install that previously locked verified provenance for a package refuses a later version without verified provenance. The artifact-history floor takes precedence over `sigstore.verify = "warn"` / `"off"`, verification skip flags, and best-effort availability. Registry attestation pointers alone are not evidence. Set with [`lpm config trust-policy`](/docs/infra/config#setup-wizards).                                                                              |
| `typosquat-guard`                                           | `"default"` \| `"on"` \| `"off"`                      | unset / `"default"` (enabled)                                                | Suspicious direct dependency name analysis before a new name enters a project. `lpm config typosquat --set default` removes this key; `on` forces the guard on even when the diagnostic env toggle is set; `off` is a guarded machine-wide weakening. Prefer project [`policy.typosquat.allow`](/docs/reference/lpm-toml#typosquat-policy) entries for intentional names instead of disabling the guard globally.                                                                                                                                                                                                    |
| `firewall.mode`                                             | `"off"` \| `"monitor"` \| `"enforce"`                 | `"off"`                                                                      | LPM Firewall verdict checks for selected public npm package versions. The hosted verdict service is an LPM.dev Registry Pro/Org feature, so active modes send LPM.dev Registry auth; CI can use `LPM_TOKEN` or registry-audience OIDC. `monitor` warns and continues; `enforce` blocks packages whose effective firewall action is `block` or denied by entitlement. npm metadata and tarballs still use the direct npm route. `report` is accepted as a legacy alias for `monitor`. Set with [`lpm config firewall`](/docs/infra/config#setup-wizards). Per-process `LPM_NPM_FIREWALL` can only tighten this value. |
| `firewall.npm.policies.trusted_public_malicious_advisories` | `"allow"` \| `"warn"` \| `"block"`                    | `"block"`                                                                    | User action for public malicious-package advisories from OSV/OpenSSF/GHSA.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `firewall.npm.policies.lpm_ai_confirmed_malware`            | `"allow"` \| `"warn"` \| `"block"`                    | `"block"`                                                                    | User action for LPM Firewall AI-confirmed malware behavior such as exfiltration, remote payload execution, persistence/destructive behavior, dependency confusion, and classic malware.                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `firewall.npm.policies.lpm_ai_agent_control_surface`        | `"allow"` \| `"warn"` \| `"block"`                    | `"warn"`                                                                     | User action for LPM Firewall AI-agent control-surface policy findings. This is a dangerous-capability policy, not necessarily a malware-intent finding.                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `firewall.npm.policies.critical_vulnerability`              | `"allow"` \| `"warn"` \| `"block"`                    | `"warn"`                                                                     | User action for critical vulnerability advisories. The wizard offers block, warn, or allow for this warn-default group.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `firewall.npm.policies.static_only_suspicious`              | `"allow"` \| `"warn"` \| `"block"`                    | `"warn"`                                                                     | User action for static-only suspicious signals that LPM Firewall has not confirmed with AI or trusted public intel. The wizard offers warn or allow for this warn-default group; hand-edited `"block"` values are preserved when you review the profile.                                                                                                                                                                                                                                                                                                                                                             |
| `policy.extensions.<name>.command`                          | string array                                          | required                                                                     | Direct-spawn command for a local install policy extension. The first entry must be an absolute path or a program name found on an absolute `PATH` directory; relative executable paths are rejected, and relative or empty `PATH` entries are ignored. Later entries are argv. LPM CLI never runs this through a shell.                                                                                                                                                                                                                                                                                              |
| `policy.extensions.<name>.mode`                             | `"report"` \| `"enforce"`                             | `"report"`                                                                   | `report` prints policy decisions and continues; `enforce` fails the install when the extension returns a `block` decision.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `policy.extensions.<name>.on-error`                         | `"warn"` \| `"block"`                                 | `warn` in report, `block` in enforce                                         | What to do when the extension cannot be spawned, times out, exits non-zero, emits oversized output, or returns invalid JSON.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `policy.extensions.<name>.timeout-ms`                       | positive integer                                      | `5000`                                                                       | Per-extension timeout for the full exchange: stdin write, process exit, stdout/stderr drain, and response validation. Maximum accepted value is `120000`.                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `policy.extensions.<name>.events`                           | string array                                          | `["package.candidate"]`                                                      | Events this extension handles. `package.candidate` is the only supported event today.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `integrity`                                                 | `"source"` \| `"tree"`                                | `"source"`                                                                   | Reused v2 store object validation. `"source"` verifies source identity without rehashing expanded files; `"tree"` rehashes expanded files before reuse to detect local store tampering/corruption. Set with [`lpm config integrity`](/docs/infra/config#setup-wizards). Per-process override: `LPM_V2_OBJECT_INTEGRITY`.                                                                                                                                                                                                                                                                                             |
| `engine-strict`                                             | bool                                                  | `true`                                                                       | Enforce workspace-root `engines.lpm` / `engines.node` and dependency `engines.node` constraints. Set to `false` for warning-only behavior; incompatible dependencies remain installed.                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `strict-peer-dependencies`                                  | bool                                                  | `false`                                                                      | Turn missing required peers, peer version mismatches, and peer-conflict warnings into install failures. Per-invocation overrides: `--strict-peer-dependencies` / `--no-strict-peer-dependencies`. Project override: `package.json > lpm.strictPeerDependencies`.                                                                                                                                                                                                                                                                                                                                                     |
| `auto-install-peers`                                        | bool                                                  | `true`                                                                       | Auto-install missing non-optional `peerDependencies` at the project root after the main resolve pass. Project override: `package.json > lpm.autoInstallPeers`. Set to `false` for npm-classic / pnpm-classic peer-warning-only behavior.                                                                                                                                                                                                                                                                                                                                                                             |
| `auto-install-lpm-skills`                                   | bool                                                  | `true`                                                                       | Reconcile package-published skills from installed `@lpm.dev/*` packages. Set with [`lpm config lpm-skills`](/docs/infra/config#setup-wizards). Per-invocation overrides: `--skills` / `--no-skills` on `lpm install`, `lpm add`, and `lpm ci`. Disabling automatic installs does not delete existing `.lpm/skills/` content or affect explicit `lpm skills add`.                                                                                                                                                                                                                                                     |
| `workspace-concurrency`                                     | positive integer                                      | available parallelism                                                        | User default for concurrent workspace members in `lpm run`, `lpm test`, and `lpm bench` workspace mode. Per-invocation override: `--workspace-concurrency <N>`. Project override: `lpm.toml > [workspace].concurrency`.                                                                                                                                                                                                                                                                                                                                                                                              |
| `audit-after-install`                                       | bool                                                  | `false`                                                                      | Run [`lpm audit`](/docs/packages/audit) silently after every successful `lpm install` and emit a one-line advisory (`! Audited N packages, V vulnerabilities, S suspicious in Tms — run \`lpm audit\``). Informational only — findings never fail the install. Per-invocation overrides: `--audit-after-install`/`--no-audit-after-install`. Per-process env: `LPM\_AUDIT\_AFTER\_INSTALL\`. See [Audit after install](/docs/packages/install#audit-after-install).                                                                                                                                                  |
| `linker`                                                    | `"isolated"` \| `"hoisted"`                           | `"hoisted"` (workspaces and default peer-conflict installs use `"isolated"`) | `node_modules` layout for installs run by this user. &#x2A;*Overrides `package.json > lpm > linker`** so a user can pick their preferred layout regardless of what each project declares. Per-process override: `LPM_LINKER`. Per-invocation override: `lpm install --linker <isolated\|hoisted>`. Unknown values fail loudly at install time — there is no silent fallback.                                                                                                                                                                                                                                         |
| `script-read-allow`                                         | array of strings                                      | `[]`                                                                         | Explicitly authorize lifecycle-script reads of project-relative paths that match the [secret-file deny list](/docs/packages/rebuild#project-secret-files). Each entry is joined to the current `project_dir` at install time; traversal escapes (`..`) and absolute paths outside the project are rejected. Unioned with the per-project [`package.json > lpm > scripts > sandboxReadAllow`](/docs/reference/package-json-lpm#scripts) — duplicates are deduplicated. Allowlisted secrets remain readable; if every matching secret is allowlisted, Linux skips the namespace overlay.                               |
| `max-sandbox-write-roots`                                   | array of absolute paths                               | `[]`                                                                         | User-authorized roots that may cover absolute [`package.json > lpm > scripts > sandboxWriteDirs`](/docs/reference/package-json-lpm#the-lpmscripts-block) entries outside the project. LPM CLI resolves the root and candidate before granting access. A candidate cannot traverse a symlink, Windows junction, or reparse point below the authorized root, and dangerous system or credential roots remain denied even when listed here. Relative roots are ignored.                                                                                                                                                 |
| `tunnel.relay-url`                                          | string                                                | `"wss://relay.lpm.fyi/connect"`                                              | WebSocket URL for the tunnel relay used by LPM CLI. Per-process override: `LPM_TUNNEL_RELAY`. Each host gets its own TOFU pin under `~/.lpm/relay-pins/<host>`.                                                                                                                                                                                                                                                                                                                                                                                                                                                      |

Unknown keys are accepted silently — forward-compatible by design.

## String coercion [#string-coercion]

`lpm config set` writes ordinary generic values as TOML strings. Known typed keys can preserve native TOML types; today `lpm config set signatures true` and `lpm config set auto-install-lpm-skills false` write booleans. Readers accept both native types and the string form for typed keys:

```toml
minimum-release-age-secs = 86400      # native integer (hand-edit)
minimum-release-age-secs = "86400"    # string (lpm config set wrote this)
release-age-policy = "strict"
minimum-release-age-exclude = ["react", "@scope/pkg"]
workspace-concurrency = 4             # native integer (hand-edit)
workspace-concurrency = "4"           # string (lpm config set wrote this)
signatures = true                     # native bool
signatures = "true"                   # string form also accepted
auto-install-lpm-skills = false        # native bool
auto-install-lpm-skills = "false"      # string form also accepted
typosquat-guard = "on"                # canonical string
integrity = "tree"                    # canonical string

[firewall]
mode = "monitor"                      # canonical string
```

Both forms parse to the same value. For `typosquat-guard`, the `default` value is accepted when hand-edited, but the CLI removes the key instead of persisting `typosquat-guard = "default"`. For `firewall.mode`, boolean-like aliases are accepted when hand-edited or provided through `LPM_NPM_FIREWALL`, and `report` is accepted as a legacy alias for `monitor`; `lpm config firewall` persists the canonical `off`, `monitor`, or `enforce` value. For `integrity`, config accepts only `source` or `tree`; the wizard persists those canonical strings. Invalid values (non-numeric strings, negative numbers, zero for positive-only keys, etc.) error at load time with the file path baked in.

## npm firewall policy profile [#npm-firewall-policy-profile]

The firewall policy table is only read when LPM Firewall is active. LPM CLI sends the profile to the LPM Firewall verdict API, which returns the user-effective action for each decision.

```toml
[firewall]
mode = "enforce"

[firewall.npm.policies]
trusted_public_malicious_advisories = "block"
lpm_ai_confirmed_malware = "block"
lpm_ai_agent_control_surface = "warn"
critical_vulnerability = "warn"
static_only_suspicious = "warn"
```

Every policy group accepts `allow`, `warn`, or `block` in hand-edited config. The interactive wizard shows the profile on one review screen when you choose `enforce`: `critical_vulnerability` offers block, warn, or allow; `static_only_suspicious` normally offers warn or allow, while preserving a hand-edited `block` value if one already exists. See the [Firewall for npm guide](/docs/guides/firewall#policy-groups) for group meanings and examples.

## Policy extensions [#policy-extensions]

Policy extensions are local, verdict-only install checks. They run after dependency resolution and platform/dev filtering, before registry tarballs are fetched or packages are linked. Lockfile and offline replays run the same extension checks before linking, so a warm install does not bypass local policy. Direct remote tarball URL dependencies are rejected while policy extensions are active because V1 cannot identify the package candidate without downloading the tarball first.

Extensions are configured by hand in `~/.lpm/config.toml`:

```toml
[policy.extensions.local-feed]
command = ["/usr/local/bin/lpm-policy-feed", "--deny-list", "/etc/lpm/deny.json"]
mode = "enforce"       # report | enforce
on-error = "block"     # warn | block
timeout-ms = 5000
events = ["package.candidate"]
```

LPM CLI spawns the command directly with the provided argv, sends one JSON document on stdin, and reads one JSON document from stdout. `command[0]` must be an absolute path or a program name found on an absolute `PATH` directory; relative executable paths such as `./policy-extension` are rejected, and relative or empty `PATH` entries are ignored. The child environment is cleared except for minimal process/runtime variables such as `PATH`; package names and versions are never interpolated into a shell command.

Only `command`, `enabled`, `events`, `mode`, `on-error`, and `timeout-ms` are accepted under each extension. Unknown fields fail config loading, so typos such as `mdoe = "enforce"` cannot fall back to report mode.

Use [`lpm policy`](/docs/infra/policy) to inspect and test active extensions:

```bash
lpm policy list
lpm policy status
lpm policy doctor
lpm policy test local-feed --package react@19.0.0
```

Request:

```json
{
  "schema_version": 1,
  "event": "package.candidate",
  "packages": [
    {
      "name": "left-pad",
      "version": "1.3.0",
      "source": "registry+https://registry.npmjs.org",
      "source_kind": "registry",
      "integrity": "sha512-...",
      "registry_published_at": "2025-01-01T00:00:00.000Z",
      "is_direct": true,
      "is_lpm": false,
      "optional": false
    }
  ]
}
```

Response:

```json
{
  "schema_version": 1,
  "decisions": [
    {
      "name": "left-pad",
      "version": "1.3.0",
      "action": "block",
      "code": "local-deny-list",
      "reason": "matched local feed"
    }
  ]
}
```

The response envelope is strict: top-level fields must be `schema_version` and `decisions`, and each decision may contain only `name`, `version`, `action`, `code`, and `reason`. Missing, misspelled, or unknown fields are protocol errors. `action` must be `allow`, `warn`, or `block`. Every decision must reference a package candidate from the request by exact `name` and `version`; unknown or duplicate decisions are also protocol errors. `mode = "report"` warns and continues even for `block` decisions. `mode = "enforce"` blocks the install for `block` decisions. `on-error` controls runner and protocol failures, not package verdicts.

## Security-sensitive keys are proposals [#security-sensitive-keys-are-proposals]

For ordinary preferences, editing this file directly is fine.

For security-sensitive keys such as:

* `script-policy`
* `minimum-release-age-secs`
* `release-age-policy`
* `[sandbox] mode`
* `[sandbox] allow-degraded`
* `[sigstore] verify`
* `typosquat-guard`
* `[firewall] mode`

the file is only one input to the decision. A weaker value written here does **not** automatically become authoritative.

LPM CLI only honors a weaker value when it is already covered by the current approved machine posture or by an active temporary unlock. Otherwise:

* `lpm config ...` asks for confirmation before persisting the weaker posture in an interactive TTY
* install / rebuild / approve-scripts and related mutating commands fail with `security_approval_required` if the raw file value is weaker than the approved floor
* a managed machine policy can fail the change with `security_floor` instead

For short-lived exceptions, use [`lpm security unlock`](/docs/infra/security#unlock). For persistent changes, use [`lpm config`](/docs/infra/config) rather than relying on a hand edit alone. Raw `[sigstore].verify = "warn"` / `"off"`, raw `typosquat-guard = "off"`, and raw `[firewall].mode = "off"` or `"monitor"` below the approved floor are reported by `lpm security status` as runtime overrides until they are removed, approved, or blocked by managed policy.

## Precedence [#precedence]

For most scalar settings, the precedence chain is (highest first):

1. **CLI flag** — e.g. `--exact`, `--policy=allow`, `--min-release-age=1h`, `--no-engine-strict`
2. **`package.json > lpm`** — for keys that exist there (`scriptPolicy`, `minimumReleaseAge`, `minimumReleaseAgePolicy`, `engineStrict`, `strictPeerDependencies`)
3. **`./lpm.toml`** — project-level (today: `save-prefix`, `save-exact`, `[workspace].concurrency`)
4. **`~/.lpm/config.toml`** — this file
5. **Built-in default**

List-valued cooldown excludes are merged instead of replaced: CLI `--min-release-age-exclude` entries first, then `package.json > lpm > minimumReleaseAgeExclude`, then this file's `minimum-release-age-exclude`; duplicates collapse.

Package-published LPM.dev skill installation has its own compact chain: `--skills` / `--no-skills` wins over `auto-install-lpm-skills`, which wins over the inverted legacy `noSkills` key, then the built-in default `true`. `lpm config lpm-skills` writes the canonical boolean and removes the legacy key.

On `lpm install -g` the `package.json > lpm` tier is N/A — global installs synthesize their own package.json that doesn't carry user-edited keys. The chain collapses to CLI flag > `~/.lpm/config.toml` > built-in default for `script-policy`, `triage-advisor`, `minimum-release-age-secs`, `release-age-policy`, `strict-peer-dependencies`, `trust-policy`, `integrity`, and the script-policy aliases (`--yolo` / `--triage`). `minimum-release-age-exclude` still merges with repeated CLI `--min-release-age-exclude` flags. Registry signature verification uses `LPM_VERIFY_REGISTRY_SIGNATURES` > `signatures` > default `false`. Sigstore verification posture uses `LPM_PROVENANCE_ENFORCE` > `[sigstore].verify` > built-in default, with weaker env/config values guarded by the security approval layer. `[sigstore].scope` and `[sigstore].availability` are independent config-only axes; their defaults remain `"approved"` and `"best-effort"`.

Typosquat analysis uses `typosquat-guard` first. If that key is absent, the diagnostic `LPM_TYPOSQUAT_GUARD=0|false|off|disabled` override can disable analysis for benchmarking/debugging unless `force-security-floor = true` is active or managed policy owns the typosquat floor. If the key is present, the config file wins over the env var. The built-in default is enabled, and `lpm config typosquat --set default` removes the explicit key.

LPM Firewall uses `[firewall].mode`, defaulting to `"off"`. `LPM_NPM_FIREWALL=monitor|enforce` can tighten the mode for one process, but it cannot weaken a stricter config value. `report` remains accepted as a legacy alias for `monitor`. Active modes send LPM.dev Registry auth because the hosted firewall.lpm.dev verdict service is an LPM.dev Registry Pro/Org feature; CI can use `LPM_TOKEN` or registry-audience OIDC instead of an interactive login. The legacy diagnostic `LPM_EXPERIMENT_NPM_FIREWALL` is accepted for local benchmark compatibility; prefer `lpm config firewall --set monitor|enforce` for persistent use.

Policy extensions use only `~/.lpm/config.toml` today. Active extensions disable install-time registry tarball prefetch until their `package.candidate` verdicts pass, then normal fetch/link work resumes. Direct remote tarball URL dependencies fail before download while policy extensions are active. Extensions are local machine policy, not part of the signed approved-posture or managed-policy floor yet.

Store object validation uses `integrity`, defaulting to `"source"`. `source` validates reused v2 store objects by source identity without rehashing every expanded file. `tree` rehashes expanded files before reuse to catch local tampering/corruption, at the cost of slower warm installs. `LPM_V2_OBJECT_INTEGRITY=source|tree` overrides the config value for one process; the legacy env aliases `sri` and `tarball` mean `source`. This setting is separate from `--strict-integrity`, which controls whether tarball URL dependencies must declare an inline SRI hash before first use.

### Exception — `linker` [#exception--linker]

The `linker` key inverts the user-vs-project order. Per-user preference (this file) wins over `package.json > lpm > linker`, because the layout choice is an environmental decision (which `node_modules` shape this developer's tools and editor expect) that shouldn't be overridden by every cloned repo:

1. `lpm install --linker <isolated|hoisted>` — per-invocation
2. `~/.lpm/config.toml > linker` — this file
3. `LPM_LINKER` — per-process env var
4. `package.json > lpm > linker` — project-declared default
5. Built-in default — `"hoisted"` for single packages, `"isolated"` when LPM CLI detects a workspace root (a `package.json > workspaces` glob or a `pnpm-workspace.yaml`)

At the built-in default tier only, a fresh resolve that finds incompatible peer requirements auto-switches the install to `"isolated"` and records `auto-isolated-peer-conflicts = true` in `lpm.lock`. Any explicit linker value in the four higher tiers opts out.

The resolved mode is folded into `.lpm/install-hash` so a post-install flip of any of these surfaces invalidates the "up to date" cache and triggers a re-link on the next `lpm install`.

## File location [#file-location]

| Platform      | Path                             |
| ------------- | -------------------------------- |
| macOS / Linux | `~/.lpm/config.toml`             |
| Windows       | `%USERPROFILE%\.lpm\config.toml` |

Override the entire `~/.lpm/` root with the [`LPM_HOME`](/docs/reference/env-vars#filesystem-layout) env var (also moves the store, cache, and global install root).

The file is created on demand the first time `lpm config set` writes to it.

## See also [#see-also]

* [`lpm config`](/docs/infra/config) — CLI surface for getting / setting these keys
* [`lpm policy`](/docs/infra/policy) — inspect and test local install policy extensions
* [`lpm security`](/docs/infra/security) — inspect the effective floor or create a temporary unlock
* [`lpm.toml`](/docs/reference/lpm-toml) — project-level overrides for save policy
* [`package.json` "lpm" key](/docs/reference/package-json-lpm) — project-shared LPM CLI config
* [Environment variables](/docs/reference/env-vars) — sits above this file in precedence for many settings
