Skip to content

Interfaces

  • CLI: one command tree with one output contract. berth status, berth events -f, berth run, berth hold, berth stop, berth claims, berth pull, berth verify, berth models, berth gateway, berth wire llama-swap, berth engine check, berth config check, berth config show, berth export, berth key, berth skill install|show, berth update, berth version, and for the node itself berth daemon, berth harbor, berth service install|uninstall|status, berth reclaim, berth resume, berth prefetch, berth storage, berth civitai search|versions and the ComfyUI suite under berth engine install|show|update|rollback|remove. Berth runs fully headless.
berth wire llama-swap --config cfg.yaml          # plan: which models lack a wrapper
berth wire llama-swap --config cfg.yaml --write  # apply; a backup stays beside the file
berth wire llama-swap --config cfg.yaml --check  # exit 1 when a model is unwired
berth config check --strict          # a warning fails the check, exit 1
berth config show --format toml      # the evaluated config, ready to save
berth engine check -v                # what each engine reports, right now
berth -q status; echo $?             # exit codes only, for CI
berth status --format json | jq .leases

Results go to stdout, diagnostics go to stderr. --format is human (the default), json or yaml, and berth config show also takes toml, the config's own file format. -v adds detail to the human view, and -q suppresses stdout and leaves the exit code as the answer. Exit codes are 0 (done), 1 (validation or logic: an invalid config, a warning under --strict, an engine that did not answer, a lease the broker refused) and 2 (berth could not do its job: unknown flag, missing file, berthd unreachable). berth run passes the engine's own status through and exits 75 when no berth was granted. Every read-only command changes nothing. - Harbor web UI (berth harbor): a departures board of every lease (the HOT / WARM tiers included: WARM marks a parked engine, with its parked RAM and age), a boat ticket per lease, the collisions counter, berths with measured memory, stowaways, the event log, and engine metrics. The tide (card memory by holder) and the model timeline share a 1H / 6H / 24H / 7D / 30D picker; the Engines tab adds the library (every model on the machine with its shelf, quant, size, cached tier, the engine serving it and that engine's EST. VRAM, with the terminal commands one row of copy buttons away), a queue KPI (the berth's own queue; each engine's own queue stays on its card), the KV pool (the live slots of each engine against their model windows, stored ranges the per-minute peak slot fill), context residency (the last requests' token figures against the model's window, plus the live KV sessions), a throughput chart, a 24H / 7D / 30D leaderboard and, in advanced mode, a storage panel. The top bar shows the overall state (LIVE / DEGRADED / OFFLINE) and a strip of the alerts currently breaching, colored from the node's own threshold state. Basic and advanced modes. While its update check is on and a newer release exists, the header shows it: the release, a link to it, and a button that copies berth update, the command that does the replacing. Read-only, strict content security policy. It listens on loopback by default (127.0.0.1:9798); passing a non-loopback --listen address (e.g. 0.0.0.0:9798; a specific interface IP works too) is the explicit opt-in to expose it on your network: the startup logs a warning and the page shows a banner on every screen while exposed. There is no authentication in this release: expose it only on a network you trust; phones on that network get the full read-only dashboard. To reach it from elsewhere without exposing it, keep the loopback listener and put a same-machine reverse proxy in front (tailscale serve, caddy), passing the proxy's hostname with --allow-host. A systemd user unit is in contrib/berth-harbor.service. - Prometheus /metrics for Grafana and friends, on the [metrics] listen address. It serves loopback only and refuses a Host that is not a loopback name, so a web page cannot read it through DNS rebinding. The endpoint names your engines, leases and queue, so Berth never serves it off the machine. To scrape it from a Prometheus on another host, keep the endpoint as it is and either: - run a Prometheus agent or Grafana Alloy on the Berth machine, scrape 127.0.0.1, and remote_write to your Prometheus; or - put Caddy or nginx on the same machine in front of it, sending a loopback Host (header_up Host 127.0.0.1, proxy_set_header Host 127.0.0.1;), with the proxy's own allowlist or auth on the network side. tailscale serve passes the tailnet name as Host, which /metrics refuses. - Footprint: the node uses about 0.2% of one CPU core and ~21 MB of memory on the reference box; the harbor about 0.4% and ~23 MB, writing to disk once a minute.