- Performance first.
- Reliability first.
- Keep behavior predictable under load and during failures (session restarts, reconnects, partial streams).
If a tradeoff is required, choose correctness and robustness over short-term convenience.
opennow-stable/is the Electron app. Main-process code lives insrc/main, preload bridges insrc/preload, renderer UI insrc/renderer, and cross-process TypeScript contracts insrc/shared.native/contains the native streamer implementation and build outputs used by the Electron app. Keep native build changes isolated from Electron refactors unless the task explicitly spans both.locales/contains localization sources and generated Crowdin output. See Localization before editing.OpenNOW-Site/is a separate repository when present; do not modify it from OpenNOW tasks unless explicitly requested.
- Shared GFN main-process protocol details belong under
opennow-stable/src/main/gfn. Prefer focused modules with one owner per concern (clientHeaders.tsfor client identity/header constants,proxyFetch.tsfor proxy-aware fetches,proxyUrl.tsfor proxy URL normalization,request.tsfor common response handling). - Do not duplicate NVIDIA/GFN constants, request headers, platform/device ID mapping, auth header construction, proxy behavior, or error parsing across feature files. Add to or extract a focused shared module first, then consume it from features.
- Keep feature files (
auth.ts,games.ts,cloudmatch.ts,subscription.ts, etc.) responsible for product flow and payload shape, not for re-declaring shared client identity or transport details. - Preserve provider/alliance behavior, stable device IDs, session refresh semantics, and
SessionError.fromResponse()handling when refactoring GFN code.
- Main process owns filesystem, native process management, GFN network/session orchestration, Electron APIs, and security-sensitive logic.
- Preload exposes the minimal typed bridge needed by the renderer. Do not pass raw Electron or Node primitives into renderer code.
- Renderer code should stay UI-focused. Do not duplicate main-process GFN networking or native orchestration in React components.
opennow-stable/src/sharedis the contract boundary between main, preload, and renderer. Keep public IPC/shared interfaces stable unless the task explicitly requires a contract change.- When changing shared types, update every caller across main, preload, and renderer in the same change and run type checks.
- Avoid using
anyor renderer-only types in shared contracts. Prefer serializable DTOs and explicit unions.
Long term maintainability is a core priority. If you add new functionality, first check if there is shared logic that can be extracted to a separate module. Duplicate logic across multiple files is a code smell and should be avoided. Don't be afraid to change existing code. Don't take shortcuts by just adding local logic to solve a problem.
- Refactors should reduce ownership ambiguity: name the new owner module, move duplicated logic there, and keep behavior equivalent unless a behavior change is requested.
- Prefer small, typed helpers over broad
utilsmodules. If a helper needs knowledge of one protocol or product area, keep it beside that area. - Keep compatibility with existing persisted auth/session state unless a migration is explicitly part of the task.
Crowdin owns generated translations. When changing localized copy, edit only locales/en.json as the source language file. Do not manually edit other locales/*.json files; they are generated by Crowdin and should only change through Crowdin sync pull requests.
- For TypeScript/Electron changes, run the narrowest relevant smoke check first, then
npm --prefix opennow-stable run typecheckbefore finishing when practical. - For main-process GFN/session changes, also run
npm --prefix opennow-stable test -- --test-name-pattern gfnor the closest targeted test command available; if scripts do not support filtering, runnpm --prefix opennow-stable test. - For localization changes, run
npm --prefix opennow-stable run locales:check. - Do not claim completion if the relevant acceptance check fails. Report the failing command and failure point.
- All commands run from
opennow-stable/(or use the rootnpm run <script>wrappers). Dependencies are managed with npm (package-lock.json); thebun.lockis secondary — do not use bun. Node 22 is required. - Standard scripts are defined in
opennow-stable/package.json:dev,build,lint,typecheck,test,locales:check. Don't duplicate them; use those. - Running the app:
npm run dev(root) launcheselectron-vite devand opens the Electron window on the desktopDISPLAY(:1). It is a long-running process — start it in a background/tmux session, not a blocking foreground call. - Benign startup noise: in this container Electron logs
Failed to connect to the bus(dbus) andvkCreateInstance() failed: -9/Failed to create and initialize Vulkan(GPU). These are expected with no real GPU/dbus and do not indicate failure — the UI still renders and networks fine. - OpenNOW is a bring-your-own-account GeForce NOW client: there is no local backend. Full end-to-end gameplay/login requires a real NVIDIA/GFN account. Clicking "Sign in" opens NVIDIA's OAuth page (
login.nvgs.nvidia.com); the auth/networking path can be exercised up to that external login without credentials. - The native Rust streamer in
native/opennow-streameris optional and Windows-focused (npm run native:check/native:buildneed the Cargo toolchain). It is not required to run or develop the Electron client; the default stream path uses embedded Chromium WebRTC.