@lacneu/atrium
v0.2.0
Published
Atrium — public, self-hostable, Convex-backed web chat UI for AI agent gateways (OpenClaw today, Hermes next). Ships an origin-agnostic static bundle (Convex URL injected at runtime via /config.json).
Readme
An open-source, self-hostable web chat UI for AI agent gateways. It gives a team a clean multi-user chat front end across one or more gateways, with streaming replies, file exchange, per-user agent routing, and a built-in observability surface. OpenClaw is the first supported provider; Hermes is next — each provider lives behind a bridge adapter, so the UI stays the same as gateways are added.
Atrium is provider-agnostic by design and a community project — not affiliated with or endorsed by any gateway vendor. You bring your own gateway (OpenClaw today, Hermes next); Atrium is the chat surface in front of it.
Status
Early but functional, designed as a public, forkable foundation. The project is
0.x: the bridge protocol and APIs are documented and versioned, but breaking
changes can still happen before 1.0.
What it is
Agent gateways are event-driven and best driven over a WebSocket: a single user turn can produce multiple runs, intermediate replies, tool output, generated media, auto-compaction restarts, and messages that arrive after a browser reconnect. Atrium embraces that model instead of fighting it:
- A React + Vite front end (TypeScript, built on assistant-ui).
- A Convex self-hosted backend (TypeScript functions + reactive database) that owns chats, messages, routing, auth, and the observability data.
- A Node/TypeScript bridge with a per-provider adapter (OpenClaw today, Hermes planned) that holds a persistent operator WebSocket to the gateway, normalizes the version-specific event stream into a small stable shape, and relays turns to and from Convex. The provider is the only vendor-coupled layer.
- An external agent gateway (OpenClaw, or Hermes when available) that actually runs the agents. Atrium never runs the model itself — you bring your own gateway.
The front end never parses raw gateway frames; it subscribes to Convex, which is fed by the bridge. The result is a stable UI even as providers and versions evolve.
Browser ──▶ Convex (queries/mutations, reactive)
▲ │ schedules an outbound turn
│ live ▼
└────── Bridge ◀──▶ agent gateway (WebSocket: OpenClaw today, Hermes next)
(ingests normalized events back into Convex)See docs/ARCHITECTURE.md for the full picture.
Features
- Google and Microsoft Entra sign-in (via
@convex-dev/auth), restricted to allowed email domains; the first sign-in from an allowed domain becomes admin. - Multi-user, multi-agent, multi-instance routing: each user is routed to the gateway instance and agent assigned to them.
- Streaming assistant replies with a stable contract (deltas, snapshots, finalize, run status, tool status, media), resilient to provider and version differences, empty/duplicate finals, follow-on runs, and auto-compaction.
- File exchange in both directions (inbound attachments, outbound generated media served from Convex storage — server filesystem paths never reach the browser).
- A key-authed observability API (
/api/v1) and an MCP server (mcp/) for traces, KPIs, anomalies, and diagnostics — metadata only, no chat content. - Full internationalization (French default, English) via Paraglide JS.
Quickstart
The frontend and bridge ship as Docker images; Convex runs self-hosted. The
canonical, env-driven deployment guide (Docker Compose and Helm) lives in
deploy/:
cd deploy/compose
cp .env.example .env # fill every required value (see comments inside)
docker compose up -d # convex backend + dashboard + frontend + bridge
./bootstrap-env.sh # push the Convex-scoped vars (auth, bridge wiring)Open the app at your frontend origin and sign in. See
deploy/README.md for the full guide, including the
two-environment-scope gotcha and the stateful/stateless lifecycle.
For local development (no Docker), see docs/DEVELOPMENT.md.
Frontend distribution (npm / CDN)
Besides the Docker image, the frontend is published to npm as a prebuilt static
bundle (@lacneu/atrium) so you
can deploy the UI to any static host or CDN without building it yourself. It is
origin-agnostic: the Convex URL is read at runtime from a /config.json served
next to the bundle, so one artifact serves any deployment.
The bundle is only the UI — you still run the Convex backend and the bridge (see Quickstart). Serve a
config.jsonnext toindex.html:{ "convexUrl": "https://convex.example.com" }
- npm —
npm install @lacneu/atrium, then copy the package'sdist/to your static host / bucket / CDN and drop yourconfig.jsonbesideindex.html. - Pin a version straight from a CDN (e.g. in a deploy script) — no install:
https://unpkg.com/@lacneu/atrium@<version>/dist/https://cdn.jsdelivr.net/npm/@lacneu/atrium@<version>/dist/
- Docker — the published frontend image serves the same
dist/and writes/config.jsonfrom theCONVEX_URLenv at startup (this is what the Quickstart uses).
Documentation
- Architecture — components, data flow, auth.
- Development — local dev workflow, tests, Convex, Vite.
- Configuration — environment variable reference.
- Bridge protocol — bridge ↔ Convex ↔ gateway contract.
- Deployment → points to
deploy/. - Deployment troubleshooting — first-deploy problems with diagnosis + fix (private images, sign-in/JWT, agent discovery, …).
- OpenClaw version compatibility.
- Compliance / Trust Center — SOC 2 control mapping (incl. the
metadata-only
/api/v1surface) + the software-vs-operator shared-responsibility model. - Vision · Changelog · Third-party notices · Contributing & agent guide.
Security
Gateway tokens and device identities live only in the bridge process — never in Convex tables and never in the browser. Outbound media is served through Convex storage with no server paths exposed. See SECURITY.md.
Contributing
Contributions are welcome — see CONTRIBUTING.md and the Code of Conduct.
License
MIT. See LICENSE.
