A mobile-first, voice+vision inventory capture app. You open a box on your phone, point the camera at what's inside and talk; a Gemini Live agent records the contents into a flexible SQLite graph via tool calls. You review and edit everything afterward in a normal web UI.

Replaces an ad-hoc Excel "what do I have where" spreadsheet.

Phone browser  ──WS (app protocol)──►  Go server  ──WSS (BidiGenerateContent)──►  Gemini Live
  mic PCM16 16k                         (proxy +                                   audio/video/text in
  camera JPEG frames (≤1 FPS)            tool runtime                              toolCall out
  "capture photo" (full-res)            + SQLite)                                  audio/text out
  ◄── model audio 24k / text ──────────
  ◄── UI events (item recorded, …) ────

Two hops on purpose (browser is NOT connected directly to Gemini):

Rather than a rigid Locations → Boxes → Items hierarchy, the model is given a small graph and a few verbs, and organises things as it sees fit. This is deliberately non-restrictive; we tighten it into views/constraints later once we see what the model actually does.

  1. Live frames — browser sends downscaled JPEG frames ≤1 FPS as realtimeInput video so the model can see while you talk. NOT stored.
  2. Archival photos — on request_photo (or a manual tap) the browser captures a full-res JPEG which the server stores as a photos blob linked to the entity. Multiple per entity.

We start here and add/remove tools as we watch real sessions.

Transport uses golang.org/x/net/websocket (already vendored): Config.Header carries the auth header, Config.TlsConfig handles wss, DialContext gives cancellation.

Invite-token → session-cookie, copied from weekplan: mint a login link with inventory gen-link, open it once for a long-lived session cookie.

inventory serve    [--addr host:port] [--base-url url] <db>
inventory gen-link [--admin] [--username name] [--base-url url] <db>