lpm add
Copy package source into your project, configure its files, and update tracked source safely.
lpm add copies source files into your project so you can edit and commit them with your application.
lpm add [OPTIONS] <PACKAGE>Use lpm install to add runtime dependencies to node_modules.
lpm add supports registry package names, versions, and tags from npm, LPM.dev Registry, and private registries through .npmrc.
Only @lpm.dev/* packages always use LPM.dev Registry. See Registries.
Quickstart
Try this public source package:
lpm-source-packageA configurable source package to try with lpm add.Visitlpm add lpm-source-package --yesFor a package without source configuration, provide a destination:
lpm add lodash.merge --path src/vendor/lodash-merge --yesRun the command from the project or workspace member that must receive the files.
lpm add uses the nearest directory with a package.json, as lpm install does. From a subdirectory, it prints the directory it chose.
Without a package.json above the current directory, the current directory is the project.
Choose a delivery mode
| Package contents | Behavior |
|---|---|
A root lpm.config.json | Apply file mappings, configuration values, import rewrites, and declared dependencies. |
No lpm.config.json | Copy source files and report external imports. No automatic dependency installation. The copy leaves out package.json and lpm.config.json files, the package's lpm-skills/ and its own lpm.lock, lpm.lockb, lpm-sources.json, lpm-agent-skills.json and lpm-changes/, files or directories, and .lpm, node_modules and .git at any depth, under any spelling a file system takes for those names or Git reads as .git, and test, tests, and __tests__ directories. |
| A Swift source package | Copy Swift source and its LPM.dev Registry source dependencies. See Swift packages. |
Configuration
lpm.json has no source-delivery configuration block.
The publisher's lpm.config.json controls file selection, configuration prompts, dependency declarations, and import aliases.
A valid file activates this behavior regardless of its optional type value.
Without --path, configured packages detect a destination from the project structure and declared ecosystem.
Interactive JavaScript commands ask for a destination and offer the detected path as the default.
For plain copies, an interactive command also asks for a destination.
Non-interactive commands require --path for plain copies.
lpm add '@lpm.dev/owner.ui-kit?component=dialog' --yes
lpm add @my-co/internal --path src/vendor --yes
lpm add @my-co/internal --path "src/shared UI" --yes--path overrides the automatic or interactive destination. Like other paths you type, it is relative to the directory where you run the command. The interactive prompt's default and answer are relative to the project directory.
Paths must remain inside the project, including through symbolic links. .lpm is reserved for project state, nothing is delivered into a .git directory at any depth, where a file such as a hook would run with the next Git command, or into a directory Git reads as a Git directory under another name, such as a bare repository at vendor/tool.git, and a delivery to one of the project's own LPM records at its root (lpm.lock, lpm.lockb, lpm-sources.json, lpm-agent-skills.json, lpm-changes/), or into a directory under one of those names, is refused, under any spelling a file system takes for the record: another letter case, ſ for s, or with a character HFS+ or a Linux casefold directory leaves out of names, such as a zero-width mark. The .lpm check reads names the same way, and the .git check also takes the spellings Git reads as .git on every platform: .git., .git , git~1, and .git followed by a stream name. On a volume that makes short names (NTFS, FAT), from Windows or another system, the short name of each, such as LPM~1.LOC for lpm.lock, is refused where the name itself is. These checks go by names, links and what a Git directory holds, not by mounts: a mount you place at a destination, such as a bind mount of another directory, receives what lpm add writes there, as it would from any other tool.
Source packages cannot map multiple files to the same destination. A file destination cannot also serve as another file's directory.
Pre-answer prompts
Append query values to the package argument:
lpm add '@lpm.dev/owner.ui-kit?component=dialog&styling=panda' --yes
lpm add '@lpm.dev/owner.ui-kit?name=Team%27s+UI&components=dialog%2Cpopover' --yes
lpm add '@lpm.dev/owner.ui-kit?components=&withTests=false' --yesQuote the full argument so the shell preserves &.
Encode punctuation in values: %26 for &, %2B for +, and %27 for an apostrophe.
A + means a space. LPM CLI decodes each key and value once, then rejects malformed escapes or duplicate keys.
Inline values take precedence over defaultConfig, then the field's default.
An empty optional multi-select, such as components=, selects nothing and overrides its default.
A required selection cannot be empty.
Interactive commands prompt for fields without inline values.
--yes, --json, and commands without a terminal apply defaults and reject required fields without a usable value.
--yes does not authorize file overwrites.
Override import aliases
LPM CLI uses the publisher's import alias and the project's TypeScript or JavaScript configuration to rewrite mapped imports.
lpm add @lpm.dev/owner.ui-kit --path src/components --alias '@/components' --yes--alias overrides alias detection for this run.
Mapped JavaScript imports retain runtime extensions such as .js and .mjs.
Source delivery also preserves executable permissions on Unix systems. Directories it creates are made as mkdir makes them: with the mode your umask gives, and the access list entries the directory above passes on.
Examples
lpm add @lpm.dev/owner.ui-kit@1.2.0 --yes
lpm add @my-co/internal --path src/vendor --dry-run --json
lpm add @lpm.dev/owner.ui-kit --no-install-deps --yes
lpm add @lpm.dev/owner.ui-kit --pm auto --yes
lpm add @lpm.dev/owner.ui-kit --no-skills --yesUpdates and file conflicts
To update tracked source, run lpm add with the new version and the intended destination:
lpm add @lpm.dev/owner.ui-kit@1.2.1 --path src/components --dry-run --yes
lpm add @lpm.dev/owner.ui-kit@1.2.1 --path src/components --yesIf cached metadata lacks the requested version, LPM CLI refreshes metadata once before it reports that version unavailable. Each add downloads and extracts the source package again. Source tarballs do not enter the dependency store.
| Existing file | Default behavior |
|---|---|
| No file | Create it. |
| Tracked file with unchanged installed contents | Update it, or skip it if the new contents match. |
| Edited or untracked file | Ask interactively. Preserve it in a non-interactive command. |
| Previously tracked file absent from the new selection | Remove an unchanged created file, or restore its saved original after an overwrite. |
| Stale file that is edited, shared, or lacks ownership evidence | Preserve it. |
Use --force to overwrite file conflicts:
lpm add @lpm.dev/owner.ui-kit --path src/components --force --yesLPM CLI tracks delivered files for later updates and lpm remove in lpm-sources.json at the project root.
Commit it with the copied files. It records each source package's version, delivered files with their digests, created directories, inserted dependencies, and package skills.
Copies of the files an add overwrote stay in .lpm/added-source-backups/ on the machine that made them. On another checkout, lpm remove keeps such a file and asks you to restore the original from version control.
A .lpm/added-sources.json record from an earlier release is still read and replaced by lpm-sources.json on the next add or removal.
See Files LPM CLI creates.
Preview changes
lpm add @lpm.dev/owner.ui-kit --dry-run --yes
lpm add @lpm.dev/owner.ui-kit --dry-run --json--dry-run resolves and downloads the source package, but does not change project files or run a package manager.
It shows incoming file actions, stale-file actions, declared dependency counts, and tracked dependencies to remove.
Swift previews also include recursive source dependencies.
Preview uses the non-interactive conflict policy: preserve unmanaged or edited files unless --force is present.
It applies import rewrites before it compares contents.
A successful preview does not guarantee that dependency resolution, engine checks, or a later installation will succeed.
JSON output is one document. files paths are relative to target.
Optional stale_files paths are relative to the project.
Optional dependencies_removed lists dependency names, sections, and saved specifications.
Optional source_dependencies contains the Swift child previews.
If an earlier operation requires recovery, preview stops without changing that recovery state.
Run a regular add or lpm remove to recover first.
Dependencies
Configured packages can declare conditional dependencies in lpm.config.json.
If that field is absent, LPM CLI uses the source package's dependencies and peerDependencies.
An explicit empty dependencies field disables this fallback.
Plain copies never install dependencies automatically.
If the selected source declares dependencies, the receiving project must already have package.json.
LPM CLI stops before it copies files if that manifest is missing.
lpm init
lpm add @lpm.dev/owner.ui-kit --yesTo manage dependencies yourself, skip consumer dependency changes:
lpm add @lpm.dev/owner.ui-kit --no-install-deps --yesThis flag skips both dependency installation and stale dependency removal.
Earlier dependency ownership remains tracked for future updates or lpm remove.
Swift source dependencies still copy recursively.
Choose a package manager
lpm add @lpm.dev/owner.ui-kit --pm pnpm --yes
lpm add @lpm.dev/owner.ui-kit --pm auto --yesThe default is --pm lpm.
auto looks for pnpm, Yarn, Bun, then npm lockfiles. Without a recognized lockfile, it selects LPM CLI.
Other package managers must be available and apply their own dependency and lifecycle-script rules.
With --pm lpm, dependencies use the normal install policies.
The minimum release age policy also applies to the selected source package.
Bare dependency names select an eligible version and save the resulting range.
Explicit ranges remain unchanged and only accept eligible versions within that range.
An update removes a stale dependency only if source tracking owns it and its saved section and specification still match. Edited and pre-existing dependency declarations remain in place. Other source packages can retain shared dependency ownership.
Registry security and package skills
Source downloads require registry integrity metadata or a checksum. The typosquat guard is disabled by default. If enabled, it checks source package names before registry requests.
For routed public npm packages, active LPM Firewall modes check the source package.
monitor downloads while the check runs and warns before any files are copied. enforce finishes the check before download, blocks denied packages, and requires an eligible LPM.dev Registry account.
Private registry packages and LPM.dev Registry packages do not use the public npm verdict API.
For @lpm.dev/* packages, source delivery installs package-published skills by default.
A skills failure produces a warning after the source copy.
lpm add @lpm.dev/owner.ui-kit --no-skills --yes
lpm config lpm-skills --set false
lpm add @lpm.dev/owner.ui-kit --skills --yes--no-skills skips skills once. The configuration command changes the persistent default.
--skills overrides that default once. These controls do not remove existing skills.
lpm-sources.json records which package's skills an add installed. An online lpm install in another checkout restores them at the recorded version. If the package is also a direct dependency, the install uses the dependency's version instead.
lpm remove removes the skills unless the package is still a dependency.
See AI agent skills.
Swift packages
Use lpm install for Swift registry dependencies and Package.swift changes.
lpm add remains a legacy path for Swift source delivery.
lpm add @lpm.dev/owner.swift-components --target App --yes--target adds a destination suffix: Sources/App for SPM projects or Packages/LPMComponents/Sources/App for Xcode projects.
It does not edit Package.swift or connect an Xcode target.
--path overrides the automatic destination.
Swift source dependencies from LPM.dev Registry copy recursively, including with --no-install-deps.
LPM CLI rejects incompatible version requirements and avoids repeated delivery through dependency cycles.
Interruption recovery
After an interrupted add, run lpm add again or run lpm remove.
LPM CLI recovers copied files, overwrite backups, source tracking, and staged manifests before the next operation.
Recovery removes newly created directories only when they are empty.
It also restores original directories that source updates removed, including paths that a recursive source dependency reused.
If you edited a copied file after the interruption, recovery stops and preserves your edits.
Save those edits separately.
The error identifies the recovery directory under .lpm/install-recovery/.
Its matching JSON record identifies the source path, and its .original file contains the original bytes.
Restore those bytes and permissions, or remove a new file that had no original. Then retry the command.
Keep the recovery directory until recovery succeeds.
A hard stop can leave dependency lockfiles or node_modules changed.
Run lpm install after source recovery to reconcile dependency state.
Publish a configured source package
For a complete author workflow, see Source packages. The guide covers package files, consumer choices, publication, and agent prompts.
Include lpm.config.json at the root of the published package:
{
"$schema": "https://cli.lpm.dev/schemas/lpm.config.json",
"ecosystem": "js",
"importAlias": "@/",
"configSchema": {
"component": {
"type": "select",
"options": ["dialog", "popover"],
"default": "dialog",
"required": true
}
},
"files": [
{
"src": "src/dialog/**",
"dest": "dialog",
"include": "when",
"condition": { "component": "dialog" }
},
{
"src": "src/popover/**",
"dest": "popover",
"include": "when",
"condition": { "component": "popover" }
}
],
"dependencies": {}
}The full schema reference covers supported fields, conditions, defaults, and dependency selection.
The published schema supplies editor autocomplete through $schema.
Flags
| Flag | Effect |
|---|---|
--path <PATH> | Override the destination directory. |
-y, --yes | Skip prompts and use configuration defaults. Preserve file conflicts unless --force is present. |
--force | Overwrite file conflicts without a prompt. |
--dry-run | Preview source actions without project changes or dependency installation. |
--no-install-deps | Skip consumer dependency changes. Still copy Swift source dependencies. |
--skills | Install package-published skills for this run, overriding the persistent default. |
--no-skills | Skip automatic package skills for this run. Conflicts with --skills. |
--pm <PM> | Dependency manager: lpm, npm, pnpm, yarn, bun, or auto. Default: lpm. |
--alias <ALIAS> | Override the import alias prefix. |
--target <NAME> | Add a suffix to the automatic Swift source destination. |
--no-engine-strict | Warn on root engine mismatches. Also relax dependency checks when LPM CLI installs dependencies. |
See global flags for --json and registry overrides.
See also
lpm remove— remove tracked source and restore saved originalslpm install— install runtime or Swift registry dependencieslpm.config.json— configure a published source package- Source packages — prepare a package for source delivery
- Registries — configure package routing and credentials
- Swift Package Registry — use Swift registry packages