lpm run
Run package.json scripts — parallel, cached, watchable, workspace-aware.
lpm run <scripts...> [-- script-args...]Runs one or more scripts entries from package.json. With multiple scripts, runs them sequentially by default; pass -p to run in parallel.
Shorthand: lpm <script> without run
lpm falls through to the same task runner as lpm run <name> when the first argument isn't a known subcommand. That means plain shorthand invocations pick up lpm.json meta-tasks, dependsOn expansion, caching, and the normal script/task resolution rules.
lpm build # equivalent to lpm run build
lpm typecheck # equivalent to lpm run typecheck
lpm verify # equivalent to lpm run verify (including lpm.json meta-tasks)The lookup only kicks in for unknown subcommand names — built-in commands always win. So lpm test runs the Vitest/Jest forwarder (built-in lpm test), not your "test" script entry. To force the script entry when a built-in conflicts, use lpm run <name> explicitly.
Use lpm run when you need runner flags. lpm build --filter web forwards --filter web to your script; lpm run build --filter web applies LPM's workspace selection.
Hidden package.json scripts
Package scripts whose name starts with . are hidden helper scripts:
{
"scripts": {
"build": "lpm run .build",
".build": "tsc -p tsconfig.build.json"
}
}lpm run .build and the shorthand lpm .build are rejected when invoked directly from your shell. Hidden scripts are also omitted from missing-script suggestions and script listings.
Visible scripts may call hidden scripts, and lpm.json task dependencies may reference them:
{
"tasks": {
"build": {
"dependsOn": [".build"]
}
}
}Use this for internal building blocks you do not want to expose as top-level project commands.
Examples
lpm run build
lpm run lint test # sequential
lpm run -p lint test typecheck # parallel
lpm run dev -- --port 4000 # forward args to the script
lpm run build --filter web # workspaces: build only the web member
lpm run build --all # build every workspace member
lpm run test --affected # only members affected by recent changes
lpm run test --filter web --no-bail # keep running selected members after a failure
lpm run build --filter './packages/*' --workspace-concurrency 2
lpm run test --watch # re-run on file changes
lpm run --env=staging start # load .env.staging before runningForwarding arguments
Anything after -- is passed verbatim to the script:
lpm run dev -- --port 4000 --host 0.0.0.0
# runs: <whatever "dev" expands to> --port 4000 --host 0.0.0.0Parallel execution
lpm run -p lint test typecheckRuns all three scripts concurrently, respecting any task dependencies declared in lpm.json. Output is buffered per task by default — pass --stream for live prefixed output. With --no-bail, the runner keeps going past failed tasks and reports the failures at the end.
Workspaces
lpm run build --all # every member, topological order
lpm run build --filter web # one member
lpm run build --filter web --filter api # two members (union)
lpm run build --filter-prod ...shared # prod graph closure only
lpm run test --affected # members touched since base branch
lpm run test --affected --base develop # change base branch (default: main)
lpm run test --affected --changed-files-ignore-pattern '**/README.md'
lpm run test --affected --test-pattern '**/*.test.js'--filter accepts the filter grammar: exact name (foo), glob (@scope/*), combined name/path (@scope/*{./apps/web}), path glob (./apps/*), forward closure (foo...), reverse closure (...foo), exclusion (!foo).
Full grammar also includes path exact ({./apps/web}), git ref ([origin/main]), and the dependency/dependent-closure variants foo^... and ...^foo.
--filter-prod <EXPR> accepts the same grammar, but closure operators ignore devDependencies edges. Use it when a production deploy/build/test selection should include runtime workspace dependents without pulling in test-only packages.
--all is mutually exclusive with --filter, --filter-prod, and --affected; filters compose with --affected (the affected set is unioned with the filter result).
--all, filters, and --affected require a workspace.
--filter core does not match @babel/core — substring matching is not supported. Use --filter '*/core' for that.
--fail-if-no-match makes a typo'd filter exit non-zero — recommended in CI.
--no-bail keeps running the remaining selected workspace members after a member fails. The command still exits non-zero after the batch if any selected member failed.
--workspace-concurrency <N> caps how many selected workspace members run at once within each topological level. The command reads persistent defaults from lpm.toml > [workspace].concurrency, then ~/.lpm/config.toml > workspace-concurrency, then falls back to the host's available parallelism.
--changed-files-ignore-pattern <glob> drops matching paths before [git-ref] filters or --affected map changed files to workspace members. It also reads project defaults from lpm.toml > [workspace].changed-files-ignore-pattern.
--test-pattern <glob> marks matching changed files as test-only. Directly changed packages still run, but those packages do not seed dependent fan-out when all their changes match the test pattern. It also reads project defaults from lpm.toml > [workspace].test-pattern.
Caching
Task results are cached only when the task opts in via lpm.json (cache: true plus non-empty outputs). A cached task with unchanged inputs replays instantly without re-executing. Bypass the cache with --no-cache.
Single-script human output prints a compact stderr header before the script's own output:
› Running build
cache miss
command next build
✓ build · success in 4.82sOn a cache hit, LPM replays the captured stdout/stderr and reports that the task was restored from cache.
The local cache lives under ~/.lpm/cache/tasks/. With lpm.json > remoteCache.enabled, LPM checks the hosted cache after the local cache and uploads successful task outputs after the local cache write. Remote outages, 404s, bad signatures, and corrupt artifacts are misses — they do not fail a successful local build.
Manage cache state with lpm cache. See Task runner — Remote cache for setup.
JSON output
lpm run build --json
lpm run build --filter web --jsonlpm run --json emits an LPM metadata envelope, even for a single script in a single package. Single-package task output is captured into the task result instead of being passed through as raw stdout. The envelope includes success, task counts (total, passed, failed), and tasks[] entries with each task name, status, exit code, duration, cache-hit state, and skip reason.
Workspace selections emit the workspace envelope with package counts and per-member task status. If a workspace filter matches nothing and --fail-if-no-match is not set, JSON mode still emits a successful zero-package envelope instead of falling back to a human warning.
Environment files
lpm run start --env=stagingWith --env=staging, LPM loads .env, .env.local, .env.staging, then .env.staging.local. Without --env, it loads .env, then .env.local.
If the script name resolves to an env mode through lpm.json, LPM uses that mode automatically unless you override it with --env.
Vault-backed env secrets override file values after dotenv loading.
--no-env-check skips environment-variable schema validation if you've declared a schema.
Watch mode
lpm run dev --watchRe-runs one script in one package on file changes.
If the task declares inputs globs in lpm.json, only matching file changes retrigger the run. Otherwise, relevant project-file changes retrigger it.
--watch is single-package today: it does not support multiple script names or workspace-selection flags like --all, --filter, --filter-prod, or --affected. Watch runs fresh on every change; the task cache is not used.
Flags
| Flag | Effect |
|---|---|
-p, --parallel | Run scripts concurrently (respects task deps from lpm.json) |
--no-bail | Keep running remaining tasks or selected workspace members after a failure |
--stream | Live prefixed output instead of buffered per-task in task-graph / parallel runs |
--all | Run in every workspace member (topological order); mutually exclusive with filters / --affected |
--filter <EXPR> | Filter workspace members (repeatable; unions) |
--filter-prod <EXPR> | Filter workspace members with production-only dependency closures |
--fail-if-no-match | Exit non-zero if the selected workspace set is empty |
--workspace-concurrency <N> | Limit concurrent workspace members for --all, --filter, or --affected runs |
--affected | Only members affected by changes vs --base |
--base <REF> | Git base ref for --affected (default: main) |
--changed-files-ignore-pattern <glob> | Ignore matching git-diff paths for --affected / [git-ref] filters |
--test-pattern <glob> | Treat matching git-diff paths as test-only for --affected / [git-ref] fan-out decisions |
--no-cache | Bypass the task cache for cache-enabled tasks; ignored in watch mode |
--no-env-check | Skip env-var schema validation |
--env=<MODE> | Load .env, .env.local, .env.<MODE>, and .env.<MODE>.local |
--watch | Re-run one script in one package on file changes |
Plus the global flags.
See also
lpm exec— run a JS/TS file directly (no script needed)lpm dlx— run a package binary without installing- Task runner — caching, dependencies,
lpm.jsontask graph - Workspaces — filter grammar