Architecture
Ce contenu n’est pas encore disponible dans votre langue.
Audience: developer who wants to understand how Cortex is structured, where the business logic lives, how components communicate, and where to add code.
High-level model
Section titled “High-level model”Cortex serves two surfaces to its consumers and stores data across four backends.
+-------------------------------------------------------------+| CONSUMERS || React UI LLM clients (Claude, ...) Custom services |+------+---------------+---------------------------+-----------+ | HTTP | Model Context Protocol | HTTP/MCP+------v---------------v---------------------------v-----------+| INBOUND ADAPTERS || REST API MCP Server LangGraph |+------+---------------------+---------------------+----------+ | | |+------v---------------------v---------------------v----------+| DOMAIN CORE || Use-cases (ports inbound) || ForAtoms, ForCatalogue, ForGovernance, ForVersioning, || ForMemory, ForNavigation, ForSearch, ForWorkspace, || ForDocuments, ForLibrary, ForAudit, ForAdmin, || ForHyos, ForSpawnAgent, ForWorkerMessenger, ... || Services (business logic, pure) || AtomIndex, CatalogueService, IngestionService, || MemoryService, GovernanceBuilder, GovernanceValidator, || VersionManager, TemplateBuilder, TemplateRegistry, || SpawnAgentService, DivergenceService, SnapshotService, ...|| Model (ATOM, HYOS, governance rules, memory entries) || Ports outbound (storage, search, embed, files) |+------+---------------------+---------------------+----------+ | | |+------v---------------------v---------------------v----------+| OUTBOUND ADAPTERS || SurrealDB (graph + relational) || PostgreSQL (auth, audit, tokens, documents) || MeiliSearch (full-text + faceted search) || Ollama (local embeddings via bge-m3, LLM via Mistral) || MinIO (S3-compatible object storage) || Filesystem (artefact storage, data directory) |+-------------------------------------------------------------+Why hexagonal
Section titled “Why hexagonal”Cortex is consumed by very different clients:
- A React UI for humans browsing the catalogue and workspace.
- LLM agents that read profiles and write back decisions via MCP.
- Batch scripts that ingest artefacts in bulk.
- Third-party services that connect over HTTP or MCP.
The same business logic must be reachable from all of them, without domain code knowing anything about HTTP, MCP, SurrealDB, or React.
Domain services therefore depend only on ports (interfaces). Adapters implement those ports. This is the only architectural rule that is strictly enforced and tested. A pre-commit hook checks that domain/ never imports from adapters/. Run npm run lint:arch locally to verify.
domain/ # No import from adapters/. Pure logic.ports/ # Interfaces. Both inbound (use-cases) and outbound (boundaries).adapters/ # May import from domain/. Never the reverse.config/ # Wires adapters into ports at startup (composition root).Directory layout
Section titled “Directory layout”cortex/+-- adapters/| +-- inbound/| | +-- rest/ # Fastify/Express REST API| | | +-- routes/ # Route modules (atoms, catalogue, workspace, ...)| | | +-- schemas/ # Zod request/response schemas| | | +-- middleware.ts # Auth, role guard, project access| | | +-- response.ts # ok() / fail() envelope helpers| | +-- mcp/ # MCP server| | | +-- tools/ # Tool modules (cortex-status, cortex-search, ...)| | | +-- variants/ # Variant registrars (claude-code, cloud, praxis, public)| | | +-- server.ts # MCP server bootstrap| | | +-- oauth.ts # OAuth 2.0 support| | +-- langgraph/ # LangGraph memory agent| +-- outbound/| +-- surrealdb/ # Graph + relational storage| +-- postgresql/ # Audit, auth, documents, tokens, credentials| +-- meilisearch/ # Full-text search + projector| +-- ollama/ # Embedding + LLM (with circuit breaker)| +-- s3/ # S3-compatible object storage (MinIO)| +-- filesystem/ # Local file storage+-- domain/| +-- model/ # Domain types (atom, hyos, governance, memory, ...)| +-- ports/| | +-- inbound/ # Use-case interfaces (ForAtoms, ForCatalogue, ...)| | +-- outbound/ # Storage/service interfaces (GraphPort, SearchPort, ...)| +-- services/ # Business logic (pure, no I/O knowledge)| +-- events/ # Domain event bus + event definitions+-- config/| +-- container.ts # Composition root (DI container)| +-- env.ts # Environment variable parsing| +-- bootstrap.ts # Application startup sequence| +-- facades/ # Facade wiring per domain area| +-- services-factory.ts| +-- adapters-factory.ts+-- shared/| +-- src/types.ts # Shared types (GraphNode, GraphEdge, Memory*, Bloc, ...)+-- ui/ # React + Vite + Tailwind frontend+-- __tests__/ # Integration and unit testsInbound adapters
Section titled “Inbound adapters”REST API
Section titled “REST API”The REST API is mounted under /api by createApiRouter() in adapters/inbound/rest/routes/index.ts. It registers route modules based on the CORTEX_MODE environment variable:
fullmode (default): all routes are mounted — catalogue, workspace, memory, admin, ingestion, versioning, divergence, documents, library.libmode: read-only catalogue routes only (atoms, search, templates, governance, catalogue, library, navigation, documents, account). Used by the public Cortex demo.
Every route uses Zod schema validation (validate() middleware) and role guards (requireRole()). The response envelope is { ok: true, data: ... } for success and { ok: false, error: { message, code } } for errors.
MCP server
Section titled “MCP server”The MCP server exposes the same operations as MCP tools prefixed with cortex_*. It supports five variants that control which tools are registered:
| Variant | Tools | Use case |
|---|---|---|
main | All tools (read + write) | Self-hosted full access |
claude-code | All tools | Claude Code integration |
cloud | Read-only subset | Cloud-hosted consumers |
praxis | Read-only subset | Praxis governance agent |
public | Minimal public subset | Public demo |
The MCP server supports OAuth 2.0 for production LLM clients (Claude.ai, ChatGPT Custom Connectors, etc.) via the oauth.ts module.
LangGraph
Section titled “LangGraph”A LangGraph memory agent (adapters/inbound/langgraph/) provides a stateful memory synchronization flow. It is wired as an additional inbound adapter but does not expose a public surface.
Outbound adapters
Section titled “Outbound adapters”SurrealDB
Section titled “SurrealDB”Primary storage for the knowledge graph. Stores atoms, blocs, profiles, taxonomy nodes, edges, workspace entities (projects, missions, MCTs, ODMs, tasks, CRs), and memory entries. Uses SurrealDB v2.1.7 with file: storage mode.
Key tables: atom, bloc, profil_hyos, famille, sous_famille, project, mission, mission_contract, odm, task, cr, note_praxis, checkpoint_trace, memory_project_decision, and more.
PostgreSQL
Section titled “PostgreSQL”Stores structured relational data: audit trail, API key hashes, OAuth tokens, document metadata, governance follow-up records, protocol rejections, provider credentials (AES-256-GCM encrypted), spawn tokens, and worker messenger queues.
MeiliSearch
Section titled “MeiliSearch”Full-text search engine. The meili-projector.ts projects graph nodes into MeiliSearch documents at indexing time. The meili-sync.ts handles incremental sync. Supports faceted search with filters on famille, sous_famille, type, tags.
Ollama
Section titled “Ollama”Local AI model server. Two models:
- bge-m3 (default): 1024-dimension embeddings for semantic search and resonance scoring.
- Mistral (optional): LLM for enrichment tasks.
The adapter includes a circuit breaker (circuit-breaker.ts) that opens after repeated failures and closes after a cooldown period.
MinIO (S3)
Section titled “MinIO (S3)”S3-compatible object storage for file artefacts. Bucket is created at startup by the minio-init container. Used by the library module for document file storage.
Filesystem
Section titled “Filesystem”Local filesystem adapter for the data directory (HCM_DATA_DIR, defaults to .hcm). Used for seed data, export artifacts, and temporary files.
Domain event bus
Section titled “Domain event bus”The domain event bus (domain/events/event-bus.ts) provides a simple publish/subscribe mechanism within a single process. It is not a distributed message queue.
Events emitted:
| Event | Trigger |
|---|---|
node.deposited | Node created or updated in the graph |
checkpoint.deposited | Checkpoint trace deposited (A2A) |
memory.atom.deposited | Memory atom deposited |
note.deposited | Praxis note deposited |
profile.updated | HYOS profile updated |
project.updated | Project entity updated |
agent.spawned | Agent spawned via governance |
workspace.item.changed | Workspace entity (ODM, task, CR, …) changed |
Listeners are registered in config/event-listeners.ts during bootstrap. Typical listeners include MeiliSearch sync (re-index on node change) and resonance scoring (compute semantic links after embedding).
Composition root
Section titled “Composition root”The composition root lives in config/container.ts. It wires all adapters into the domain ports at startup:
- Parse environment variables (
env.ts). - Create outbound adapters (SurrealDB, PostgreSQL, MeiliSearch, Ollama, MinIO, Filesystem).
- Create domain services with injected outbound ports.
- Create facades that bundle related services under inbound port interfaces.
- Wire facades into the
Containerobject that inbound adapters receive.
Facades are organized by domain area in config/facades/:
atoms.ts,catalogue.ts,governance.ts,governance-builder.ts,governance-instance.tshyos.ts,memory.ts,navigation.ts,versioning.ts,library.ts,documents.tsaudit.ts,admin.ts,worker-messenger.tsworkspace/(project, mission, MCT, ODM, task, CR, orchestration facades)
Technical stack
Section titled “Technical stack”| Layer | Technology |
|---|---|
| Language | TypeScript (strict mode) |
| Runtime | Node.js >= 20 |
| HTTP server | Express (via Fastify-compatible patterns) |
| MCP server | @modelcontextprotocol/sdk |
| Validation | Zod |
| Graph DB | SurrealDB v2.1.7 |
| Relational DB | PostgreSQL 16 |
| Search | MeiliSearch v1.12 |
| Embeddings | Ollama (bge-m3) |
| Object storage | MinIO (S3-compatible) |
| Frontend | React + Vite + Tailwind CSS |
| Tests | Vitest |
| Container | Docker Compose |
Contents
Section titled “Contents”data-model— ATOM model (six layers), HYOS profiles, blocs, taxonomy, edge typesingestion-pipeline— write path from Zod validation to SurrealDB persistence
Principles
Section titled “Principles”- The
domain/is isolated: it knows neither I/O, nor composition, nor adapters. - Adapters consume domain ports; they never depend on each other.
- All writes go through the ingestion pipeline or the template builder. There is no direct graph mutation from route handlers (except legacy workspace routes, which is a documented technical debt).
- Governance validation happens server-side in the Cortex engine, not in the LLM client.