name: adom-desktop-presence description: How Adom Bridge lives quietly on a Mac. Covers the menu-bar agent model (signed-in launches go straight to the menu bar with no window and no Dock icon), summoning the window from the menu-bar item, close-to-menu-bar behavior (the close button hides the window, Bridge keeps serving), launch at login via LaunchAgent (default ON, self-healing), the shared Adom sign-in in the keychain, and the window title markers. Use when a user or AI asks why Bridge is still running after closing the window, where the app went after launch, why there is no Dock icon, how to enable or disable launch at login, why the menu-bar item is missing, or what the window title markers mean.

Adom Bridge presence: menu-bar agent, hidden window, launch at login

Adom Bridge is a menu-bar agent (since 1.9.186). Its window is hidden most of its life; the working core is a small native (Rust) process that keeps serving the relay, direct API, bridges, notifications, and approvals whether or not the window is on screen.

The menu-bar agent model

  • A SIGNED-IN standalone launch goes straight to the menu bar: no window, and no Dock icon. Whenever the window is hidden, Bridge runs under the macOS Accessory activation policy (no Dock icon, no Cmd-Tab entry), in BOTH standalone and embedded modes. The menu-bar item is the always-present control surface.
  • A signed-OUT launch still shows the window: the first-run sign-in flow needs a surface, and "installed it, nothing happened" on a fresh machine is a bug class we never want back.
  • The window is a settings-and-approvals surface. It is summoned three ways:
    • the menu-bar item (Show Window / Settings)
    • launching the app a second time (single-instance: the running instance shows and focuses its window)
    • automatically, when Bridge needs the human: an approval dialog or the sign-in flow flips the app from Accessory to Regular (Dock icon appears) and activates the window. Hiding the window again returns to Accessory.
  • Closing the window returns Bridge to the menu bar. It does not exit.

The menu-bar item's menu: Show Window, Connect All, Disconnect All, Settings, Quit.

Close to menu bar: the close button hides, Bridge keeps serving

  • Clicking the window's close button does NOT exit Bridge. The close request hides the window and Bridge keeps running and serving (relay, direct API, bridges, notifications). This is by design: Bridge must stay reachable as the machine's recovery channel.
  • It is never silent: the FIRST 3 TIMES the user closes the window, Bridge shows a notification explaining that it moved to the menu bar, then stops reminding. The counter lives at ~/.adom/tray-notice-count (a legacy one-shot tray-notice-shown file seeds the count at 1 so existing users are not re-nagged from scratch).
  • Launching Bridge again while it is hidden is never a no-op (single-instance):
    • standalone: the existing instance shows and focuses its window
    • embedded with Adom Hydrogen alive: a notification says where Bridge lives (inside Hydrogen)
    • embedded but Hydrogen is dead (stale flag): treated as standalone, the window shows
  • The ONLY thing that exits Bridge is the desktop_shutdown verb (POST /command {"command":"shutdown"} on the direct API) or Quit in the menu-bar menu. Closing the window never does.

The menu-bar item: standalone only

  • In STANDALONE mode Bridge has a menu-bar item.
  • When EMBEDDED in Adom Hydrogen, Bridge HIDES its menu-bar item; Hydrogen is the app the human sees. When Hydrogen goes away, Bridge reverts to standalone and the menu-bar item comes back.
  • The absence of the menu-bar item plus a running Bridge process is therefore the normal embedded state, not a failure.

The hidden window costs nothing extra

There is no separate renderer-suspension machinery on macOS: a hidden window is simply hidden, and the Accessory policy keeps Bridge out of the Dock and Cmd-Tab. The Rust side keeps doing ALL real work while hidden: relay, direct API, bridges, bridge supervision (persistent respawn plus duplicate collapse), notifications, and shell approvals. UI-only work (LED probes, status emits that exist to paint the GUI) is skipped while the window is hidden and self-heals within one health tick of showing it.

Launch at login: default ON, self-healing

  • The intent is config.launch_on_boot, DEFAULT TRUE. The Settings checkbox (launch at login) reads and writes this intent and is checked by default.
  • The mechanism is a per-user LaunchAgent: ~/Library/LaunchAgents/inc.adom.desktop.plist.
  • A reconcile runs on EVERY launch, in BOTH standalone and embedded modes:
    • intent ON and the plist is missing or stale: (re)write it
    • intent OFF and the plist exists: delete it
  • This is the self-heal: a plist that was never created, got deleted, points at a moved app path, or failed to write is corrected on the next launch. An update that relocates the app rewrites the LaunchAgent to the new path.
  • Never create the LaunchAgent manually; the reconcile owns it.

Shared Adom sign-in (keychain)

One Adom sign-in serves both Adom Bridge and Adom Hydrogen: the session token lives in a SHARED keychain item, and ~/.adom/session.json is a rebuilt cache. Consequences:

  • Signing in to either app signs in both.
  • The sign-in survives uninstall and reinstall (the keychain item persists; the file cache is rehydrated from it).
  • Signing out deletes the keychain item, so it signs out everywhere.

Window title markers

The window title carries live version and provenance markers: the running VERSION (for example Adom Bridge — v1.9.187 release), the git SHA and build timestamp, and a signed or unsigned marker for the running binary's code signature. This is the quick truth check for which build is actually running.

Foreground attribution (v1.9.175)

Bridge never raises its own window silently. Every self-foreground (sign-in completion, notification click, shell-approve grant, request_shell_approval, menu-bar menu, second launch) is logged to the Activity Log as a foreground event naming the source and reason, and to startup.log as a FOREGROUND: line. An update-apply relaunch is deliberately QUIET: the updater drops ~/.adom/update-quiet-relaunch and the relaunched Bridge consumes it (10-minute freshness gate) and stays in the menu bar. If a user reports "Bridge randomly came to the front", read the Activity Log or startup.log; the answer is always recorded.