@lacneu/atrium
v0.82.1
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, voice read-aloud and dictation, and a built-in observability surface. OpenClaw and Hermes are both supported — each provider lives behind a bridge adapter, and the UI is capability-driven: it discovers what a given gateway can do and shows only that, so the same front end serves either provider without per-provider UI code.
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 or Hermes); 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 and Hermes) that holds a persistent connection 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. Hermes offers two transports — a JSON-RPC WebSocket (the default, richer surface) or an OpenAI-compatible REST/SSE API — selectable per instance.
- An external agent gateway (OpenClaw or Hermes) 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.
The browser only ever talks to Convex; it has no direct connection to the bridge.
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. - Two gateway providers, one UI: OpenClaw and Hermes, each behind a bridge adapter. The UI is capability-driven — it discovers what a gateway supports and shows only that, so a control a provider lacks is simply absent rather than broken.
- Multi-user, multi-agent, multi-instance routing: each user is routed to the gateway instance and agent assigned to them — and within one conversation, each turn can be addressed to a different assigned agent (composer selector, per-reply attribution) with the shared thread carried over. When a gateway is unreachable, its chats grey their composer with an explanatory banner and recover automatically.
- 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.
- Structured agent activity: tool calls, delegated sub-agents, and Hermes Mixture-of-Agents runs surface as an inline, drill-down monitor — the aggregator and its reference models rendered as a hierarchy.
- Voice: per-instance read-aloud of replies and microphone dictation. The read-aloud engine is chosen per instance — the browser's built-in voices (no key, works on any provider) or, on providers that expose a text-to-speech RPC, the gateway's own configured TTS voices.
- File exchange in both directions (inbound attachments, outbound generated media served from Convex storage — server filesystem paths never reach the browser).
- Document viewer: files preview in a right-hand panel while the conversation continues — PDFs in-app (thumbnails + zoom), images/video/audio, text, and markdown rendered with a raw toggle. Office documents are converted to PDF by a designated converter agent (no embedded conversion service) and cached per file.
- Branch a conversation: fork any reply into a new chat that carries the same history (messages, files, agent attribution) — explore a tangent while the original continues, with the agent re-grounded on the branch's first message.
- Agent workspace files (identity / rules / tools) viewable and editable per instance, with concurrent-edit protection.
- 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.
That is the abridged form. The ordered procedure — every step with its
precondition, its exact command and how you verify it — is
docs/installation/COMPOSE.md, and
docs/installation/HELM.md is its Kubernetes peer.
What applies to both, including the two-environment-scope gotcha, is
deploy/README.md.
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
docs/ is the index — every page, grouped by what you are
trying to do, with what each one is for. The three entry points:
- Installation — start here. Which profile fits you — evaluating Atrium, or running it for a team — what each one gives you and what it does not, plus an ordered procedure per method — Compose or Helm — every step states its precondition, its command and how to verify it, written to be followed literally by a person or by an agent.
- Development — the local workflow if you want to work on Atrium rather than run it.
- Deployment — the canonical deploy guide (Compose and Helm), with troubleshooting for first-deploy problems.
Also: Compliance / Trust Center — SOC 2 control mapping (incl. the
metadata-only /api/v1 surface) and the software-vs-operator shared-responsibility
model · 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.
