Aller au contenu

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.


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) |
+-------------------------------------------------------------+

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).

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 tests

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:

  • full mode (default): all routes are mounted — catalogue, workspace, memory, admin, ingestion, versioning, divergence, documents, library.
  • lib mode: 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.

The MCP server exposes the same operations as MCP tools prefixed with cortex_*. It supports five variants that control which tools are registered:

VariantToolsUse case
mainAll tools (read + write)Self-hosted full access
claude-codeAll toolsClaude Code integration
cloudRead-only subsetCloud-hosted consumers
praxisRead-only subsetPraxis governance agent
publicMinimal public subsetPublic demo

The MCP server supports OAuth 2.0 for production LLM clients (Claude.ai, ChatGPT Custom Connectors, etc.) via the oauth.ts module.

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.


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.

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.

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.

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.

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.

Local filesystem adapter for the data directory (HCM_DATA_DIR, defaults to .hcm). Used for seed data, export artifacts, and temporary files.


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:

EventTrigger
node.depositedNode created or updated in the graph
checkpoint.depositedCheckpoint trace deposited (A2A)
memory.atom.depositedMemory atom deposited
note.depositedPraxis note deposited
profile.updatedHYOS profile updated
project.updatedProject entity updated
agent.spawnedAgent spawned via governance
workspace.item.changedWorkspace 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).


The composition root lives in config/container.ts. It wires all adapters into the domain ports at startup:

  1. Parse environment variables (env.ts).
  2. Create outbound adapters (SurrealDB, PostgreSQL, MeiliSearch, Ollama, MinIO, Filesystem).
  3. Create domain services with injected outbound ports.
  4. Create facades that bundle related services under inbound port interfaces.
  5. Wire facades into the Container object that inbound adapters receive.

Facades are organized by domain area in config/facades/:

  • atoms.ts, catalogue.ts, governance.ts, governance-builder.ts, governance-instance.ts
  • hyos.ts, memory.ts, navigation.ts, versioning.ts, library.ts, documents.ts
  • audit.ts, admin.ts, worker-messenger.ts
  • workspace/ (project, mission, MCT, ODM, task, CR, orchestration facades)

LayerTechnology
LanguageTypeScript (strict mode)
RuntimeNode.js >= 20
HTTP serverExpress (via Fastify-compatible patterns)
MCP server@modelcontextprotocol/sdk
ValidationZod
Graph DBSurrealDB v2.1.7
Relational DBPostgreSQL 16
SearchMeiliSearch v1.12
EmbeddingsOllama (bge-m3)
Object storageMinIO (S3-compatible)
FrontendReact + Vite + Tailwind CSS
TestsVitest
ContainerDocker Compose

  • data-model — ATOM model (six layers), HYOS profiles, blocs, taxonomy, edge types
  • ingestion-pipeline — write path from Zod validation to SurrealDB persistence

  • 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.