~/.lpm/config.toml
User-level CLI defaults — applies to every project on this machine.
~/.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 and Security-sensitive keys are proposals.
You can edit the file directly, or use lpm config to manage it from the CLI:
lpm config set save-prefix '~'
lpm config get save-prefix
lpm config list
lpm config delete save-prefixKnown keys
# Save policy
save-prefix = "^"
save-exact = false
# Lifecycle scripts
script-policy = "deny"
triage-advisor = "none"
# Recently-published-package cooldown
minimum-release-age-secs = 86400
# Engine constraints (engines.lpm + engines.node)
engine-strict = true
# Peer-dependency diagnostics
strict-peer-dependencies = false
# 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"]
# Lifecycle-script sandbox
[sandbox]
mode = "default"
allow-degraded = false
# Provenance verification posture
[sigstore]
verify = "deny"
# 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. 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. Applies to both lpm install and lpm install -g. |
sandbox.mode | "default" | "strict" | "none" | "default" | Default lifecycle-script sandbox posture for this machine. Set with lpm config sandbox. |
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. |
engine-strict | bool | true | Enforce engines.lpm and engines.node from the workspace root package.json. Set to false to fall back to npm's read-but-don't-enforce behavior (mismatches print as stderr warnings). |
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. |
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 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. |
linker | "isolated" | "hoisted" | "hoisted" (workspaces and default peer-conflict installs use "isolated") | node_modules layout for installs run by this user. 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 | [] | Project-relative paths the sandbox should let lifecycle scripts read despite matching the secret-file deny list. 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 — duplicates are deduplicated. Use this when the same secret file (.env, .npmrc) is consistently needed by your builds across every project. |
tunnel.relay-url | string | "wss://relay.lpm.fyi/connect" | WebSocket URL for the LPM tunnel relay. 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
lpm config set writes every value as a TOML string. The reader accepts both native types and the string form:
minimum-release-age-secs = 86400 # native integer (hand-edit)
minimum-release-age-secs = "86400" # string (lpm config set wrote this)
workspace-concurrency = 4 # native integer (hand-edit)
workspace-concurrency = "4" # string (lpm config set wrote this)Both forms parse to the same value. Invalid values (non-numeric strings, negative numbers, zero for positive-only keys, etc.) error at load time with the file path baked in.
Security-sensitive keys are proposals
For ordinary preferences, editing this file directly is fine.
For security-sensitive keys such as:
script-policyminimum-release-age-secs[sandbox] mode[sandbox] allow-degraded[sigstore] verify
the file is only one input to the decision. A weaker value written here does not automatically become authoritative.
LPM 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_requiredif the raw file value is weaker than the approved floor - a managed machine policy can fail the change with
security_floorinstead
For short-lived exceptions, use lpm security unlock. For persistent changes, use lpm config rather than relying on a hand edit alone. Raw [sigstore].verify = "warn" or "off" is reported by lpm security status as a runtime override until it is removed, approved, or blocked by managed policy.
Precedence
For most settings, the precedence chain is (highest first):
- CLI flag — e.g.
--exact,--policy=allow,--min-release-age=1h,--no-engine-strict package.json > lpm— for keys that exist there (scriptPolicy,minimumReleaseAge,engineStrict,strictPeerDependencies)./lpm.toml— project-level (today:save-prefix,save-exact,[workspace].concurrency)~/.lpm/config.toml— this file- Built-in default
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, strict-peer-dependencies, and the script-policy aliases (--yolo / --triage). Sigstore verification uses LPM_PROVENANCE_ENFORCE > [sigstore].verify > built-in default, with weaker env/config values guarded by the security approval layer.
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:
lpm install --linker <isolated|hoisted>— per-invocation~/.lpm/config.toml > linker— this fileLPM_LINKER— per-process env varpackage.json > lpm > linker— project-declared default- Built-in default —
"hoisted"for single packages,"isolated"when LPM detects a workspace root (apackage.json > workspacesglob or apnpm-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
| Platform | Path |
|---|---|
| macOS / Linux | ~/.lpm/config.toml |
| Windows | %USERPROFILE%\.lpm\config.toml |
Override the entire ~/.lpm/ root with the LPM_HOME 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
lpm config— CLI surface for getting / setting these keyslpm security— inspect the effective floor or create a temporary unlocklpm.toml— project-level overrides for save policypackage.json"lpm" key — project-shared LPM config- Environment variables — sits above this file in precedence for many settings