goq agent guide
goq is a one-host, one-user game-streaming appliance. The public project and website are goq.sh. Sigil is the pure Rust Linux host command and daemon. Portal is the installed Tauri client that opens a session to a Sigil host.
Product boundary
- Sigil runs on a dedicated, physically headless bare-metal Linux machine.
- Gamescope owns the private Steam/game display; capture must not require an interactive desktop or XDG ScreenCast portal.
- The host is a pure Rust daemon. It must never depend on Tauri, WebKit, or a host-facing UI.
- Portal is client-only. It must not bundle host capture, encoding, daemon, identity, configuration, or Linux input-injection assets.
- Iroh owns native connectivity, endpoint identity, encryption, direct-path discovery, and relay fallback.
- Exactly one media generation is active at a time. Native MoQ control v2
shares that single generation with up to
max_viewersauthenticated clients (default 3, hard ceiling 8); control v1 and grouped v3 stay single-client exclusive and reject a second client. No capture, encoder, publisher, or actuator scales with viewer count. - At most one viewer holds slot-0 input focus. Every other viewer is a spectator, and a former holder is fully neutralized before a successor is granted.
- Controller is the primary interaction model. Keyboard and relative mouse are secondary inputs.
Current architecture
crates/owns bounded, versioned handshakes, capabilities, media/audio headers, input messages, protocol limits, and ALPN constants.sigil-protocol crates/builds thesigil-host sigildaemon andsigil-probediagnostic.main.rsowns the CLI, endpoint/router setup, and capture probes.server.rsowns session admission and separate media, input, and audio protocols.source.rsowns test-pattern and Gamescope PipeWire capture plus AMD GstVA H.264 encoding. Externalgst-launchremains the default; an explicitly feature-gated in-process backend owns bounded encoder control.input.rsowns strict Linuxuinputpointer, keyboard, and Xbox-style virtual gamepad devices.audio.rsowns bounded PipeWire/Opus capture.identity.rsandconfig.rsown fail-closed persistent host state.
src-tauriis Portal's native boundary.commands/owns Iroh connections, bounded media-object receive, binary Tauri channels, input transport, and diagnostics.network.rs commands/owns FIDO2auth.rs hmac-secretderivation.commands/owns launch options and process-wide bounded state.state.rs
portal/and the focusedmain.js portal/modules own WebCodecs decode, AudioWorklet playback, controller-first navigation, input capture, A/V synchronization, window geometry, and client diagnostics.*.mjs website/is the static goq.sh site. A merge tomainpublishes it through thegoq-shCloudflare Worker after the static-site gate passes.
Proven baseline
- Sigil is independent of Tauri/WebKit and passes the pure-host dependency gate.
- Gamescope's exact PipeWire node is resolved from strict configured properties. AMD GstVA H.264 sustains the fixed 1280x800/60 first target on the GPD Pocket 4 test host with bounded post-encode delivery.
- Existing host configurations default to the proven external
gst-launchbackend.encoder_backend = "in-process-gstreamer"fails closed unless the Linux binary was explicitly built with that feature and its runtime GStreamer elements are available. The opt-in backend currently requires CBR; CQP remains on the external compatibility backend. - The preferred media path authenticates each viewer over
sigil/, then admits that exact peer to one host-owned upstreamcontrol/ 2 iroh-moqbroadcast and static H.264 track shared by every viewer. One configured GOP maps to one bounded native MoQ group; a newer independently decodable group cancels its predecessor and provides the latest-frame barrier.sigil/and the custom media v3, v2, and v1 protocols remain explicit single-client compatibility fallbacks.control/ 1 - Media objects on the shared generation are Ed25519-authenticated against a host-signed generation certificate, and each viewer's MoQ attachment carries an endpoint-bound, expiring subscription capability. The host advertises the authorization revision it minted that capability against in the same accepted control-v2 hello, so a client never has to assume an enrollment revision.
- Portal crosses Rust-to-webview video and audio through bounded binary Tauri channels. It reports transport, frontend, decoder, presentation, and audio queue/drop timing separately.
- Input uses an Iroh connection independent of media backpressure. The host advertises only operational capabilities and neutralizes every held pointer, keyboard, and gamepad state when a session ends.
- Relative pointer movement, scroll, keyboard, virtual gamepad reports, Opus audio, reconnects, and second-client rejection have focused and loopback coverage. Hardware acceptance that remains incomplete is listed below.
- Portal preserves the user's native window geometry across sessions and relaunches. The stream surface scales and letterboxes within those bounds so larger or differently shaped client windows never stretch the host image.
- Portal's proven relative-pointer capture path is macOS-only. Non-macOS
builds must mask relative-pointer negotiation unless explicitly built with
experimental-non-macos-pointer-capture; that feature is for platform UAT only and must not enter an ordinary or published build.
Security boundary
- Portal's FIDO
hmac-secretderives its stable Iroh peer identity. Sigil signs a short-lived, host-bound invitation for that exact peer and atomically persists the enrolled grants before accepting the first media session. --dev-connectis a test-only routing bypass, never an authorization claim. Debug builds and the explicitdemo-direct-nodefeature may accept it and must display the development warning. Ordinary release builds must reject it.- Enrollment is one-time; ordinary startup remains PIN -> tap -> play and reconnects authenticate the enrolled Iroh peer without replaying a ticket.
- View, pointer/keyboard, and gamepad permissions must be independently grantable. Replay, expiry, peer mismatch, cross-host use, and capability escalation must fail closed.
- The authorization state and replay ledger are security-sensitive host state; preserve their owner-only permissions and atomic update rules.
docs/freezes Portal's FIDO/Iroh derivation, Sigil's local runtime child, and its Linux virtual-input identity tuple. Never rename one in place or add a silent alternate acceptance path.compatibility-identifiers.md
Release and installation boundary
- Sigil is machine setup, not a desktop download. The public bootstrap is
curl -fsSL https:/./ goq.sh/ install-sigil | bash website/intentionally fails closed until a reviewed Minisign publisher key and immutable signed release tag are configured.install-sigil - Product Sigil packages must come from clean committed source, contain only the allowlisted runtime payload, carry complete checksums/provenance, and have a detached Minisign signature. Installation must preserve identity and host configuration and must not silently start, restart, or enable the service.
- Product Sigil assets use the target-contract suffix
linux-glibc2.17-x86_64, pinned byrelease/. That name describes the binary ABI, not validated host support; the public bootstrap remains Bazzite-only until another environment passes its own packaging and hardware gates.sigil-target-contract.txt - Portal is a compiled desktop download, never a shell install. The only
published target is macOS arm64. It is ad-hoc signed and deliberately NOT
Developer ID signed or notarized, so trust comes from exact-tag GitHub build
provenance plus the published SHA-256, and every Portal asset must carry that
provenance. The packaging gate refuses to build in ad-hoc mode if any
APPLE_*credential is present, and no published surface may claim notarization or Gatekeeper verification. Do not advertise an unavailable platform/architecture as a download. - The Minisign secret, host identity, and FIDO-derived secrets must never enter the repository, release archive, logs, command line, or general website deployment environment.
Latency and correctness invariants
- Bound every capture, encode, media, frontend, decode, audio, and input queue.
- Prefer dropping or cancelling stale video over increasing latency.
- Keep input transport independent from media and audio backpressure.
- Never send uncompressed video through Tauri IPC or Iroh.
- Never reintroduce base64 media events; use binary Tauri channels.
- A discontinuity must resume from a keyframe carrying codec configuration.
- A slow or resetting receiver must not accumulate a playable history.
- Keep H.264 at 1280x800/60 as the known-safe target until adaptive work is measured end to end. Do not select codecs by compression ratio alone.
- Preserve native pointer coordinates independently from encoded resolution or client window size.
- Map a differently shaped focused Xwayland root through a centered aspect-fit region in the native pointer surface; never stretch pointer axes independently.
- Session teardown must release all held input transitions and emit a neutral gamepad state even after an error or disconnect.
Remaining public-alpha gates
- Issue #3's repository work is implemented: one-time capability enrollment, replay protection, grant intersection, and controller-usable Portal import. Its exact release candidates still participate in the issue #6 hardware UAT.
- Issue #4: configure the offline Minisign trust root, publish the signed Sigil asset set, and prove clean install plus upgrade/rollback from the public command.
- Issue #5: publish the ad-hoc signed, attested macOS arm64 Portal DMG, digest, and manifest, with the un-notarized first-launch consequence stated plainly on every user-facing surface.
- Issue #6: prove physically headless cold boot, physical client controller gameplay, mouse buttons consumed by Gamescope/an actual game, sustained A/V and resource percentiles without latency growth, difficult-NAT relay diagnostics, and reconnect/second-client rejection using the exact release candidates.
- Issues #7-#10 are streaming hardening: Iroh/MoQ recovery hardening, adaptive
bitrate, motion-sensitive resolution, and automatic low-latency codec
selection. The preferred path now uses pinned upstream
iroh-moq; the externalgst-launchencoder can still honor a keyframe request only at its next natural configured IDR. An opt-in in-process GStreamer control path now exists; hardware loss/relay proof remains before claiming issue #7 complete. The in-process encoder backend is not part of the product release feature set until its native Bazzite and cross-build/package dependency gates pass.
Working rules
-
Use Rust edition 2024. Sigil and Portal require Rust 1.91 or newer and the repository pins Rust 1.95 in
rust-toolchain.toml;sigil-protocolretains a 1.85 minimum. Source~/before invoking Cargo directly..cargo/ env -
Building Sigil with
in-process-gstreamerrequires the GStreamer core, app, and video development packages. Deployment requires their matching runtime libraries plusappsink,pipewiresrc, parser/conversion elements, and the selected GstVA encoder plugin; never treat build headers as runtime payload. -
Run
./for the complete repository gate. It covers Rust format/tests/clippy, the Linux cross-build when available, frontend syntax/tests, ShellCheck, package tests, loopback transport, and release-profile containment ofscripts/ verify-demo-build.sh --dev-connect. -
Run
./for every website or public installer change. Exercise interactive website changes in a real browser.scripts/ verify-website.sh -
Treat
docs/,fresh-bazzite-host.md docs/, and GitHub issues #3-#10 as the current acceptance sources. Distinguish local tests from hardware proof and from still-pending operator acceptance.public-release-delivery.md -
Treat
docs/as the claim contract. Until both required rows pass the same exact candidate, name hardware results as reference-host evidence; do not use unqualifiedhardware-uat/ MATRIX.md hardware-provenlanguage. A development matrix pass is not release-matrix proof. -
Use the strict live capture gate on Bazzite when capture changes:
sigil capture probe \ --source gamescope-pipewire \ --config ~/.config/sigil-spark/host.toml \ --frames 300 \ --expect-size 1280x800 \ --minimum-fps 55 -
Any change that can affect Sigil startup, capture, encoding, transport, decoding, A/V, input, or session behavior requires a real Portal -> UMPC Gamescope connection from the exact candidate commit. A successful config check, capture probe, headless probe, or loopback is supporting evidence, not a substitute for that end-to-end session. Starting a bypass-enabled daemon and observing that it listens is also not an end-to-end test: Portal must connect to that exact daemon, the host must admit the session, live media diagnostics must advance, and the affected interaction or recovery path must be exercised from Portal. Fresh exact-commit builds are not expected to be enrolled. This also applies when authentication or identity code changed: do not skip the connection because ordinary authentication blocks it. For development hardware testing, build Sigil with
demo-auth-bypass, run it with--dev-allow-unauthorizedand a bounded--max-runtime-seconds, and connect a debug Portal with--dev-connect. Verify the affected live diagnostics and interaction path, then stop the bypass process, undo temporary Gamescope controls, and restore and verify the ordinary authenticatedsigil-host.servicebefore calling the test complete. -
The bypass proves the exact runtime connection, not authorization semantics. For authentication, enrollment, identity, grants, invitation, and reconnect changes, supplement that session with deterministic FIDO-response tests and a persistent software Iroh identity using signed invitations and authenticated probes. Cover the relevant grant, replay, expiry, peer/host binding, and ticket-free reconnect behavior. A physical security-key PIN or tap is not required unless the operator explicitly requests authenticator hardware acceptance.
-
On Linux with NVIDIA, set
WEBKIT_DISABLE_DMABUF_RENDERER=1for Portal. -
Treat
experimental-non-macos-pointer-captureas an explicit non-release build mode. Complete the per-platform checklist indocs/, including a real Portal -> UMPC session, before changing a platform's support status or its default feature policy.portal-platform-support.md -
Preserve the inherited
sigilcheckout that sits beside this repository on the development machine untouched; it is not this working repository. -
Preserve unrelated worktree changes. Never sweep generated credentials, evidence, local Claude/Codex configuration,
.envfiles, or test-host state into commits. -
Do not weaken a fail-closed production path to make a development proof pass. Keep explicit development flags visibly labeled and build-time contained.