openvibers/openvibe.computer AGENTS.md
AGENTS.md
| 1 | # AGENTS.md — OpenVibe.Computer |
| 2 | |
| 3 | ## Project overview |
| 4 | |
| 5 | The front door and API facade for OpenVibe computers: a public site that renders the product, signs a |
| 6 | person in through OpenVibe.Network SSO, and forwards that person's Network token **unchanged** to |
| 7 | OpenVibe.Run. Run owns sessions, placement, budgets and the actual computer; Computer owns no |
| 8 | sessions and stores nothing. |
| 9 | |
| 10 | - Origin `https://openvibe.computer`, port `5135`, unit `openvibe-computer.service`, |
| 11 | release root `/opt/openvibe.computer`. |
| 12 | - Node.js/Express, CommonJS, **no database, no migrations, no build step**; server-rendered pages. |
| 13 | |
| 14 | ## What it owns |
| 15 | |
| 16 | - The public pages: `/`, `/templates`, `/pricing`, `/docs`, `/updates`, legal pages. |
| 17 | - `/api/v1/computers` and `/api/v1/computers/{id}[/stop|/screenshot|/act|/handoff]` — a thin facade |
| 18 | that calls Run with the caller's own bearer token. |
| 19 | - `/auth/*` — the Network OAuth client `computer` (callback `/auth/callback`), the session cookie and |
| 20 | optional auth for pages. |
| 21 | - `/llms.txt`, `/llms-full.txt`, `/sitemap.xml`, `/robots.txt`, `/openapi.json`, |
| 22 | `/.well-known/agent.json`, `/release.json`, `/shared/*`, `/api/health`. |
| 23 | |
| 24 | It does not own: the computer, the browser, placement, the allowance, per-minute pricing, the |
| 25 | session budget, screenshots or control handoff. Those are Run's. The UI marks what Run does not yet |
| 26 | expose as **pending**, and that must stay honest. |
| 27 | |
| 28 | ## Who it calls, and who calls it |
| 29 | |
| 30 | - **OpenVibe.Run** — every session action goes through [server/run-client.js](server/run-client.js) to |
| 31 | `OV_RUN_URL` (`/api/v1/sessions…`, `/commands`, `/control`, `/timeline`, `/snapshot`). The person's |
| 32 | Network token is passed through as `Authorization: Bearer`; Computer never mints or broadens one. |
| 33 | - **OpenVibe.Network** — SSO through `openvibe-sdk/sso` (`createSsoClient`), OAuth client `computer`. |
| 34 | - Called by people in the browser and by agents that read the public pages/OpenAPI. There is no |
| 35 | service-to-service caller and no contract of its own. |
| 36 | |
| 37 | ## Repository map |
| 38 | |
| 39 | - **Entry:** [server/index.js](server/index.js) — `createApp()`, listen on `config.port`/`config.host`. |
| 40 | - **App:** [server/app.js](server/app.js) — helmet CSP, SSO router + optional auth, health, robots, |
| 41 | sitemap, legal, llms files, openapi, agent descriptor, `/api/v1`, release, `/shared`, static, |
| 42 | pages, error handler. |
| 43 | - **Config:** [server/config.js](server/config.js) — env load (`PORT`, `BASE_URL`, `OV_RUN_URL`, |
| 44 | `OV_OAUTH_CLIENT_ID/SECRET`, `OV_NETWORK_*`, secure cookies). |
| 45 | - **Run client:** [server/run-client.js](server/run-client.js) — `RunError`, `list/get/create/stop/ |
| 46 | command/control/take/timeline/snapshot`; creates browser sessions only. |
| 47 | - **API:** [server/api.js](server/api.js) — token extraction, RFC 9457 problem+json errors, the routes. |
| 48 | - **Pages:** [server/pages.js](server/pages.js), [server/layout.js](server/layout.js), |
| 49 | [server/html.js](server/html.js), [server/product.js](server/product.js). |
| 50 | - **Deploy:** [deploy/systemd/openvibe-computer.service](deploy/systemd/openvibe-computer.service), |
| 51 | [deploy/nginx/openvibe.computer.conf](deploy/nginx/openvibe.computer.conf), |
| 52 | [deploy/LAUNCH.md](deploy/LAUNCH.md) (DNS, TLS, OAuth, service add, vhost swap). |
| 53 | - **Static:** [public/openapi.json](public/openapi.json), [public/llms.txt](public/llms.txt), |
| 54 | [public/.well-known/agent.json](public/.well-known/agent.json), [public/css/computer.css](public/css/computer.css). |
| 55 | |
| 56 | ## Commands |
| 57 | |
| 58 | ```bash |
| 59 | npm ci |
| 60 | cp .env.example .env # if present; the README lists the variables |
| 61 | npm run dev # NODE_ENV=development node server/index.js |
| 62 | npm start # node server/index.js, http://127.0.0.1:5135 |
| 63 | npm test # node --test test/*.test.js |
| 64 | ov test # the harness's sharded run of what the change reaches |
| 65 | node --check <file.js> |
| 66 | ``` |
| 67 | |
| 68 | ## Auth |
| 69 | |
| 70 | `openvibe-sdk/sso` owns the OAuth flow and cookie (`createSsoClient({ site: 'computer', … })`). |
| 71 | Pages use `sso.optionalAuth()`; API routes take the bearer token with `sso.extractToken(req)` and |
| 72 | answer `401 application/problem+json` (`computer.auth.required`) when it is absent. Run authorizes |
| 73 | the token and its budget — Computer does not decide entitlement. `OV_OAUTH_CLIENT_SECRET` is required |
| 74 | for sign-in; without it the flow cannot complete. |
| 75 | |
| 76 | ## Frontend loading model |
| 77 | |
| 78 | Server-rendered HTML from `server/pages.js`/`server/layout.js` and `server/html.js`; no SPA, no |
| 79 | bundler, no transpiler. Static files are served from `public/`; shared frame assets come from the |
| 80 | pinned `openvibe-shared` tarball through `/shared/*` (`openvibe-shared/serve`). The CSP in |
| 81 | [server/app.js](server/app.js) is the real allow-list (Network, Chat, Billing, Events, Media, |
| 82 | Cloudflare insights, self) — add an origin there before using it. |
| 83 | |
| 84 | ## Deploy |
| 85 | |
| 86 | `sudo ovhost service add computer` (once) then `sudo ovhost deploy computer --restart` |
| 87 | ([deploy/LAUNCH.md](deploy/LAUNCH.md)). Unit `openvibe-computer.service`, env |
| 88 | `/etc/openvibe/computer.env` (0600), vhost installed with `sudo ovhost nginx render computer --install`. |
| 89 | The launch is a host-level swap: the `openvibe.computer` parked redirect is removed **only after** |
| 90 | review and readiness, in the same change that installs the vhost. Do not remove the redirect in a |
| 91 | service PR. Health check: `http://127.0.0.1:5135/api/health`. |
| 92 | |
| 93 | ## Tests |
| 94 | |
| 95 | `npm test` is Node's built-in runner over [test/computer.test.js](test/computer.test.js) and |
| 96 | [test/link-brand.test.js](test/link-brand.test.js). They pin the facade contract: 401 without a |
| 97 | token, browser-only creation, the three templates, Run errors mapped to problem+json, the public |
| 98 | pages/llms/sitemap, the brand rules and the CSP. `ov test` runs the same suite. |
| 99 | |
| 100 | ## Conventions |
| 101 | |
| 102 | - CommonJS, 4-space indent, single quotes, semicolons; `server/` modules export factories |
| 103 | (`createApp`, `createApi`, `createPages`) so tests inject config/SSO/Run. |
| 104 | - Public-facing copy is calm and specific; no unverified capability claims ("pending" stays pending). |
| 105 | - Error bodies follow RFC 9457 (`application/problem+json`) with a stable `code`. |
| 106 | - DNS/TLS/OAuth/vhost steps belong in [deploy/LAUNCH.md](deploy/LAUNCH.md), not in code. |
| 107 | |
| 108 | ## Pitfalls |
| 109 | |
| 110 | - **Computer is a facade.** Do not add session state, a database, billing logic or placement here; |
| 111 | that belongs in Run. |
| 112 | - **Never mint or rewrite the forwarded token.** Pass the person's own token through. |
| 113 | - **The parked redirect is intentional** until the review in `deploy/LAUNCH.md`; removing it early |
| 114 | sends the domain to a service that may not be live. |
| 115 | - **CSP is enforced.** A new script/font/frame origin must be added to the helmet directives or it |
| 116 | will be blocked; do not add `unsafe-eval`. |
| 117 | - **Run support is partial.** Desktop/GPU/always-on, live streams, B3 control modes, control handoff |
| 118 | timelines, snapshots and non-browser kinds are not available yet; the UI says so. |
| 119 | - **No build step:** a change to `public/` or the view strings is live on the next deploy/restart. |
| 120 | |
| 121 | ## Documentation |
| 122 | |
| 123 | - [README.md](README.md) — product summary and the current Run support. |
| 124 | - [deploy/LAUNCH.md](deploy/LAUNCH.md) — the host-level launch sequence. |
| 125 | - [public/openapi.json](public/openapi.json) — the API surface served to clients. |
| 126 |