Web UI (bnerd web)¶
bnerd web starts a local web server that serves a browser interface to the bnerd AI agent — the same agent you can drive from the TUI and the MCP server, now reachable from your browser.
It is designed for a single local user: the server binds to loopback only, generates a one-time access token, and opens your browser straight into a chat session.
This prints a URL like http://127.0.0.1:54321/?token=… and (unless --no-open) opens it in your default browser.
What you get¶
- Streaming chat with the agent over Server-Sent Events.
- Tool-call cards showing each tool the agent runs, its parameters, status, and any diff/output (click a card to expand details).
- Write confirmations: when the agent wants to perform a write or destructive action, a dialog asks you to Approve or Deny before it runs — mirroring the TUI's confirmation flow and honouring the active safety mode.
- Interactive dialogs for plan approval, phased-execution checkpoints, structured questions, and ticket / reply proposals.
The initial mode (chat, code, or pa) is chosen at launch with --mode, and you can switch between them live from the mode selector in the chat header. Each mode uses the same tools and system prompt as the corresponding TUI mode, with its own conversation kept per mode.
Resource dashboard¶
Alongside chat, the web UI is growing into a browser peer of the TUI for managing cloud resources. The dashboard is reached from the resources → link in the chat header (or /ui/zones), with a left-hand nav per resource.
Each resource view supports browsing, live fuzzy filtering, a detail panel, and — where the resource allows it — create / edit / delete through inline forms with a confirmation step on destructive actions. A project selector in the nav re-scopes project-scoped views (it mirrors the TUI's :projects).
Rolling out by resource
Available today:
- DNS — zones (browse + drill into records) and full record CRUD.
- Compute — servers, volumes, networks, routers, and load balancers (browse, filter, detail; read-only, matching the TUI).
- Kubernetes — clusters (browse, filter, detail) plus create and edit (name, version, machine type, and node-pool sizing).
- Tickets — browse, filter, detail (with the body and comment thread), create, comment, and delete.
- DNS domains — browse, filter, detail (verification status/method).
- Apps — browse, filter, detail (project-scoped).
- Org & access — organizations, members, and invitations (browse, detail).
- Invoices — browse and detail.
- Billing — cost breakdown by service for the active scope.
All three AI modes — chat, the code assistant, and the personal assistant — are available in the browser and switchable from the mode selector in the chat header (no restart needed). When Slack/email is configured, the PA's inbox/Slack tools work in chat (the messaging hub runs inside the web server). The dedicated inbox peek UI (live thread list/triage) is still terminal-only and tracked as a follow-up. Read/write views go through the shared pkg/resources service layer, so the dashboard and the TUI stay in lock-step.
Flags¶
| Flag | Default | Description |
|---|---|---|
--listen | 127.0.0.1:0 | Address to bind (host:port; port 0 picks a random free port). |
--mode | chat | AI mode: chat, code, or pa. |
--no-open | false | Do not open the browser automatically (just print the URL). |
--auth-token | (generated) | Use a fixed UI access token instead of a random one. |
AI provider, model, keys, organization/project scope, and integrations are read from the usual configuration (flags, BNERD_* env vars, or ~/.bnerd.yaml) — the same keys the TUI uses. See Configuration.
Security model¶
Local-only by design
The server is meant to run on your own machine. Its safeguards assume a trusted localhost:
- Loopback bind. Defaults to
127.0.0.1, so it is not reachable from other machines. - One-time token. A random token is generated per run and exchanged for an
HttpOnly,SameSite=Strictcookie on first visit. Every request requires it; a missing or wrong token returns401. - Origin / Host guard. Requests whose
OriginorHostis not the bound loopback address are rejected with403, blocking cross-site and DNS-rebinding attempts.
Binding to a non-loopback address with --listen exposes the UI to your network. Only do this on a trusted network, and keep the token secret — anyone with the URL and token can drive the agent with your credentials.
Notes & limitations¶
- Single session. The server runs one chat session and processes one message at a time; a second send while one is in flight is rejected. Multiple browser tabs share the same session and stream.
- Stateless across restarts. Conversation history lives in memory for the life of the process; it is not persisted like TUI sessions are.
- The resource dashboard is being filled in one resource at a time (DNS first); a documented local REST API is still deferred — see the roadmap.