openvibers/openvibe.studio AGENTS.md

AGENTS.md

main 5.9 KB · 99 lines · markdown

1# AGENTS.md — OpenVibe.Studio
2
3## Project overview
4
5OpenVibe.Studio is the network's creative-app host at `https://openvibe.studio`. It serves two
6open-source native editors compiled to WebAssembly — **Photo** (PhotoCraft, a layered photo editor)
7and **Light** (LightCraft, a photo library and RAW developer) — inside an OpenVibe account, plus the
8signed-in hand-offs from Video and Cam and the Pics image tools.
9
10- **Entry:** `server/index.js` (`node server/index.js`); app in `server/app.js`; config
11 `server/config.js`; port `5155`, drill port `15155`, service id `studio`.
12- **Pages and API:** `server/pages.js` (the app pages and `/edit`), `server/api.js`
13 (`/api/v1/studio/*`: file bytes, media bytes, publish, image edits), `server/app.js` mounts
14 health, `/auth`, `/shared`, discovery (`/robots.txt`, `/sitemap.xml`, `/llms.txt`,
15 `/llms-full.txt`, `/.well-known/agent.json`) and `/openapi.json`.
16- **Adapters:** `server/adapters/` — `contract.js`, `index.js`, `photo.js`, `light.js`. One adapter
17 per app keeps the same contract (`open(file)`, `save()`, `commands()`) so a base can be swapped.
18- **OpenVibe clients:** `server/openvibe/media.js`, `pics.js`, `video.js` — each call is scoped to
19 the person's own Network token.
20- **Browser:** `public/js/drivers.js` (one driver per app), `studio.js`, `edit-video.js`,
21 `image-tools.js`; own CSS in `public/css`. The apps run in a same-origin iframe with the shared
22 navbar outside it. No bundler for our layer.
23- **Bundles:** `scripts/build-bundles.sh`, `scripts/fetch-bundles.sh`, `scripts/smoke.js`; the
24 `bundles` GitHub workflow builds from pinned upstream tags and publishes an artifact with a
25 checksum file. A bundle is never committed.
26
27## Owns, does not own
28
29Owns the service layer, the adapter contract, the signed-in hand-off routes, the Pics image-edit
30endpoint and the `STUDIO_BUNDLE_ROOT` bundle upload/fetch path. It does not own the editors: Photo is
31[PhotoCraft](https://github.com/storytold/photocraft), Light is
32[LightCraft](https://github.com/storytold/lightcraft), both MIT OR Apache-2.0, built from pinned
33release tags; the licence and attribution stay with every build (`ATTRIBUTION.md`, `NOTICE`,
34`STATUS.json`). It does not own media bytes (Media/Video), pictures (Pics), the download drive
35(Download) or identity (Network).
36
37## Who calls it, what it calls
38
39A signed-in person opens the app pages; Video and Cam send them to
40`GET /edit?media=<Video id>&from=video` and `GET /edit?pics=<Pics slug>&from=cam`. Studio asks the
41source service with the person's own Network token whether that person may read the object, and a
42private object of someone else answers 404 exactly like a missing id. It calls OpenVibe.Video
43(`/api/v1/video/studio/publish` to send a trimmed range, cover, title and visibility), OpenVibe.Pics
44(read bytes, save a separate private picture through its re-encoding pipeline), OpenVibe.Download
45(hand an export to the person's drive) and Network (SSO/JWKS). The Pics image edit needs
46`STUDIO_IMAGE_WORKER_URL`, an operator-controlled worker (`POST /edit`, image in/out); no person token
47is sent to it, and without it the endpoint answers 503 and the UI disables submission.
48
49## Auth
50
51Network SSO (RS256 JWT + session cookie). Every Studio API and hand-off is the signed-in person's own
52call — never a service token on their behalf — and authorization is the source service's answer with
53that token. A private object of another person is a 404, not a 403. The image worker receives only
54the selected picture, never a token.
55
56## Bundles and deploy
57
58The `bundles` workflow checks out the pinned upstream tags, builds with Rust stable,
59`wasm32-unknown-unknown`, Trunk 0.21.14 (PhotoCraft) or `cargo xtask web` + wasm-bindgen 0.2.129
60(LightCraft), runs the first-frame smoke test in headless Chrome and publishes the bundle with a
61checksum file. The deploy fetches that artifact, verifies the checksums and unpacks it into
62`STUDIO_BUNDLE_ROOT` (default `public/apps`); without a bundle the page says so instead of showing an
63empty frame. `sudo ovhost deploy studio` deploys the service; unit
64`deploy/systemd/openvibe-studio.service`, env `/etc/openvibe/studio.env`, nginx
65`deploy/nginx/openvibe.studio.conf`. Rollback with `sudo ovhost rollback studio --to <sha>`.
66
67## Commands and tests
68
69```bash
70npm ci
71npm start # http://127.0.0.1:5155
72npm test # node --test test/*.test.js
73node scripts/smoke.js --app light --dir artifacts/light # first-frame check
74node scripts/fetch-bundles.sh # fetch the built artifact in a deploy
75```
76
77`npm test` uses the built-in Node test runner (not `openvibe-shared/test-runner`); tests use an
78in-process fake image worker and stub services, never model calls or spending. `test/adapters.test.js`
79enforces the one adapter contract; `test/studio.test.js`, `test/media.test.js` and
80`test/image-tools.test.js` cover the pages, hand-off authorization, publish polling and the worker
81fallback.
82
83## Conventions and pitfalls
84
85- CommonJS, 4-space indent, single quotes, semicolons; no linter. Server-rendered pages with the
86 shared Frame; phone-first CSS.
87- **A bundle is never committed.** Ship it as an artifact, verify the checksums, unpack into the
88 bundle root; a bundle that loads but never reaches its first frame is worse than no bundle.
89- **Keep the adapter contract identical** across apps (`assertAdapter`/`assertDriver`); a new base is
90 an adapter, not a fork of the page.
91- **The hand-off never trusts an id:** ask the source service with the person's token, and keep the
92 private-object 404 indistinguishable from missing.
93- **Photo has no scriptable browser API:** a dropped file and no export the page can ask for — say so
94 on the page instead of faking a bridge.
95- **Image edits need the operator worker**; without it, fail available/503, never call a model from
96 the service.
97- **Honest limits stay documented:** the heavy first load, the 4 GB phone memory warning and
98 online-only use are product statements, not bugs to hide.
99