LPM-cli

~/.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-prefix

Known keys

~/.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

# 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"
KeyTypeDefaultNotes
save-prefix"^" | "~" | """^"Prefix used when lpm install <pkg> writes to package.json. * is rejected.
save-exactboolfalseForce 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-secsu6486400 (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-degradedboolfalseAllow 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-strictbooltrueEnforce 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-dependenciesboolfalseTurn 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-concurrencypositive integeravailable parallelismUser 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-installboolfalseRun 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-allowarray 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-urlstring"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-policy
  • minimum-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_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. 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):

  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, engineStrict, strictPeerDependencies)
  3. ./lpm.toml — project-level (today: save-prefix, save-exact, [workspace].concurrency)
  4. ~/.lpm/config.toml — this file
  5. 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:

  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 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

PlatformPath
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