The Go halves of this product cross-compile to Windows from any machine.
The engine does not: PyInstaller bundles the interpreter and the native
wheels of the machine it runs on, so a frozen engine can only be built on
Windows. That one fact was the entire reason no release had ever been
cut - two of the three binaries were ready for weeks.
behavision-setup installs the engine from source instead. It finds a
Python, builds a private virtual environment beside the database,
installs the engine into it, downloads the models, records how to start
it in the same agent.json the app reads, and then starts it and waits
for its API to answer.
That last step is the point. An installer that reports success and
leaves a shop with an engine that will not run has done worse than
failing: the failure surfaces later, to somebody who did not install it.
The trade, since whoever runs this is standing in a shop: it needs
Python and internet at install time and takes minutes, where a frozen
build needs neither. What it buys is a release that exists.
Details that are not incidental:
- `py -3` is tried before `python` on Windows. The launcher is what the
official installer puts on PATH; `python` there is often the Store
stub that prints an advert and exits 9009.
- a virtual environment, not the system Python. A shop PC may have
Python for something else, and the engine pins numpy below 2.0 -
installing that into a shared interpreter breaks the other thing
months later and silently.
- EngineExe is written absolute. The app resolves a relative one
against its install root under Program Files, where no interpreter
lives.
- pip's output is shown, not swallowed. When it fails on a proxy or a
missing build tool it says exactly what is wrong, and hiding that
leaves the operator with "setup failed" and nothing to act on.
- the console pauses before closing. Double-clicked from Explorer, a
program that finishes closes instantly and success and failure look
identical.
Verified as far as a Mac can: `pip install .` builds the wheel and
resolves every dependency, and `python -m behavision` then runs from
site-packages rather than the working directory - which is the mechanism
this depends on and had never been exercised, because the project has
only ever been run out of its own checkout.
NOT verified: any of it on Windows. Nothing here has run on the target
platform, and the `py -3` path and the ProgramData layout are exactly
where that will show.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pcn9asw19WGBfCEaHvNug6
Behavision agent (Go)
The half of the edge install that touches the network. The Python engine keeps the cameras and the models; this keeps the tray icon, the UI shell, the MQTT connection and the offline queue.
┌─ agent (Go) ───────────────────┐ ┌─ engine (Python) ────────┐
│ tray icon + WebView2 window │ │ RTSP capture │
│ supervises the engine process │───────▶│ YuNet / ArcFace / FAISS │
│ MQTT publish + offline spool │◀───────│ SQLite (biometric) │
│ S3 handoff, tenant config │ local │ localhost API + events │
└────────────────────────────────┘ HTTP └──────────────────────────┘
Why the split
Go cannot run ONNX, OpenCV or FAISS, so the engine stays Python and ships frozen. Go is here for what it is actually better at: a durable queue that survives a store's internet dropping, a supervised child process, and one language shared with the server so the MQTT contract has a single definition.
Why 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. Since the product is "user starts and stops it from the tray", the agent is a normal user-session process that spawns the engine as a child. That also means it never needs elevation at runtime: starting a child process does not, controlling a service does.
internal/engine is written so a service wrapper can be added later without
touching the supervision logic.
Layout
main.go entry point, mode dispatch
internal/engine start/stop/supervise the Python engine, health polling
internal/spool durable event queue (survives restart and outage)
internal/mqtt broker client, publishes from the spool
internal/config tenant identity, broker settings, credentials
frontend/ React UI served into the WebView
Build
go build ./... # agent alone
wails build # agent + frontend, once the UI is added