# System Tray Indicator

Omnius ships a native per-login tray indicator for Linux, macOS, and Windows
on x64 hosts. It is separate from the REST daemon: closing the indicator never
stops the daemon, and the daemon remains usable in headless sessions.

## Install And Control

```bash
omnius tray install                 # register login startup and start now
omnius tray status                  # indicator, health, endpoint, registration
omnius tray restart
omnius tray stop                    # stop only the indicator
omnius tray uninstall               # stop it and remove login startup
```

From an active Omnius TUI, use the local slash command instead:

```text
/indicator                         # start and report readiness
/indicator status                  # inspect without starting
```

`/tray` is retained as an alias. Login registration and the full
start/stop/restart lifecycle remain available through the top-level
`omnius tray` command.

`/indicator` first reconciles the current Omnius daemon on its configured
loopback port (11435 by default), waits for verified online health, repairs a
stale tray endpoint/autostart registration, and only then starts the native
indicator. Untracked processes occupying the port are reported as blockers and
are never terminated automatically.

The indicator polls the daemon's loopback-only `GET /health` route. It does not
load a model or contact the configured inference backend. If the daemon uses a
non-default port, Omnius discovers `OMNIUS_HOST`/`OMNIUS_PORT` from the current
environment and, on Linux, from the installed user service. Override it
explicitly when needed:

```bash
omnius tray install --endpoint http://127.0.0.1:11535
```

Non-loopback endpoints are rejected. The menu provides the current health and
version, dashboard and log shortcuts, service-manager-aware daemon controls,
login-startup control, and **Quit indicator**. Daemon stop is a separate,
explicit menu action.

## Health And Updates

The indicator refreshes daemon health and update availability at startup and
every 10 seconds. Update discovery uses the same cached registry lookup and
semver comparator as the CLI and dashboard, so an older registry/cache value is
never presented as an upgrade.

The first menu row always shows the live daemon version and health. It is greyed
and non-clickable while that version is current. When a newer exact version is
available, the same row changes to **update to vX.Y.Z available** and becomes the
primary update button. While an update runs it displays the durable transaction
phase; if verification fails it stays clickable as a retry and its tooltip shows
the remediation/error instead of silently returning to the current state.

Clicking the row starts the same verified global update transaction as
`POST /v1/update` and `/update quick`. The coordinator:

1. installs the exact target through the real global npm flow;
2. verifies the installed package and resolved `omnius` executable;
3. restarts the daemon and verifies the target runtime and boot/package hashes;
4. relaunches and verifies the indicator because it was running when the update
   started.

State persists in `~/.omnius/update-state.json` and detailed output in
`~/.omnius/update.log`, so a daemon or tray restart does not turn an incomplete
install into a false success. The dashboard can inspect the same operation with
`GET /v1/update`.

## Linux / Ubuntu

GNOME needs a StatusNotifier/AppIndicator host. Ubuntu Desktop normally ships
the `gnome-shell-extension-appindicator` extension; the native helper uses
Ayatana AppIndicator when available. On a minimal installation:

```bash
sudo apt install gnome-shell-extension-appindicator libayatana-appindicator3-1
```

Verify the desktop host without touching the daemon:

```bash
gdbus call --session \
  --dest org.kde.StatusNotifierWatcher \
  --object-path /StatusNotifierWatcher \
  --method org.freedesktop.DBus.Properties.Get \
  org.kde.StatusNotifierWatcher IsStatusNotifierHostRegistered
```

Login registration is written to
`~/.config/autostart/omnius-tray.desktop`. Runtime PID/state stays under
`$XDG_RUNTIME_DIR/omnius`; logs are under
`$XDG_STATE_HOME/omnius` (usually `~/.local/state/omnius`). This avoids tying a
desktop process to the daemon's persistent `~/.omnius` data directory.

## Platform Registration

| Platform | Login registration |
| --- | --- |
| Linux | XDG autostart desktop entry |
| macOS | `~/Library/LaunchAgents/ai.omnius.tray.plist` |
| Windows | per-user Startup-folder command |

The optional native helper is exact-pinned and its platform executable is
checked against a release SHA-256 before execution. Omnius remains usable when
optional dependencies are disabled; only the tray command reports the missing
helper. The current helper release targets x64. Other architectures fail with
an explicit diagnostic instead of falling back to a headless or emulated tray.

## Troubleshooting

```bash
omnius tray status --json
tail -f ~/.local/state/omnius/tray.err.log   # Linux default
```

- **No icon on GNOME:** confirm the AppIndicator extension is active and the
  session watcher reports a registered host.
- **Offline despite a running daemon:** pass the daemon's loopback endpoint
  with `--endpoint`; avoid `0.0.0.0` in client URLs.
- **No graphical session:** run `omnius tray start` from the logged-in desktop
  session so `DISPLAY`/`WAYLAND_DISPLAY` and the session D-Bus address exist.
