lpm add
Copy source files from a package into your project (shadcn-style).
lpm add <package>lpm add extracts a package's source files into your project rather than installing it as a runtime dependency. Think shadcn-ui style: the code lands in your repo, you own it, you edit it.
lpm install is the runtime-dependency command. lpm add is the source-delivery command. The two are not aliases.
Works with any registry the resolver can reach โ LPM.dev Registry, npmjs.org, or a .npmrc-declared private registry. Anything that ships a tarball is fair game.
Try the public npm example package:
lpm add lpm-source-packagelpm-source-package is a minimal configurable source package published to npm, so it exercises the same registry-agnostic lpm add path without requiring an LPM.dev Registry package.
Like lpm install, lpm add rejects a likely typosquatted package name before any registry fetch. Intentional names use the committed policy.typosquat.allow list in lpm.toml.
When npm firewall mode is monitor or enforce, LPM CLI checks the selected source package with LPM Firewall at firewall.lpm.dev when it is a routed public npm package. LPM Firewall is an LPM.dev Registry Pro/Org feature, so active modes send LPM.dev Registry auth; run lpm login locally, or use LPM_TOKEN / registry-audience OIDC in CI. monitor warns and continues when entitlement is denied, while enforce blocks packages whose effective firewall action is block or denied by entitlement before the source tarball is downloaded or copied. In human output, the source-package download line shows ๐ฅ LPM Firewall active when that check is active. LPM.dev Registry packages and other .npmrc-declared private/custom registry packages are not sent to the npm firewall verdict API. Dependencies installed after a config-aware source copy use the normal install pipeline and its firewall checks. The legacy string report is still accepted as a monitor alias.
Examples
lpm add @lpm.dev/owner.ui-kit # add an LPM.dev Registry package
lpm add @lpm.dev/owner.ui-kit@1.2.0 # add a specific version
lpm add @lpm.dev/owner.ui-kit?component=dialog # add only one component
lpm add lodash.merge # add an npm package's source
lpm add @my-co/internal --path ./src/vendor # custom destination
lpm add my-pkg --dry-run # preview without writing
lpm add @lpm.dev/owner.ui-kit --no-skills # skip package skills onceHow it works
- Resolves the spec against the appropriate registry.
- Downloads the tarball into a temporary file and extracts it to a tempdir. Unlike
lpm install, the tarball is not persisted to~/.lpm/store/โlpm addis a copy-and-discard flow. Re-runninglpm addre-downloads. - Picks where to put the files. With
--path, honors it. Without--pathin a TTY (and not--yes/--json), prompts for an install directory. Non-interactive (--yes,--json, or non-TTY) requires--pathfor simple-path packages (nolpm.config.json); config-aware packages auto-detect from their declared ecosystem. - Copies the source into the destination, prompting on conflicts.
- If the package declares an
lpm.config.json, runs the package's configured install steps (component selection, alias rewrites, dep installation). If not, it's a plain source copy and you handle dependencies yourself.
lpm add does not auto-install bare imports it discovers in the copied source. It will surface them at the end of the run so you can add them yourself.
With the default --pm lpm, declared dependencies honor the same minimum release age policy as lpm install. A bare dependency or name@latest selects the newest version old enough to install, then saves the project range from that selected version. An author-written range such as name@^1.11.5 remains unchanged: fallback can only select older versions that still satisfy that range. If no mature version satisfies it, lpm add fails and restores the copied files, package.json, and lockfiles to their pre-add state.
Human output is structured around the source-copy flow:
โบ Downloading source package source-pkg@1.0.0
โบ Detecting project structure
Framework: Vite
Install path: src/components
Import alias: @/src/components/
โ Files copied
+ Foo.tsx
โบ Installing declared dependencies
+ lucide-react@^0.400.0
โ Done ยท added 1 file and 1 dependency in 486msFile conflicts use a slim warning line (! File exists: ...) before the interactive choice.
Config-aware vs simple copy
A package becomes "config-aware" by shipping an lpm.config.json at the tarball root. That file declares components, dependencies to auto-install, import aliases, and editor integration hints. Without it, lpm add is a plain source copy โ useful for any tarball, not just LPM.dev Registry packages.
For @lpm.dev/* source packages, lpm add also reconciles package-published agent guidance into .lpm/skills/<package>/ by default. Use --no-skills to skip that step once, or lpm config lpm-skills --set false to persist the preference. --skills overrides the persistent opt-out for one run. The setting does not delete existing package skills or affect explicit lpm skills add commands; see AI agent skills.
Swift packages
For Swift packages, prefer lpm install โ it's the right command for SPM dependencies (resolves through the SE-0292 registry and edits Package.swift). lpm add still works for Swift sources today and respects --target for Xcode-target wiring, but consider it the legacy path for that ecosystem.
Authoring config-aware packages: lpm.config.json
Ship lpm.config.json at the root of your tarball to control how lpm add extracts your package. With the file present, lpm add becomes a configurable installer โ interactive prompts, conditional file copying, conditional dependency injection, import-path rewriting.
Install the lpm-guide skill if you want an agent to draft the config from your source tree:
npx skills add lpm-dev/lpm-guideThen paste a prompt like this into your agent:
Use the lpm-guide skill's Source Config workflow. Inspect this package's source tree and generate an lpm.config.json for a configurable source package.
Identify the options consumers should choose, such as components, styling framework, variants, or optional examples. Use required fields when choices would conflict, add defaultConfig so lpm add --yes works, map files[] from the package root to the consumer install path, declare conditional dependencies, and include example lpm add commands with query params.{
"$schema": "https://cli.lpm.dev/schemas/lpm.config.json",
"ecosystem": "js",
"importAlias": "@/",
"configSchema": {
"component": {
"type": "select",
"label": "Which component?",
"options": ["dialog", "popover"],
"default": "dialog",
"required": true
},
"withTests": { "type": "boolean", "label": "Include tests?", "default": false }
},
"files": [
{ "src": "src/dialog/**", "dest": "dialog", "include": "when",
"condition": { "component": "dialog" } },
{ "src": "tests/**", "dest": "__tests__", "include": "when",
"condition": { "withTests": true } }
],
"dependencies": {
"withTests": { "true": ["vitest"] }
}
}The full schema reference โ every field, every value type, every default โ lives at lpm.config.json. The published JSON Schema at https://cli.lpm.dev/schemas/lpm.config.json drives editor autocomplete (add $schema as shown above).
Pre-answering prompts
Prompts can be pre-answered from the CLI by appending ?key=value&key=value to the package spec:
lpm add @lpm.dev/owner.ui-kit?component=dialog&styling=pandaInline values bypass the prompt entirely. With --yes, prompts are skipped and defaultConfig / configSchema.<field>.default fill in any required fields the user didn't supply.
Behavior matrix
| State | What lpm add does |
|---|---|
No lpm.config.json | Plain copy of the package's source. No prompts. No auto-install. Surfaces bare imports for you to install yourself. |
lpm.config.json present, TTY | Prompts for every configSchema key not already inlined; copies per files[] rules; installs dependencies matching the chosen values. |
lpm.config.json present, --yes / --json / non-TTY | Skips prompts; uses defaults for required fields; copies per matching rules; installs deps. |
Prerequisites
If the source package declares dependencies (config-driven or via its own package.json), your project must already have a package.json. lpm add runs a preflight check before copying any files and exits early with a remediation hint if the manifest is missing โ there's nowhere for the dep entries to land otherwise, and we'd rather fail loudly than copy source files you can't import from.
$ lpm add @author/ui-kit
error: this source package declares dependencies, but the project has no
`package.json` to record them in.
Run `lpm init` (or `npm init -y`) first to create a manifest, then
re-run `lpm add`.
To copy the source files without installing the declared dependencies,
pass `--no-install-deps` and resolve the imports yourself.If you only want the source files (and you'll handle the imports yourself), pass --no-install-deps to skip the preflight and let the copy proceed without touching package.json.
Flags
| Flag | Effect |
|---|---|
--path <DIR> | Target directory (overrides interactive prompt and auto-detection) |
-y, --yes | Skip interactive prompts, use defaults |
--force | Overwrite existing files without prompting |
--dry-run | Show what would be done without writing anything |
--no-install-deps | Skip dependency installation after copy (for config-aware packages) |
--skills | Install package-published LPM.dev skills for this invocation, overriding user config |
--no-skills | Skip package-published LPM.dev skill auto-install for this invocation |
--no-editor-setup | Compatibility flag. Package skills do not create editor integrations. |
--pm <NAME> | Package manager for dep installation (lpm, npm, pnpm, yarn, bun, auto; default lpm) |
--alias <ALIAS> | Import alias prefix (e.g., @/components) โ overrides auto-detection |
--target <NAME> | Swift SPM target name (Swift packages only) |
--no-engine-strict | Use warning-only root checks and, when LPM installs dependencies, dependency checks (see lpm install). Root preflight runs before any manifest mutation, so a constraint violation can't leave the project half-modified. |
Plus the global flags.
See also
lpm removeโ undo anlpm addlpm installโ install runtime dependencies- Registries โ how packages route
- Swift Package Registry โ SE-0292 design and the
lpm install-preferred path for Swift