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



`lpm.toml` is an **optional** TOML file that sits next to `package.json`. It pins per-project defaults for behaviors that aren't part of publishable package metadata — most notably the [save policy](/docs/packages/save-policy) and the project sandbox posture.

LPM CLI reads this file with a 16 MiB limit enforced before TOML parsing. Missing remains equivalent to no project-level config; an oversized file fails with its path and byte limit instead of falling through to user defaults. See [local configuration size limits](/docs/project-setup#local-configuration-size-limits) for the complete scope and exclusions.

The file is intentionally separate from `package.json > lpm` because these keys are tool behavior, not publishable metadata. Mixing them into the manifest creates avoidable diff churn whenever someone tweaks a personal preference. Keeping them in `lpm.toml` lets each team decide whether to commit the file or `.gitignore` it.

## Today's keys [#todays-keys]

```toml title="lpm.toml"
save-prefix = "^"     # one of "^", "~", or "" (empty for exact, no prefix)
save-exact  = false   # bool; true forces exact regardless of save-prefix

[workspace]
concurrency = 4       # positive integer; caps workspace run/test/bench fan-out
changed-files-ignore-pattern = ["**/README.md", "docs/**"]
test-pattern = ["**/*.test.js", "**/*.spec.ts"]

[sandbox]
mode = "default"      # "default" | "strict" | "none"
allow-degraded = false

[tidy]
ignore-unused = ["eslint-config-next"]
ignore-phantom = ["virtual:*"]
ignore-paths = ["generated/**"]

[[policy.typosquat.allow]]
package = "axois"
similar-to = "axios"
reason = "Intentional internal compatibility package"
```

| Key                                      | Type                                  | Default               | Notes                                                                                                                                                                                                                                |
| ---------------------------------------- | ------------------------------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `save-prefix`                            | `"^"` \| `"~"` \| `""`                | `"^"`                 | Prefix applied when `lpm install <pkg>` saves to `package.json`. `*` is **not** accepted.                                                                                                                                            |
| `save-exact`                             | bool                                  | `false`               | Force exact saves regardless of `save-prefix`.                                                                                                                                                                                       |
| `workspace.concurrency`                  | positive integer                      | available parallelism | Project default for concurrent workspace members in `lpm run`, `lpm test`, and `lpm bench` workspace mode.                                                                                                                           |
| `workspace.changed-files-ignore-pattern` | string or string array                | `[]`                  | Project default for git-diff paths to ignore before `[git-ref]` filters or `--affected` map changed files to members. CLI `--changed-files-ignore-pattern` entries append to this list.                                              |
| `workspace.test-pattern`                 | string or string array                | `[]`                  | Project default for changed files treated as test-only. Test-only packages stay selected, but they do not seed dependent fan-out for `[git-ref]` reverse closures or `--affected`. CLI `--test-pattern` entries append to this list. |
| `sandbox.mode`                           | `"default"` \| `"strict"` \| `"none"` | `"default"`           | Project-default lifecycle-script sandbox posture. CLI flags still win per invocation.                                                                                                                                                |
| `sandbox.allow-degraded`                 | bool                                  | `false`               | Allow degraded sandbox fallback for this repo on hosts that cannot provide the full posture.                                                                                                                                         |
| `tidy.ignore-unused`                     | string or string array                | `[]`                  | Suppress [`lpm tidy`](/docs/packages/tidy) unused-dependency findings by package-name glob.                                                                                                                                          |
| `tidy.ignore-phantom`                    | string or string array                | `[]`                  | Suppress `lpm tidy` phantom-import findings by package-name glob.                                                                                                                                                                    |
| `tidy.ignore-paths`                      | string or string array                | `[]`                  | Ignore source imports from matching project-relative path globs during `lpm tidy`.                                                                                                                                                   |
| `policy.typosquat.allow[]`               | table array                           | `[]`                  | Reviewable exceptions for intentional suspicious direct package names. Each entry needs `package`, `reason`, and optionally `similar-to`.                                                                                            |

Invalid values (`save-prefix = "*"`, `save-prefix = ">="`, etc.) are rejected at load time with a clear error pointing at the offending file. Unknown keys are accepted silently for forward compatibility.

## Precedence [#precedence]

### Save policy [#save-policy]

Save policy resolves in this order, highest first:

1. **CLI flag** — `--exact`, `--tilde`, or `--save-prefix '<p>'` on the install command
2. **`./lpm.toml`** — this file
3. **`~/.lpm/config.toml`** — user-level fallback
4. **Built-in default** — `save-prefix = "^"`, `save-exact = false`

See [Save policy](/docs/packages/save-policy) for the full table of how each combination flows into `package.json`.

### Workspace concurrency [#workspace-concurrency]

Workspace package fan-out for `lpm run`, `lpm test`, and `lpm bench` resolves in this order, highest first:

1. **CLI flag** — `--workspace-concurrency <N>`
2. **`./lpm.toml > [workspace].concurrency`** — this file
3. **`~/.lpm/config.toml > workspace-concurrency`** — user-level fallback
4. **Built-in default** — available host parallelism

### Git-diff workspace filters [#git-diff-workspace-filters]

`changed-files-ignore-pattern` and `test-pattern` under `[workspace]` are project defaults for workspace selections that read git changes: `[git-ref]` filter atoms and `--affected`. CLI flags append to the project lists for the current invocation.

### Sandbox [#sandbox]

Sandbox mode resolves in this order, highest first:

1. **CLI flag** — `--no-sandbox`, `--strict-sandbox`, or `--paranoid`
2. **`LPM_STRICT_SANDBOX`** — strict-mode env override
3. **`./lpm.toml > [sandbox]`** — this file
4. **`~/.lpm/config.toml > [sandbox]`** — user-level fallback
5. **Built-in default** — `mode = "default"`, `allow-degraded = false`

If this repo asks for a weaker sandbox than the machine currently allows, install or rebuild does **not** silently obey the file. It fails with `error_code: "security_approval_required"` and points you at [`lpm security unlock`](/docs/infra/security#unlock) instead.

### Tidy ignores [#tidy-ignores]

`[tidy]` keys are project-local only. They affect [`lpm tidy`](/docs/packages/tidy) report and fix mode; `ignore-unused` and `ignore-phantom` match package names, while `ignore-paths` matches project-relative source paths before imports are analyzed.

### Typosquat policy [#typosquat-policy]

`policy.typosquat.allow` is the committed exception list for suspicious direct package names. It is consulted by [`lpm install`](/docs/packages/install#typosquat-guard) and [`lpm add`](/docs/packages/add) before network access or manifest mutation.

```toml title="lpm.toml"
[[policy.typosquat.allow]]
package = "crossenv"
similar-to = "cross-env"
reason = "Internal migration package kept for compatibility"
```

`package` is the exact direct dependency name to allow. `similar-to` narrows the exception to the popular package LPM CLI detected; omit it only when the same local name may intentionally resemble more than one popular package. `reason` is required so the exception is reviewable in code review.

## See also [#see-also]

* [`~/.lpm/config.toml`](/docs/reference/config-toml) — user-level CLI defaults (broader surface)
* [`package.json` "lpm" key](/docs/reference/package-json-lpm) — publishable / project-shared LPM CLI config
* [`lpm security`](/docs/infra/security) — temporary approvals and floor status
* [`lpm.json`](/docs/reference/lpm-json) — dev-server, task-runner, and publish config
* [`lpm tidy`](/docs/packages/tidy) — dependency hygiene report and prune command
* [Save policy](/docs/packages/save-policy) — full rules and edge cases
