lpm
Run it natively
Each process gets its own pane. No image, no volume, no container to create — dependsOn for order, profiles for subsets.
Compose gives every machine the same stack, at the cost of a Linux VM, a shared filesystem and a container to create before anything runs. lpm reads the repo, lists the same processes, and runs them straight on the host, one live pane each.
Most people end up splitting it: app code native, stateful infrastructure still in compose.
Facts checked . The file-sharing and rebuild rows were re-checked against Docker's current defaults, not the osxfs era; every lpm cell was re-read in the app source on the same date, after lpm began listing compose files as a service.
The short answer
Yes — for every service your Mac can run directly. Add the folder and lpm lists the processes it recognises — Rails, Django, a Next.js or Vite dev server, Go, and the compose file itself — then starts them together, each in its own live pane, with dependsOn for start order and profiles for subsets of the stack.
What you give up is the container boundary: no pinned image versions, no separate network namespace, and no guarantee that a teammate on Linux gets an identical stack. Which is why most people end up splitting it — application code native, stateful infrastructure still in compose, both started from the same window.
services:
compose: docker compose up
api:
cmd: bin/rails s
port: 3000
dependsOn: [compose]
web:
cmd: npm run dev
port: 5173
dependsOn: [api]
profiles:
backend: [compose, api]Commit it at the repo root and a teammate who clones gets the same graph. lpm still adds what it detects when they add the folder, so they may find a double to delete. Keep the attached form — docker compose up, not -d — if you want the container output in an lpm pane. The config reference documents every field.
lpm
Each process gets its own pane. No image, no volume, no container to create — dependsOn for order, profiles for subsets.
Both
Keep Postgres, Redis or Kafka in containers. Adding the folder already makes docker compose up one lpm service, its output in a pane beside your native ones.
Docker Compose
Prod parity down to the image tag, a teammate whose laptop is not a Mac, or an image there is no native way to install. Five rows in the table go to Compose, and the description names them.
You do not have to move the whole file. This is the mapping for the parts you do move.
| docker compose | lpm | Notes |
|---|---|---|
docker compose up | lpm start | every service in the default profile, one pane each |
docker compose up web | lpm service web start | |
docker compose --profile full up | lpm start --profile full | |
docker compose down | lpm stop | |
docker compose ps | lpm project <name> | services, terminals, actions, live status |
docker compose ls | lpm list | every project, its running state and service counts |
docker compose logs -f web | lpm logs web | prints that pane's recent output; the live follow is the pane itself |
docker compose run --rm web bin/rails db:migrate | an action, or lpm run migrate | |
depends_on: | dependsOn: | start order; cycles are rejected when the config is validated |
healthcheck + condition: service_healthy | lpm wait --port 5432 | an explicit gate rather than a condition on the dependency |
profiles: | profiles: | same idea, same name |
environment: | env: | per service |
ports: "3000:3000" | port: 3000 + portConflict: ask | free | fail | not a mapping — the process binds the host port itself; declaring it lets lpm check the port first and name the process holding it |
committed docker-compose.yml | committed .lpm.yml | merged underneath each developer's own project file, which also holds what lpm detected when they added the folder |
docker compose
docker compose uplpm
lpm startevery service in the default profile, one pane each
docker compose
docker compose up weblpm
lpm service web startdocker compose
docker compose --profile full uplpm
lpm start --profile fulldocker compose
docker compose downlpm
lpm stopdocker compose
docker compose pslpm
lpm project <name>services, terminals, actions, live status
docker compose
docker compose lslpm
lpm listevery project, its running state and service counts
docker compose
docker compose logs -f weblpm
lpm logs webprints that pane's recent output; the live follow is the pane itself
docker compose
docker compose run --rm web bin/rails db:migratelpm
an action, or lpm run migratedocker compose
depends_on:lpm
dependsOn:start order; cycles are rejected when the config is validated
docker compose
healthcheck + condition: service_healthylpm
lpm wait --port 5432an explicit gate rather than a condition on the dependency
docker compose
profiles:lpm
profiles:same idea, same name
docker compose
environment:lpm
env:per service
docker compose
ports: "3000:3000"lpm
port: 3000 + portConflict: ask | free | failnot a mapping — the process binds the host port itself; declaring it lets lpm check the port first and name the process holding it
docker compose
committed docker-compose.ymllpm
committed .lpm.ymlmerged underneath each developer's own project file, which also holds what lpm detected when they added the folder
The lpm column splits in two. lpm start, lpm stop and a service restart are requests to the open lpm window — that is where the panes live, and closing it leaves the services you already started running. lpm list and lpm logs read those services with the window shut. Every field on the right — profiles, dependsOn, env and portConflict — is in the config reference.
Five rows go to Compose: container isolation, identical runtimes and a network namespace of its own outright, plus health-gated start order and pinned image versions on substance. Those five are why the split-stack setup below exists.
| Capability | lpm | Docker Compose |
|---|---|---|
| Starts a multi-service dev stack in one command | click Start, or lpm start with the app open | Yes |
| Declares startup order between services | dependsOn | order + health gate |
| Time from start to services listening | process start | container create + start |
| Rebuild needed when dependencies change | reinstall | image rebuild |
| Reads your source straight off the host filesystem | Yes | through the VM's file sharing |
| Containerized service isolation | No | Yes |
| Pins the exact service version the team runs | whatever is installed on the host | pinned by image tag |
| Identical runtimes on every teammate's machine | No | Yes |
| Own network namespace, so two projects can both use 5432 | No | Yes |
| A live pane per service, open the whole time you work | Yes | docker compose logs, or a container's Logs tab in Docker Desktop |
| Checks a declared port before start and names what holds it | ask, free, or fail | no pre-start check documented |
| Starts, stops and switches between many repos from one window | Yes | docker compose ls lists them; switching means changing directory |
| Service graph committed to the repo | .lpm.yml | docker-compose.yml |
| Turns your compose file into something it runs | adds docker compose up as a service when you add the folder | that file is compose's own input |
| Your coding agent gets a tab next to the service panes | Claude Code and Codex report Working, Needs you or Done | the agent runs in a terminal you open yourself |
| Free to use inside a large company | MIT, at any company size | Compose is Apache-2.0; Docker Desktop needs a paid subscription above Docker's size threshold |
Isolation is where the concessions above bite hardest, and this is the exact position when a second agent needs the same project: copy it and the copy edits its own files, so two agents never save over each other. Nothing else is namespaced — one host, one set of ports, one Postgres — and lpm checks a declared port before the project starts, then tells you which process is holding it. A linked worktree starts from the tracked files only: an ignored .env is not in it, and Node packages are installed only if you turn on Install dependencies. How the copies work.
There is no migration to finish. Compose keeps the services you want pinned; lpm runs the code you edit.
Your Rails or Django server, the Next.js dev server, a Go binary, background workers, anything with a file watcher. Each is one service with a pane of its own; the watcher inside it picks up your edits, and if the process dies its last output stays in the pane until you start it again.
Postgres, Redis, Kafka, Elasticsearch, LocalStack, a vendor image nobody installs natively. lpm lists the compose file as one service in the attached form — compose: docker compose up, not -d — so its output lands in a pane next to the rest.
Add the folder. lpm reads the manifests, lists the native services — with the framework's default port where there is one — and adds docker compose up as one more. Generate with AI in the config editor is there if you want a different first pass.
Move the processes with file watchers out of the compose file and into services:, one at a time.
Leave the rest as a single compose service and bring the project up with one click — or lpm start, with the window open.
Compose profiles have a direct equivalent: named subsets you switch between from the header.
A friendly split. If your daily loop is native code running on your laptop, lpm leans in. If your daily loop depends on containerized infra matching prod, Compose still wins.
A short video: pick a folder or clone a repo, and it joins the sidebar.Click anything — both halves run live in your browser.
lpm is a macOS app with a multi-pane terminal workspace. Open this page on your computer to try the interactive demo.
Get lpm for MacOr check your Macs from your iPhoneClick a step to run it in the window.
Done poking around? Get lpm for Mac and point it at your own projects.
docker compose up, not -d — if you want the container output in an lpm pane; a detached start hands you nothing to watch.docker-compose.yml (or compose.yaml) and lists compose: docker compose up as one service — the attached form, so the container output has a pane — next to the native services it found in the same pass. It does not parse the compose service graph. To split the infrastructure further, edit the list, or press Generate with AI in the config editor for a second draft from Claude Code, Codex, Gemini CLI or OpenCode.What port, portConflict, env, dependsOn and profiles each do inside a project file.
The supervisor question rather than the container one: what keeps a process alive after it dies.
Three ways to start the same handful of processes when the stack is Procfile lines, not images.
Where Claude Code and Codex sit once the services are up, and what their tabs report while they work.
Put the services and the agents on a Linux machine and drive all of it from the Mac app.
Which repos are up right now, which services each one is running, and one click to switch between them.
Add the folder, get a live pane per service, and docker compose up as one of those services when a container is the right answer. Free, open source, native macOS app.