1# goq agent guide23goq is a one-host, one-user game-streaming appliance. The public project and4website are **goq.sh**. **Sigil** is the pure Rust Linux host command and5daemon. **Portal** is the installed Tauri client that opens a session to a6Sigil host.78## Product boundary910- Sigil runs on a dedicated, physically headless bare-metal Linux machine.11- Gamescope owns the private Steam/game display; capture must not require an12 interactive desktop or XDG ScreenCast portal.13- The host is a pure Rust daemon. It must never depend on Tauri, WebKit, or a14 host-facing UI.15- Portal is client-only. It must not bundle host capture, encoding, daemon,16 identity, configuration, or Linux input-injection assets.17- Iroh owns native connectivity, endpoint identity, encryption, direct-path18 discovery, and relay fallback.19- Exactly one media generation is active at a time. Native MoQ control v220 shares that single generation with up to `max_viewers` authenticated clients21 (default 3, hard ceiling 8); control v1 and grouped v3 stay single-client22 exclusive and reject a second client. No capture, encoder, publisher, or23 actuator scales with viewer count.24- At most one viewer holds slot-0 input focus. Every other viewer is a25 spectator, and a former holder is fully neutralized before a successor is26 granted.27- Controller is the primary interaction model. Keyboard and relative mouse are28 secondary inputs.2930## Current architecture3132- `crates/sigil-protocol` owns bounded, versioned handshakes, capabilities,33 media/audio headers, input messages, protocol limits, and ALPN constants.34- `crates/sigil-host` builds the `sigil` daemon and `sigil-probe` diagnostic.35 - `main.rs` owns the CLI, endpoint/router setup, and capture probes.36 - `server.rs` owns session admission and separate media, input, and audio37 protocols.38 - `source.rs` owns test-pattern and Gamescope PipeWire capture plus AMD GstVA39 H.264 encoding. External `gst-launch` remains the default; an explicitly40 feature-gated in-process backend owns bounded encoder control.41 - `input.rs` owns strict Linux `uinput` pointer, keyboard, and Xbox-style42 virtual gamepad devices.43 - `audio.rs` owns bounded PipeWire/Opus capture.44 - `identity.rs` and `config.rs` own fail-closed persistent host state.45- `src-tauri` is Portal's native boundary.46 - `commands/network.rs` owns Iroh connections, bounded media-object receive,47 binary Tauri channels, input transport, and diagnostics.48 - `commands/auth.rs` owns FIDO2 `hmac-secret` derivation.49 - `commands/state.rs` owns launch options and process-wide bounded state.50- `portal/main.js` and the focused `portal/*.mjs` modules own WebCodecs decode,51 AudioWorklet playback, controller-first navigation, input capture, A/V52 synchronization, window geometry, and client diagnostics.53- `website/` is the static goq.sh site. A merge to `main` publishes it through54 the `goq-sh` Cloudflare Worker after the static-site gate passes.5556## Proven baseline5758- Sigil is independent of Tauri/WebKit and passes the pure-host dependency59 gate.60- Gamescope's exact PipeWire node is resolved from strict configured61 properties. AMD GstVA H.264 sustains the fixed 1280x800/60 first target on62 the GPD Pocket 4 test host with bounded post-encode delivery.63- Existing host configurations default to the proven external `gst-launch`64 backend. `encoder_backend = "in-process-gstreamer"` fails closed unless the65 Linux binary was explicitly built with that feature and its runtime66 GStreamer elements are available. The opt-in backend currently requires CBR;67 CQP remains on the external compatibility backend.68- The preferred media path authenticates each viewer over `sigil/control/2`,69 then admits that exact peer to one host-owned upstream `iroh-moq` broadcast70 and static H.264 track shared by every viewer. One configured GOP maps to one71 bounded native MoQ group; a newer independently decodable group cancels its72 predecessor and provides the latest-frame barrier. `sigil/control/1` and the73 custom media v3, v2, and v1 protocols remain explicit single-client74 compatibility fallbacks.75- Media objects on the shared generation are Ed25519-authenticated against a76 host-signed generation certificate, and each viewer's MoQ attachment carries77 an endpoint-bound, expiring subscription capability. The host advertises the78 authorization revision it minted that capability against in the same accepted79 control-v2 hello, so a client never has to assume an enrollment revision.80- Portal crosses Rust-to-webview video and audio through bounded binary Tauri81 channels. It reports transport, frontend, decoder, presentation, and audio82 queue/drop timing separately.83- Input uses an Iroh connection independent of media backpressure. The host84 advertises only operational capabilities and neutralizes every held pointer,85 keyboard, and gamepad state when a session ends.86- Relative pointer movement, scroll, keyboard, virtual gamepad reports, Opus87 audio, reconnects, and second-client rejection have focused and loopback88 coverage. So does the multi-viewer path: bounded admission, one shared89 generation, slot-0 focus handoff with the former holder neutralized before a90 successor is granted, same-peer replacement, slow-viewer isolation, and91 admission against a configured host at real enrollment revisions. Hardware92 acceptance that remains incomplete is listed below.93- Portal preserves the user's native window geometry across sessions and94 relaunches. The stream surface scales and letterboxes within those bounds so95 larger or differently shaped client windows never stretch the host image.96- Portal's proven relative-pointer capture path is macOS-only. Non-macOS97 builds must mask relative-pointer negotiation unless explicitly built with98 `experimental-non-macos-pointer-capture`; that feature is for platform UAT99 only and must not enter an ordinary or published build.100101## Security boundary102103- Portal's FIDO `hmac-secret` derives its stable Iroh peer identity. Sigil signs104 a short-lived, host-bound invitation for that exact peer and atomically105 persists the enrolled grants before accepting the first media session.106- `--dev-connect` is a test-only routing bypass, never an authorization claim.107 Debug builds and the explicit `demo-direct-node` feature may accept it and108 must display the development warning. Ordinary release builds must reject it.109- Enrollment is one-time; ordinary startup remains **PIN -> tap -> play** and110 reconnects authenticate the enrolled Iroh peer without replaying a ticket.111- View, pointer/keyboard, and gamepad permissions must be independently112 grantable. Replay, expiry, peer mismatch, cross-host use, and capability113 escalation must fail closed.114- The authorization state and replay ledger are security-sensitive host state;115 preserve their owner-only permissions and atomic update rules.116- `docs/compatibility-identifiers.md` freezes Portal's FIDO/Iroh derivation,117 Sigil's local runtime child, and its Linux virtual-input identity tuple.118 Never rename one in place or add a silent alternate acceptance path.119120## Release and installation boundary121122- Sigil is machine setup, not a desktop download. The public bootstrap is123 `curl -fsSL https://goq.sh/install-sigil | bash`.124- `website/install-sigil` intentionally fails closed until a reviewed Minisign125 publisher key and immutable signed release tag are configured.126- Product Sigil packages must come from clean committed source, contain only127 the allowlisted runtime payload, carry complete checksums/provenance, and have128 a detached Minisign signature. Installation must preserve identity and host129 configuration and must not silently start, restart, or enable the service.130- Product Sigil assets use the target-contract suffix131 `linux-glibc2.17-x86_64`, pinned by132 `release/sigil-target-contract.txt`. That name describes the binary ABI, not133 validated host support; the public bootstrap remains Bazzite-only until134 another environment passes its own packaging and hardware gates.135- Portal is a compiled desktop download, never a shell install. The only136 published target is macOS arm64. It is ad-hoc signed and deliberately NOT137 Developer ID signed or notarized, so trust comes from exact-tag GitHub build138 provenance plus the published SHA-256, and every Portal asset must carry that139 provenance. The packaging gate refuses to build in ad-hoc mode if any140 `APPLE_*` credential is present, and no published surface may claim141 notarization or Gatekeeper verification. Do not advertise an unavailable142 platform/architecture as a download.143- The Minisign secret, host identity, and FIDO-derived secrets must never enter144 the repository, release archive, logs, command line, or general website145 deployment environment.146147## Latency and correctness invariants148149- Bound every capture, encode, media, frontend, decode, audio, and input queue.150- Prefer dropping or cancelling stale video over increasing latency.151- Keep input transport independent from media and audio backpressure.152- Never send uncompressed video through Tauri IPC or Iroh.153- Never reintroduce base64 media events; use binary Tauri channels.154- A discontinuity must resume from a keyframe carrying codec configuration.155- A slow or resetting receiver must not accumulate a playable history.156- Keep H.264 at 1280x800/60 as the known-safe target until adaptive work is157 measured end to end. Do not select codecs by compression ratio alone.158- Preserve native pointer coordinates independently from encoded resolution or159 client window size.160- Map a differently shaped focused Xwayland root through a centered aspect-fit161 region in the native pointer surface; never stretch pointer axes162 independently.163- Session teardown must release all held input transitions and emit a neutral164 gamepad state even after an error or disconnect.165166## Remaining public-alpha gates167168- Issue #3's repository work is implemented: one-time capability enrollment,169 replay protection, grant intersection, and controller-usable Portal import.170 Its exact release candidates still participate in the issue #6 hardware UAT.171- Issue #4: configure the offline Minisign trust root, publish the signed Sigil172 asset set, and prove clean install plus upgrade/rollback from the public173 command.174- Issue #5: publish the ad-hoc signed, attested macOS arm64 Portal DMG, digest,175 and manifest, with the un-notarized first-launch consequence stated plainly on176 every user-facing surface.177- Issue #6: prove physically headless cold boot, physical client controller178 gameplay, mouse buttons consumed by Gamescope/an actual game, sustained A/V179 and resource percentiles without latency growth, difficult-NAT relay180 diagnostics, and reconnect/second-client rejection using the exact release181 candidates.182- Issues #7-#10 are streaming hardening: Iroh/MoQ recovery hardening, adaptive183 bitrate, motion-sensitive resolution, and automatic low-latency codec184 selection. The preferred path now uses pinned upstream `iroh-moq`; the185 external `gst-launch` encoder can still honor a keyframe request only at its186 next natural configured IDR. An opt-in in-process GStreamer control path now187 exists; hardware loss/relay proof remains before claiming issue #7 complete.188 The in-process encoder backend is not part of the product release feature set189 until its native Bazzite and cross-build/package dependency gates pass.190191## Working rules192193- Use Rust edition 2024. Sigil and Portal require Rust 1.91 or newer and the194 repository pins Rust 1.95 in `rust-toolchain.toml`; `sigil-protocol` retains a195 1.85 minimum. Source `~/.cargo/env` before invoking Cargo directly.196- Building Sigil with `in-process-gstreamer` requires the GStreamer core, app,197 and video development packages. Deployment requires their matching runtime198 libraries plus `appsink`, `pipewiresrc`, parser/conversion elements, and the199 selected GstVA encoder plugin; never treat build headers as runtime payload.200- Run `./scripts/verify-demo-build.sh` for the complete repository gate. It201 covers Rust format/tests/clippy, the Linux cross-build when available,202 frontend syntax/tests, ShellCheck, package tests, loopback transport203 including three-viewer admission and slot-0 focus handoff, legacy204 second-client rejection, and release-profile containment of `--dev-connect`.205- Run `./scripts/verify-website.sh` for every website or public installer206 change. Exercise interactive website changes in a real browser.207- Treat `docs/fresh-bazzite-host.md`, `docs/public-release-delivery.md`, and208 GitHub issues #3-#10 as the current acceptance sources. Distinguish local209 tests from hardware proof and from still-pending operator acceptance.210- Treat `docs/hardware-uat/MATRIX.md` as the claim contract. Until both211 required rows pass the same exact candidate, name hardware results as212 reference-host evidence; do not use unqualified `hardware-proven` language.213 A development matrix pass is not release-matrix proof.214- Use the strict live capture gate on Bazzite when capture changes:215216 ```bash217 sigil capture probe \218 --source gamescope-pipewire \219 --config ~/.config/sigil-spark/host.toml \220 --frames 300 \221 --expect-size 1280x800 \222 --minimum-fps 55223 ```224225- Any change that can affect Sigil startup, capture, encoding, transport,226 decoding, A/V, input, or session behavior requires a real Portal -> UMPC227 Gamescope connection from the exact candidate commit. A successful config228 check, capture probe, headless probe, or loopback is supporting evidence, not229 a substitute for that end-to-end session. Starting a bypass-enabled daemon230 and observing that it listens is also not an end-to-end test: Portal must231 connect to that exact daemon, the host must admit the session, live media232 diagnostics must advance, and the affected interaction or recovery path must233 be exercised from Portal. Fresh exact-commit builds are not234 expected to be enrolled. This also applies when authentication or identity235 code changed: do not skip the connection because ordinary authentication236 blocks it. For development hardware testing, build Sigil with237 `demo-auth-bypass`, run it with238 `--dev-allow-unauthorized` and a bounded `--max-runtime-seconds`, and connect239 a debug Portal with `--dev-connect`. Verify the affected live diagnostics240 and interaction path, then stop the bypass process, undo temporary Gamescope241 controls, and restore and verify the ordinary authenticated242 `sigil-host.service` before calling the test complete.243- The bypass proves the exact runtime connection, not authorization semantics.244 For authentication, enrollment, identity, grants, invitation, and reconnect245 changes, supplement that session with deterministic FIDO-response tests and246 a persistent software Iroh identity using signed invitations and247 authenticated probes. Cover the relevant grant, replay, expiry, peer/host248 binding, and ticket-free reconnect behavior. A physical security-key PIN or249 tap is not required unless the operator explicitly requests authenticator250 hardware acceptance.251252- On Linux with NVIDIA, set `WEBKIT_DISABLE_DMABUF_RENDERER=1` for Portal.253- Treat `experimental-non-macos-pointer-capture` as an explicit non-release254 build mode. Complete the per-platform checklist in255 `docs/portal-platform-support.md`, including a real Portal -> UMPC session,256 before changing a platform's support status or its default feature policy.257- Preserve the inherited `sigil` checkout that sits beside this repository on258 the development machine untouched; it is not this working repository.259- Preserve unrelated worktree changes. Never sweep generated credentials,260 evidence, local Claude/Codex configuration, `.env` files, or test-host state261 into commits.262- Do not weaken a fail-closed production path to make a development proof pass.263 Keep explicit development flags visibly labeled and build-time contained.