Architecture

25 containers · Phases 1–5 v1.0

Overview

xbrain runs as 25 Docker containers on a single VM, connected via a private Docker network (xbrain_net). All external traffic enters through nginx on port 80/443. Internal services never expose ports to the internet.

The central invariant is memory-api: every data point from every frontend (LibreChat, Open WebUI, Chrome extension, agents) passes through memory-api before persisting. memory-api enforces the 7-field tagging contract and routes data to the right stores: PostgreSQL (event store), Qdrant (vector search), and Neo4j (knowledge graph).

Architecture Diagram

                    ┌─────────────────┐
  Browser ─────────►│  nginx (80/443)  │
                    └────────┬────────┘
                             │
              ┌────────────┼────────────┐
              │              │              │
       ┌──────▼──┐   ┌──────▼──┐   ┌─────▼──────┐
       │ LibreChat │   │Open WebUI│   │ memory-api  │
       └──────┬──┘   └──────┬──┘   └─────┬──────┘
              │              │              │
       ┌─────▼───────────▼──┐   ┌─────▼──────┐
       │  librechat-bridge        │   │ PostgreSQL  │
       │  openwebui-pipeline      │   │ Qdrant      │
       └─────────────────────────┘   │ Neo4j       │
                                      └────────────┘
       ┌──────────────┐   ┌──────────────────────────┐
       │ agent-runtime │   │ MCP Gateway               │
       │ (LangGraph)   │   │ mcp-scraper               │
       └──────┬────────┘   │ mcp-drive-read            │
              │            │ mcp-calendar              │
       ┌─────▼───────┐   │ mcp-deck                  │
       │ graphiti-svc  │   └──────────────────────────┘
       └───────────────┘

       ┌──────────────┐   ┌────────────────────────┐
       │ drive-sync   │   │ Langfuse (observability) │
       └──────────────┘   │ ClickHouse / Redis       │
                          │ MinIO (Chainguard)       │
                          └────────────────────────┘

  All containers: xbrain_net (Docker bridge network)

Container Reference

All 25 containers across Phases 1–5. The Phase column indicates when each container is first introduced. Containers from earlier phases remain active in later phases.

Container Image Phase Purpose RAM (idle)
nginx nginx:1.27-alpine 1 Reverse proxy, TLS termination, routing to all services 64 MB
postgres postgres:17 1 Primary relational DB: event store, audit logs, user/team data 256 MB
qdrant qdrant/qdrant:v1.17.1 1 Vector store: semantic search, scoped by team_scope + truth_level 300 MB
memory-api xbrain/memory-api 1 Core API: tagging contract enforcer, routes to PostgreSQL + Qdrant + Neo4j 384 MB
librechat-mongo mongo:7 1 LibreChat conversation and message storage (MongoDB) 300 MB
librechat-meili getmeili/meilisearch:v1.10 1 LibreChat full-text search index 192 MB
librechat librechat/librechat:v0.8.2-rc2 1 Primary chat frontend — Claude, GPT, Grok support, MCP-ready 400 MB
open-webui ghcr.io/open-webui/open-webui:v0.9.0 1 Secondary chat + admin UI, RAG testing, agent experimentation 600 MB
librechat-bridge xbrain/librechat-bridge 1 Listens for LibreChat messages, forwards to memory-api with JWT auth 128 MB
openwebui-pipeline xbrain/openwebui-pipeline 1 Open WebUI pipeline plugin: intercepts messages, sends to memory-api 192 MB
agent-runtime xbrain/agent-runtime 2 LangGraph agent executor with human-in-the-loop (HITL) support 384 MB
langfuse langfuse/langfuse:3 2 LLM observability web UI — traces, scores, evaluations 512 MB
langfuse-worker langfuse/langfuse-worker:3 2 Langfuse background processing — async ingestion, exports 512 MB
clickhouse clickhouse/clickhouse-server 2 OLAP backend for Langfuse trace storage and analytics 1.5 GB
redis redis:7 2 Langfuse cache, job queues, rate limiting 50 MB
minio cgr.dev/chainguard/minio 2 S3-compatible object storage: PDFs, images, Langfuse blobs 256 MB
neo4j neo4j:2026.04.0-community 3 Knowledge graph: entity nodes, MENTIONS edges, relationship lineage 1 GB
mcp-gateway xbrain/mcp-gateway 3 MCP tool registry and proxy — routes LibreChat MCP calls to sidecars 256 MB
mcp-scraper xbrain/mcp-scraper 3 Web scraping MCP tool (port 8100) — Playwright-based content extraction 128 MB
mcp-drive-read xbrain/mcp-drive-read 3 Google Drive read/write MCP tool (port 8101) — file listing, content fetch 128 MB
mcp-calendar xbrain/mcp-calendar 3 Google Calendar read MCP tool (port 8102) — event listing, availability 128 MB
drive-sync xbrain/drive-sync 3 Incremental Google Drive sync + Push Notifications (webhooks) 128 MB
mcp-deck xbrain/mcp-deck 4 PPTX generation MCP tool — creates slide decks from structured data 256 MB
graphiti-service xbrain/graphiti-service 5 Temporal fact extraction (port 8300) — enriches Neo4j graph, fail-soft 512 MB
projects-dashboard Firebase Hosting (static) 5 Team project dashboard — React SPA, deployed on Firebase Hosting N/A

Network Architecture

All containers connect on xbrain_net, a Docker bridge network defined in docker-compose.yml. Container-to-container communication uses service names as hostnames (e.g., http://memory-api:8000).

Exposed ports

Port Service Accessible from
80 nginx Internet (HTTP → redirects to 443)
443 nginx (with Cloudflare) Internet (HTTPS)

Internal-only ports

Port Service Notes
8000 memory-api FastAPI — all frontends and agents write here
9100 agent-runtime LangGraph HTTP API
8080 mcp-gateway MCP tool registry + proxy
8100 mcp-scraper Web scraping MCP sidecar
8101 mcp-drive-read Google Drive MCP sidecar
8102 mcp-calendar Google Calendar MCP sidecar
8300 graphiti-service Temporal fact extraction service
6333 qdrant Qdrant HTTP + gRPC API
7687 neo4j Neo4j Bolt protocol
5432 postgres PostgreSQL

No host networking

No container uses network_mode: host. All inter-service communication stays within xbrain_net. Only nginx is bound to host ports 80 and 443.

Data Flow — Chat Message

Here is what happens from the moment a user sends a message in LibreChat to the moment it becomes a searchable memory item:

  1. User sends a message in LibreChat.
  2. LibreChat saves the message to MongoDB (librechat-mongo) — its own conversation history.
  3. librechat-bridge detects the new message via the LibreChat webhook/event.
  4. bridge sends POST /v1/messages to memory-api with a Bearer JWT.
  5. memory-api enforces the tagging contract — all 7 mandatory fields must be present or the request returns 422.
  6. Message is stored in PostgreSQL (event store + audit log) and Qdrant (vector embedding for semantic search).
  7. If the message payload includes an entities field, the Neo4j outbox is updated by a background worker.
  8. graphiti-service enriches the knowledge graph with temporal facts — this call is fail-soft and async (a graphiti-service outage does not block the memory write).
  9. Audit log entry written to PostgreSQL with timestamp, source, and team_scope.

Open WebUI follows the same flow

Messages from Open WebUI pass through openwebui-pipeline instead of librechat-bridge, but arrive at the same memory-api endpoint with the same tagging contract.

VM Sizing

xbrain's container count grows with each phase. Plan your VM size before deploying a new phase — attempting Phase 2 on a 4 GB VM will cause OOM kills.

Phase VM RAM Cost / mo Notes
Phase 1 e2-medium 4 GB ~25€ ~2.2 GB used. Monitor OOM. Do not add Phase 2 services without upgrade.
Phase 2 e2-standard-2 8 GB ~49€ Upgrade before adding mem0 + LangGraph + ClickHouse.
Phase 3+ e2-standard-4 16 GB ~98€ Or split: xbrain on e2-standard-2 + Langfuse on e2-small (~62€/mo total).

See the Deployment guide for detailed instructions on how to resize a GCP VM without data loss.