Private developer notes for the interfire-ui GPUI app under ui/.
Linux desktop client with personal-firewall tray/alert path and dense Rules
chrome (left nav + tables). Same Unix IPC as interfirectl /
interfire-tui. Rules is the primary surface.
InterFire overrides the kit theme after gpui_kit::init via ui/src/theme.rs
(apply_phoenix_theme). Settings exposes a Theme switcher: System | Light |
Dark. Brand PNGs live under docs/brand/ and are embedded
from ui/src/brand.rs (light nav uses the light app icon variant).
Shared brand accents stay the same in both modes (#F84800 / #F03105).
| Role | Dark | Light | Use |
|---|---|---|---|
| Canvas | #0E1114 |
#F5F6F8 |
Window / sidebar |
| Surface | #161B20 |
#FFFFFF |
Content panel |
| Elevated | #1E252C |
#ECEFF3 |
Overlays, Settings rows |
| Border | #2C3540 |
#D0D7DE |
Separators |
| Text | #E8EDF2 |
#1F2328 |
Primary labels |
| Muted | #8B97A5 |
#656D76 |
Secondary labels |
| Accent | #F84800 / #F03105 |
same | Selected nav, Allow, CTA |
| Brand deep | #D00000 |
same | Active / pressed |
| Danger | #EF5350 / #DC3545 |
same | Deny |
| Ok / Warn | #3DDC97 / #F5A623 |
same | Tray chips |
Orange is brand identity. Do not fall back to stock kit blue for selected
chrome. Tray icons use brand pixmaps (not stock dialog-* names). The TUI
reuses the same roles in crates/interfire-tui/src/palette.rs (--theme=light
or --theme=dark, default dark).
+--------+------------------------------------------+
| Status | content for selected section |
| Apps | |
| Rules* | (Rules: dense table + detail/actions) |
| Log | |
| Network| |
| Profil.| (daemon + UI RSS/CPU) |
| Settings| |
+--------+------------------------------------------+
| section | daemon | Ready|Loading|Saving |
+---------------------------------------------------+
Tray: protected | prompting | degraded | daemon-unavailable (Linux SNI via
ksni; state also mirrored in Status chrome and the window status bar).
Unavailable uses a muted phoenix-orange pixmap (icon-tray-unavailable-64.png)
so the icon stays readable on dark panels. When the tray registers successfully,
closing the main window leaves the process running (QuitMode::Explicit); tray
menu Open InterFire / Quit InterFire UI reopen or exit. Session
autostart installs /etc/xdg/autostart/interfire.desktop. On Debian GNOME, a
visible tray needs a shell that exposes StatusNotifierItem; when SNI
registration fails, Status still shows tray state and must not claim an icon is
present (and closing the window quits as usual). Pop!_OS is a primary verify
target alongside Debian GNOME.
Rules: live list / select / add / delete over Unix IPC (rule-list,
rule-add, rule-delete). Log: capped at 2,000 rows with a virtualized
viewport; long-lived audit-subscribe id interfire-ui (reconnect
replaces; tear-down on window/host drop). Applications lists observed process
identities from the daemon cache (v1 process-list: absolute path, PID + start
ticks, cmdline, uid, recent destinations, effective rule) with optional open-in
htop/atop/btop/top when those binaries are on PATH.
Network shows only InterFire-owned nftables (inet interfire): status,
install queue rule, and remove table (network-status /
network-install / network-remove). Settings covers socket, tray, and
theme.
Harness coverage for prompt Allow/Deny frames (including stale/expired
disable) and audit reconnect that reuses the stable interfire-ui
subscriber id. Run with the Linux UI packages above.
| Crate | Version | Role |
|---|---|---|
gpui-kit |
0.6.0 (crates.io) | One dependency wrapping GPUI + components + shell |
| Transitive | gpui-pre 0.3.x, gpui-component 0.6.x |
Pulled by gpui-kit |
hotpath |
0.25.x (crates.io) | Optional profiler; see Memory and profiling |
Pinned 2026-09-07 (gpui-kit). hotpath added 2026-09-08 for RSS investigation.
Rebuild with make ui. Prefer gpui-ce only if Linux tray work is blocked by
upstream gaps.
Linking interfire-ui needs development packages on the primary targets
(Debian and Pop!_OS both use apt):
sudo apt-get install -y \
libxkbcommon-dev libxkbcommon-x11-dev \
libxcb1-dev libxcb-xfixes0-dev libxcb-shape0-dev \
libfontconfig1-dev libfreetype6-devmake test excludes interfire-ui so machines without those packages stay green.
Use make ui-test (and CI) when the packages are present.
- Binary name:
interfire-ui - Tree:
ui/(workspace member) - Local smoke:
make run-ui(sharedSOCKET, default/tmp/interfire.sock; seeDEVELOPMENT.md) - Packaging:
make debbuildsinterfire_*.debfor Debian (stable) GNOME and Pop!_OS; verify with../docs/install-matrix.md
GPUI needs a modern GPU path. Weak or older cards often fail at startup (wgpu
pipeline validation). Default: the binary re-execs with CPU software GL
(LIBGL_ALWAYS_SOFTWARE=1, WGPU_BACKEND=gl) unless:
INTERFIRE_UI_NATIVE_GPU=1(use the real GPU / existing graphics env), orWGPU_BACKENDis already set (honour memcheck, profile, or operator override).
Expect lower frame smoothness on software GL; that is intentional so low-end
dogfood machines still run the desktop client. make memcheck-ui / make profile-ui
already set the software env explicitly.
make memcheck-ui samples /proc/<pid>/VmRSS on a release interfire-ui
with software GL defaults (LIBGL_ALWAYS_SOFTWARE=1, WGPU_BACKEND=gl).
| Process | Typical idle VmRSS | Gate | Notes |
|---|---|---|---|
interfired |
~6–7 MiB | < 40 MiB (make memcheck) |
Enforcement path; this is the firewall budget that matters |
interfire-ui |
~190 MiB | < 220 MiB idle / < 260 MiB prompt-load | GPUI + wgpu + fonts/atlas; framework floor before InterFire tables grow |
| Combined daemon + idle UI | ~200 MiB | < 260 MiB | Dominated by the UI process |
Recorded context (2026-09): release GPUI + wgpu on Linux idles around 190 MiB even with empty Rules / no big audit buffer. That is not InterFire policy state and not the daemon. Do not market the desktop client as a tiny process. Original sketch ceilings (80 / 120 / 150 MiB for UI / combined) were retired after measurement; gates were raised to measured ceilings with headroom, not lowered by pretending the floor is smaller.
Order-of-magnitude context (not InterFire-measured): a minimal Electron app often idles in the ~150–300 MiB band (main + renderer + GPU processes). Real Electron products are often higher. GPUI here sits in the Electron-low / mid band, not in a GTK/Qt tray-applet band (~10–50 MiB). Cutting under ~80 MiB idle for a full GPUI main window is unlikely without a different UI strategy (tray-only, thinner toolkit, or deferred window).
make memcheck-uiNeeds DISPLAY or xvfb-run. Prompt-load stages 100 pending prompts, an alert,
and a full 2,000-row audit buffer inside the UI process.
| Condition | Budget | Env override |
|---|---|---|
| Idle UI | < 220 MiB | INTERFIRE_UI_IDLE_BUDGET_KIB (default 225280) |
| Prompt-load UI | < 260 MiB | INTERFIRE_UI_PROMPT_BUDGET_KIB (default 266240) |
| Combined daemon + idle UI | < 260 MiB | INTERFIRE_UI_COMBINED_BUDGET_KIB (default 266240) |
Settle time: INTERFIRE_UI_MEMCHECK_SETTLE_SECS (default 4). Fail the release if
any sample exceeds budget. Do not raise these ceilings further to greenwash.
Product contract summary: ../docs/ux-interfire.md.
Upstream: hotpath.rs, blog notes at
hotpath.rs/blog. Crate hotpath 0.25.x (MIT).
Wired only on interfire-ui. Default make ui / packaging builds stay cold:
macros and CountingAllocator are pass-through unless features are enabled.
| Cargo feature | Effect |
|---|---|
hotpath |
Enable timing / instrumentation (hotpath/hotpath) |
hotpath-alloc |
Track allocations via hotpath::CountingAllocator (hotpath/hotpath-alloc) |
make profile-ui
# equivalent:
cargo build -p interfire-daemon --release
cargo build -p interfire-ui --release --features hotpath,hotpath-alloc
bash scripts/profile-ui.shscripts/profile-ui.sh:
- Starts a temp daemon (
--no-ebpf --no-nfqueue). - Runs release
interfire-ui --rss-probe=idleunder DISPLAY orxvfb-run. - Sets
HOTPATH_SHUTDOWN_MS(default 8000) soHotpathGuardBuilder::build_with_shutdownprints the report and exits.
Instrumented InterFire paths (see #[hotpath::measure]):
App::newApp::apply_rss_probeprompt_load_fixturepoll_snapshot
How to read a report:
- If instrumented InterFire functions allocate little vs ~190 MiB VmRSS, the floor is GPUI/wgpu (expected). Document and keep honest gates; do not claim a low-RSS desktop shell.
- If InterFire paths dominate growth (prompt-load / log), cut those paths and
only then lower
INTERFIRE_UI_*_BUDGET_KIBdefaults. - Never enable
hotpath/hotpath-allocin default release or.debbuilds.
Env knobs: HOTPATH_SHUTDOWN_MS, HOTPATH_ALLOC_METRIC=count (upstream), plus
the memcheck overrides above.
- Product contract:
../docs/ux-interfire.md - Make index:
DEVELOPMENT.md - Private structure study and manuals:
.cursor/refs/kerio/(not in application git)