cat / goq
clone

turns a linux box into a private steam streaming appliance: plug in, tap your key, play from another computer

1-n-sigls
goq / AGENTS.md
AGENTS.md 15.2K rendered
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. Hardware acceptance that remains incomplete is listed below.89- Portal preserves the user's native window geometry across sessions and90 relaunches. The stream surface scales and letterboxes within those bounds so91 larger or differently shaped client windows never stretch the host image.92- Portal's proven relative-pointer capture path is macOS-only. Non-macOS93 builds must mask relative-pointer negotiation unless explicitly built with94 `experimental-non-macos-pointer-capture`; that feature is for platform UAT95 only and must not enter an ordinary or published build.9697## Security boundary9899- Portal's FIDO `hmac-secret` derives its stable Iroh peer identity. Sigil signs100 a short-lived, host-bound invitation for that exact peer and atomically101 persists the enrolled grants before accepting the first media session.102- `--dev-connect` is a test-only routing bypass, never an authorization claim.103 Debug builds and the explicit `demo-direct-node` feature may accept it and104 must display the development warning. Ordinary release builds must reject it.105- Enrollment is one-time; ordinary startup remains **PIN -> tap -> play** and106 reconnects authenticate the enrolled Iroh peer without replaying a ticket.107- View, pointer/keyboard, and gamepad permissions must be independently108 grantable. Replay, expiry, peer mismatch, cross-host use, and capability109 escalation must fail closed.110- The authorization state and replay ledger are security-sensitive host state;111 preserve their owner-only permissions and atomic update rules.112- `docs/compatibility-identifiers.md` freezes Portal's FIDO/Iroh derivation,113 Sigil's local runtime child, and its Linux virtual-input identity tuple.114 Never rename one in place or add a silent alternate acceptance path.115116## Release and installation boundary117118- Sigil is machine setup, not a desktop download. The public bootstrap is119 `curl -fsSL https://goq.sh/install-sigil | bash`.120- `website/install-sigil` intentionally fails closed until a reviewed Minisign121 publisher key and immutable signed release tag are configured.122- Product Sigil packages must come from clean committed source, contain only123 the allowlisted runtime payload, carry complete checksums/provenance, and have124 a detached Minisign signature. Installation must preserve identity and host125 configuration and must not silently start, restart, or enable the service.126- Product Sigil assets use the target-contract suffix127 `linux-glibc2.17-x86_64`, pinned by128 `release/sigil-target-contract.txt`. That name describes the binary ABI, not129 validated host support; the public bootstrap remains Bazzite-only until130 another environment passes its own packaging and hardware gates.131- Portal is a compiled desktop download, never a shell install. The only132 published target is macOS arm64. It is ad-hoc signed and deliberately NOT133 Developer ID signed or notarized, so trust comes from exact-tag GitHub build134 provenance plus the published SHA-256, and every Portal asset must carry that135 provenance. The packaging gate refuses to build in ad-hoc mode if any136 `APPLE_*` credential is present, and no published surface may claim137 notarization or Gatekeeper verification. Do not advertise an unavailable138 platform/architecture as a download.139- The Minisign secret, host identity, and FIDO-derived secrets must never enter140 the repository, release archive, logs, command line, or general website141 deployment environment.142143## Latency and correctness invariants144145- Bound every capture, encode, media, frontend, decode, audio, and input queue.146- Prefer dropping or cancelling stale video over increasing latency.147- Keep input transport independent from media and audio backpressure.148- Never send uncompressed video through Tauri IPC or Iroh.149- Never reintroduce base64 media events; use binary Tauri channels.150- A discontinuity must resume from a keyframe carrying codec configuration.151- A slow or resetting receiver must not accumulate a playable history.152- Keep H.264 at 1280x800/60 as the known-safe target until adaptive work is153 measured end to end. Do not select codecs by compression ratio alone.154- Preserve native pointer coordinates independently from encoded resolution or155 client window size.156- Map a differently shaped focused Xwayland root through a centered aspect-fit157 region in the native pointer surface; never stretch pointer axes158 independently.159- Session teardown must release all held input transitions and emit a neutral160 gamepad state even after an error or disconnect.161162## Remaining public-alpha gates163164- Issue #3's repository work is implemented: one-time capability enrollment,165 replay protection, grant intersection, and controller-usable Portal import.166 Its exact release candidates still participate in the issue #6 hardware UAT.167- Issue #4: configure the offline Minisign trust root, publish the signed Sigil168 asset set, and prove clean install plus upgrade/rollback from the public169 command.170- Issue #5: publish the ad-hoc signed, attested macOS arm64 Portal DMG, digest,171 and manifest, with the un-notarized first-launch consequence stated plainly on172 every user-facing surface.173- Issue #6: prove physically headless cold boot, physical client controller174 gameplay, mouse buttons consumed by Gamescope/an actual game, sustained A/V175 and resource percentiles without latency growth, difficult-NAT relay176 diagnostics, and reconnect/second-client rejection using the exact release177 candidates.178- Issues #7-#10 are streaming hardening: Iroh/MoQ recovery hardening, adaptive179 bitrate, motion-sensitive resolution, and automatic low-latency codec180 selection. The preferred path now uses pinned upstream `iroh-moq`; the181 external `gst-launch` encoder can still honor a keyframe request only at its182 next natural configured IDR. An opt-in in-process GStreamer control path now183 exists; hardware loss/relay proof remains before claiming issue #7 complete.184 The in-process encoder backend is not part of the product release feature set185 until its native Bazzite and cross-build/package dependency gates pass.186187## Working rules188189- Use Rust edition 2024. Sigil and Portal require Rust 1.91 or newer and the190 repository pins Rust 1.95 in `rust-toolchain.toml`; `sigil-protocol` retains a191 1.85 minimum. Source `~/.cargo/env` before invoking Cargo directly.192- Building Sigil with `in-process-gstreamer` requires the GStreamer core, app,193 and video development packages. Deployment requires their matching runtime194 libraries plus `appsink`, `pipewiresrc`, parser/conversion elements, and the195 selected GstVA encoder plugin; never treat build headers as runtime payload.196- Run `./scripts/verify-demo-build.sh` for the complete repository gate. It197 covers Rust format/tests/clippy, the Linux cross-build when available,198 frontend syntax/tests, ShellCheck, package tests, loopback transport, and199 release-profile containment of `--dev-connect`.200- Run `./scripts/verify-website.sh` for every website or public installer201 change. Exercise interactive website changes in a real browser.202- Treat `docs/fresh-bazzite-host.md`, `docs/public-release-delivery.md`, and203 GitHub issues #3-#10 as the current acceptance sources. Distinguish local204 tests from hardware proof and from still-pending operator acceptance.205- Treat `docs/hardware-uat/MATRIX.md` as the claim contract. Until both206 required rows pass the same exact candidate, name hardware results as207 reference-host evidence; do not use unqualified `hardware-proven` language.208 A development matrix pass is not release-matrix proof.209- Use the strict live capture gate on Bazzite when capture changes:210211 ```bash212 sigil capture probe \213 --source gamescope-pipewire \214 --config ~/.config/sigil-spark/host.toml \215 --frames 300 \216 --expect-size 1280x800 \217 --minimum-fps 55218 ```219220- Any change that can affect Sigil startup, capture, encoding, transport,221 decoding, A/V, input, or session behavior requires a real Portal -> UMPC222 Gamescope connection from the exact candidate commit. A successful config223 check, capture probe, headless probe, or loopback is supporting evidence, not224 a substitute for that end-to-end session. Starting a bypass-enabled daemon225 and observing that it listens is also not an end-to-end test: Portal must226 connect to that exact daemon, the host must admit the session, live media227 diagnostics must advance, and the affected interaction or recovery path must228 be exercised from Portal. Fresh exact-commit builds are not229 expected to be enrolled. This also applies when authentication or identity230 code changed: do not skip the connection because ordinary authentication231 blocks it. For development hardware testing, build Sigil with232 `demo-auth-bypass`, run it with233 `--dev-allow-unauthorized` and a bounded `--max-runtime-seconds`, and connect234 a debug Portal with `--dev-connect`. Verify the affected live diagnostics235 and interaction path, then stop the bypass process, undo temporary Gamescope236 controls, and restore and verify the ordinary authenticated237 `sigil-host.service` before calling the test complete.238- The bypass proves the exact runtime connection, not authorization semantics.239 For authentication, enrollment, identity, grants, invitation, and reconnect240 changes, supplement that session with deterministic FIDO-response tests and241 a persistent software Iroh identity using signed invitations and242 authenticated probes. Cover the relevant grant, replay, expiry, peer/host243 binding, and ticket-free reconnect behavior. A physical security-key PIN or244 tap is not required unless the operator explicitly requests authenticator245 hardware acceptance.246247- On Linux with NVIDIA, set `WEBKIT_DISABLE_DMABUF_RENDERER=1` for Portal.248- Treat `experimental-non-macos-pointer-capture` as an explicit non-release249 build mode. Complete the per-platform checklist in250 `docs/portal-platform-support.md`, including a real Portal -> UMPC session,251 before changing a platform's support status or its default feature policy.252- Preserve the inherited `sigil` checkout that sits beside this repository on253 the development machine untouched; it is not this working repository.254- Preserve unrelated worktree changes. Never sweep generated credentials,255 evidence, local Claude/Codex configuration, `.env` files, or test-host state256 into commits.257- Do not weaken a fail-closed production path to make a development proof pass.258 Keep explicit development flags visibly labeled and build-time contained.