# lpm cache (/docs/packages/cache)



```bash
lpm cache <action>
```

`lpm cache` covers two adjacent concerns: ephemeral caches under `~/.lpm/cache/` (registry metadata, task results, dlx tarballs) and the global package store at `~/.lpm/store/`.

## Examples [#examples]

```bash
lpm cache path                          # print ~/.lpm/cache/
lpm cache path metadata                 # print ~/.lpm/cache/metadata/

lpm cache clean                         # wipe metadata + tasks + dlx
lpm cache clean metadata                # only wipe registry metadata
lpm cache clean tasks                   # only wipe task-runner cache
lpm cache clean dlx                     # only wipe dlx tarball cache

lpm cache status                        # local task cache usage + remote status
lpm cache status --json                 # structured status for CI

lpm cache prune                         # preview orphan store entries (dry-run)
lpm cache prune --apply                 # actually remove orphans
lpm cache prune --max-age 30d --apply   # only entries last touched > 30d ago
lpm cache prune --project ./my-app      # manual repair: walk one project only
```

## Actions [#actions]

| Action   | Effect                                                                                                                    |
| -------- | ------------------------------------------------------------------------------------------------------------------------- |
| `path`   | Print the cache root (`~/.lpm/cache/`) or one of its subcategories                                                        |
| `clean`  | Wipe ephemeral caches (`~/.lpm/cache/`). `lpm cache clear` is an alias.                                                   |
| `status` | Report local task-cache usage and hosted remote-cache status for the current project                                      |
| `prune`  | Reference-aware orphan removal from the global store (`~/.lpm/store/`) plus a sweep of deferred global-install tombstones |

`clean` accepts an optional subcategory (`metadata`, `tasks`, `dlx`); without one, all three are wiped. `clean` never touches the global package store — for that, use `prune`.

## Status [#status]

`lpm cache status` reports the local task-cache path and size. If the current project has `lpm.json > remoteCache.enabled`, it also calls the hosted cache status endpoint and reports the remote status, usage, and quota when the server returns them.

Remote status failures do not make `lpm cache status` fail; the JSON envelope includes `remote.error` so CI can decide whether to warn or ignore.

## Prune [#prune]

`lpm cache prune` walks the global store and removes entries no project still references, then sweeps any deferred global-install tombstones left behind by `lpm uninstall -g`. Default is dry-run; pass `--apply` to mutate.
Human output ends with an elapsed summary; `--json` keeps the machine-readable report shape and includes `success`.

The tombstone sweep runs even when the orphan walk is skipped (registry missing or corrupt — see [Safety rails](#safety-rails)), so `lpm uninstall -g`'s deferred cleanup always has a way to reach disk.

If the project registry is corrupt, prune disables only the project-reachability
walk. It still plans or applies crash recovery and age-based eviction for
compatibility islands and native build artifacts, cleans their orphaned lock
files, and sweeps global-install tombstones. In JSON mode,
`registry_corrupt: true` and `registry_corrupt_reason` carry the registry
problem; tombstone inspection and sweep failures are reported separately.

### How it decides what to keep [#how-it-decides-what-to-keep]

LPM CLI tracks every project it has installed into in a registry at `~/.lpm/known-projects.json`. For each registered project, prune walks the project's `node_modules/` symlinks back into `~/.lpm/store/v2/links/<graph-key>/`, then BFS through each link entry's sidecar metadata to mark every reachable graph-key. Anything not marked is an orphan. Object directories under `~/.lpm/store/v2/objects/` are pruned the same way — by collecting every surviving link entry's object reference and removing the rest. On macOS, cached compatibility islands under `~/.lpm/store/v2/compat/` are pruned by crash recovery and LRU age: incomplete islands are eligible immediately, and complete islands are eligible only when their last-used sentinel is older than `--max-age`.

Native lifecycle-build artifacts under `~/.lpm/store/v2/builds/` use the same
crash-recovery and LRU rule on macOS and Linux. An incomplete publication is
eligible immediately. A complete artifact is kept unless its last-used
sentinel is older than `--max-age`. This cleanup is independent of project
reachability, so it remains safe and active when the project registry is
missing or corrupt. `--apply` also removes advisory build-key lock files that
no longer have an artifact and graph-entry lock files whose link entry was
removed.

Stale registry entries (projects that have moved or been deleted) are dropped silently during the walk. The `--max-age` filter operates on each link entry's `last_referenced_at` timestamp (recorded in the entry's sidecar at first population, refreshed by `lpm install` cache hits) — not on the project registry's `last_seen`, which is set at install-time only.

### Manual repair: `--project <path>` [#manual-repair---project-path]

When the registry is missing, corrupted, or doesn't reflect actual machine state (after a restore, after copying `~/.lpm/` between machines, etc.), pass `--project <path>` to walk only that project's lockfile + `node_modules/` for roots. The registry is ignored.

This mode is for scripted cleanup of a single project's footprint. **Default mode is safer when you have multiple projects on the machine** — `--project` only sees the one you point it at, so any link entry referenced by another project would look like an orphan.

### Safety rails [#safety-rails]

* **Dry-run by default.** No deletions without `--apply`.
* **Reachability-degraded mode.** If the registry is missing, corrupt, or unreadable AND no `--project <path>` is supplied, prune cannot identify link/object orphans safely (without trustworthy roots, every link entry would look unreachable). `--apply` skips only link/object orphan removal. Reachability-independent compatibility-island and native-build-artifact cleanup, orphan lock cleanup, and the tombstone sweep still run. LPM CLI prints a warning naming the cause; for corrupt registries it includes the parser's reason ("not valid JSON" / "unknown schema version" / I/O details) so you can repair the file or delete it for a clean rebuild.
* **Canonicalized paths.** The registry stores fully resolved absolute paths, so symlink-cwd quirks don't accumulate aliased entries.
* **Atomic registry rewrites.** Updates go through `<path>.tmp.<pid>` → rename. No partial-write corruption.
* **In-flight installs are respected.** Prune coordinates with concurrent `lpm install`, `lpm audit`, and `lpm query` invocations through the store reader/writer lock — dry-run takes the shared half, `--apply` takes the exclusive half. See [`lpm store` — Locking model](/docs/infra/store#locking-model).

## Flags [#flags]

| Flag               | Applies to | Effect                                                                                                  |
| ------------------ | ---------- | ------------------------------------------------------------------------------------------------------- |
| `--apply`          | `prune`    | Actually remove orphans + sweep tombstones (default is dry-run)                                         |
| `--max-age <DUR>`  | `prune`    | Only prune entries last touched older than this. Accepts `<N>d` (days) or `<N>h` (hours) — nothing else |
| `--project <PATH>` | `prune`    | Manual repair: walk only this project's roots, ignore the registry                                      |

Plus the [global flags](/docs/commands#global-flags).

## JSON output [#json-output]

```bash
lpm cache status --json

lpm cache prune --json            # dry-run report
lpm cache prune --apply --json    # post-apply report (same shape, mutations recorded)
```

`status --json` emits:

| Field                                       | Meaning                                                      |
| ------------------------------------------- | ------------------------------------------------------------ |
| `local.path` / `local.bytes` / `local.size` | Local task-cache location and usage                          |
| `remote.enabled` / `remote.status`          | Hosted cache configuration and server status                 |
| `remote.usage_bytes` / `remote.limit_bytes` | Hosted usage and included quota when the server returns them |
| `remote.error`                              | Status lookup error, if any                                  |

`prune --json` reports both the orphan walk and the tombstone sweep:

| Field                                                                     | Meaning                                                                                                                                                                                                                    |
| ------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `success`                                                                 | `false` when prune could not complete every requested inspection or cleanup step                                                                                                                                           |
| `applied`                                                                 | `true` when `--apply` was passed                                                                                                                                                                                           |
| `projects_walked` / `registry_entries_dropped`                            | Project-registry coverage stats                                                                                                                                                                                            |
| `link_entries_total` / `_reachable` / `_orphaned[]`                       | Link-entry walk results; `_orphaned[]` is a list of paths                                                                                                                                                                  |
| `object_entries_total` / `_reachable` / `_orphaned[]`                     | Object-entry walk results                                                                                                                                                                                                  |
| `compat_islands_total` / `_orphaned[]`                                    | Cached compatibility-island results; `_orphaned[]` lists incomplete or stale LRU islands                                                                                                                                   |
| `build_artifacts_total` / `_orphaned[]`                                   | Native lifecycle-build artifact results; `_orphaned[]` lists incomplete or stale LRU artifacts                                                                                                                             |
| `bytes_freed_or_eligible`                                                 | Bytes the orphan walk would free (dry-run) or did free (apply)                                                                                                                                                             |
| `registry_missing` / `registry_corrupt` / `registry_corrupt_reason`       | Reachability-degraded flags — when either is true, link/object orphan arrays are empty because that walk was skipped; compatibility-island, native-build-artifact, lock, and tombstone cleanup still operate independently |
| `tombstones_pending` / `_swept` / `_retained[]` / `tombstone_bytes_freed` | Tombstone sweep results — `_swept` and `_bytes_freed` are zero on dry-run                                                                                                                                                  |

`lpm cache clean` emits a parallel `{success, cleaned[], total_bytes_freed, total_freed}` envelope per subcategory.

## See also [#see-also]

* [Content-addressable store](/docs/packages/content-addressable-store) — design overview, on-disk layout
* [`lpm store`](/docs/infra/store) — integrity checks, store path, blunt full wipe
* [`lpm doctor`](/docs/infra/doctor) — surfaces store-size hints alongside other checks
