Source Configuration
The lpm.config.json file makes source packages configurable. It controls how lpm add filters and delivers source files to consumers.
Tip: The LPM Guide skill can generate
lpm.config.jsonfor you. Install it withnpx skills add lpm-dev/lpm-guide, then ask your AI coding agent to "generate lpm config" - it will analyze your package structure and create the right configuration automatically.
Place it alongside your package.json:
my-package/
├── package.json
├── lpm.config.json
├── components/
│ ├── dialog/
│ └── button/
├── styles/
│ ├── panda.config.js
│ └── tailwind.config.js
└── lib/
└── utils.js
Consumer Experience
When someone runs lpm add, the CLI reads your config and prompts interactively:
# Interactive — prompts for each option
lpm add @lpm.dev/acme.ui-kit
# URL params — pre-configured, skips prompts
lpm add "@lpm.dev/acme.ui-kit?component=dialog,button&styling=panda"
# Use defaults, skip all prompts
lpm add @lpm.dev/acme.ui-kit --yes
Config Schema
Define interactive prompts with configSchema. Each key becomes a config parameter.
{
"configSchema": {
"component": {
"type": "select",
"multiSelect": true,
"label": "Which components do you want?",
"options": [
{ "value": "dialog", "label": "Dialog" },
{ "value": "button", "label": "Button" },
{ "value": "tabs", "label": "Tabs" }
]
},
"styling": {
"type": "select",
"required": true,
"label": "Styling framework",
"options": [
{ "value": "panda", "label": "Panda CSS" },
{ "value": "tailwind", "label": "Tailwind CSS" }
],
"default": "panda"
},
"darkMode": {
"type": "boolean",
"label": "Include dark mode styles?",
"default": true
}
}
}
Field Types
| Type | UI | Value format |
|---|---|---|
select | Single-choice dropdown | "panda" |
select + multiSelect: true | Checkbox list | "dialog,button" |
boolean | Yes/No | "true" / "false" |
Schema Properties
| Property | Type | Description |
|---|---|---|
type | "select" or "boolean" | Field type |
label | string | Display label for the prompt |
options | array | For select type. Array of { value, label } objects or plain strings |
multiSelect | boolean | Show checkbox UI instead of radio |
required | boolean | Consumer must provide a value. Prevents include-all behavior |
default | any | Default value when consumer doesn't choose |
File Rules
The files array controls which files get copied and where.
{
"files": [
{
"src": "components/dialog/**",
"dest": "components/ui/dialog/",
"include": "when",
"condition": { "component": "dialog" }
},
{
"src": "lib/utils.js",
"dest": "lib/utils.js",
"include": "always"
},
{
"src": "internal/test-utils.js",
"include": "never"
}
]
}
File Rule Properties
| Property | Type | Description |
|---|---|---|
src | string | Source path relative to package root. Supports ** glob |
dest | string | Destination path. If omitted, uses src. If ends with /, preserves filename |
include | string | "always" (default), "never", or "when" |
condition | object | Required when include is "when". Key-value pairs with AND logic |
Include Behavior
| Value | Behavior |
|---|---|
always | Always included (default) |
never | Never included - exclude internal/test files |
when | Included only when condition matches |
Include-All by Default
When a condition key is not provided by the consumer (not in URL params, not answered in prompts), the file is included regardless of the condition value:
# No component filter → ALL components installed
lpm add "@lpm.dev/acme.kit?styling=panda"
# Only dialog installed
lpm add "@lpm.dev/acme.kit?component=dialog&styling=panda"
# Dialog + button installed
lpm add "@lpm.dev/acme.kit?component=dialog,button&styling=panda"
Use required: true on fields where include-all doesn't make sense (e.g., styling where panda and tailwind configs would conflict at the same destination path).
Import Alias
The importAlias field enables smart import rewriting. Declare the alias prefix you use during development:
{
"importAlias": "@/"
}
How It Works
When you develop your package, you write imports naturally - relative or with your configured alias:
// Author writes (with @/ alias configured in tsconfig):
import { cn } from "@/lib/cn"
import Icon from "@/atoms/Icon"
When a consumer runs lpm add, the CLI prompts for their import alias:
? Import alias for this directory? @/components/design-system
The CLI rewrites every internal import to use the consumer's alias:
// Consumer gets:
import { cn } from "@/components/design-system/lib/cn"
import Icon from "@/components/design-system/atoms/Icon"
External imports (react, next/link, @radix-ui/dialog) are never touched.
Without importAlias
If you don't set importAlias, the CLI still asks the consumer for their alias. Relative imports between internal files are rewritten to use the consumer's alias when provided. If the consumer skips the alias prompt, relative imports are left as-is.
When to Use
- Use when your package has multiple files that import each other
- Use when you use alias imports (like
@/) during development - Not needed for single-file packages or packages with no internal cross-references
Conditional Dependencies
Declare npm dependencies that should be installed based on config choices:
{
"dependencies": {
"styling": {
"panda": ["@pandacss/dev"],
"tailwind": ["tailwindcss", "autoprefixer"]
},
"iconLibrary": {
"lucide": ["lucide-react"],
"heroicons": ["@heroicons/react"]
}
}
}
Regular npm packages are installed via the detected package manager. @lpm.dev/ packages are shown as manual install commands.
Default Config
Provide defaults so the --yes flag works without prompts:
{
"defaultConfig": {
"styling": "panda",
"baseColor": "neutral"
}
}
Full Example
A complete lpm.config.json:
{
"importAlias": "@/",
"configSchema": {
"component": {
"type": "select",
"multiSelect": true,
"label": "Components",
"options": [
{ "value": "dialog", "label": "Dialog" },
{ "value": "button", "label": "Button" }
]
},
"styling": {
"type": "select",
"required": true,
"label": "Styling Framework",
"options": [
{ "value": "panda", "label": "Panda CSS" },
{ "value": "tailwind", "label": "Tailwind CSS" }
],
"default": "panda"
}
},
"defaultConfig": {
"styling": "panda"
},
"files": [
{
"src": "components/dialog/**",
"dest": "components/ui/dialog/",
"include": "when",
"condition": { "component": "dialog" }
},
{
"src": "components/button/**",
"dest": "components/ui/button/",
"include": "when",
"condition": { "component": "button" }
},
{
"src": "lib/tokens.js",
"dest": "lib/tokens.js",
"include": "always"
},
{
"src": "styles/panda.config.js",
"dest": "styles/config.js",
"include": "when",
"condition": { "styling": "panda" }
},
{
"src": "styles/tailwind.config.js",
"dest": "styles/config.js",
"include": "when",
"condition": { "styling": "tailwind" }
}
],
"dependencies": {
"styling": {
"panda": ["@pandacss/dev"],
"tailwind": ["tailwindcss"]
}
}
}
Validation Rules
The CLI validates your config and rejects invalid files:
| Rule | Constraint |
|---|---|
| File size | Max 1 MB |
| File rules count | Max 1000 |
src / dest paths | Must be relative, no path traversal (..) |
configSchema types | Must be "select" or "boolean" |
select fields | Must have non-empty options array |
include values | Must be "always", "never", or "when" |
include: "when" | Must have a condition object |
importAlias | Must be a string ending with / |