openvibers/openvibe.ai AGENTS.md

AGENTS.md

main 11.3 KB · 182 lines · markdown

1# AGENTS.md — OpenVibe.AI
2
3## Project overview
4
5The AI authority of the OpenVibe network: providers, models, routing, versioned prompt templates and
6workflows, runs, citations, scoped cache, quotas, free allowance, abuse limits, BYO keys and the public
7AI Exchange API. Node.js/Express, PostgreSQL (`ov_ai`), CommonJS, **no build step**. Extracted from
8OpenVibe.Live's AI subsystem; Live now runs with `AI_SERVICE=remote`.
9
10- Service id `ai`, port `4700`, public origin `https://ai.openvibe.services`, API host
11 `https://api.openvibe.exchange`, unit `openvibe-ai.service`.
12- The reusable rule: a run returns a **draft/evidence package** (structured output + citations +
13 provenance) attributed to a workflow version, model and run id — never to a person. AI never owns
14 publication truth; Wiki, Blog, News, Live, Report and the rest decide what to publish.
15
16## What it owns, and what it must not touch
17
18Owns the eleven record groups in `migrations/`: providers, models, routing profiles, prompt
19templates, workflow definitions, runs, the request log (hashes, not prompts), citations, cache,
20quotas/usage and audit. Also owns people's provider keys (`server/credentials.js`,
21`server/vault.js`), people's own machines as providers (`server/machines.js`), free allowance
22(`server/free-allowance.js`), tiers/budgets (`server/govern.js`, `server/run-budgets.js`), abuse
23prevention (`server/abuse/`), the public price book and Exchange APIs (`server/api/exchange.js`,
24`server/pricebook/`), GPU supply/provisioning (`server/gpu/`, `server/platform/supply.js`),
25batches, deep dives, memory and the `ai.run.*` events.
26
27Does **not** own: publication (it drafts/evidences), the recordings it analyses (OpenVibe.Media),
28identity (OpenVibe.Network), or the meaning of a product's prompt (each workflow's owner).
29
30## Who calls it, and whom it calls
31
32- Callers: every first-party product, with an OpenVibe.Network **service token** audience
33 `openvibe.ai` and the route's capability (`ai.run.create`, `ai.workflow.manage`, `ai.app.run`, …).
34 Live (`AI_SERVICE=remote`), Network (footer site copy), Actor (model routing), Blog (devblog
35 agent), Exchange pages and developer apps are the current callers.
36- Depends on: PostgreSQL 18 through `openvibe-sdk/db`; Network (`server/auth.js`: JWKS, service
37 tokens, SSO for the console); Events (`ai.run.queued|succeeded|failed|cached` outbox, and the
38 `bench.rating.changed` subscription); Bench (ratings/cost boards for routed evidence); Media
39 (recordings read over allow-listed https/signed URLs); Bot (`bot.machine.ai` for a person's own
40 machine); provider APIs, whisper.cpp and `openvibe-llm.service` on this host.
41
42## Repository map
43
44- **Entry:** [server/index.js](server/index.js) — `start()` wires config, database, registry, provider
45 pool, cache, quotas, runs, engine, auth, subscriptions and telemetry; also what tests call.
46- **App:** [server/app.js](server/app.js) — Express middleware, CSP headers, CORS for the public
47 reads, the `/api/v1`, `/internal`, `/you`, `/console` mounts, `/shared`, legal pages.
48- **Config:** [server/config.js](server/config.js) — pure `load(env)`; secrets are only ever read by
49 **name** through `secretRef()`.
50- **Database:** [server/db.js](server/db.js) opens/migrates `ov_ai`; schema in
51 [migrations/](migrations/) (currently `0001_initial.sql` … `0081_deep_dives.sql`).
52- **Auth:** [server/auth.js](server/auth.js) — `openvibe-contracts` `serviceAuth` + capabilities; the
53 JWKS key comes from `openvibe-sdk/auth`. Person sessions in [server/person-session.js](server/person-session.js).
54- **API:** [server/api/](server/api/) — `runs.js`, `admin.js`, `exchange.js`, `openai.js`,
55 `messages.js` (Anthropic-compatible), `models.js`, `credential.js`, `batches.js`, `actions.js`.
56- **Workflows:** [server/workflows/engine.js](server/workflows/engine.js), definitions and seed in
57 [server/workflows/](server/workflows/).
58- **Providers:** [server/providers/](server/providers/) — adapters, pool, circuits, fallbacks.
59- **Registry/run state:** [server/registry.js](server/registry.js), [server/runs.js](server/runs.js),
60 [server/cache.js](server/cache.js), [server/quota.js](server/quota.js).
61- **Public pages:** [server/home.js](server/home.js), [server/openapi.js](server/openapi.js);
62 server-rendered run receipts in [server/run-pages.js](server/run-pages.js).
63- **Console:** [server/console/](server/console/) — operator console, Network staff only.
64- **Capture worker:** [server/capture/worker.js](server/capture/worker.js) — headless Chrome for deep
65 dives, separate unit `openvibe-ai-capture.service` on `127.0.0.1:4711`.
66
67## Commands
68
69```bash
70npm install # or npm ci
71cp .env.example .env
72npm run dev # NODE_ENV=development, http://localhost:4700
73npm start # node server/index.js
74npm test # every test/*.test.js
75npm test -- quota cache # only files whose name contains one of the words
76ov test # the harness's sharded run of what the change reaches
77node --check <file.js> # syntax check; no linter/formatter configured
78```
79
80Without a provider key everything falls back to the deterministic stub provider, so no test needs the
81network or a paid key.
82
83## Database and migrations
84
85PostgreSQL database `ov_ai` on the host's data role (ADR-035). Without `DATABASE_URL`, development and
86tests use embedded PGlite. Every read/write is async through `openvibe-sdk/db`; an INSERT that needs
87its id uses `RETURNING id`. Migrations are `migrations/NNNN_name.sql`, applied at boot; **never edit a
88migration that has run** — `ov_migrations` records its checksum (see
89[docs/cutover-pr-openvibe-ai-15.md](docs/cutover-pr-openvibe-ai-15.md)). Add a new number instead.
90Migrations only add tables and columns.
91
92## Auth and capabilities
93
94Every API route needs a Network service token for audience `openvibe.ai`, the route's capability and,
95for runs, a namespace the token's `ns` claim allows (namespaces fail closed). Capability ids are
96decided by the **pinned** `openvibe-contracts` release: an unknown id is refused, never allowed. The
97operator console is Network staff only and needs `AI_CONSOLE_SESSION_SECRET` and
98`OV_OAUTH_CLIENT_SECRET`; person routes under `/api/v1/me/*` accept only the person's own token or
99AI's same-origin session — never a service token or `on_behalf_of`. Developer-app tokens
100(`sub app:app_<ULID>`) are accepted **only** on `ai.app.run` routes and act as their project.
101
102## HTTP surface (short)
103
104- Service-to-service: `POST /api/v1/runs`, `GET /api/v1/runs/:id`, workflows, providers, models,
105 credentials, quotas, usage and audit under `/api/v1/*`.
106- Developer apps: `POST /api/v1/{chat,generate,summarize,classify,extract,embed}` and
107 `GET /api/v1/runs/:id`, rate-limited per address on the public vhost.
108- Exchange: the OpenAI-compatible `POST /v1/chat/completions` and Anthropic-compatible
109 `POST /v1/messages`, model lists, read APIs and `/openapi.json`, served on
110 `api.openvibe.exchange`.
111- Health: `/api/health`, `/api/ready`; `/metrics` for direct loopback callers only.
112
113## Frontend loading model
114
115There is **no SPA and no build step**. Human pages are server-rendered strings with the console's
116classes and CSP (no external script on run receipts); the public human pages moved to
117OpenVibe.Exchange in 2026-11-07 and this service 301s them by name. `/shared/*` is served from the
118pinned `openvibe-shared` package in `node_modules` by `openvibe-shared/serve`. Never edit
119`node_modules`; change the package and bump the pinned release.
120
121## Deploy
122
123`sudo ovhost deploy ai` (strategy `git-checkout`): fetch, fast-forward `/opt/openvibe.ai`, install on
124a lockfile change, restart, wait for `/api/ready`, roll back automatically on failure. Unit
125`openvibe-ai.service`, env `/etc/openvibe/ai.env` (0600), vhost
126[deploy/nginx/ai.openvibe.services.conf](deploy/nginx/ai.openvibe.services.conf). The release migrates
127`ov_ai` at boot. `sudo ovhost rollback ai --to <sha>`; `sudo ovhost drill ai` for a restore drill.
128Never put a secret in a command line, a file or a log.
129
130## Tests
131
132`npm test` runs `test/run.js`, which executes each `test/*.test.js` in its own process through
133`openvibe-shared/test-runner` (PGlite by default; `npm run test:pg` uses PostgreSQL). Local servers on
134random ports, generated signing keys, the stub provider. A test that cannot run prints
135`<label>: skipped (<why>)` and is not counted as passed; `-- --strict` makes a skip fail. Read
136`test/README`-style guarantees in the README's "Acceptance" table: every guarantee names its test.
137`ov test` is the harness wrapper for the same suite.
138
139## Conventions
140
141- CommonJS (`require`/`module.exports`), 4-space indent, single quotes, semicolons.
142- `camelCase` JS, `snake_case` PostgreSQL columns/tables.
143- Errors are RFC 9457 `application/problem+json` from `openvibe-contracts` `http`; never return raw
144 provider errors or secrets.
145- The request log keeps hashes, not prompts; raw prompts and inline images are not stored; cache
146 entries never cross requester/actor/target/attribution scope.
147- `openvibe-contracts`, `openvibe-sdk` and `openvibe-shared` are pinned release tarballs in
148 `package.json`; bump by changing the tag, never by editing installed files.
149- CORS: exact origins for `/stats` and `/release.json`, `*` only for the public creation catalogue;
150 token and console routes never use that list.
151
152## Key pitfalls
153
154- **Capabilities come from the pinned contracts release.** A feature that adds a capability must bump
155 `openvibe-contracts` first, or the route refuses every caller.
156- **Namespaces fail closed.** A service token without `ns` runs nothing; do not add a fallback.
157- **The public pages are Exchange's.** Do not re-grow HTML here; redirect instead.
158- **Never edit an applied migration** (checksum recorded) and never create a table at runtime.
159- **Secrets by name only.** `env:NAME` references, AES-256-GCM for people's keys with
160 `AI_CREDENTIALS_KEY`; a response or log must never carry a value.
161- **Egress is allow-listed.** Media is fetched only from approved OpenVibe https hosts with every DNS
162 answer and redirect hop re-checked (`test/ssrf.test.js`).
163- **Quotas refuse before any provider call**, with 429 + `Retry-After`; abuse limits and the free
164 allowance run before metered capacity.
165- **`/metrics` is host-local.** Do not expose it on the public vhost.
166- **The capture worker is separate on purpose** (memory cap, one browser); a page that eats memory
167 must not take the API down.
168- **Docs drift:** the README's "Depends on" version list can lag `package.json`; `package.json` is
169 what runs.
170
171## Documentation
172
173- [README.md](README.md) — the full product, API and acceptance record.
174- [docs/migration.md](docs/migration.md) — cutover from Live and the `ov_ai` layout.
175- [docs/abuse-prevention.md](docs/abuse-prevention.md) — trust tiers, device cookie, proof of work.
176- [docs/provider-matrix.md](docs/provider-matrix.md) — what may be resold and what is UNVERIFIED.
177- [docs/provider-adapters.md](docs/provider-adapters.md), [docs/provider-registry.md](docs/provider-registry.md).
178- [docs/ai-exchange-baseline.md](docs/ai-exchange-baseline.md), [docs/exchange-platform.md](docs/exchange-platform.md).
179- [docs/memory-m5.md](docs/memory-m5.md), [docs/private-ai.md](docs/private-ai.md),
180 [docs/measured-metrics.md](docs/measured-metrics.md), [docs/deep-dive.md](docs/deep-dive.md).
181- Contracts live in OpenVibe.Contracts; the service's own schemes are documented in `README.md`.
182