Files
Behavision/desktop
Suriyakumarvijayanayagam 5f83a1077d Enrolment hands out the broker CA, and now the PC keeps it
The server has always sent the broker's CA certificate in the enrolment
response, precisely so it never has to ship in an installer. Nothing on
the receiving end wrote it anywhere: the agent read the field under the
wrong name (ca_pem, the server says ca_cert) and the desktop app read it
correctly and dropped it. Every claimed PC therefore dialled
tls://mcp.loyaly.ai:8883 with the system trust store, the private CA
failed verification, and the agent reported 'the broker did not accept
this PC' - a TLS failure is indistinguishable from a refusal at that
layer. No real site could ever have published a visit.

Found by claiming this Mac as a real shop against production; fixed by
writing the CA to broker-ca.crt beside agent.json on both claim paths.
Verified: broker connected over TLS, camera pushed from head office,
engine streaming it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KGcjxF1cNLcuwc3DAPcnfj
2026-09-18 12:16:43 +05:30
..

Behavision desktop

The store-facing app: a tray icon, a window, and the supervisor for the Python recognition engine.

Why one process, not three

The tray, the window and the supervisor all need the same state, and a user who quits the tray expects recognition to stop. Splitting them means two things can disagree about whether the engine is running.

It is deliberately not a Windows service. A service runs in session 0 and cannot draw a tray icon — that is Windows session isolation, not a library limitation. Spawning a child process also needs no elevation, while controlling a service does, so this design never triggers UAC at runtime.

Layout

main.go       wails.Run, window options
app.go        the methods bound to the frontend
tray.go       fyne.io/systray — wails v2 has no tray of its own
icons.go      tray icons generated at run time, not embedded
internal/local  client for the engine on 127.0.0.1:8010
internal/cloud  client for https://mcp.loyaly.ai
frontend/     React + Vite

The supervisor, durable spool, broker client and path resolution come from ../agent/pkg/* — the same tested code the headless agent runs, imported rather than copied.

Build

cd frontend && npm install && npm run build   # then, from this directory:
wails build -platform windows/amd64

wails build needs the Wails CLI:

go install github.com/wailsapp/wails/v2/cmd/wails@v2.9.2

Without it, go build still type-checks everything provided frontend/dist exists — the embed directive requires it.

What the frontend talks to

Nothing is imported from generated bindings. src/bridge.js calls window.go.main.App.* directly, so npm run build works without running wails generate, and there is one place that handles "the engine is not running yet" — the state every screen has to survive on a fresh install.