pi-web is launch-options only today. bin/pi-web-options.js defines four options (--port, --hostname, --no-open, --help), and parseLaunchOptions rejects every positional, so there is no subcommand surface at all. Finding out which version is installed means reading package.json or running npm ls -g, updating means re-running npm install -g @agegr/pi-web@latest by hand after stopping the server with Ctrl+C, and that is exactly what the README tells people to do.
That is fine for the happy path, but it blocks the shell workflows people expect from a dev-server CLI: is it running, is it still alive, stop it, am I current, is my environment sane.
Proposed commands
-
pi-web version (-v, --version, --json) — report the installed version plus the resolved install source (global prefix vs npx cache) so the two can be told apart. Since Pi Web shares its data directory with the pi CLI, also report the pi version in use and the agent data directory that was resolved.
-
pi-web update — check for and install a newer release. --check should only report; --stop-first should stop a running server before reinstalling. The registry comparison can reuse lib/app-update.ts (isNewerStableVersion, getPiWebReleaseUrl) and the npm invocation can reuse lib/node-cli.ts (findNodeCliScript), so Windows stays shell-free. A running server must not be replaced underneath itself — next start has .next/ open — so the command should detect that case, print the pid it found, and refuse.
-
pi-web doctor — environment check: Node >= 22.19.0 (that check already exists in bin/node-version.js and can be reused), pi CLI presence and version, readability of PI_CODING_AGENT_DIR / ~/.pi/agent, whether the port is already taken, whether a non-loopback bind has PI_WEB_PASSWORD set (today that warning is printed once during startup and then lost), and whether the data directory is writable.
-
pi-web status and pi-web stop — whether a server is running, on which host and port, since when, and a way to stop it. bin/process-lifecycle.js forwards SIGINT/SIGTERM and force-kills after 5s, but nothing is persisted, so the CLI can answer neither question today. A pid file under ~/.pi-web/ next to projects.json is the missing piece, and it is also what update and doctor need.
-
pi-web serve — the current behaviour under an explicit name, so help text can read pi-web [command] [options]. Bare pi-web keeps working exactly as it does now.
-
pi-web open — open the UI in a browser without starting a second server; today the browser only opens as a side effect of launching one.
-
pi-web completion <shell> — bash, zsh and fish completions for the commands and options above.
Nice-to-have, if the CLI surface grows anyway
pi-web projects add|remove|list — ~/.pi-web/projects.json is already the registry of project entries the UI offers.
pi-web sessions ls|export|rm — mirror /api/sessions and /api/sessions/[id]/export, reading ~/.pi/agent/sessions/... directly when no server is running.
pi-web models, auth, mcp, skills — line up with the pi CLI subcommands of the same name; the HTTP side already exists (/api/models-config/test, /api/mcp/test, /api/plugins/check).
pi-web run <project> -- "<prompt>" — one non-interactive task via pi --print.
Notes for implementation
- Backwards compatibility first: match a known command name before running the existing
parseArgs, keep --help at exit 0 and unknown input at exit 1, and point unknown commands at pi-web --help.
- Docs to keep in sync with a new command surface:
getHelpText() plus the four READMEs.
No ordering is implied. version, doctor, the pid file, status/stop and update --check would already cover most of it without touching a single API route.
pi-webis launch-options only today.bin/pi-web-options.jsdefines four options (--port,--hostname,--no-open,--help), andparseLaunchOptionsrejects every positional, so there is no subcommand surface at all. Finding out which version is installed means readingpackage.jsonor runningnpm ls -g, updating means re-runningnpm install -g @agegr/pi-web@latestby hand after stopping the server with Ctrl+C, and that is exactly what the README tells people to do.That is fine for the happy path, but it blocks the shell workflows people expect from a dev-server CLI: is it running, is it still alive, stop it, am I current, is my environment sane.
Proposed commands
pi-web version(-v,--version,--json) — report the installed version plus the resolved install source (global prefix vsnpxcache) so the two can be told apart. Since Pi Web shares its data directory with the pi CLI, also report the pi version in use and the agent data directory that was resolved.pi-web update— check for and install a newer release.--checkshould only report;--stop-firstshould stop a running server before reinstalling. The registry comparison can reuselib/app-update.ts(isNewerStableVersion,getPiWebReleaseUrl) and the npm invocation can reuselib/node-cli.ts(findNodeCliScript), so Windows stays shell-free. A running server must not be replaced underneath itself —next starthas.next/open — so the command should detect that case, print the pid it found, and refuse.pi-web doctor— environment check: Node >= 22.19.0 (that check already exists inbin/node-version.jsand can be reused), pi CLI presence and version, readability ofPI_CODING_AGENT_DIR/~/.pi/agent, whether the port is already taken, whether a non-loopback bind hasPI_WEB_PASSWORDset (today that warning is printed once during startup and then lost), and whether the data directory is writable.pi-web statusandpi-web stop— whether a server is running, on which host and port, since when, and a way to stop it.bin/process-lifecycle.jsforwards SIGINT/SIGTERM and force-kills after 5s, but nothing is persisted, so the CLI can answer neither question today. A pid file under~/.pi-web/next toprojects.jsonis the missing piece, and it is also whatupdateanddoctorneed.pi-web serve— the current behaviour under an explicit name, so help text can readpi-web [command] [options]. Barepi-webkeeps working exactly as it does now.pi-web open— open the UI in a browser without starting a second server; today the browser only opens as a side effect of launching one.pi-web completion <shell>— bash, zsh and fish completions for the commands and options above.Nice-to-have, if the CLI surface grows anyway
pi-web projects add|remove|list—~/.pi-web/projects.jsonis already the registry of project entries the UI offers.pi-web sessions ls|export|rm— mirror/api/sessionsand/api/sessions/[id]/export, reading~/.pi/agent/sessions/...directly when no server is running.pi-web models,auth,mcp,skills— line up with the pi CLI subcommands of the same name; the HTTP side already exists (/api/models-config/test,/api/mcp/test,/api/plugins/check).pi-web run <project> -- "<prompt>"— one non-interactive task viapi --print.Notes for implementation
parseArgs, keep--helpat exit 0 and unknown input at exit 1, and point unknown commands atpi-web --help.getHelpText()plus the four READMEs.No ordering is implied.
version,doctor, the pid file,status/stopandupdate --checkwould already cover most of it without touching a single API route.