Repository navigation
Replace the local web dashboard with a native GTK4 OpenFrag app #48
Copy link
Copy link
Open
Labels
wayfinder:claimedA session is working this ticket nowA session is working this ticket nowwayfinder:taskTask ticket: manual work that unblocks the discussionTask ticket: manual work that unblocks the discussion
Description
Goal
Replace the local browser dashboard with an installed native GTK4 desktop client before v1. Keep the daemon and recorder as background processes so capture and Game State Integration continue when the window is closed.
Settled architecture
One OpenFrag installation ships:
openfrag, the GTK4 desktop client for stats, setup, Doctor, Match evidence, Clip review, settings, and status.openfragd, the private background service that owns SQLite, files, capture coordination, Game State Integration, imports, and mutations.openfrag-recorder, the pinned supervised capture helper.
The desktop client communicates with the daemon through a private Unix domain socket. It never opens SQLite directly. Remove the browser launcher, embedded dashboard HTML, loopback TCP listener, and public HTTP-shaped product language.
Five-round decision: GTK4 versus Tauri
- Product fit: GTK4 wins because the requested product is genuinely native; Tauri remains a webview.
- Existing UI reuse: Tauri wins because it could reuse HTML, CSS, and JavaScript.
- Linux integration and accessibility: GTK4 wins through native widgets and desktop integration.
- Security boundary: GTK4 wins because it removes the browser renderer and localhost transport from the trusted UI path.
- Packaging and long-term ownership: GTK4 wins because OpenFrag is Linux-first and Rust-based, while Tauri adds a frontend toolchain plus a system webview dependency.
Winner: GTK4, four rounds to one. The short-term rewrite cost is accepted to avoid shipping a v1 interface already marked for replacement.
Required implementation
- Add a Rust GTK4 desktop binary with canonical application identity and one main window.
- Preserve domain logic below the UI. Expose typed daemon operations over a private, permission-restricted Unix socket.
- Implement setup, Doctor, Match and Rating evidence, stats, Clip preview/review/trim/export, Manual Flag status, capture status, errors, and empty/loading states.
- Keep capture and Game State Integration alive when the window closes. The app may activate or focus an existing window without starting a second daemon.
- Remove the embedded HTML dashboard, JavaScript, browser launch path, localhost API listener, and their packaging/runtime dependencies.
- Make every state keyboard accessible, screen-reader legible, deterministic under test, and safe with untrusted file names and imported content.
- Package the client, daemon, service, launcher, icons, desktop metadata, and recorder as one product in AUR, Fedora 43, and Fedora 44 channels. The removed generic binary tar channel is not a v1 target.
- Add focused widget/presenter tests, typed transport contract tests, accessibility-tree assertions, headless native journeys, and installed desktop smoke checks.
- Update the support matrix with real KDE Wayland and GNOME Wayland results.
Acceptance criteria
- Launching OpenFrag opens a native desktop window, not a browser.
- No shipped process listens on TCP for the UI.
- Closing the window does not stop an enabled replay buffer or Game State Integration.
- The client cannot mutate SQLite or media outside the daemon contract.
- Every dashboard capability represented in v1 has an equal or stronger native workflow and automated proof.
- Installed AUR, Fedora 43, and Fedora 44 packages contain and launch the same application identity.
- PC1 and PC2 complete the native installed journey with explicit human observation.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
wayfinder:claimedA session is working this ticket nowA session is working this ticket nowwayfinder:taskTask ticket: manual work that unblocks the discussionTask ticket: manual work that unblocks the discussion
Activity
NtrpyDev commentedon Jul 15, 2026
User-authored placeholder assets supplied on 2026-07-15:
/home/glorg/Pictures/openfrag-icons/openfrag_icon.png, 512 x 512 RGBA, SHA-256660579ff55d5f5a7cf2e84411fd45a544926210f2454fd9ff598249849779200/home/glorg/Pictures/openfrag-icons/openfrag_banner.png, 1500 x 500 RGBA, SHA-256652be5d4f5d480fa64f54035d22a5061422d526d34c88e86ddf1a50b327bef1fPreserve the originals and import their exact bytes for the native app and documentation. Any later redesign is a separate explicit decision. Do not silently overwrite or regenerate these files.
NtrpyDev commentedon Jul 15, 2026
Five-round transport decision: bounded JSON frames vs binary frames
The settled seam is one typed request and one typed response per private Unix-socket connection. Demo import passes an explicitly selected local path, and Clip preview returns a daemon-authorized path, so the transport does not need to carry large media payloads.
Winner: bounded JSON, four rounds to one.
The implementation will cap request and response frames, reject trailing or unknown data, create the runtime directory with private permissions, create the socket with mode 0600, verify the peer user, and handle one request per connection. The small external interface is
Client::execute(Request) -> Reply; storage, imports, capture, and setup remain behind the daemon adapter.NtrpyDev commentedon Jul 15, 2026
Native vertical-slice progress:
f7a566b.07f1689.cargo test -p openfrag --lib,cargo test -p openfrag-ipc,cargo test -p openfragd --test ipc_contract, and targeted Clippy with warnings denied.Ticket remains claimed. Clip editing, preview, trim, export, setup actions, diagnostics, match detail, Receipts, packaging, and native journey tests still remain before resolution.
NtrpyDev commentedon Jul 15, 2026
Five-round setup mutation decision: broad form versus action enum
The native client must invoke setup mutations without letting invalid field combinations become routine protocol states.
Winner: a dedicated setup action enum, four rounds to one. The daemon adapter will translate it into the existing internal setup request so domain logic remains unchanged.
NtrpyDev commentedon Jul 15, 2026
Native Doctor progress:
e6eb4a2exposes the daemon setup snapshot and renders every check and action in the GTK Doctor.35b7b9ftypes every setup mutation and proves a real defer-GSI state change through daemon composition.fd1a6b9wires GTK controls, required-field validation, explicit consent confirmation, asynchronous socket I/O, and full Doctor rerendering.target/debug/openfragshowed Last Session and reached Setup and Compatibility Doctor entirely by keyboard.openfragdprocess remained alive.Ticket remains claimed. Match details and Receipts, complete Clip workflows, import, Manual Flag, accessibility-tree automation, dashboard removal, and packaging remain.
NtrpyDev commentedon Jul 15, 2026
Five-round Match navigation decision: inline expansion versus dedicated evidence page
Winner: a dedicated Match evidence page, four rounds to one. The Match list remains a fast, single-action index, and selecting a row opens the evidence page inside the same native window.
NtrpyDev commentedon Jul 15, 2026
Five-round Demo picker decision: FileChooserNative versus FileDialog
Winner: FileDialog, three rounds to one with one tie. OpenFrag will raise its declared GTK feature floor to 4.10 and pass only the explicitly selected local Demo path to the private daemon.
NtrpyDev commentedon Jul 15, 2026
Native evidence and import progress:
07710a6adds typed Match detail and Receipt requests, dedicated GTK pages, loading states, back navigation, bounded imported evidence text, and typed not-found errors.963c9d2raises the supported GTK floor to 4.10, opens a filtered native Demo picker, passes only the selected absolute path, rejects relative paths, non-Demo files, non-regular files, symlinks, and files over 2 GiB, and refreshes Matches after a completed import.Ticket remains claimed. Clip preview and mutations, Manual Flag and diagnostics, browser-surface removal, accessibility automation, and native packaging still remain.
NtrpyDev commentedon Jul 15, 2026
Five-round Manual Flag placement decision: Setup versus Last Session
Winner: Last Session, four rounds to one. Setup retains approval and repair actions; Last Session gains typed diagnostics, current capture status, and the Manual Flag action with a deterministic result or explicit error.
NtrpyDev commentedon Jul 15, 2026
Native Manual Flag and status progress:
08b6eccadds typed Diagnostics and Manual Flag requests and replies to the private Unix-socket protocol.Ticket remains claimed. Browser-surface removal, native accessibility journeys, installed packaging, and complete acceptance evidence still remain.
NtrpyDev commentedon Jul 15, 2026
Five-round browser-surface removal decision: unreachable compatibility code versus complete deletion
Winner: complete deletion, four rounds to one. The official loopback Game State Integration endpoint remains a separate Valve-facing input; all desktop control moves exclusively through the private Unix socket.
NtrpyDev commentedon Jul 15, 2026
Five-round reply framing decision: wrapper structs versus adjacent tagging
The original internally tagged reply enum cannot serialize sequence newtypes such as Match and Clip collections. Both valid fixes preserve typed JSON and the one-frame socket boundary.
{result, data}regardless of whether its payload is a struct, list, or scalar.Winner: adjacent tagging, four rounds to one. Replies will use a bounded
{result, data}envelope, while errors remain typed payloads inside the same envelope.NtrpyDev commentedon Jul 15, 2026
Browser-surface removal progress:
fc7fde7removes the embedded HTML and JavaScript dashboard, all desktop HTTP routes, multipart upload and media streaming handlers, and their runtime dependencies.{result, data}framing, four rounds to one, and80ebc47fixes and round-trips collection frames.80ebc47also removes Playwright, Node, the browser launcher, xdg-open, and the generic binary archive channel from product, CI, release, and test configuration.openfragclient alongsideopenfragdand the bundled recorder. The desktop entry launchesopenfragdirectly.48c14f0pins the deterministic native-channel source archive at SHA-256fc6ed0884f5bd7decf93d29b47d6623cbe57882049f957dd7ae938d04cb1fe14, and the AUR/COPR source verifier passes.Ticket remains claimed. Native accessibility-tree and headless window journeys, installed client launch proof, final package environments, and physical desktop observations still remain.
8 remaining items
NtrpyDev commentedon Jul 15, 2026
Five-round decision: populated native acceptance harness
Option A: extend the existing AT-SPI harness with a populated-state mode and an existing private socket
Option B: create a second GUI test script dedicated to populated Matches and Clips
Winner: Option A, 4-1. The reusable harness will support fresh and populated modes; the complete installed journey will reuse its live private socket and assert Match, Receipt, Clip editor, export, and delete-confirmation controls.
NtrpyDev commentedon Jul 15, 2026
Decision: GTK StackSidebar versus explicit grouped native navigation controls.
Round 1, visual fit: explicit controls win because they reproduce the supplied left-aligned mock navigation directly.
Round 2, dynamic-page behavior: explicit controls win because Match, Receipt, and Clip editor pages never become primary destinations or clear the navigation contract.
Round 3, implementation size: StackSidebar wins because it requires less application code.
Round 4, keyboard and assistive technology: explicit controls win because each destination exposes a stable toggle-button action and deterministic focus order.
Round 5, acceptance reliability: explicit controls win because the same native actions work in fresh and populated AT-SPI journeys without test-only workarounds.
Winner: explicit grouped native navigation controls, 4-1.
Implemented evidence: supplied UI mocks now drive the native layout, Tonight remains renamed to Last Session, Match and Clip rows expose explicit native buttons, transient evidence/editor pages stay out of primary navigation, and the installed acceptance journey traverses populated Match, Receipt, Clip editor, and delete confirmation state against a live external daemon. Fresh and populated accessibility journeys pass, the installed MVP journey passes, and the optimized fast suite passes in 10.52s with four jobs.
NtrpyDev commentedon Jul 15, 2026
Decision: install the supplied icon through the freedesktop hicolor theme versus reference a package-private absolute asset path.
Round 1, desktop compatibility: hicolor wins because the desktop entry can use the canonical application ID on KDE, GNOME, and other freedesktop shells.
Round 2, native package conventions: hicolor wins because both Arch and Fedora expect application icons under the shared theme hierarchy.
Round 3, per-user installation: hicolor wins because the same hierarchy works under XDG_DATA_HOME without rewriting the desktop Icon field.
Round 4, upgrade and uninstall ownership: hicolor wins because every channel can replace and remove one canonical file while preserving user data.
Round 5, verification: hicolor wins because package-root and staged lifecycle checks can compare exact bytes and mode at the same relative path.
Winner: the standard hicolor application path, 5-0.
Implemented evidence: the 512x512 supplied icon now ships through static, AUR, and RPM channels; source archives include it; release authority checks require it; all upgrade and removal verifiers cover it; the previously undefined full Linux asset-verifier command was removed. Full Linux asset verification passes, deterministic AUR/COPR source verification passes, and the four-job fast suite passes in 9.15s.
NtrpyDev commentedon Jul 15, 2026
Documentation structure decision, five rounds.
Option A was a single comprehensive README. Option B was a concise README that routes users by intent into installation, first-run, troubleshooting, architecture, support, testing, contribution, and security documents.
Winner: intent-routed documentation, 4-1. The README is now the stable entry point, and every new local link passes a repository-wide target check.
NtrpyDev commentedon Jul 15, 2026
Clean-package dependency decision, five rounds.
Option A was to maintain a second hand-written dependency list inside the container verifier. Option B was to install the dependency declarations from PKGBUILD and the RPM spec.
Winner: recipe-driven dependency installation, 4-1. The verifier will source the trusted PKGBUILD arrays and use Fedora builddep on the checked-in spec before building.
NtrpyDev commentedon Jul 15, 2026
Recorder root-boundary decision, five rounds.
Option A allows only the side-effect-free
--versionquery before the recorder root refusal. Option B keeps every argument behind the root refusal and makes each build or package verifier switch users for version inspection.Winner: root-safe version inspection, 3-1 with one tie. Capture and every other command continue to fail for effective UID 0.
NtrpyDev commentedon Jul 15, 2026
Shared-drive source-mode decision, five rounds.
Option A was to build archives only from
git archiveat committed HEAD. Option B was to copy the selected working-tree bytes and then normalize each file to its Git index mode.Winner: copy bytes then normalize Git modes, 2-1 with two ties. The bundle will apply
100644and100755from each repository index after extraction.NtrpyDev commentedon Jul 15, 2026
Packaged recorder checksum decision, five rounds.
Option A disables post-install stripping for the package so the recorder bytes hashed during package assembly are the bytes installed. Option B lets package tooling transform the binary and weakens or regenerates the checksum later.
Winner: preserve packaged recorder bytes, 3-2. Arch and Fedora will explicitly opt out of post-install stripping with a documented integrity reason; the runtime checksum remains strict.
NtrpyDev commentedon Jul 15, 2026
Third-party notice collision decision, five rounds.
Option A merges OpenFrag and recorder notices into one generated file. Option B installs the original notices under distinct stable filenames.
Winner: distinct installed notice files, 4-1. Every package verifier will byte-compare the OpenFrag notice, recorder fork description, and recorder third-party notice separately.
NtrpyDev commentedon Jul 15, 2026
Complete software and package gate passed for the native v1 candidate.
Evidence:
c5e16898ae03a3dd4223d33f97b3a881ee1f6064963de70378754caf4a88d783.f9566cf1b0467bc43918ac5322d2c9fe0d6cdb1b, preserves Git file modes on NTFS/FUSE, and packages distinct verified legal notices.Result directory:
/mnt/shared/openfrag/target/openfrag-suite/runs/complete-20260715T215036Z-158873.Ticket remains claimed because physical KDE/AMD PC1 and GNOME/NVIDIA PC2 installed journeys are still acceptance criteria.
NtrpyDev commentedon Jul 15, 2026
The supplied Doctor, Clips, Last Session, and Matches mocks are now the visual contract for this ticket, with the settled Last Session terminology replacing Tonight.
The first real KDE launch exposed a scaffold-quality shell: oversized generic cards, sparse hierarchy, and malformed title controls. Commits a7fee34 and 4169322 tighten the native shell, add the mock's Session Matches, baseline, best Clips, and compact evidence hierarchy, fix native title controls, and align page names.
The mocks also exposed a real data-contract omission. Storage retained Rating components, values, weights, and Receipt links, but the daemon discarded them before the Native Client. Commit f774bb7 carries that evidence through the versioned Unix-socket protocol and renders accessible component rows without fabricating unavailable player data. The red-to-green proof is a presenter contract plus the populated installed AT-SPI journey.
Evidence after the changes:
The ticket remains open for final visual refinement and physical PC1 and PC2 qualification.
NtrpyDev commentedon Jul 15, 2026
Final software candidate qualification passed.
189b8ea23272a2a05aa7245eb9b141daae7611bbd04d3c6020c061aed7f3186etarget/openfrag-suite/runs/complete-20260715T223942Z-3121579Publication remains blocked on the explicit PC1 KDE/AMD and PC2 GNOME/NVIDIA physical qualification gates. This Wayfinder ticket remains open.
NtrpyDev commentedon Jul 15, 2026
Physical PC2 probing exposed and resolved a Doctor-state bug.
The first implementation incorrectly treated a running desktop portal as an approved OpenFrag shortcut. The fast suite rejected that overclaim. The final model now distinguishes three states: unavailable, available but approval required, and approved. The regression proves that an available unapproved portal remains blocked with accurate remediation.
Corrected candidate evidence:
d00119eef5b4a7c2fc2fe54d5c03555e37c945e6fa9b5341348e544b00bae224target/openfrag-suite/runs/complete-20260715T230715Z-3789923PC2 partial physical evidence:
Full PC1/PC2 capture, portal approval, visual, playback, upgrade, and uninstall gates remain. Ticket stays open.
NtrpyDev commentedon Jul 16, 2026
Final corrected candidate evidence:
1ecd655609a2bbbe3d199a86001cf1922cb6cd0fcaa883d8483bd9b2df9fdfc6target/openfrag-suite/runs/complete-20260716T002754Z-1541080Physical exact-artifact state:
bdb9d886fd832bfbbe46949a8f3af214267bcb9c24ef4fb9534f54f6f6ba4d1303e8adf2619c23dab0a35d1d55dda878ca0b501d52b0de891ae3f6d13f5eea7a782c56f947697ce04afd5987dcd61a826cff5b921ce0128fc4b6a1f609297e44/mnt/shared/SteamLibrary, capture dependencies are ready, daemon restart/bootstrap passed, service remains active and disabledRemaining gates require human-visible consent or observation: GUI visual/accessibility on KDE and GNOME, shortcut approval, real AMD/NVIDIA capture, audio selection, FFprobe/playback observation, GSI consent/write and live CS2 freshness on PC1, plus physical upgrade/uninstall preservation. Publication remains blocked and this ticket stays open.
NtrpyDev commentedon Jul 16, 2026
PC2 physical qualification progress found and fixed two release-blocking capture defects.
Implemented:
8a0c0e2andcb35ca4let replay capture and Manual Flag composition start before Steam identity or GSI credentials exist.4f58fb1corrects the bundled recorder contract to Matroska, H.264, default-output audio, and AAC; FFprobe now rejects saved media unless it has exactly one video and one audio stream.Ctrl+Alt+F10Manual Flag default and stores a private mode-0600 screen-capture portal restore token.Real GNOME/NVIDIA evidence on PC2:
Ctrl+Alt+F10forio.github.ntrpydev.openfrag.Remaining PC2 blocker:
gnome-control-center-global-shortcuts-providercrashes ingdk_surface_get_displaywhile rebinding the already-approved shortcut with no parent window.app-io.github.ntrpydev.openfragservice identity and is now part of the service-lifecycle release gate.Ticket remains claimed. No Wayfinder ticket is being closed.