cat / goq
clone

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

docs: rewrite readme as a public project description

Dami committed 2837eab
Lead with what the appliance is and is not, fold the website tagline in
as the hook, describe the landed adaptive and management surfaces at
their current hardware-acceptance status, and reorder getting started
so host provisioning precedes enrollment.
commit
2837eab57e5b4987e408c5beefdd634b93a8088b
parent
cbae9bbc741a13e5ebb0807987d2996d70bf32f2
author
Dami <dami.etoile@gmail.com>
1 file changed, +153 -310
MREADME.md463++++++++++--------------------
M README.md +153 -310
@@ -1,344 +1,187 @@
11 # goq.sh22 3-goq.sh is one-to-one, low-latency Steam streaming over iroh: Portal is the4-installed Tauri client, and Sigil is the pure Rust bare-metal Linux host.5-6-The project starts from an inherited working remote-desktop implementation. Native7-iroh connectivity, hardware video encoding, WebCodecs decoding, FIDO-derived8-identity, and remote input are already present. The next phase replaces the9-desktop-oriented hot path with a headless Gamescope pipeline.10-11-## Target architecture3+**Your key is the address. Plug in, tap, play.**4+5+goq turns one Linux machine into a personal Steam streaming appliance. You6+dedicate that machine to your games, plug in nothing but power and network,7+and play from another computer with a controller. The goal is the latency of8+sitting at the machine, not the latency of a screen-sharing tool.9+10+goq is not a multi-tenant streaming service and not a desktop-sharing tool.11+It streams a private [Gamescope](https://github.com/ValveSoftware/gamescope)12+session that exists only for your games: the host needs no monitor, no13+desktop environment, and no interactive login. Exactly one client is admitted14+to exactly one session at a time, authenticated by a hardware security key.15+16+## The two programs17+18+- **Sigil** is the host: a pure Rust daemon for a bare-metal, physically19+ headless Linux machine. Gamescope owns the private game display, PipeWire20+ provides capture, and hardware H.264 plus Opus leave the machine over21+ [iroh](https://github.com/n0-computer/iroh), so the client reaches the host22+ by its cryptographic identity rather than an IP address.23+- **Portal** is the client: an installed Tauri desktop application with a24+ native iroh endpoint, WebCodecs video decode, AudioWorklet playback, and25+ controller-first navigation.1226 1327 ```text14-Sigil · bare-metal Linux host15- Gamescope headless16- -> PipeWire video/audio17- -> hardware H.264 + Opus18- -> iroh/MoQ19-20-Portal · Tauri client21- native iroh endpoint22- -> binary Tauri channel23- -> WebCodecs video24- -> audio output25- controller/keyboard/mouse26- -> iroh input protocol27- -> host uinput devices28+Sigil · bare-metal Linux host Portal · installed desktop client29+ Gamescope headless session native iroh endpoint30+ -> PipeWire video/audio -> binary Tauri channels31+ -> hardware H.264 + Opus -> WebCodecs video + audio out32+ -> iroh / MoQ media objects controller, keyboard, mouse33+ uinput virtual devices <---- -> iroh input protocol2834 ```2935 30-The host is intended to run without a physical display or desktop environment.31-Gamescope supplies the private graphical session and virtual display seen by32-Steam and games.33-34-## Current migration status35-36-- A shared, bounded and versioned protocol crate owns handshakes, H.264 media,37- input messages, limits, and ALPNs.38-- The Linux host is the pure Rust `sigil` binary with no Tauri or webview39- dependency.40-- The core host captures the standard upstream Gamescope PipeWire video source,41- derives the encoded size from its bounded native caps by default, and uses42- AMD GstVA H.264. An explicit width/height pair remains available for43- downscale proofs; 1280×800/60 is the first measured target, not a product44- constraint. Bazzite remains the only packaged appliance, and the GPD Pocket45- 4 run is reference-host evidence rather than a completed hardware matrix.46- SteamOS packaging, cold boot, encoder availability, and cross-host hardware47- UAT remain unproven.48-- Gamescope video keeps the proven external `gst-launch` pipeline as its49- configuration default. Linux builds made explicitly with50- `in-process-gstreamer` can opt into an in-process pipeline for bounded51- bitrate, force-keyframe, and two-tier resolution control. Published Sigil52- packages include that backend while keeping the external pipeline as the53- runtime default.54-- Portal reports bounded receiver queue, drop, latency, and recovery telemetry55- over a session-authenticated feedback stream. The host combines it with56- trusted path and scheduler pressure, applies hysteresis, and commits an57- in-process CBR bitrate decision only after exact encoder readback. External58- encoder sessions remain explicitly advisory-only.59-- On the opt-in in-process backend, fresh damage-driven frame progress and60- authenticated receiver pressure select either the resolved native mode or61- an exact same-aspect three-quarter motion tier when one exists. A switch62- commits only when GStreamer emits a target-size IDR with SPS/PPS; Portal then63- starts a new decoder epoch while pointer mapping remains tied independently64- to the native Gamescope surface. Modes without an exact even reduced tier65- continue at native resolution instead of rejecting the stream.66-- Portal delivers encoded frames to WebCodecs through a raw Tauri binary67- channel. The handoff is capped at four frames, the decode queue and68- presentation queue at two, and a bounded watchdog recovers a suspended69- webview animation-frame callback without presenting a frame twice. Its70- transport/frontend/decoder drop counters are reported separately.71-- Media and input use separate Iroh connections; one active client is enforced.72-- Linux `uinput` supports bounded relative-mouse and keyboard injection plus a73- separate Xbox-style virtual gamepad, with strict device74- ownership/mode/ACL preflight and neutralization when a session ends.75-- The installed Portal application is client-only: it contains no host daemon,76- host registration, capture, encoder, or desktop input-injection path.77-- FIDO2 `hmac-secret` derives Portal's stable Iroh peer identity. A signed,78- short-lived Sigil invitation enrolls that peer once with exact view,79- pointer/keyboard, and gamepad grants; ordinary reconnects remain80- **PIN -> tap -> play**. Debug builds retain a visibly labeled routing bypass,81- while release builds reject it. The82- [identity and appliance compatibility identifiers](docs/compatibility-identifiers.md)83- are frozen independently from display branding.84-- Controller-first client navigation includes a D-pad PIN pad, negotiated85- latest-state gamepad routing, and a one-second Back+Start escape chord.86-- Portal's proven relative-pointer capture is macOS-only. Default non-macOS87- builds negotiate absolute pointer, keyboard/text, and gamepad without88- advertising relative capture; the Tao + browser Pointer Lock path requires89- the explicitly experimental `experimental-non-macos-pointer-capture` build90- feature and the platform UAT in91- [`docs/portal-platform-support.md`](docs/portal-platform-support.md).92-- The Bazzite host has an allowlisted deterministic runtime package with93- checksum-bound release IDs, serialized install/upgrade, tamper-checked94- rollback, and package-owned user assets that follow the active release.95-- Sigil exposes a versioned, redacted local appliance-status document and96- daemon-lifetime lock as the foundation for a controller-first Decky Loader97- management plugin. The plugin remains a UI over the user service, not a98- second streaming host.99-100-The software JPEG client decode fallback and legacy wire compatibility remain.101-The preferred video path authenticates the client over a dedicated control102-connection, then admits that exact peer to a session-scoped upstream103-`iroh-moq` broadcast. Sigil publishes an immutable `catalog.json` snapshot;104-Portal discovers and strictly validates the versioned Goq extension before it105-subscribes to the H.264 track. The extension identifies Goq's `SGV1` media106-envelope and GOP layout, so it does not falsely advertise the track as a107-standard Hang rendition. Older hosts without a catalog retain an explicit108-static-track compatibility path. Configured GOPs become bounded native MoQ109-groups, and a new independently decodable group cancels the stale predecessor.110-The custom media v3, v2, and v1 transports remain explicit compatibility modes.111-A dedicated persistent PipeWire sink, bounded Opus datagrams, WebCodecs decode,112-and AudioWorklet playback are implemented; longer-run audio/video113-synchronization measurement remains. The debug direct-node bypass is routing,114-not authentication.115-116-## Immediate milestones117-118-1. **Done:** split Sigil into a pure Rust host binary; keep Portal client-only.119-2. **GPD Pocket 4/Bazzite reference-host evidence:** capture the exact Gamescope120- PipeWire node without an XDG portal. Physically headless cold boot and121- service startup remain public-alpha acceptance gates.122-3. **GPD Pocket 4/Bazzite reference-host evidence:** encode H.264 at123- 1280x800/60 with bounded buffers and no B-frames.124-4. **Done:** replace base64 WebCodecs delivery with a bounded binary Tauri channel.125-5. **Upstream Iroh/MoQ transport implemented; hardware proof pending:** an126- authenticated control lease gates a session-scoped upstream MoQ broadcast;127- bounded native groups cancel stale GOPs and recover through explicit128- keyframe requests. The opt-in in-process encoder turns recovery requests129- into coalesced forced IDRs without blocking media publication; the external130- encoder responds at its next natural configured IDR. Bazzite/package131- acceptance and induced-loss relay proof remain in issue #7.132-6. **GPD Pocket 4/Bazzite reference-host evidence; physical client controller133- pending:** the virtual Xbox-style controller negotiated over Iroh and134- produced the expected button, stick, trigger, D-pad, and neutral-release135- events on that host. Client controller navigation and mapping are covered136- by focused tests; the remaining integration gate is forwarding a physical137- controller attached to the client. Keyboard injection was exercised on the138- same reference host, and the conventional relative mouse replaces139- Gamescope-incompatible absolute motion.140-7. **GPD Pocket 4/Bazzite reference-host evidence:** bounded PipeWire audio141- capture, a persistent headless sink, Opus delivery, and client playback.142- Quantify longer-run A/V synchronization.143-8. **Done:** add signed, peer-bound, one-time capability enrollment with144- durable replay protection and controller-usable Portal onboarding.145-9. **Adaptive control implemented; hardware proof pending:** feedback remains146- constant-size and generation-scoped, coalescing retains cumulative pressure,147- and `applied=true` requires exact in-process encoder readback. Native Ubuntu148- x264 control is CI-proven; Bazzite GstVA loss/relay acceptance and product149- packaging remain in issue #8.150-10. **Motion-sensitive resolution implemented; hardware proof pending:** the151- in-process backend lowers resolution during sustained damage-driven motion152- or receiver pressure and restores native detail only after stillness,153- clean feedback, and cooldown. Every transition is an exact configured-IDR154- discontinuity with truthful per-frame dimensions. Portal reconfigures155- WebCodecs atomically and preserves native pointer mapping. Ubuntu x264 CI156- covers downscale and restore; repeated GstVA/Portal acceptance on Bazzite157- remains in issue #9.158-159-## Development160-161-Requirements:36+## Design principles37+38+- **Latency over history.** Every capture, encode, transport, decode, and39+ input queue is bounded. Stale video is dropped or cancelled rather than40+ buffered, so a slow receiver never accumulates a playable backlog. Media41+ travels as bounded MoQ groups: one GOP is one group, and a newer42+ independently decodable group cancels its predecessor.43+- **Input is independent.** Controller, keyboard, and relative mouse travel44+ on their own iroh connection, unaffected by media backpressure. Session45+ teardown always releases held keys and emits a neutral gamepad state, even46+ after an error or disconnect.47+- **Fail closed.** Portal derives its stable iroh identity from a FIDO2 key48+ with `hmac-secret`. A signed, short-lived, peer-bound invitation from Sigil49+ enrolls that one client once, with independently granted view,50+ pointer/keyboard, and gamepad permissions and durable replay protection.51+ Every ordinary launch after that is **PIN -> tap -> play**.52+- **Strict product boundary.** Sigil never depends on Tauri or a webview.53+ Portal never bundles capture, encoding, a daemon, or host input injection.54+55+## Status56+57+goq is pre-release. The reference host is an AMD machine running58+[Bazzite](https://bazzite.gg); H.264 at 1280x800/60 is the known-safe59+measured benchmark, while production capture accepts any even native mode60+within the protocol's bounded pixel limits.61+62+Working today:63+64+- The pure Rust Sigil daemon: Gamescope PipeWire capture at the display's65+ native mode, AMD GstVA H.264 encoding, and bounded PipeWire/Opus audio.66+- Authenticated session admission over a control connection, then a67+ session-scoped upstream `iroh-moq` broadcast with a strictly validated68+ catalog, with earlier custom media protocols kept as explicit compatibility69+ fallbacks.70+- Adaptive bitrate and motion-sensitive resolution on the opt-in in-process71+ encoder backend: session-authenticated receiver feedback, hysteresis, and72+ changes that commit only on exact encoder readback or a target-size IDR.73+- Portal playback through bounded binary Tauri channels into WebCodecs and an74+ AudioWorklet, with per-stage queue, drop, and latency diagnostics.75+- Linux `uinput` keyboard, relative mouse, and an Xbox-style virtual gamepad,76+ with strict device preflight and end-of-session neutralization.77+- One-time FIDO-bound enrollment, replay protection, and controller-usable78+ onboarding in Portal.79+- A deterministic, checksum-bound Bazzite runtime package with serialized80+ install/upgrade and tamper-checked rollback, plus the foundation of a81+ controller-first Decky Loader management plugin over a redacted local82+ appliance-status contract.83+84+The streaming-hardening roadmap, where the remaining work is hardware85+acceptance on the reference host, is tracked as86+[MoQ recovery hardening](https://github.com/FelineStateMachine/goq/issues/7),87+[adaptive bitrate](https://github.com/FelineStateMachine/goq/issues/8),88+[motion-sensitive resolution](https://github.com/FelineStateMachine/goq/issues/9),89+and [automatic codec selection](https://github.com/FelineStateMachine/goq/issues/10).90+The remaining public-alpha acceptance gates (headless cold boot, physical91+controller gameplay, sustained A/V measurement, and the signed public release92+path) are tracked in issues93+[#4](https://github.com/FelineStateMachine/goq/issues/4) to94+[#6](https://github.com/FelineStateMachine/goq/issues/6).95+96+## Repository layout97+98+| Path | Contents |99+| --- | --- |100+| `crates/sigil-protocol` | Bounded, versioned handshakes, media/audio headers, input messages, limits, ALPNs |101+| `crates/sigil-host` | The `sigil` daemon and the `sigil-probe` diagnostic |102+| `src-tauri/` | Portal's native side: iroh transport, FIDO2 identity, binary channels |103+| `portal/` | Portal frontend: WebCodecs decode, audio playback, controller navigation |104+| `decky/` | Decky Loader management plugin for the Sigil appliance |105+| `website/` | The static goq.sh site, published via a Cloudflare Worker |106+| `scripts/` | Build, packaging, verification, and host provisioning tooling |107+| `docs/` | Runbooks and contracts for provisioning, releases, and hardware acceptance |108+109+## Getting started110+111+You need:162112 163113 - Rust 1.91 or newer (the repository pins Rust 1.95)164114 - Tauri v2 system dependencies165-- A FIDO2 key with `hmac-secret` support for the normal identity flow166-167-The Linux `in-process-gstreamer` host feature additionally needs the GStreamer168-core, app, and video development libraries at build time. Its matching runtime169-libraries and plugins, including `appsink`, must be installed on the host.170-Published Sigil packages include this feature while retaining the external171-pipeline as the runtime default until a host opts into the in-process backend.172-173-### Enroll one Portal174-175-On first launch, enter the security-key PIN and choose **show portal id**. On176-the Sigil host, create an invitation for that exact peer:177-178-```bash179-sigil invitation create \180- --config ~/.config/sigil-spark/host.toml \181- --peer PORTAL_PEER_ID \182- --pointer-keyboard \183- --gamepad \184- --output ~/portal.goq-invite185-```186-187-Move the owner-only invitation file to the client, open it with Portal, and188-confirm the displayed host, peer, expiry, and grants. Sigil consumes it once;189-future launches are simply **PIN -> tap -> play**. `--print-deep-link` is190-available for an explicit `goq://invite/...` handoff, but prints the short-lived191-credential to the terminal and should not be used in recorded shells.192-193-To move Portal to another Sigil, revoke the host enrollment first, disconnect194-Portal, then use **client -> reset enrollment** and confirm the displayed host.195-The reset is intentionally explicit and controller reachable; importing a new196-invitation never silently replaces a working enrollment.197-198-Activate an installed dedicated AMD host with the portable, package-owned199-[Sigil host activation guide](docs/sigil-host-activation.md). It uses the200-current gaming user, dynamically discovered hardware, and installed package201-assets without assuming a maintainer hostname or checkout path. The202-[fresh Bazzite host runbook](docs/fresh-bazzite-host.md) remains the engineering203-and hardware-acceptance log, including the temporary `slate` stand-in.204-The backward-compatible [appliance status v1 contract](docs/sigil-appliance-status-v1.md)205-and explicit [v2 contract](docs/sigil-appliance-status-v2.md) define the local,206-redacted interface intended for the Decky management surface.207-The [transactional configuration v1 contract](docs/sigil-appliance-config-v1.md)208-defines its bounded, crash-recoverable settings workflow.209-The [enrollment reset v1 contract](docs/sigil-appliance-enrollment-reset-v1.md)210-defines the offline, identity-preserving reset used by that surface.211-Run `scripts/bazzite-inventory.sh` on a candidate host for a read-only report;212-add `--smoke` to exercise a bounded 1280×800/60 VA-API encode. On the first SSH213-login after a physically headless cold boot, use `--cold-boot` for a strict,214-read-only connector, session, service, PipeWire, and boot-order gate.215-216-Run the complete local demo gate before transferring a snapshot:115+- A FIDO2 security key with `hmac-secret` support116+- For a host: a dedicated AMD Linux machine (Bazzite is the packaged target)217117 218-```bash219-./scripts/verify-demo-build.sh220-```118+Building Sigil with the optional Linux `in-process-gstreamer` feature119+additionally needs the GStreamer core, app, and video development libraries;120+the matching runtime libraries and plugins must be installed on the host.221121 222-After transferring the two prebuilt Linux binaries to a Bazzite host, stage an223-exact hash-pinned release without starting it:122+Run Portal against a Sigil host during development:224123 225124 ```bash226-scripts/stage-bazzite-release.sh \227- --release-id <commit-or-source-snapshot-sha256> \228- --host-binary <absolute-path> --host-sha256 <sha256> \229- --probe-binary <absolute-path> --probe-sha256 <sha256>125+source ~/.cargo/env126+cargo tauri dev230127 ```231128 232-The stager atomically updates the user-owned `current` symlink only after both233-binaries, their dynamic libraries, and bounded startup commands validate. Host234-identity, hardware-specific configuration, and service activation remain235-separate gates in the package-owned activation guide.129+On Linux with NVIDIA, prefix with `WEBKIT_DISABLE_DMABUF_RENDERER=1`.236130 237-The thin binary stager is only for unmanaged development layouts. It refuses238-activation when package-managed service, audio, rollback, or udev links follow239-`current`; use the complete runtime package installer for those hosts so the240-active release always includes matching assets and rollback metadata.131+### Provision a host241132 242-Create the Bazzite runtime package from a committed source revision. Product243-mode exports clean tagged `HEAD` and builds the host and probe itself with244-locked `cargo-zigbuild` in an isolated target directory; it never accepts245-externally supplied binaries. The builder emits an unsigned candidate for the246-separate offline signing ceremony; the explicit development flags are only for247-temporary testing:133+Activate an installed dedicated AMD host with the portable134+[Sigil host activation guide](docs/sigil-host-activation.md). To evaluate a135+candidate machine first, run `scripts/bazzite-inventory.sh` for a read-only136+hardware report; add `--smoke` to exercise a bounded 1280x800/60 VA-API137+encode, or `--cold-boot` on the first login after a physically headless boot138+for a strict readiness gate.248139 249-```bash250-scripts/package-bazzite-release.sh \251- --release-tag v0.1.0 \252- --output /tmp/sigil-v0.1.0-linux-glibc2.17-x86_64.tar.gz253-254-# Temporary development package only:255-scripts/package-bazzite-release.sh \256- --output /tmp/sigil-spark-host-dev.tar.gz \257- --allow-dirty --allow-unsigned258-259-# Temporary externally built binaries require both development flags:260-scripts/package-bazzite-release.sh \261- --output /tmp/sigil-spark-host-prebuilt-dev.tar.gz \262- --allow-dirty --allow-unsigned \263- --host-binary /absolute/path/to/sigil \264- --probe-binary /absolute/path/to/sigil-probe265-```140+### Enroll one Portal266141 267-Verify the unsigned candidate, then follow the offline signing and protected268-draft-promotion ceremony in [public release delivery](docs/public-release-delivery.md).269-The GitHub workflow and package builder never receive the Minisign secret.270-271-The package contains the primary `sigil` host executable, its byte-identical272-`sigil-host` compatibility copy, the `sigil-probe` diagnostic, installer and273-rollback tools, service/audio/udev assets, the portable activation guide,274-license, checksums, and build provenance. It cannot contain the source tree,275-`.env` files, identities, host configuration, or test evidence. Its release ID276-is the SHA-256 of the complete installed-file checksum manifest. Identical277-inputs produce a byte-identical archive. The manifest marks product binaries278-as built from clean `HEAD`; caller-supplied development binaries are explicitly279-marked as having unverified provenance.280-281-During the legacy rollback window, `sigil-host.service` deliberately starts282-the byte-identical `sigil-host` compatibility filename. Interactive and283-documented host commands use `sigil`; retaining the service filename allows an284-older installed rollback helper to validate and reactivate a newer release.285-286-Verify the detached signature against the separately trusted public key before287-extracting, then run `payload/stage-this-release.sh` as the gaming user. Install288-and upgrade never restart PipeWire or start/enable the service. Roll back an289-installed upgrade with `sigil-spark-host-rollback`; add `--restart` only when a290-service interruption is intended.291-292-The macOS Portal build currently produces an arm64 DMG for development. A public293-Portal release additionally requires Developer ID signing with hardened294-runtime, notarization, stapling, and strict Gatekeeper verification; ad-hoc295-development signatures are not a distributable package. Before tagging, the296-public TeamIdentifier in `release/portal-apple-team-id.txt` must match the297-protected certificate, and the tag-ref workflow attests every published Portal298-asset. With Apple credentials configured as described by the official299-[Tauri macOS signing guide](https://v2.tauri.app/distribute/sign/macos/), run:142+On Portal's first launch, enter the security-key PIN and choose **show portal143+id**. On the Sigil host, create an invitation for that exact peer:300144 301145 ```bash302-scripts/package-macos-client.sh \303- --release-tag v0.1.0 \304- --output-dir /absolute/release/directory146+sigil invitation create \147+ --config ~/.config/sigil-spark/host.toml \148+ --peer PORTAL_PEER_ID \149+ --pointer-keyboard \150+ --gamepad \151+ --output ~/portal.goq-invite305152 ```306153 307-The repository publication and website-manifest procedure is documented in the308-[Portal release runbook](docs/portal-release.md).309-310-Run Portal against Sigil during development:154+Move the owner-only invitation file to the client and open it with Portal.155+Sigil consumes it once; every later launch is **PIN -> tap -> play**. To move156+Portal to a different Sigil host, revoke the enrollment on the old host and157+use **client -> reset enrollment**. A new invitation never silently replaces158+a working enrollment.311159 312-```bash313-source ~/.cargo/env314-cargo tauri dev315-```160+## Verification316161 317-On Linux with NVIDIA:162+Run the complete repository gate before sharing work:318163 319164 ```bash320-WEBKIT_DISABLE_DMABUF_RENDERER=1 cargo tauri dev165+./scripts/verify-demo-build.sh321166 ```322167 323-The static `website/` directory is published as Cloudflare Worker static assets324-after a merge to `main`. See the [Cloudflare Worker release setup](docs/cloudflare-worker.md)325-for the one-time service and GitHub environment configuration.168+It covers Rust format, tests, and clippy, the Linux cross-build when169+available, frontend syntax and tests, ShellCheck, package tests, and loopback170+transport proof. Website and installer changes go through171+`./scripts/verify-website.sh`. Hardware acceptance evidence lives under172+[`docs/hardware-uat/`](docs/hardware-uat/README.md), separate from local173+tests.326174 327-Portal is distributed as a compiled, signed desktop application; it is never328-installed through a shell pipe. Sigil uses a separate Bazzite machine bootstrap329-at `https://goq.sh/install-sigil`. That bootstrap intentionally fails closed330-until the Minisign publisher trust root and first signed release exist. The331-[public release delivery contract](docs/public-release-delivery.md) defines the332-remaining signing and asset gates.175+## Releases333176 334-The promoted streaming-hardening roadmap is tracked as bounded335-[Iroh/MoQ media objects](https://github.com/FelineStateMachine/goq/issues/7),336-[adaptive bitrate](https://github.com/FelineStateMachine/goq/issues/8),337-[motion-sensitive resolution](https://github.com/FelineStateMachine/goq/issues/9),338-and [Auto Codec](https://github.com/FelineStateMachine/goq/issues/10). H.264 at339-1280×800/60 remains a known-safe benchmark while production capture accepts340-any even native mode within the protocol's bounded pixel limits.177+Sigil is machine setup, not a desktop download: the public bootstrap is178+`https://goq.sh/install-sigil`, and it intentionally fails closed until the179+Minisign publisher trust root and the first signed release exist. Portal is a180+compiled, signed desktop application, never a shell install; the first public181+target is macOS arm64. The packaging, signing, and publication ceremonies are182+documented in [public release delivery](docs/public-release-delivery.md) and183+the [Portal release runbook](docs/portal-release.md).341184 342185 ## License343186 344-MIT187+[MIT](LICENSE)