# 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.