Architecture
System design overview of Cortex — dual-storage, policy-enforced, fully audited.
Cortex is built on a dual-storage architecture with a policy engine at the center. Every operation passes through RBAC checks before reaching storage.
System Overview
graph TB
subgraph "Client Layer"
CLI[Cortex CLI]
MCP[MCP Server]
API[REST API]
UI[Dashboard UI]
end
subgraph "Application Layer"
ORCH[Memory Orchestrator]
POLICY[Policy Engine]
EMBED[Embedding Service]
AUDIT[Audit Logger]
CONFLICT[Conflict Resolver]
end
subgraph "Storage Layer"
PG[(PostgreSQL)]
QDRANT[(Qdrant)]
RG[(Redis)]
end
CLI --> API
MCP --> API
UI --> API
API --> ORCH
ORCH --> POLICY
ORCH --> EMBED
ORCH --> AUDIT
ORCH --> CONFLICT
ORCH --> PG
ORCH --> QDRANT
POLICY --> PG
AUDIT --> PG
CONFLICT --> PG
EMBED --> RG
Core Components
Memory Orchestrator
The central coordinator for all read and write operations. It enforces policies, manages embeddings, and ensures audit compliance.
Write Path:
- Resolve scope and clearance from source/author
- Check for near-neighbour conflicts (>0.75 similarity)
- Generate embedding via OpenAI
- Insert Postgres row
- Upsert Qdrant vector point
- Audit the write
- Resolve conflicts (authority-based)
- Update knowledge graph (best-effort)
Read Path:
- Resolve caller's allowed scopes from policy matrix
- Generate query embedding
- Search Qdrant with permission filters
- Defence-in-depth re-check on Postgres rows
- Attach citations to results
- Audit the access (allowed or denied)
Policy Engine
Turns identity (role within an org) into an allowed-scope list. Pure functions for testability.
// Pure: role + policy rows → allowed scopes
function computeScopes(role: string, rows: PolicyRow[]): string[] {
const allowed = new Set<string>();
const denied = new Set<string>();
for (const r of rows) {
if (r.role !== role) continue;
if (r.effect === "deny") denied.add(r.scopeKey);
else allowed.add(r.scopeKey);
}
return [...allowed].filter((s) => !denied.has(s)).sort();
}
Deny always beats allow. If a role has both allow and deny for the same scope, the deny wins.
Dual Storage
| Store | Purpose | Consistency |
|---|---|---|
| PostgreSQL | Authoritative source for memories, users, policies, audit logs | Strong |
| Qdrant | Vector embeddings for semantic search | Eventual |
Postgres is always authoritative. If Qdrant is unavailable, writes succeed (vector is retried) but semantic search degrades.
Embedding Pipeline
- Content is tokenized and truncated to 20,000 characters
- OpenAI embedding API generates a vector
- Vector is stored in Qdrant with metadata payload
- Metadata includes: memory_id, org_id, scope_key, clearance_min, user_id
Data Model
erDiagram
organizations ||--o{ users : has
organizations ||--o{ memories : contains
organizations ||--o{ policies : defines
organizations ||--o{ scopes : defines
users ||--o{ memories : authors
users ||--o{ agents : operates
memories ||--o{ conflicts : involved_in
memories ||--o{ audit_log : logged
agents ||--o{ audit_log : executes
Key Tables
| Table | Purpose |
|---|---|
organizations | Team/company workspaces |
users | User accounts with roles and levels |
memories | Indexed knowledge entries |
policies | RBAC rules (role → scope → effect) |
scopes | Allowed scope keys per org |
agents | AI agent identities with API keys |
audit_log | Complete access history |
conflicts | Detected contradictions |
facts | Deterministic company facts |
fact_values | Versioned fact values |
Security Model
Agent Authentication
Every MCP request must include a valid agent key:
Authorization: Bearer crtx_...
The key is hashed and looked up in the agents table. Each agent is bound to an acting_user, and all operations execute under that user's identity.
Permission Flow
sequenceDiagram
participant Agent
participant MCP as MCP Gateway
participant Policy as Policy Engine
participant DB as Database
Agent->>MCP: recall("rate limiting")
MCP->>MCP: Authenticate agent key
MCP->>Policy: resolveScopes(agent.actingUser)
Policy->>DB: Load policy matrix
DB-->>Policy: Policy rows
Policy-->>MCP: Allowed scopes
MCP->>MCP: Vector search (scoped)
MCP->>DB: Defence-in-depth check
DB-->>MCP: Verified results
MCP-->>Agent: Cited memories
Note over MCP,DB: Audit logged
Clearance Levels
| Level | Rank | Can Access |
|---|---|---|
Contractor | 1 | Contractor+ content |
Junior | 2 | Junior+ content |
Senior | 3 | Senior+ content |
Staff | 4 | Staff+ content |
Principal | 5 | All content |
CEO | 6 | All content + admin |
Technology Stack
| Layer | Technology |
|---|---|
| Framework | Next.js 16 (App Router, Turbopack) |
| Language | TypeScript (strict mode) |
| Database | PostgreSQL (Neon) |
| Vector DB | Qdrant |
| ORM | Drizzle |
| Embeddings | OpenAI |
| MCP | @modelcontextprotocol/sdk |
| Styling | Tailwind CSS v4 + shadcn/ui |
| State | Zustand |