docs(packaging): document desktop GUI frontends and optdepends

The GUI frontends landed with README/CLI/operations docs but no packaging
coverage. Add a PACKAGING.md section with the command/script/requirement
table for both frontends, note why stdlib tkinter is still an optdepend
rather than a hard dependency, and record that packaging must not grant the
GUIs privileges beyond the operator's own account.

Add the matching PKGBUILD optdepends (`tk`, `pyside6`), plus
`python-pystray`/`python-pillow` for the tray applet, which were never
listed when it shipped. Also add `gui/` to the CLAUDE.md architecture notes
and state snapshot.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JX86xeoBJVBb16qHkDf53K
This commit is contained in:
Luna 2026-07-22 04:33:55 -07:00
parent 457c7604ba
commit 3dd82ab18b
No known key found for this signature in database
3 changed files with 38 additions and 1 deletions

View file

@ -87,6 +87,10 @@ Implemented investigation/response state:
runs `check --json` quick checks. Its logic modules (`tray/state.py`, runs `check --json` quick checks. Its logic modules (`tray/state.py`,
`actions.py`, `notify.py`) are GUI-free and tested; only `tray/app.py` `actions.py`, `notify.py`) are GUI-free and tested; only `tray/app.py`
imports GUI libs, and the core agent stays stdlib-only. imports GUI libs, and the core agent stays stdlib-only.
- Optional windowed desktop dashboards mirror the same pattern:
`enodia-sentinel gui` (stdlib tkinter) and `enodia-sentinel gui-qt`
(`[qt]` extra with PySide6). Both are read-only over detection state, share
the GUI-free `gui/model.py`, and display response plans for review only.
- IPS behavior is currently explicit workflow: posture hardening plus reviewed - IPS behavior is currently explicit workflow: posture hardening plus reviewed
dry-run containment actions. There is no automatic inline blocking or silent dry-run containment actions. There is no automatic inline blocking or silent
host mutation yet. host mutation yet.
@ -156,6 +160,10 @@ Start with:
- `tray/` is the optional desktop tray frontend over the CLI and systemctl; - `tray/` is the optional desktop tray frontend over the CLI and systemctl;
only `tray/app.py` may import `pystray`/`PIL` (enforced by an import-guard only `tray/app.py` may import `pystray`/`PIL` (enforced by an import-guard
test). test).
- `gui/` is the optional windowed desktop dashboard. `gui/model.py` is the
GUI-free presentation model over `tui.collect_model`; only `gui/app.py`
(tkinter) and `gui/qt_app.py` (PySide6, `[qt]` extra) import GUI libraries,
enforced by import-guard tests.
- `go-agent/` is the isolated Phase 1 sidecar with Go config, process-state, - `go-agent/` is the isolated Phase 1 sidecar with Go config, process-state,
detector, schema, and sweep-loop packages. It writes JSONL to stdout and detector, schema, and sweep-loop packages. It writes JSONL to stdout and
must not share or mutate Python daemon state during parity development. must not share or mutate Python daemon state during parity development.

View file

@ -190,6 +190,31 @@ empty.
not installed to a system autostart path by default — desktop users copy it to not installed to a system autostart path by default — desktop users copy it to
`~/.config/autostart/` themselves. `~/.config/autostart/` themselves.
## Desktop GUI Frontends (optional)
Two windowed dashboards ship alongside the tray applet. Both are optional
frontends over the same local state the TUI and web console read; neither is
required by the daemon, and core runtime dependencies stay empty.
| Frontend | Command | Console script | Requirement |
| --- | --- | --- | --- |
| tkinter | `enodia-sentinel gui` | `enodia-sentinel-gui` | stdlib `tkinter` (distro `tk` / `python-tk` / `python-tkinter`) |
| Qt6 | `enodia-sentinel gui-qt` | `enodia-sentinel-gui-qt` | `[qt]` extra (`PySide6`) |
Notes:
- `tkinter` is stdlib but is packaged separately on most distros, so it is an
`optdepends` (Arch `tk`), never a hard dependency.
- The `[qt]` extra (`pip install 'enodia-sentinel[qt]'`) pulls in `PySide6`
only for the Qt frontend; the Arch package lists `pyside6` as an optdepend.
- Both GUIs are read-only over detection state and display response plans for
review only — packaging must not grant them privileges beyond what the
operator's own account has. Daemon start/stop/restart goes through
`systemctl` and prompts for polkit authorization as usual.
- Only `gui/app.py` (tkinter) and `gui/qt_app.py` (Qt) import GUI libraries;
`gui/model.py` stays import-clean so headless builders can run the test
suite without a display server or `PySide6` installed.
## Terminal TUI and Completion ## Terminal TUI and Completion
The terminal dashboard is stdlib-only and available through The terminal dashboard is stdlib-only and available through

View file

@ -10,7 +10,11 @@ depends=('python>=3.11' 'iproute2' 'procps-ng')
optdepends=('python-bpfcc: eBPF event-driven execve/syscall monitors (catches short-lived processes and memory telemetry)' optdepends=('python-bpfcc: eBPF event-driven execve/syscall monitors (catches short-lived processes and memory telemetry)'
'bpftrace: execve tracing of short-lived processes in snapshots' 'bpftrace: execve tracing of short-lived processes in snapshots'
'libnotify: desktop notifications on alert' 'libnotify: desktop notifications on alert'
'libarchive: signed-package verification against cached package .MTREE manifests') 'libarchive: signed-package verification against cached package .MTREE manifests'
'tk: stdlib tkinter desktop dashboard (enodia-sentinel gui)'
'pyside6: Qt6 desktop dashboard (enodia-sentinel gui-qt)'
'python-pystray: desktop tray applet (enodia-sentinel-tray)'
'python-pillow: desktop tray applet icon rendering')
backup=('etc/enodia-sentinel.toml') backup=('etc/enodia-sentinel.toml')
source=() source=()
sha256sums=() sha256sums=()