Files
Behavision/desktop
Suriyakumarvijayanayagam f5eb2bb124 The green button was disabled by an options block that was not there
Reported from the Mac build: the window cannot be maximised. It is not a
Wails limitation or a WebView quirk, it is an omission with a very
specific consequence.

Wails computes zoomable INSIDE `if frontendOptions.Mac != nil`:

    var fullSizeContent, hideTitleBar, zoomable, ... C.int   // 0
    if frontendOptions.Mac != nil {
        zoomable = bool2Cint(!frontendOptions.Mac.DisableZoom)
    }

and the native side then acts on the zero:

    if (!zoomable && resizable) {
        NSButton *button = [self.mainWindow
                              standardWindowButton:NSWindowZoomButton];
        [button setEnabled: NO];
    }

So leaving Mac unset does not mean "take the defaults" - it means the
green button is created and then explicitly disabled. There was a Windows
options block and no Mac one, which is how this survived: the platform
that was configured behaved, and the platform that was not looked broken.

Fixed by the block existing. The fields are written out rather than left
as an empty struct so it reads as a decision rather than something half
typed.

Verified at runtime rather than by reasoning about the source alone: all
three title-bar buttons report enabled=true through the accessibility
API, and the window resizes to 1440x900, the full display.

One correction to my own first check, recorded because it nearly sent me
the wrong way: querying AXFullScreenButton as an ATTRIBUTE of the window
returns "missing value" whether or not the button exists. It has to be
found by subrole among the window's buttons. The button was fine; the
question was wrong.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KGcjxF1cNLcuwc3DAPcnfj
2026-09-30 13:22:04 +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.