Repository navigation
Architecture Map
Canonical source:
context/architecture-map.md— this page is rendered from it on every publish; edit the source.
Review when the service topology, data ownership boundary, or gateway routing changes. Last verified: 2026-10-05.
Authority level 3 — below
CLAUDE.mdandrules/00-non-negotiable-rules.md, above everything else structural. This is the single source of truth for the shape of the system. Facts (ports/events/routes) are machine-readable in.ai/manifests/*.json; this file explains the topology and the rules that govern it. If a count here disagrees with a regenerated manifest, the manifest wins — fix this file.
Product: "Every AI, one workspace" — positioning is canonical in
docs/01-executive-context/product-vision.md
(ADR-126).
Architecturally, a local-first AI orchestration platform. It routes chat, image, file, and
research work across cloud AI providers and local runtimes (Ollama, llama.cpp,
ComfyUI, Stable Diffusion), with memory, context packs, workspace connectors,
and a desktop agent — all behind one authenticated gateway.
It is an npm-workspace monorepo: 21 NestJS microservices + 1 Next.js
frontend + 6 shared packages = 28 workspaces (each with a package.json under
apps//packages/; the frontend counts as an app). See
workspace-map.md.
┌──────────────────────────────────────────────────────────────────────┐
│ Browser (https://claw.local) │
└──────────────────────────────────────────────────────────────────────┘
│ HTTPS
▼
┌──────────────────────────────────────────────────────────────────────┐
│ Next.js frontend (claw-frontend, port 3000) │
│ page.tsx → controller hook → query/mutation hooks → repository → API │
└──────────────────────────────────────────────────────────────────────┘
│ /api/v1/* (fetch, Bearer JWT)
▼
┌──────────────────────────────────────────────────────────────────────┐
│ nginx reverse proxy (TLS terminate; longest-prefix route to service) │
└──────────────────────────────────────────────────────────────────────┘
│ HTTP/HTTPS to service:port
▼
┌──────────────────────────────────────────────────────────────────────┐
│ 21 NestJS services (ports 4001-4021) │
│ Controller (3-line) → Service (≤30 ln) → Repository (no throw) │
│ ↘ Manager (≤80 ln orchestration) │
│ ↘ Adapter (wraps vendor SDKs) │
└──────────────────────────────────────────────────────────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────┐ ┌──────────────────────┐ ┌──────────────────────┐
│ Per-service │ │ RabbitMQ topic exch. │ │ Direct HTTP between │
│ database │ │ `claw.events` │ │ services (internal │
│ (owned) │ │ DLQ + 3 retries │ │ endpoints) │
└─────────────┘ └──────────────────────┘ └──────────────────────┘
Shared cross-cutting stores: RabbitMQ (event bus), Redis (caching),
and — for local AI — Ollama, ComfyUI, Stable Diffusion runtimes plus
ClamAV for upload scanning. See service-catalog.md and
.ai/manifests/docker-services.json.
18 of the services have a *_SERVICE_PORT constant in @claw/shared-constants. Two
services (client-logs 4010, server-logs 4011) have NO port constant — their
port is env-only (CLIENT_LOGS_PORT / SERVER_LOGS_PORT). This gap is called
out by the inventory audit (portCoverageGaps) and detailed in
port-and-service-map.md.
| Service | Port | DB |
|---|---|---|
| auth | 4001 | PostgreSQL |
| chat | 4002 | PostgreSQL |
| connector | 4003 | PostgreSQL |
| routing | 4004 | PostgreSQL |
| memory | 4005 | PostgreSQL |
| file | 4006 | PostgreSQL |
| audit | 4007 | MongoDB |
| ollama | 4008 | PostgreSQL |
| health | 4009 | none |
| client-logs | 4010 (env-only) | MongoDB |
| server-logs | 4011 (env-only) | MongoDB |
| image | 4012 | PostgreSQL |
| file-generation | 4013 | PostgreSQL |
| workspace | 4014 | PostgreSQL |
| agent | 4015 | PostgreSQL |
| research | 4016 | PostgreSQL |
| llamacpp | 4017 | PostgreSQL (Debian base image) |
| payment | 4018 | PostgreSQL |
| threads | 4019 | PostgreSQL (claw_threads) |
| thread-generation | 4020 | PostgreSQL (claw_thread_generation) |
| plugin | 4021 | PostgreSQL (claw_plugin) |
Most PostgreSQL services use Prisma 7.8; the three Mongo services (audit,
client-logs, server-logs) use Mongoose. health has no database.
- The browser hits the Next.js app; the app calls
/api/v1/*with a Bearer JWT (never a token in the URL). -
nginx terminates TLS and routes by longest-prefix match to the target
service port. Route table is ground-truth in
.ai/manifests/nginx-routes.json; e.g./api/v1/chat-threads→ chat:4002,/api/v1/memories→ memory:4005,/api/v1/agent→ agent:4015, and/api/v1/paymentsor/api/v1/billing→ payment:4018. Internal payment contracts are deliberately absent from nginx./api/v1/thread-publications-> threads:4019; the legacy/api/v1/threadsalias remains routed to chat:4002. nginx also blanksCF-IPCountry,CF-Connecting-IPandTrue-Client-IPon every proxied request. ClawAI is not behind a CDN, so those headers reach the origin only if a client sent them.X-Real-IPis the one address a service may trust, because nginx overwrites it with$remote_addr;X-Forwarded-Foris appended to and its head is never trusted. - The service's AuthGuard/RolesGuard (from
@claw/shared-auth) verifies the JWT and permissions, then the request flows Controller → Service → Repository/Manager. - Side effects fan out three ways: write to the owned DB, publish a RabbitMQ event, or call another service's internal HTTP endpoint.
Streaming (chat SSE) uses @Sse('stream/:threadId'); nginx must set
proxy_buffering off for those routes. Full paths in
request-flow-map.md.
-
One topic exchange:
claw.events(durable), with a DLQ and 3 retries with backoff, provided by@claw/shared-rabbitmq. - Event patterns (routing keys, e.g.
message.routed,connector.synced) and theirEventPatternkeys live in@claw/shared-types— the contract must be added there first. - The generated
.ai/manifests/event-graph.jsonlists every pattern with its producers and consumers (heuristic inference; treat as a strong hint, verify in code).audit-serviceis the near-universal consumer;routing-serviceandchat-serviceconsume the message/connector/model lifecycle events. -
log.serveris special: all 17 non-health services publish it; theserver-logs-servicepersists it to MongoDB (TTL 30 days).
Rules for events: every producer needs a documented consumer; handlers must never swallow errors silently. See event-flow-map.md.
Each service owns its database. No service ever reads or writes another service's database. Cross-service data flows only through:
-
HTTP — internal endpoints (
/internal/*) protected by a service token, or -
RabbitMQ — asynchronous events on
claw.events.
This is a non-negotiable rule (CLAUDE.md, rules/00-non-negotiable-rules.md).
Which service owns which models is in
database-ownership-map.md and
.ai/manifests/services.json (prismaModels / mongooseModels).
Controller → Service → Repository (data access only)
↘ Manager (complex orchestration, external calls)
↘ Adapter (wraps a vendor SDK/API)
- Controller — 3-line methods: extract params, call ONE service method, return. No try/catch, no throw, no business logic, no DB access.
- Service — business logic; ≤30 lines per method; owns ownership/permission validation and event publishing.
- Manager — orchestration only (multiple calls, retries, external APIs); ≤80 lines per method, complexity ≤15.
- Repository — pure data access; never throws (returns data or null).
- Adapter — the only place a third-party SDK is imported.
Full rules in backend-architecture.md and
rules/02-backend-rules.md. Declaration placement (no inline
types/enums/consts) is in
declaration-ownership-map.md.
page.tsx (render only) → controller hook (useX) → query/mutation hooks
→ repository → /api/v1/*
- Pages render composition only, one controller hook, and must handle loading/empty/error/success states.
- TanStack Query owns all server state; Zustand holds minimal client state (auth, sidebar, filters).
- shadcn/ui for all form controls; i18n across 13 locales (en, ar, de, es, fr, hi, it, pt, ru, ja, th, fa, zh; ar and fa are RTL) — no hardcoded user-facing text.
Full rules in frontend-architecture.md and
rules/03-frontend-rules.md.
Six packages under packages/ carry everything cross-service. The rule:
types → @claw/shared-types, values → @claw/shared-constants, functions →
@claw/shared-utilities, plus @claw/shared-auth (guards/decorators),
@claw/shared-rabbitmq (event bus module), @claw/shared-entitlements (plan
gates). Internal dependency edges are in
.ai/manifests/workspace-dependency-graph.json. See
package-boundaries.md.
Build is TypeScript 7 (run-ts7.mjs) + tsc-alias (not nest build); tests are vitest
(every workspace) / playwright (E2E); docker is orchestrated
by scripts/claw.sh. Exact commands are canonical in
stack-and-toolchain.md.
| Concern | Manifest |
|---|---|
| Services, ports, DBs, models, deps |
.ai/manifests/services.json, ports.json
|
| Events (producers/consumers) |
.ai/manifests/event-graph.json, rabbitmq-events.json
|
| HTTP routes at the gateway | .ai/manifests/nginx-routes.json |
| API endpoints per service | .ai/manifests/api-endpoints.json |
| Frontend pages (102) | .ai/manifests/frontend-routes.json |
| Docker service → compose files | .ai/manifests/docker-services.json |
| Package dependency edges | .ai/manifests/workspace-dependency-graph.json |
| Permissions (38) | .ai/manifests/permissions.json |
| Env vars (335) | .ai/manifests/environment-variables.json |
Connector-service owns custom OpenAI-compatible provider definitions, seeded
built-in provider status, and connector credentials. Built-in identities and
adapter settings are protected; compatible presets still resolve through the
ADR-117 registry, and bespoke providers keep their existing adapters. It
resolves a definition for runtime adapter settings,
publishes provider identity with synced models, and exposes config over its
existing internal API. Routing keeps dynamic provider keys in
ModelDeployment.runtimeProviderKey; services communicate over existing HTTP
boundaries and do not read each other's databases. Existing connectors are
linked to their built-in definitions without rewriting connector or model data.
ClawAI Wiki · source-controlled under wiki/ · generated/mirrored from the current repository knowledge layer.
ClawAI Wiki
Product
- Product-Vision
- Flagship-Features
- Business-Overview
- Requirements-Register
- Drift-Log
- Runtime-Managed-Connector-Providers
- Threads
- ADR-Index
Architecture
- System-at-a-Glance
- Architecture-Map
- System-Architecture
- Message-Flow
- End-to-End-Data-Flow
- Routing-Engine
- Event-Bus
- Security-Architecture
Platform
- Backend-Services
- Frontend-Architecture
- Shared-Packages
- Database-Reference
- API-Reference
- Provider-Catalog
- Memory-and-Context-Architecture
- File-Support-Architecture
- Research-and-Web-Crawling
Runtime & Ops
- Docker-Guide
- Nginx-Reference
- CI-CD-Pipeline
- Logging-and-Observability
- Operational-Runbooks
- Troubleshooting
Quality
Engineering OS
- AI-Native-Engineering-OS
- Generated-Manifests
- Rules-Catalog
- Skills-Catalog
- Context-Layer
- Engineering-Memory
- Tooling-and-Automation
- Scripts-and-Operations
- ESLint-and-Architecture-Enforcement
- Extended-Work-Skills
Agents
Reference