lazycomd

CLI

lazycomd CLI

Command What it does
lazycomd serve Run the daemon in the foreground
lazycomd ls Name, state, pid, uptime, restarts
lazycomd start <name> [-d] [--wait 30s] Start; -d starts dependencies first, --wait blocks until ready
lazycomd stop <name> SIGTERM the process group, SIGKILL after 10s
lazycomd restart <name> Stop then start
lazycomd logs <name> [-n N] [-f] Show or follow output
lazycomd reload Re-read the config and apply the diff
lazycomd run <name> Start with dependencies, follow output, stop on Ctrl-C
lazycomd port [N] Who is listening, and which command owns it
lazycomd doctor Check the catalog for what will fail to start
lazycomd files [add <dir>] Directories whose lazycomd.yaml is read
lazycomd group start\|stop\|restart <name\|-> Act on every command carrying a group
lazycomd mcp Serve the Model Context Protocol on stdio — see Agents
lazycomd version Print the build version

A name that is not exact matches on a unique prefix, so lazycomd logs tool finds toolweb. An ambiguous one lists the candidates and exits 1. Flags may come before or after the command name: logs api -f and logs -f api both work.

lazycomd run on a command that is already running attaches to its output and leaves it running on Ctrl-C — it only stops what it started.

Exit codes: 0 success, 1 daemon or client error, 2 usage error.

Start and wait for it

start returns as soon as the process spawns, which is too early to run anything against it. --wait holds until the command is actually ready:

lazycomd start api --wait 30s && npm test

Ready means its health: URL answers 2xx; with no health URL, that its port: accepts a connection; with neither, that it is running. A command that exits while starting fails immediately rather than at the deadline, and the daemon caps the wait at two minutes.

The daemon does the waiting, not the CLI — the health URL and the port are on the daemon’s machine, which is not always yours.

ls draws the same grouping the TUI does — a heading per group: label, the commands carrying it underneath:

$ lazycomd ls
NAME                         STATE    PID  UPTIME  RESTARTS
console
  mdm-console:toolweb        running  814  3m12s   0
databases
  proxy:aviron-db-alpha-dev  running  792  4m01s   0

A catalog where nothing sets a group stays flat. - is the commands with no group.

Who owns this port

$ lazycomd port 3000
PORT  ADDR       PID    PROCESS  COMMAND
3000  127.0.0.1  41022  node     app:web

The COMMAND column is the lazycomd command that owns the listener, by process group, or - for anything else on the machine. With no port, it lists every listener.

What is about to break

$ lazycomd doctor
error port 8080 is claimed by [api web]
error worker: cwd does not exist: /Users/me/old-checkout
warn  the directory ~/coding/app is gone, so its commands are not loaded

It reports the mistakes that only ever show up as a process that will not start: a program that is not on the daemon’s PATH, two commands claiming one port, a depends_on naming nothing, a cwd that moved, a listed directory that is gone. An error exits 1 so a script can gate on it; a warn does not.

The PATH it checks against is the daemon’s, not your shell’s — those differ under launchd and systemd, which is the whole reason a command can run in your terminal and fail here. See what a command inherits.

JSON

ls, start, stop, restart, logs, port, doctor, files and group all take --json, so the CLI is usable from something other than a person:

$ lazycomd ls --json | jq -r '.[] | select(.state=="failed") | .name'
app:worker

$ lazycomd doctor --json | jq '[.[] | select(.level=="error")] | length'
2

Empty results are [], never null. logs --json returns {"name":..., "lines":[...]}; following and JSON do not mix, so --json wins and returns the buffer as it stands.