Web Observer
Check on your agents from a browser with read-only, one-time share links that expire and can be revoked.
The web observer shows your agents in a browser: which are working, which are blocked on a question, which are done. You can open their screens and follow them live. It is read-only: nothing in it can type into a terminal, change a layout, or start or stop anything.
hive web runtime add laptop --all --screens # 1. allow it to observe this sessionhive web serve # 2. run it at http://localhost:8484hive web share --runtime laptop --screens # 3. print a one-time sign-in linkOpen the link in a browser. It signs that browser in for 8 hours unless you choose otherwise, and hive web revoke <id> ends the access at once.
How it fits together
browser ──HTTPS──▶ hive web serve ──observer socket──▶ Hive daemon (this machine) (its own process, └─ ssh … hive proxy --observer ──▶ Hive daemon (buildbox) no control socket)- A separate process.
hive web serveis not part of any daemon. - One runtime, one observer credential. Each runtime it shows (a session on a machine) is reached only through that daemon’s observer socket, with a credential made for it. The web observer never holds a control socket, so it can only read, and a browser can reach even less.
- Tokens stay on the server. Runtime tokens live in
~/.hive/web(mode 0600). Browsers hold only a session cookie scoped by their link.
Runtimes
hive web runtime add <name> (--all | --env <id>… | --pane <id>…) [--screens] [--expires 2160h]hive --remote buildbox web runtime add buildbox --env ci --screenshive web runtime listhive web runtime remove <name>Adding a runtime is explicit consent: nothing reaches a browser until you run runtime add and share a link. runtime add creates an observer credential named hive-web:<name> on the runtime the command reaches (this session, --session, --remote, or --machine) and keeps its token in the web observer’s state. The runtime’s scope and --screens cap what any link can show.
Remote runtimes are reached the same way hive --remote reaches them: SSH, then hive proxy --observer. To hold the web observer’s machine to read-only access, give it an SSH key restricted to the observer socket. Removing a runtime disconnects it and revokes its credential when the daemon is reachable; otherwise Hive prints the command that does.
Share access
hive web share [--runtime <name>]… [--env <id>… | --pane <id>…] [--screens] [--history] [--expires 8h] [--link-expires 15m] [--uses 1] [--label "…"]hive web grants # what is shared, and which browsers are signed inhive web revoke <id> # a grant and all its browsers, or one browser sessionhive web audit [--grant <id>]- One-time code, kept out of URLs. A share link looks like
https://…/login#hwc_…. The code sits in the URL fragment, which browsers never send to a server, so it never reaches access logs, proxies, orRefererheaders. - Exchanged for a cookie. The sign-in page posts the code, the server swaps it for an HttpOnly, SameSite=Strict session cookie (
__Host-hive_weband Secure under HTTPS), and the code leaves the address bar. - Short-lived. The code works for
--link-expires(15 minutes by default) and for--usesbrowsers (one by default). Access lasts--expires(8 hours by default, at most 30 days) and cannot be extended; share again instead. - Hashes only. The server stores hashes of codes and cookies, never the values.
A link sees the intersection of its runtime’s scope and its own --env or --pane scope:
| The link allows | The viewer sees |
|---|---|
| Default | Runtimes, environments, tabs, panes, agents and their states, reported metadata, and activity |
--screens |
Also each pane’s current screen, live |
--history |
Also output history (scrollback) on request, one audited read at a time |
hive web revoke ends access immediately: open pages go to the sign-in page, which says access was revoked, and later requests are refused. Expiry works the same way.
Being observed is visible. The multiplexer’s tab bar shows ◉ observed by … and watched panes show [watched]. The web observer connects to a runtime only while someone views it (plus a minute), so the marks mean someone is looking now. Every page in the browser shows a Read-only badge, and the Access page shows what the link allows and when it ends.
Audit. ~/.hive/web/audit.log records links shared, sign-ins, refused links, sign-outs, history reads, and revocations, naming the grant, client address, and user agent but never a code or cookie. Each daemon’s own hive observer audit also records the web observer’s connections.
The app
- Agents. Every agent the link can see, across runtimes, with blocked agents first, then done. Press / to search and Esc to clear; filter by state. Filters stay in the URL, so filtered views can be bookmarked.
- Runtime. Connection, version, uptime, and last sync; environments with git state and agent counts; agents; recent activity.
- Environment. Directory, worktree, git and reported metadata, plus tabs, panes, and activity.
- Pane. The agent’s state, why, and since when, plus its program and metadata. With
--screens, the live screen; with--history, a button that reads recent output.
States follow Hive’s agent detection: working, blocked, done, idle, exited, or unknown.
Each page holds one server-sent event stream, and the server sends only the parts that changed, at most about 7 updates a second per page and 4 per pane screen. The header shows Live, Connecting, Reconnecting, or Offline, and stale after 45 seconds of silence. While a runtime is unreachable, pages keep showing the last known state, marked with its time; when it returns, the web observer takes a fresh snapshot and continues, including after a daemon restart.
Every page works from the keyboard and without JavaScript (only live updates need it), the connection state is announced to screen readers, and light and dark themes both meet WCAG AA contrast.
On phones, the web observer installs as an app with an Attention view, push notifications, and deep links to agents. See Hive on Your Phone.
Privacy
- No telemetry, and no outside resources: scripts and styles are built into
hive, and the Content-Security-Policy forbids anything else. - Nothing written to disk. Screens and output pass through memory to the browser. Pages are sent with
Cache-Control: no-store, and the browser keeps nothing but the theme choice. - Screens and history are opt-in twice: the runtime must allow them, and so must the link. History is read only when a viewer presses the button, and every read is audited.
Deploy it
[web]listen = "127.0.0.1:8484" # this machine onlypublic_url = "" # where browsers reach it, for share linkstls_cert = "" # certificate and key to serve HTTPStls_key = ""behind_proxy = false # a reverse proxy in front terminates TLSpush = true # phone and browser notificationspush_contact = ""push_allow_any_endpoint = falsehive web serve flags (--listen, --public-url, --tls-cert, --tls-key, --behind-proxy) override these settings. Its log is ~/.hive/web/web.log.
TLS is required beyond loopback. Plain HTTP is allowed only on 127.0.0.1, ::1, or localhost. On any other address, the web observer refuses to start without its own TLS (TLS 1.2+, with HSTS) or --behind-proxy. Behind a proxy, also set --public-url https://… so links and origin checks use the proxy’s address. Authentication is built in through share links; a proxy may add SSO or client certificates on top.
Reverse proxies
Caddy:
hive.example.com { reverse_proxy 127.0.0.1:8484}nginx must not buffer event streams and must let them stay open:
location / { proxy_pass http://127.0.0.1:8484; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $remote_addr; proxy_http_version 1.1; proxy_buffering off; proxy_read_timeout 1h;}Then run hive web serve --listen 127.0.0.1:8484 --behind-proxy --public-url https://hive.example.com. Let only the proxy reach the web observer: keep it on loopback or firewall it.
Network patterns
- Your machine only: use the defaults and open the link locally.
- Your phone on the same network or a tailnet: use TLS, for example a certificate from
tailscale cert, or a proxy. - A shared team server: run the web observer behind a proxy and add runtimes from developers’ machines with
--remote, using SSH keys restricted to the observer socket. Each runtime’s credential, scope, and expiry still apply.
Run it as a service
[Unit]Description=Hive web observer
[Service]ExecStart=%h/.local/bin/hive web serveRestart=on-failure
[Install]WantedBy=default.targetGET /healthz answers 200 while the process serves. GET /readyz answers 200 when it has runtimes and readable state, 503 otherwise. Neither requires sign-in or names a runtime. hive web status shows each runtime’s connection, last sync, and last error.
Limits
| What | Limit |
|---|---|
| Pages open per browser session | 12 |
| Live screen watches per runtime | 6 (more refresh every 2 s instead) |
| Browsers per link | 1 to 20 |
| Access per link | 1 minute to 30 days |
| Output history per read | 200 lines |
| Activity kept per runtime | Last 200 events |
| Sign-in attempts | 10 a second, bursts of 20 |
Browsers: current Chrome, Edge, Firefox, and Safari 16.4+, on desktop and mobile. Runtimes: Hive daemons at observer API level 10 (1.0.5) or newer. URLs are stable within 1.x, so bookmarks keep working; the pages themselves are not an API, so program against the observer API instead.
Troubleshooting
serving beyond this machine needs TLS: see the TLS requirements above.- A page says Access refused for a runtime: its observer credential was revoked or expired. Run
hive web runtime add <name> …again. - A page stays on Reconnecting: the runtime’s daemon is down or unreachable. Check
hive web status, andhive --remote <host> statusfor remote ones. - Updates arrive late or in bursts behind a proxy: the proxy is buffering; turn buffering off.
- A link says it is invalid: links work once, briefly. Create another with
hive web share. the web observer is not running:share,grants,revoke,audit, andstatustalk to a running server through~/.hive/web/web.sock.