Operate

Self-hosting

Engram deploys per client: your Postgres, your object store, your hosting — no memory content ever touches shared infrastructure. The entire stack is configured by environment variables; a new deployment is configuration, not code.

The only external services in any deployment are OpenAI (embeddings and answers — swappable for any OpenAI-compatible endpoint) and Clerk (identity only; it never sees memory content).

Environment variables

VariableWhat it configures
ENGRAM_MODETenancy model: "self-hosted" (default — one workspace per deployment, first sign-in claims ownership) or "hosted" (multi-org SaaS: each Clerk Organization auto-provisions its own workspace)
HOSTED_SIGNUPSHosted mode only: "open" (default) provisions a workspace for any new organization; "closed" makes Engram Cloud invite-only
DATABASE_URLAny Postgres with the vector extension available (Railway, RDS, Supabase, self-hosted)
S3_BUCKET / AWS_REGIONObject store bucket for memory bodies, and its region
AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEYObject store credentials
S3_ENDPOINTOptional — point at any S3-compatible store (MinIO, R2, client-VPC); enables path-style addressing
OPENAI_API_KEYEmbeddings + answers
COMPAT_BASE_URL / COMPAT_API_KEYOptional — OpenAI-compatible endpoint (Azure OpenAI, vLLM) via the provider seam
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY / CLERK_SECRET_KEYYour own Clerk application (identity only — never memory content)
PM_WEBHOOK_SECRETOptional, recommended — HMAC verification for inbound PM webhooks
<PROVIDER>_CLIENT_ID / _CLIENT_SECRETOptional per provider — enables one-click OAuth connect for Linear, GitHub, Slack, Atlassian, Notion (paste-credentials works without)

Deployment recipes

A. Railway (the default)

  • New Railway project → add Postgres (pgvector ships in Railway's image).
  • Deploy this repo as a service; set the env vars above.
  • Bucket: any S3 provider you already have, or Railway's MinIO template with S3_ENDPOINT.
  • Run the one-time setup below against the new database.

B. Docker Compose (fully self-contained)

App + pgvector Postgres + MinIO on one host; data stays on that host.

cp .env.self-host.example .env    # fill in Clerk + OpenAI keys
docker compose up -d --build

The compose stack is written but not yet smoke-tested end-to-end — verify it before handing it to a client.

C. Anywhere Node runs

pnpm install
pnpm --filter @engram/web build   # Next.js standalone output
pnpm --filter @engram/web start

One-time setup (all recipes)

From the repo, with DATABASE_URL (and the S3 vars) pointing at the new stack:

pnpm db:push                                          # schema
cd packages/agents
pnpm tsx scripts/bootstrap-workspace.ts "Client Name"  # empty workspace

The bootstrap creates the pgvector extension, one workspace (it refuses to run if one already exists — one workspace per deploy), starter folders (/company/policies, /departments, /projects), a default employee → viewer@/company role mapping, and the demo Report Drafter agent. Then:

  • Sign in at /app the first user becomes the workspace owner, so sign in before sharing the URL. This first-signer rule applies only when ENGRAM_MODE is unset or self-hosted.
  • Mint the owner's personal token: pnpm tsx scripts/mint-personal-token.ts.
  • Connect MCP, add connectors, capture the first memories.

For a demo instance with the seeded “Meridian Systems” workspace, run scripts/seed-meridian.ts and scripts/seed-agent.ts instead of the bootstrap. To start a deployment over, scripts/wipe-db.ts --yes drops the whole schema (then re-run db:push and the bootstrap).

What lives where

DataLocation
Memory text, embeddings, metadata, audit logYour Postgres
Memory bodies, uploaded source filesYour bucket
Content sent for embedding / answeringOpenAI, or your compatible endpoint
User identities (email, SSO) — no memory contentClerk