Actions
Try it — click test or Deploy to Production in the app below. Actions with confirm: true ask before running; everything else just runs.
name: myapp
root: ~/Projects/myapp
services:
web: npm run dev
actions:
test: npm test # shorthand
deploy: # full form
cmd: ./scripts/deploy.sh
label: Deploy to Production # display name in the UI
confirm: true # ask before running
display: header # main button row (default; omit to get the same)
env:
NODE_ENV: production
cmdstringThe shell command to run — whatever you’d type into a terminal yourself. Required unless the action groups child actions with
actionsbelow.labelstringThe friendly name shown on the button. If you skip it, lpm shows the action’s key as-is —
db-resetstaysdb-reset, whilelabel: Reset DBreads better.emojistringA single emoji shown in front of the label, so a crowded toolbar stays scannable. It’s prefixed to whatever the label resolves to —
emoji: 🚀withlabel: Deployrenders as🚀 Deploy.cwdstringRun the command from a different folder than the project root — useful for monorepos or when the action lives in a subfolder. Relative paths resolve from
root; absolute paths are used as-is (see Path resolution). Nested actions inherit this from their parent.envmapExtra environment variables to set just for this action — handy for one-off flags like
NODE_ENV=production. Nested actions inherit these from their parent.confirmboolShow a confirmation dialog before running. Turn this on for anything you’d regret clicking by accident — deletes, resets, production deploys.
displaystringWhere the action appears. The default,
header, pins it to the project toolbar so it’s always one click away — omitdisplayentirely to get the same result.footertucks it into the status bar below the terminal — handy for tight, always-visible controls. Or name a zone to put the button in it.menustill works as a legacy value (overflow menu) but is no longer suggested by the editor.typestringHow the action runs. The default pops open a modal and streams output while the command runs.
terminalopens a persistent interactive pane (see the Terminals section below).backgroundruns the command hidden behind a small live card that counts the time, keeps the output a click away with Cancel and Copy output, and shows success or failure when it finishes — perfect for slow, boring commands whose only interesting signal is “did it succeed.”commandtypes the command into the terminal you have focused.actionsmapGroup related commands under this action. They show up as a dropdown. If the parent also has a
cmd, it renders as a split button — clicking the main part runs the parent, clicking the chevron opens the group.primarystringOnly for actions with nested
actions: which child the main half of the split button runs. Name a child’s key (primary: staging) to pin it, or uselast-usedso the button follows whichever child you ran most recently — remembered per project on that computer. It takes precedence over the parent’s owncmd.
| Field | Type | Description |
|---|---|---|
cmd | string | The shell command to run — whatever you’d type into a terminal yourself. Required unless the action groups child actions with actions below. |
label | string | The friendly name shown on the button. If you skip it, lpm shows the action’s key as-is — db-reset stays db-reset, while label: Reset DB reads better. |
emoji | string | A single emoji shown in front of the label, so a crowded toolbar stays scannable. It’s prefixed to whatever the label resolves to — emoji: 🚀 with label: Deploy renders as 🚀 Deploy. |
cwd | string | Run the command from a different folder than the project root — useful for monorepos or when the action lives in a subfolder. Relative paths resolve from root; absolute paths are used as-is (see Path resolution). Nested actions inherit this from their parent. |
env | map | Extra environment variables to set just for this action — handy for one-off flags like NODE_ENV=production. Nested actions inherit these from their parent. |
confirm | bool | Show a confirmation dialog before running. Turn this on for anything you’d regret clicking by accident — deletes, resets, production deploys. |
display | string | Where the action appears. The default, header, pins it to the project toolbar so it’s always one click away — omit display entirely to get the same result. footer tucks it into the status bar below the terminal — handy for tight, always-visible controls. Or name a zone to put the button in it. menu still works as a legacy value (overflow menu) but is no longer suggested by the editor. |
type | string | How the action runs. The default pops open a modal and streams output while the command runs. terminal opens a persistent interactive pane (see the Terminals section below). background runs the command hidden behind a small live card that counts the time, keeps the output a click away with Cancel and Copy output, and shows success or failure when it finishes — perfect for slow, boring commands whose only interesting signal is “did it succeed.” command types the command into the terminal you have focused. |
actions | map | Group related commands under this action. They show up as a dropdown. If the parent also has a cmd, it renders as a split button — clicking the main part runs the parent, clicking the chevron opens the group. |
primary | string | Only for actions with nested actions: which child the main half of the split button runs. Name a child’s key (primary: staging) to pin it, or use last-used so the button follows whichever child you ran most recently — remembered per project on that computer. It takes precedence over the parent’s own cmd. |
More fields. The table above covers what the examples on this page use. Actions also take these, and the app’s action editor sets most of them for you:
colorstringAn accent for the button and the tab it opens: a name like
blue,claudeorrose, the same name plus-deep, or any CSS color (quote a leading#).shortcutstringA key combo that runs the action while the project is open, like
cmd+shift+b.inputsmapValues lpm asks for before running — text, password, or a choice of options — filled into the command wherever
{{key}}appears.promptstringOn a terminal that starts Claude Code, Codex, Gemini CLI, or OpenCode: the task sent to the agent once it’s ready.
reuseboolOn a terminal: use the pane that’s already open instead of opening a new one each click.
labelRefreshstringHow often commands in a
labeloremojirun, like5m. See dynamic labels below.positionnumberOrder among the buttons of its bar, or inside its zone. Lower comes first.
portnumber | listPorts that must be free before running: a number, a range like
"3002-3010", or a list.portConflictsays what to do when one is taken:ask,free, orfail.modestringSSH projects only:
remoteruns on the host;synccopies the project here, runs the command on this computer, and syncs the changes back.
| Field | Type | Description |
|---|---|---|
color | string | An accent for the button and the tab it opens: a name like blue, claude or rose, the same name plus -deep, or any CSS color (quote a leading #). |
shortcut | string | A key combo that runs the action while the project is open, like cmd+shift+b. |
inputs | map | Values lpm asks for before running — text, password, or a choice of options — filled into the command wherever {{key}} appears. |
prompt | string | On a terminal that starts Claude Code, Codex, Gemini CLI, or OpenCode: the task sent to the agent once it’s ready. |
reuse | bool | On a terminal: use the pane that’s already open instead of opening a new one each click. |
labelRefresh | string | How often commands in a label or emoji run, like 5m. See dynamic labels below. |
position | number | Order among the buttons of its bar, or inside its zone. Lower comes first. |
port | number | list | Ports that must be free before running: a number, a range like "3002-3010", or a list. portConflict says what to do when one is taken: ask, free, or fail. |
mode | string | SSH projects only: remote runs on the host; sync copies the project here, runs the command on this computer, and syncs the changes back. |
Dynamic labels. A label can keep itself current: the branch with {{git.branch}}, your last release and how long ago it was with {{git.tag}} and {{git.tagAge}}, or whatever a command prints with $(…), refreshed on a timer or the moment the code changes. The lesson below sets one up and has Claude Code add another:
Shorthand. If all your action needs is a command, write it as a single line — the key becomes the label and you skip the nested form entirely. Great for everyday dev commands:
name: myapp
root: ~/Projects/myapp
services:
web: npm run dev
actions:
test: npm test
lint: npm run lint
build: npm run build
typecheck: npx tsc --noEmit
format: npx prettier --write .
Destructive actions. For anything you don’t want to click by accident — cache wipes, rollbacks, production deploys — add confirm: true to get a confirmation dialog, and pair it with display: header (the default) so the action lives in the toolbar where you’ll find it:
name: myapp
root: ~/Projects/myapp
services:
web: npm run dev
actions:
reset-cache:
cmd: rm -rf .next node_modules/.cache
label: Reset Cache
confirm: true
display: header
rollback:
cmd: ./scripts/rollback.sh
label: Rollback Deploy
confirm: true
env:
NODE_ENV: production
Grouping related actions. Give a parent action both a cmd and nested actions and lpm renders it as a split button: the main part runs the parent’s command, the chevron opens a menu with the children. Use this when there’s a sensible default plus a few alternatives — like “Deploy staging” with production and preview tucked behind it:
name: myapp
root: ~/Projects/myapp
services:
web: npm run dev
actions:
deploy:
cmd: ./deploy.sh staging # split button — main click runs this
label: Deploy
emoji: 🚀 # icon shown next to the label
display: header
confirm: true
actions: # chevron opens these
production:
cmd: ./deploy.sh production
label: Production
emoji: 🔴
confirm: true
preview:
cmd: ./deploy.sh preview
label: Preview
emoji: 👁️
Remembering your last choice. Add primary: last-used instead of a parent cmd and the main part of the split button becomes whichever option you clicked last — deploy to staging once, and the button reads “Staging” until you pick something else. Set primary to a child’s name (like primary: staging) to pin one option as the default instead:
name: myapp
root: ~/Projects/myapp
services:
web: npm run dev
actions:
deploy:
primary: last-used # main click repeats the last used option
actions: # chevron opens these
staging:
cmd: ./deploy.sh staging
label: Staging
emoji: 🟢
production:
cmd: ./deploy.sh production
label: Production
emoji: 🔴
confirm: true
Dropdown-only groups. Drop the parent’s cmd and the whole button becomes a dropdown. Good for a set of related commands with no obvious default — like a database toolkit (Migrate, Seed, Reset):
name: myapp
root: ~/Projects/myapp
services:
web: npm run dev
actions:
db:
label: Database
emoji: 🗄️
display: header
cwd: ./backend
actions:
migrate:
cmd: python manage.py migrate
label: Migrate
emoji: 📦
seed:
cmd: python manage.py seed
label: Seed
emoji: 🌱
reset:
cmd: python manage.py flush
label: Reset
emoji: 💣
confirm: true
Background actions. For slow, boring commands where the only thing you care about is whether they succeeded — builds, migrations, docker pulls, git fetch — add type: background. The command runs hidden while a small live card counts the time and keeps its output a click away, with Cancel and Copy output, then shows success or failure when it’s done. No modal to dismiss, no terminal tab to clean up, and you can fire several in parallel while you keep working:
name: myapp
root: ~/Projects/myapp
services:
web: npm run dev
actions:
db-reset:
cmd: npm run db:reset && npm run db:seed
label: Reset DB
type: background # runs hidden, with a live progress card
confirm: true # pair with confirm for destructive ones
A note on inheritance
Nested actions inherit cwd and env from their parent unless they override them. Set cwd: ./backend on the parent once and every child runs from there — no need to repeat yourself.