openvibers/openvibe.codes AGENTS.md
AGENTS.md
| 1 | # AGENTS.md — OpenVibe.Codes |
| 2 | |
| 3 | ## Project overview |
| 4 | |
| 5 | The open coding-agent harness: one place to send a coding task to the agent that fits it (by what the |
| 6 | task needs first, then cost), hand it over when an agent gets stuck, and keep the run in one place. |
| 7 | The same package runs on a person's own machine with their CLIs and keys; the site is the front door, |
| 8 | the router and the record. Node.js/Express + the `harness/` package, PostgreSQL (`ov_codes`), |
| 9 | CommonJS, **no build step**. |
| 10 | |
| 11 | - Service id `codes`, port `4900`, origin `https://openvibe.codes`, unit `openvibe-codes.service`, |
| 12 | release root `/opt/openvibe.codes`; live on openvibe-ovh. |
| 13 | - Design: plan T16 and [ADR-050](docs/adr/050-codes-harness-fabric.md). The developer console that |
| 14 | used to live here moved to **OpenVibe.Services** on 2026-10-08; every one of its addresses here is |
| 15 | a permanent redirect there. |
| 16 | - `package.json` `main` is [harness/index.js](harness/index.js) — the installable harness — while |
| 17 | `npm start` runs [server/index.js](server/index.js), the site. |
| 18 | |
| 19 | ## What it owns |
| 20 | |
| 21 | - The harness catalog and routing policy over it; placement itself is `openvibe-sdk/placement`. |
| 22 | - The harness package ([harness/](harness/), [bin/](bin/)): adapters for Claude Code, Codex, OpenCode, |
| 23 | Command Code, Aider, the DeepSeek API and self-hosted models; the shared event format, hand-offs |
| 24 | and the local run store. |
| 25 | - The site's records: `run_tasks` (tasks started on the site or API), `codes_session_lines`, |
| 26 | attempts/hand-offs, inbound Run events and the `codes.task.*` outbox. |
| 27 | - Knowledge (`codes_knowledge`), skills/Rules/MCP/commands/hooks with immutable versions |
| 28 | (`codes_skills`, `codes_skill_versions`), sharing, the task API/SSE stream and the agent catalog. |
| 29 | - Pages: `/`, `/start`, `/run`, `/run/tasks/:id`, `/knowledge`, `/skills`, `/harnesses`, `/improve`, |
| 30 | `/policy*`, `/updates`, and the machine endpoints. |
| 31 | |
| 32 | Not owned: the sandboxes/browsers (OpenVibe.Run), the machine's Link plugin (Link), the OpenVibe Git |
| 33 | host (`git.openvibe.codes`, repo OpenVibe-Git), the AI model runs (`openvibe.ai`, called through the |
| 34 | catalog), identity/grants (Network/Services), and the console that moved to Services. |
| 35 | |
| 36 | ## Who calls it, and whom it calls |
| 37 | |
| 38 | - Callers: people in the browser; services with a Network service token audience `openvibe.codes` and |
| 39 | `codes.task.start|read|cancel` (OpenVibe.Actor is the main one), using `X-OV-Subject` (and |
| 40 | `X-OV-Project`) to act for a person; the CLI `openvibe-codes task` with the person's own token. |
| 41 | - Depends on: **Network** (SSO client `codes`, PKCE, JWKS); **AI** (`ai.openvibe.services` — the |
| 42 | model catalog and completion); **Run** (`server/domain/run-client.js` — jobs in class `code`, |
| 43 | artifact `[email protected]`, `trust: user-owned`, placed only on the person's machines); |
| 44 | **Link** (`openvibe-codes job` in the machine's job sandbox); **Network projects** for delegation; |
| 45 | **Git** (`git.openvibe.codes` — branch push and pull request with Codes' service token acting for |
| 46 | the person); PostgreSQL and Valkey; Events for the outbox. |
| 47 | |
| 48 | ## Repository map |
| 49 | |
| 50 | - **Site entry:** [server/index.js](server/index.js) — `createApp()`, listen, graceful stop. |
| 51 | - **App:** [server/app.js](server/app.js) — helmet/CSP, `/internal/events`, |
| 52 | `/internal/sandbox-workers`, `/auth`, `/shared`, `/api/v1` (agent, task, knowledge, skills and |
| 53 | resource routers), pages, moved-address redirects, machine endpoints. |
| 54 | - **Harness entry:** [harness/index.js](harness/index.js) — `createHarness({ env, fetch, store })`, |
| 55 | `agents()`, `route()`, `run()` and the event stream; [harness/job.js](harness/job.js) is the job the |
| 56 | Link runs. |
| 57 | - **Domain:** [server/domain/](server/domain/) — `run-tasks.js`, `attempts.js`, `harnesses.js`, |
| 58 | `harness-placement.js`, `knowledge.js`, `skills.js`, `run-client.js`, `github.js`, `redact.js`. |
| 59 | - **HTTP:** [server/http/](server/http/) — `pages.js`, `api.js`, `tasks-api.js`, `run.js`, |
| 60 | `knowledge.js`, `skills-pages.js`, `moved.js`, `discovery.js`, `openapi.js`. |
| 61 | - **Catalog:** [server/data/harness-offers.json](server/data/harness-offers.json) (validated at boot). |
| 62 | - **Browser:** [public/js/run.js](public/js/run.js), `composer.js`, `chat.js`, `c4.js`, `copy.js`, |
| 63 | `setup.js`; CSS in [public/css/](public/css/). |
| 64 | - **Sandbox:** [sandbox/](sandbox/) (bwrap/seccomp/egress, worker/supervisor), |
| 65 | [deploy/sandbox/](deploy/sandbox/). |
| 66 | - **Deploy:** [deploy/systemd/openvibe-codes.service](deploy/systemd/openvibe-codes.service), |
| 67 | [deploy/nginx/openvibe.codes.conf](deploy/nginx/openvibe.codes.conf). |
| 68 | |
| 69 | ## Commands |
| 70 | |
| 71 | ```bash |
| 72 | npm ci |
| 73 | npm run dev # NODE_ENV=development node server/index.js |
| 74 | npm start # node server/index.js, http://127.0.0.1:4900 |
| 75 | npm test # test/run.js, temp PGlite, mock Network/Events/Media |
| 76 | npm run test:pg # same suite on PostgreSQL (CODES_TEST_STORE=pg) |
| 77 | npm test -- schedule # filter by file name; --strict makes a skip fail |
| 78 | ov test # the harness's sharded run of what the change reaches |
| 79 | ``` |
| 80 | |
| 81 | The harness is also run from a machine: |
| 82 | |
| 83 | ```bash |
| 84 | npm install -g <this repo tarball> |
| 85 | openvibe-codes agents # what this machine can run, and why not the rest |
| 86 | openvibe-codes run "…" # routed, handed off on failure, kept |
| 87 | ``` |
| 88 | |
| 89 | ## Database and migrations |
| 90 | |
| 91 | PostgreSQL database `ov_codes` on the host's data role (ADR-035); PGlite in development/tests. |
| 92 | Async through `openvibe-sdk/db`; migrations `migrations/NNNN_*.sql` applied at boot with the owner |
| 93 | connection (`DATABASE_DIRECT_URL`). Never edit an applied migration. **Migration 0002 dropped the old |
| 94 | console tables** (rows were copied into `ov_services`): a rollback to a release before it finds no |
| 95 | console tables, so roll forward or restore `ov_codes` from the pre-deploy backup. Skills are |
| 96 | versioned: every save is an immutable version and a rollback copies an old version into a new one — |
| 97 | never UPDATE a version body. |
| 98 | |
| 99 | ## Auth and task ownership |
| 100 | |
| 101 | - The site signs people in with Network SSO (OAuth client `codes`, PKCE S256); session tokens are |
| 102 | HttpOnly cookies. A FedCM assertion, an app token or a service token is never a session. |
| 103 | - The task API accepts either the person's own Network access token (they see every task they own, |
| 104 | whoever started it) or a first-party service token with the route's capability plus |
| 105 | `X-OV-Subject`; a service reads/cancels only the tasks it started for that person (otherwise 404). |
| 106 | - `idempotency_key` makes a retry answer the first task (`200`, `created: false`). |
| 107 | - Per-person budgets: starts and cancels 6/minute, 60/hour. `permission` is `review` (read-only), |
| 108 | `edit` (default) or `full`. |
| 109 | - Codes never sends or accepts a shared loopback key (tested by grep and at runtime). |
| 110 | |
| 111 | ## Frontend loading model |
| 112 | |
| 113 | Everything on the site is **server-rendered and usable without JavaScript**; small no-build scripts |
| 114 | under [public/js/](public/js/) enhance the run view, composer, chat and C4 pages. There is no SPA, |
| 115 | bundler or transpiler. `openvibe-shared` supplies the Frame, the session view |
| 116 | (`openvibe-shared/agent-session.js`) and `/shared/*` from the pinned node_modules. CSP is in |
| 117 | [server/app.js](server/app.js); crawl files use `openvibe-shared/seo` and IndexNow on deploy. |
| 118 | |
| 119 | ## Deploy |
| 120 | |
| 121 | `sudo ovhost deploy codes` (git-checkout: fetch, fast-forward `/opt/openvibe.codes`, install on a |
| 122 | lockfile change, restart, wait for `/api/ready`). Unit `openvibe-codes.service` on `127.0.0.1:4900`, |
| 123 | env `/etc/openvibe/codes.env`; vhost |
| 124 | [deploy/nginx/openvibe.codes.conf](deploy/nginx/openvibe.codes.conf). Rollback |
| 125 | `sudo ovhost rollback codes --to <sha>` — mind migration 0002 above. The sandbox worker is a separate |
| 126 | unit/service installed from [deploy/sandbox/install.sh](deploy/sandbox/install.sh). |
| 127 | |
| 128 | ## Tests |
| 129 | |
| 130 | `npm test` runs each `test/*.test.js` in its own process through `openvibe-shared/test-runner`, with |
| 131 | PGlite and in-process Network/Events/Media mocks. It covers the harness adapters and hand-offs, |
| 132 | routing/catalog, the task API and attempts/SSE, knowledge and skills, redaction, the moved redirects, |
| 133 | the pages/llms/openapi, sandbox rules and the contracts. `ov test` runs the same. |
| 134 | |
| 135 | ## Conventions |
| 136 | |
| 137 | - CommonJS, 4-space indent, single quotes, semicolons; domain logic in `server/domain/`, HTTP in |
| 138 | `server/http/`, harness in `harness/`; injectable config/db/clock/fetch/log. |
| 139 | - The harness is standalone: it must not need OpenVibe to run, and nothing about a local run goes |
| 140 | through OpenVibe unless the person asks. |
| 141 | - Errors are RFC 9457 problem+json with stable codes (`harness.invalid`, `harness.task_unknown`, |
| 142 | `codes.no_project`); never leak a path, a key or a request body. |
| 143 | - IDs and capability names come from `openvibe-contracts`; bump the pin before using a new one. |
| 144 | |
| 145 | ## Pitfalls |
| 146 | |
| 147 | - **Never push the branch a task started from.** A job may push a new branch (never the base) and open |
| 148 | a pull request only when asked and the machine holds `GITHUB_TOKEN`. |
| 149 | - **The API loop stays in the working directory**, never reads `.env`, never writes under `.git`; |
| 150 | the permission levels (`review`/`edit`/`full`) are enforced by the adapters, not by prompt text. |
| 151 | - **`/run` tasks run on the person's own machine**, not OpenVibe's. A task with no `/run` project is |
| 152 | `409 codes.no_project`; do not "fix" it by placing work anywhere else. |
| 153 | - **Knowledge is private by default and redacted** before storage; a shared row goes through the |
| 154 | share gate, never a raw link. |
| 155 | - **Skills are immutable versions**; a rollback is a new version. |
| 156 | - **Moved addresses are 301 for GET/HEAD and 308 for anything else**, preserving path, query, method |
| 157 | and body — do not reintroduce the console. |
| 158 | - **`/metrics` is loopback only**; readiness is truthful (database + catalog required). |
| 159 | - **A service may act only for the person it names** and only on the tasks it started. |
| 160 | |
| 161 | ## Documentation |
| 162 | |
| 163 | - [README.md](README.md) — every surface, the harness, API, configuration and deploy. |
| 164 | - [docs/adr/050-codes-harness-fabric.md](docs/adr/050-codes-harness-fabric.md) — the boundaries. |
| 165 | - [docs/harness-runtime.md](docs/harness-runtime.md), [docs/cli.md](docs/cli.md), |
| 166 | [docs/checkpoints.md](docs/checkpoints.md), [docs/agent-runs.md](docs/agent-runs.md). |
| 167 | - [docs/model-plans.md](docs/model-plans.md), [docs/g3-local-clone.md](docs/g3-local-clone.md), |
| 168 | [docs/governance/](docs/governance/), [CONTRIBUTING.md](CONTRIBUTING.md). |
| 169 |