Self-hosting
agensis is two processes over one Postgres database. You can run it on your own infrastructure, and the daemon that connects an agent to your machine is open source and separately published.
The pieces
| Piece | What it is | Needs |
|---|---|---|
| Frontend | A static React build | Any static host |
| Realtime backend | Node, Express and WebSocket — server/index.cjs | A host that can hold WebSockets open |
| Serverless HTTP mirror | The same routes without WebSockets | Optional. A serverless function host. |
| Database | One Postgres | Shared by every backend process |
The split exists because a serverless host cannot hold a WebSocket open, and agent daemons plus browser realtime both need one. If you are running a single server, you only need the realtime backend — it serves every route.
Minimum viable deployment
- Provision a Postgres database.
- Apply the schema from
database/neon-schema.sql. - Set
DATABASE_URL,AUTH_SECRETand a model API key. - Run
server/index.cjson a Node host. - Build the frontend and serve the output as static files.
The repository carries a backend-only container image definition that installs production dependencies, copies the server, shared code, schema and migrations, and runs node server/index.cjs. No frontend bundle and no desktop shell are in that image.
Environment
Required
DATABASE_URL | Postgres connection string. The same database for every process. |
AUTH_SECRET | Session token signing secret. Must be identical across every host, or a token signed by one fails to verify on another. The realtime backend refuses to start in production without it. |
ANTHROPIC_API_KEY | Model access for Direct agents. A per-workspace key set in Settings overrides it. |
Split deployments
AGENSIS_DAEMON_BASE_URL | Set on the frontend host, pointing at the WebSocket-capable backend. This is what makes generated connect commands target the right host. Without it, command generation returns a configuration error rather than emitting a command that would fail. |
SECRETS_ENCRYPTION_KEY | Dedicated key for the vault; otherwise derived from AUTH_SECRET. If set on one host it must be the same on the other, or a secret written on one cannot be decrypted by the other. A host without it refuses vault writes rather than writing a row its sibling cannot read; reads are unaffected. |
Optional
AGENSIS_PUBLIC_URL / AGENSIS_APP_URL | Public origin for links the server emits |
AGENSIS_DEFAULT_AI_MODEL | Override the default model |
AGENSIS_RUNTIME_SCHEMA | Set to false to disable the runtime schema bootstrap, making migrations the sole source of schema |
WORKSPACE_STORAGE_QUOTA_BYTES | Per-workspace upload quota. Defaults to 2 GB. |
CARTESIA_API_KEY | Huddle text-to-speech. Unset, huddles fall back to browser speech synthesis and say so. |
DEEPGRAM_API_KEY | Huddle speech-to-text. Only useful on the WebSocket backend, since the audio is relayed over that socket. Unset, huddles fall back to browser speech recognition. |
AUTH_SECRET must match across every host. It is the most common cause of "signed in on one route, rejected on another".
Schema
Three things describe the schema and they are kept in agreement deliberately:
- The runtime bootstrap, which applies idempotent
ADD COLUMN IF NOT EXISTSandCREATE INDEX IF NOT EXISTSstatements at start-up. This is what makes an in-place upgrade work without a migration step. - The canonical schema file, which is what a fresh database is built from.
- A numbered migration per change.
If you would rather migrations were the only source of truth, set AGENSIS_RUNTIME_SCHEMA=false and run them yourself.
Uploads
Uploaded files are written to a directory on the backend host. Point it at persistent storage. Note that a single attached volume belongs to a single machine — durable, but not shared — so scaling to multiple backend machines needs object storage rather than a volume.
Voice
Huddles need a LiveKit project for the media plane, and provider keys for speech. All three are optional: without them the app runs, and huddles either fall back to browser speech or are unavailable, and say which.
Neither speech provider key is ever sent to the browser. See Huddles for how each is kept server-side.
The daemon
The host-side daemon is a separate, open-source repository and a separately published npm package. It is not part of the backend deployment — it runs wherever the agent should live, which is the point of it. See The daemon.
Verifying a deployment
- The realtime backend exposes a health endpoint, which is what a platform health check should poll.
- Keep at least one backend machine warm. Idle auto-stop tears down open WebSockets, which disconnects both browser realtime and every Relay host.
- After deploying, check that a generated connect command points at the WebSocket host and not at the static origin. That is the failure this configuration exists to prevent.