← All guides

CLI guide

Start, configure, update, and manage a PiChamber server from the terminal.

The PiChamber CLI guides common server tasks in an interactive terminal and keeps the same commands usable from scripts. Run pichamber --help for the current command list.

Start a server

Run this in a terminal:

pichamber serve

When pichamber serve has no setup flags and both standard streams are TTYs, it asks you to choose:

  1. Access: this machine only, local network, or a custom bind address.
  2. Port.
  3. UI authentication. Local-only servers may choose no password; network access requires one.
  4. Browser UI and API, or API only.
  5. Background or foreground process mode.

The CLI shows the choices and asks for confirmation before starting. A generated password is printed once. Save it before leaving the terminal.

Use explicit flags for scripts, CI, and non-interactive shells:

pichamber serve --port 3000 --ui-password "choose-a-strong-password"
pichamber serve --port 3000 --lan --ui-password "choose-a-strong-password"
pichamber serve --port 3000 --api-only --ui-password "choose-a-strong-password"

The bare pichamber command remains a quick start. It uses the default server settings without opening the setup wizard. --foreground runs the server in the current process for systemd or another process manager.

Server runtime

Server needs Node.js 22.19 or newer (24 recommended) or Bun 1.4 or newer (1.4.2 recommended). Background servers pick Node first with Bun fallback. Foreground servers run in the current runtime. Startup services reuse the pinned runtime from startup enable. Docker images launch from pinned Bun 1.4.2. Dev servers use the same Node-first order while builds stay on Bun. The desktop app runs its bundled Node in-process. The mobile app connects to an existing server.

Update PiChamber

Run:

pichamber update

In an interactive terminal, the CLI reviews the current version, target version, package manager, and restart plan before it changes the install. Use --yes or -y to skip the confirmation. The saved server update channel defaults to stable; use --channel for a one-time override without changing that default:

pichamber update --yes
pichamber update --channel rc

The rc channel compares the latest stable and numbered release candidate and offers the higher version. The installer pins the exact version selected by the check, so a moving npm dist-tag cannot change a running update job.

The update command only replaces a trusted global package-manager install. For a server managed by pichamber startup enable, it runs the installer in a temporary systemd unit and restarts pichamber.service after verifying the new version. This also works from PiChamber's browser terminal. Deployments that cannot update themselves stop before changing the installation and explain the required action:

  • Containers must pull the newer image and recreate the container (docker compose pull then docker compose up -d). Do not run pichamber update inside the image.
  • Source checkouts must update their checkout, rebuild the web package, and restart the server.
  • Custom systemd units must run pichamber update from a normal terminal and then restart the unit with the command shown in the error.
  • An installation owned by another account must be updated by that account, or reinstalled under the account that runs the service.

After a package update, the command reports instances that could not restart.

Use --json for a machine-readable result. The result includes the previous, installed, and latest versions, the selected channel, the package manager, restart counts, and any version-mismatch or partial-restart warnings. --quiet prints one concise result line without the review. A version mismatch or failed restart also returns a non-zero exit code, even when the package manager completed.

Manage startup and running instances

Enable startup integration with a guided setup:

pichamber startup enable

The interactive flow asks for the bind address, port, password, and final confirmation. Pass --host, --port, --lan, and --ui-password to keep it non-interactive. Check or remove the service with:

pichamber startup status
pichamber startup disable

Inspect or control running instances with:

pichamber status
pichamber stop --port 3000
pichamber restart --port 3000

A broad pichamber stop asks for confirmation when it would stop more than one instance. Use --force to skip that confirmation. --json and --quiet never prompt.

Read logs

pichamber logs follows the latest running instance. Use --no-follow for a one-time tail:

pichamber logs --no-follow
pichamber logs --port 3000 --lines 100 --no-follow
pichamber logs --all --no-follow

Use --quiet for raw log lines without the interactive frame. Use --json --no-follow for a JSON response. JSON logs cannot follow a live file because the result must be finite.

Start a tunnel

The tunnel command also has a guided flow:

pichamber tunnel start

In an interactive terminal, the CLI can select a saved profile, choose a mode, ask for a managed-remote hostname and token, find a managed-local config file, select a running instance, and offer to save a reusable profile. It shows a final review before starting when the provider and mode were not already specified.

Use a profile or explicit mode for repeatable commands:

pichamber tunnel start --profile prod-main
pichamber tunnel start --mode quick
pichamber tunnel start --mode managed-remote \
  --token-file ~/.secrets/cloudflare-token \
  --hostname app.example.com
pichamber tunnel start --mode managed-local \
  --config ~/.cloudflared/config.yml

Non-interactive runs must provide every value required by the selected mode. Use --dry-run to validate the inputs without starting a tunnel. Stop a tunnel without stopping its server:

pichamber tunnel stop --port 3000

Use pichamber tunnel stop --all to target every instance. In an interactive terminal, stopping multiple tunnels asks for confirmation unless --force is provided. Saved managed-remote profiles can be managed with:

pichamber tunnel profile list
pichamber tunnel profile add --provider cloudflare --mode managed-remote \
  --name prod-main --hostname app.example.com \
  --token-file ~/.secrets/cloudflare-token
pichamber tunnel profile remove --name prod-main

Pair devices and check the version

connect-url creates a one-time pairing link. It starts a server on the selected port when one is not already running:

pichamber connect-url --qr
pichamber connect-url --server https://pichamber.example.com --qr
pichamber connect-url --relay --name "Laptop"

Use --server when a reverse proxy or tunnel provides the public URL. Use --relay to include the private relay as a fallback candidate. --qr renders QR art only in an interactive terminal; non-interactive output remains the pairing link or JSON payload.

Print the installed package version with either command:

pichamber version
pichamber --version

Both commands support --json.

Interactive and script modes

The CLI uses the same validation in every mode:

ModeBehavior
Interactive TTYShows prompts, reviews, and spinners for guided operations.
Non-TTYNever prompts. Supply required values as flags or receive a clear error.
--quietSuppresses framing and keeps essential result lines.
--jsonEmits JSON only. Warnings and partial results are included in the payload.

Prompt cancellation leaves the associated operation unapplied. Use pichamber tunnel completion bash, zsh, or fish to generate shell completion for the tunnel command tree.

These guides are synced from the PiChamber repository at 720cb33 and may lag behind main. Spot something stale? Propose an edit upstream, then re-run npm run sync:docs here.