Skip to content
DocsService detection

Automatic service detection

When you add a folder or clone a repository, lpm reads the project’s own files and writes a service for each thing it can run. Nothing is sent anywhere and no AI is involved, so adding a project stays instant. The app then tells you what it found, like “Found 2 services: web, api”.

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 Procfile
    One 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 locks

    Named 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 dev

    Named app · port from the task

  • Djangomanage.py
    python3 manage.py runserver

    Named web · port 8000

  • FastAPIfastapi dependency + an app module like main.py
    uvicorn main:app --reload

    Named api · port 8000

  • Flaskflask dependency + app.py or wsgi.py
    flask run --debug

    Named web · port 5000

  • RailsGemfile with rails + bin/rails
    bin/develse bin/rails server

    Named web · port 3000

  • Laravelartisan
    php artisan serve

    Named web · port 8000

  • Phoenixmix.exs with :phoenix
    mix phx.server

    Named web · port 4000

  • Spring BootSpring Boot in pom.xml or build.gradle
    ./mvnw spring-boot:runmvn spring-boot:run without mvnw; ./gradlew bootRun for Gradle

    Named web · port 8080

  • .NETa single .csproj
    dotnet watch run

    Named app · port —

  • Gogo.mod
    go run .air with an .air.toml; go run ./cmd/<name> per command when there's no main.go

    Named app, or the command's name · port from the command

  • RustCargo.toml with a binary
    cargo runcargo run -p <crate> for each workspace binary

    Named app, or the crate's name · port from the command

  • Docker Composecompose.yml or docker-compose.yml
    docker compose up

    Named compose · port —

  • make / justMakefile or justfile, when nothing else matched
    make devor just dev; serve, run, and start targets work too

    Named app · port —

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:

~/.lpm/projects/shop.yml
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.