Automatic service detection
Where it looks. The project root first, then every workspace member declared in package.json or pnpm-workspace.yaml, then these subfolders if they exist: api, app, backend, client, frontend, server, ui, web, www, and every folder under apps/ or services/.
What it recognizes. Node commands use the package manager your repo declares or locks. Python commands run through the folder’s .venv (or venv), uv, Poetry, or Pipenv when it has one.
- ProcfileProcfile.dev, else ProcfileOne service per process line; release is skipped
Named the process name · port from the command
- Node.jspackage.json dev, start, or serve script
npm run devor pnpm, yarn, bun — whichever the repo declares or locksNamed web, api, or app · port the script's, else the framework's: Next.js 3000, Vite 5173, Astro 4321…
- Denodeno.json dev, start, or serve task
deno task devNamed app · port from the task
- Djangomanage.py
python3 manage.py runserverNamed web · port 8000
- FastAPIfastapi dependency + an app module like main.py
uvicorn main:app --reloadNamed api · port 8000
- Flaskflask dependency + app.py or wsgi.py
flask run --debugNamed web · port 5000
- RailsGemfile with rails + bin/rails
bin/develse bin/rails serverNamed web · port 3000
- Laravelartisan
php artisan serveNamed web · port 8000
- Phoenixmix.exs with :phoenix
mix phx.serverNamed web · port 4000
- Spring BootSpring Boot in pom.xml or build.gradle
./mvnw spring-boot:runmvn spring-boot:run without mvnw; ./gradlew bootRun for GradleNamed web · port 8080
- .NETa single .csproj
dotnet watch runNamed app · port —
- Gogo.mod
go run .air with an .air.toml; go run ./cmd/<name> per command when there's no main.goNamed app, or the command's name · port from the command
- RustCargo.toml with a binary
cargo runcargo run -p <crate> for each workspace binaryNamed app, or the crate's name · port from the command
- Docker Composecompose.yml or docker-compose.yml
docker compose upNamed compose · port —
- make / justMakefile or justfile, when nothing else matched
make devor just dev; serve, run, and start targets work tooNamed app · port —
| Stack | Runs | Named | Port |
|---|---|---|---|
| ProcfileProcfile.dev, else Procfile | One service per process line; release is skipped | the process name | from the command |
| Node.jspackage.json dev, start, or serve script | npm run devor pnpm, yarn, bun — whichever the repo declares or locks | web, api, or app | the script's, else the framework's: Next.js 3000, Vite 5173, Astro 4321… |
| Denodeno.json dev, start, or serve task | deno task dev | app | from the task |
| Djangomanage.py | python3 manage.py runserver | web | 8000 |
| FastAPIfastapi dependency + an app module like main.py | uvicorn main:app --reload | api | 8000 |
| Flaskflask dependency + app.py or wsgi.py | flask run --debug | web | 5000 |
| RailsGemfile with rails + bin/rails | bin/develse bin/rails server | web | 3000 |
| Laravelartisan | php artisan serve | web | 8000 |
| Phoenixmix.exs with :phoenix | mix phx.server | web | 4000 |
| Spring BootSpring Boot in pom.xml or build.gradle | ./mvnw spring-boot:runmvn spring-boot:run without mvnw; ./gradlew bootRun for Gradle | web | 8080 |
| .NETa single .csproj | dotnet watch run | app | — |
| Gogo.mod | go run .air with an .air.toml; go run ./cmd/<name> per command when there's no main.go | app, or the command's name | from the command |
| RustCargo.toml with a binary | cargo runcargo run -p <crate> for each workspace binary | app, or the crate's name | from the command |
| Docker Composecompose.yml or docker-compose.yml | docker compose up | compose | — |
| make / justMakefile or justfile, when nothing else matched | make devor just dev; serve, run, and start targets work too | app | — |
Names and ports. At the root, a service is named for its role — web, api, app, or the Procfile’s process name. In a subfolder, a lone service takes the folder’s name and a cwd pointing there; several share the folder name as a prefix, like backend-web. A port is written when the command names one (--port 3001, PORT=3001, localhost:5173) or the framework has a usual dev port. Adding a folder with a Compose file at the root, a Django app with its own .venv in backend/, and a Vite app using pnpm in frontend/ writes:
name: shop
root: ~/Projects/shop
services:
compose:
cmd: docker compose up
backend:
cmd: .venv/bin/python manage.py runserver
cwd: backend
port: 8000
frontend:
cmd: pnpm dev
cwd: frontend
port: 5173
Limits. Detection stops at 20 services. In a monorepo, the root’s own script (say, turbo dev) is left out once the workspace members turn up services of their own, so nothing starts twice. It runs once, when the project is added, and never rewrites a config you’ve edited.
When nothing is found
lpm writes one placeholder service, dev: echo 'configure me', for you to replace — or let an agent draft the whole file with Generate with AI. SSH projects are never scanned: a new one gets a shell service that opens a login shell on the host. Adding a folder that’s already a project just points you to that project.