LPM CLI

lpm rebuild

Run approved dependency lifecycle scripts, retry failed builds, and reuse eligible native build outputs.

Run install scripts for dependencies that are already installed. Use this command after approval, after a build failure, or when build inputs change.

lpm rebuild [OPTIONS] [PACKAGES]...

Quickstart

# Install dependencies, then review blocked scripts
lpm install
lpm approve-scripts

# Preview and run the approved builds
lpm rebuild --dry-run
lpm rebuild

LPM CLI installs dependencies with dependency scripts blocked by default. lpm approve-scripts records approvals without executing scripts.

ModeSelection
No package argumentsPackages permitted by the effective script policy
Package namesAll installed versions and instances of each selected name
--allEvery installed package with executable install scripts
--dry-runPreview the selection without executing scripts
--deny-allBlock all execution, including trusted packages

Explicit untrusted selections require signed authorization. --all and package names do not bypass that requirement.

The command acts on the nearest directory with a package.json, as lpm install does. From a subdirectory, it prints the directory it chose.

Examples

# Rebuild selected dependencies
lpm rebuild esbuild sharp

# Retry approved packages, including completed builds
lpm rebuild --force

# Give each lifecycle phase up to ten minutes
lpm rebuild --timeout 600

# Require strict containment and deny outbound network access
lpm rebuild --strict-sandbox

# Emit a report for automation
lpm rebuild --json

For a reusable build task, use an uncached command:

lpm.json
{
  "tasks": {
    "deps:rebuild": {
      "command": "lpm rebuild --strict-sandbox",
      "cache": false
    }
  }
}
lpm run deps:rebuild

lpm.json has no dedicated rebuild fields. command holds the invocation. cache: false prevents the task runner from skipping the rebuild check.

For a one-run preview, use lpm rebuild --strict-sandbox --dry-run directly. An explicit lpm.json task command takes precedence in lpm run.

What runs

The command requires a usable lpm.lock and installed package contents. In a workspace member, it uses that member's projected dependency graph.

For each selected dependency, these phases run in order:

  1. preinstall
  2. install
  3. postinstall

A package with only prepare, publish scripts, or uninstall scripts is outside this queue. Root project lifecycle scripts are also outside this command.

Dependencies build before their dependents. Up to four independent packages build concurrently.

If one phase fails, later phases of that package do not run. Other selected packages continue. Any failed package makes the command exit nonzero.

By default, each phase has a 300-second timeout. --timeout changes the limit for this invocation.

Default selection

The effective policy comes from the CLI, then package.json > lpm > scriptPolicy, then user configuration, then the deny default.

The machine's authorized security policy can reject weaker requests.

PolicyEligible packages
denyPackages with matching project approvals or authorized lifecycle scope trust
triageTrusted packages plus green scripts eligible for automatic execution
allowAll packages with executable install scripts

Local JavaScript delegates still require approval, even when their static classification is green.

Manage individual approvals with lpm approve-scripts. Manage scopes with lpm trust lifecycle-scope.

Rich approvals bind the package to its recorded integrity and script hash. Changed scripts can invalidate an approval. Legacy name-only approvals produce a migration warning.

force-security-floor = true suspends persistent package approvals. An authorized one-run policy override can still permit explicit execution.

Explicit package names

lpm rebuild esbuild sharp --dry-run

An exact package name takes precedence. A dot-suffix shorthand works only when it identifies one distinct package name.

If multiple names match a shorthand, the command fails and lists the alternatives. Overlapping selectors select each installed instance once.

Every requested name must have installed, executable install scripts. Missing names and scriptless packages fail, including when the entire queue is empty.

Authorization and non-interactive use

Routine rebuilds of approved packages require no selection prompt:

lpm rebuild --json

To authorize all scripted packages for a limited period, start from a user-controlled terminal:

lpm security unlock scripts-allow --project . --ttl 10m
lpm rebuild --all --json

For one named package, add --package esbuild to the unlock command, then run lpm rebuild esbuild --json.

The unlock command requires user approval. The signed grant applies to that project and expires. It does not transfer to another machine.

--policy=allow and --yolo request the same script-policy widening. Managed policy can reject it.

Project capability changes require their own authorization. A script-policy grant does not authorize broader environment, file, or sandbox access.

Dry runs retain policy and authorization checks. They skip execution, engine enforcement, and sandbox or native-cache preparation.

Dependency tools and script context

With the default store, each dependency script first finds executables from its own dependencies and peers. Project executables and the inherited PATH follow.

If a project tool has the same executable name, this selection preserves the dependency's tool version.

The sandbox permits reads from those installed dependencies. These read grants do not permit writes to dependency tools or their helper packages.

Each script receives its own npm context. INIT_CWD remains the directory where the CLI command started.

Scripted dependencies run before their dependents, including through packages with no scripts. Cyclic dependencies cannot guarantee that order.

Build state and --force

A successful generic build records its lifecycle script hash. The hash includes recognized local JavaScript delegates and their reachable local imports.

An unchanged hash lets a later rebuild skip that package. Changed script commands or covered file contents make it eligible again.

Old empty build markers require one authorized rebuild. Script hashes do not capture every external build input.

If an input outside the recorded hash changes, force a rebuild:

lpm rebuild --force

--force skips completed-build checks. It does not grant execution permission or override --deny-all.

Native build cache

Eligible native builds can reuse outputs from the shared store. A restored artifact avoids executing the lifecycle scripts again.

Eligibility requires a recognized native installer, strict containment, denied outbound network access, and baseline lifecycle capabilities.

Examples include node-gyp, prebuild-install, and supported esbuild or sharp installers. Wider project read/write grants or environment grants disable reuse.

Native artifact reuse is available on macOS and Linux. Windows still executes builds through its normal sandbox.

The cache key includes package integrity, dependency and peer identities, patches, script commands, runtime identity, platform, exposed environment, and discoverable toolchain state.

The key also includes the selected dependency tools and their live helper files. Changes to those files or executable permissions invalidate reuse.

Packages with a nested dependency of the same name bypass artifact reuse. Their dependency links remain intact during rebuild.

A changed key invalidates the local native build state. Before a replacement native build, LPM CLI restores pristine package contents.

Corrupt or incomplete artifacts count as misses. --force bypasses artifact lookup and replaces the eligible artifact after a successful build.

Reuse in CI

Keep the store and workspace paths stable across runs. Absolute paths are visible build inputs, so moving a checkout can prevent reuse.

lpm rebuild --strict-sandbox --json

Toolchain checks use a validated metadata snapshot with a maximum lifetime of one hour. lpm cache clean metadata removes these snapshots.

The fingerprint detects normal toolchain and package-manager changes. It does not hash every system header or library.

After a manual system-library change, use lpm rebuild --strict-sandbox --force to rebuild approved packages from pristine native inputs.

Sandbox

The default sandbox limits filesystem writes and filters the environment. Strict mode also denies outbound network access.

lpm rebuild --strict-sandbox
ModeBehavior
DefaultPackage write containment and a filtered environment, subject to configured policy
--strict-sandbox, --paranoidStrict containment, filtered environment, and outbound network denial
--sandbox-logmacOS diagnostic mode that reports accesses without enforcing containment
--no-sandboxFull host filesystem, network, and environment access, including credentials

Weaker modes require signed authorization. --no-sandbox conflicts with strict and diagnostic modes.

A clean diagnostic run does not prove that a strict sandbox run will succeed.

The project's .lpm directory

The project's .lpm/ directory holds LPM CLI's own state, such as certificates, env sync state, tunnel captures, and recovery backups. Its package directories, .lpm/wrappers/ and .lpm/hoisted/nested/, hold installed packages of the isolated and hoisted layouts. Sandboxed scripts can read them, and a script can write only its own package's directory there, not another package's. With the default readProject: "narrow", those are also the only parts of .lpm/ that scripts can read. A package.json > lpm.scripts.sandboxWriteDirs entry inside .lpm or above the project is rejected. On Linux, scripts don't run when a directory they can write, or a mount below one, shows .lpm, the LPM home or the repository's git directory (a worktree's common one included) under another path, as a bind mount can, or when the mount table can't be read to check that. An NFS mount counts by the server directory its source names, so a bind of a directory in that state, or a mount of the same server with other options, is refused too. Scripts can write ~/.cache, ~/.npm, and ~/.node-gyp, so a project inside one of them can't run dependency scripts in the sandbox: LPM CLI refuses them until you move the project.

Project reads and environment variables

By default, readProject: "narrow" permits dependency directories, package manifests, lockfiles, and root tsconfig*.json files.

Builds also retain access to their package files and permitted toolchain, cache, and writable locations. Other project source files require a read grant.

On Windows, scripts can read the directories on PATH, each with everything below it. An entry that isn't an absolute path, that holds the project, your home directory, or the LPM home, or that is in the project's .lpm/ directory, gets no access, so keep tools that scripts run in a directory of their own.

On Windows, a package's scripts run in one AppContainer per project. Each run grants it the access the run needs and takes back what an earlier run had and this one doesn't, so its access doesn't build up. When a package leaves the project, lpm uninstall takes its access back and removes its AppContainer; lpm cache clean does the same for projects that no longer exist. Earlier versions created an AppContainer for every run and left its access entries behind; the first run in this version removes those from the directories it grants, once.

Approved readProject: "full" permits the entire project tree, including project secrets and the project's .lpm/ directory, which holds local certificates and tunnel captures. It does not grant access to credentials outside the project.

The baseline environment contains operating-system, user, locale, terminal, path, and CI values. Other names require passEnv and authorization:

package.json
{
  "lpm": {
    "scripts": {
      "readProject": "narrow",
      "passEnv": ["BUILD_SERVICE_TOKEN"]
    }
  }
}

Only approved names pass through. Similar names do not inherit access. See project script configuration for reserved variables and capability limits.

Project secret files

The sandbox protects conventional secret files, including nested .env files and custom names such as .env.preview.

Explicit sandboxReadAllow entries can grant access to individual files. The CLI combines them with user-level script-read-allow entries.

Read grants must name project files. Directories, symlinks, and paths outside the project are invalid. Missing files grant no current access.

Changed read grants and sandboxWriteDirs require renewed authorization. Writable directories also permit reads.

On Linux, protection of otherwise-readable secret files can require a namespace overlay. If that protection is unavailable, execution fails.

Linux and Windows inspect existing secret files before execution. This protection cannot cover a new secret created inside an already-readable directory afterward.

Timeouts, cancellation, and child processes

Ctrl+C and SIGTERM cancel active scripts. Interrupted builds do not receive successful build markers.

Linux prevents sandboxed scripts from creating separate process groups. Windows uses a Job Object to contain descendants.

On macOS, detached or reparented native child processes can survive completion or cancellation. Their filesystem and network restrictions remain active.

For complete process-lifetime isolation, use a disposable virtual machine or container.

--deny-all

lpm rebuild --deny-all --json

The flag and package.json > lpm > scripts > denyAll: true block every script, including trusted scripts.

After normal CLI checks, this mode returns without inventory or execution. It is not a check of installed scripts or their approvals.

lpm.scripts.autoBuild controls automatic builds during lpm install. It does not change manual rebuild selection.

JSON output

lpm rebuild --dry-run --json
lpm rebuild --json > rebuild.json

Dry-run reports contain success, dry_run, count, and packages. Each package includes its name, version, scripts, and trust status.

Live reports contain success, built, failed, and build_cache metrics. Security posture fields appear when a security floor or suppression needs reporting.

built counts packages whose scripts completed successfully in this invocation. Cache reuse has separate metrics.

Script output goes to stderr. Stdout contains one JSON report, including when a script fails. Failed builds report success: false and exit 1.

During install auto-build, rebuild leaves the JSON report to lpm install.

Pre-execution errors use the shared JSON error envelope. Deny-all results include denied_all: true and an empty successful report.

Fix common problems

If the lockfile or installed contents are missing, run lpm install, then retry the preview.

If an approval drifts, review the changed scripts with lpm approve-scripts before retrying.

If authorization fails, use the project unlock command shown in the error from a user-controlled terminal.

If a build fails, read its stderr output. Correct the missing tool, denied capability, or script error, then rerun the same selection.

Flags

FlagEffect
--allSelect every scripted package, with authorization for untrusted execution.
--dry-runPreview without execution. Authorization still applies.
--forceRerun selected packages and bypass eligible native artifact lookup.
--timeout <TIMEOUT>Set the per-phase timeout in seconds. Default: 300.
--deny-allBlock all script execution.
--policy <deny|allow|triage>Override the script policy for this invocation.
--yoloRequest --policy=allow.
--triageRequest --policy=triage.
--strict-sandboxRequire strict containment and outbound network denial.
--paranoidRequest strict sandbox mode.
--no-sandboxDisable containment and environment filtering with authorization.
--sandbox-logUse macOS diagnostic sandbox mode.
--no-engine-strictUse warning-only engine checks.
--jsonEmit one JSON report and send script output to stderr.

--policy, --yolo, and --triage are mutually exclusive. See the global flags for shared options.

See also