Technology stack
cortex is a set of Node.js services, one React single-page application, a per-project execution engine and a container build system, all running on one AWS EKS cluster in two environments. This page lists every component, its language and runtime, the frameworks and third parties it depends on, where its state lives and how it is built and deployed. Versions come from the repository's package.json files, Dockerfiles and CI scripts at the time of writing (branch dev, September 2026). Applications that cortex generates for a customer are not part of this stack; they are described on the page Generated applications are independent of cortex.
Overview: three planes
cortex is easiest to read as three planes. Each plane runs in its own containers and talks to the others over HTTP.
Control plane. The cortex backend (REST API, auth, RBAC, project registry, job queue), the React UI, and the assistant (an MCP server that exposes the platform's typed tools to AI clients and hosts the in-product chat). This plane owns the configuration of every project: which data sources, rules, targets, requirements, tests and apps a project has. Configuration is stored in Dolt (versioned, one commit per write) and in a Postgres database named cortex_ops.
Engine plane. The Flow engine. Every cortex project has a paired Flow "fork": a catalog of endpoints (flow graphs) and services (containers) stored in MongoDB and executed by the engine. The engine runs pipelines, workflows, ML training, RAG indexing and every data operation an app calls. It is one deployable image run as several servers (web, rpc, endpoints-flow, service-manager, exporter, ai-assistant). The service manager builds and runs project-owned containers.
Runtime plane. The generated applications: app services, each an arbitrary Dockerfile plus source tree owned by the project, built in-cluster with kaniko and run as its own Deployment with its own public hostname. cortex frames these applications; it does not render them. A project's function services (Node.js or Python handlers) and its Postgres target databases sit on this plane as well.
Components
| Component | Directory | Language and runtime | Frameworks and notable libraries | State it owns | Image and deployment |
|---|---|---|---|---|---|
| Backend | backend/ |
Node.js 24, JavaScript | Fastify 5.4 (@fastify/cors, helmet, rate-limit, swagger, websocket, static), mysql2 3.22 (Dolt over the MySQL wire), pg 8.16, pg-boss 12.13 (job queue and schedules), @aws-sdk/client-s3, jsonwebtoken, bcryptjs, openid-client 5.7 |
Dolt recipe CRUD, cortex_ops Postgres |
Dockerfile, node:24-alpine, runs as user node; Deployment backend |
| Frontend | frontend/src/ |
TypeScript 5.8, React 19.1 | Vite 7.2, Tailwind CSS 4.1, React Router 7.7, Radix UI, ReactFlow 11.11 (pipeline and workflow canvases), Recharts 3.1, d3 7.9, RxJS 7.8, CodeMirror 6, xterm, zod 4.2, lucide-react | none (browser state only) | Dockerfile.frontend, node:24-alpine build stage, served by nginx:alpine; Deployment cortex-client |
| Assistant (cortex MCP server and chat) | assistant/ |
Node.js 24, JavaScript | @modelcontextprotocol/sdk 1.29, Fastify 5.4, Express 5.2, node-pty; bundled agent runtime uses @anthropic-ai/sdk 0.32 and @anthropic-ai/bedrock-sdk 0.29 (esbuild to dist/headless.js); ships the Claude Code CLI 2.1.266 and a Python venv with litellm[proxy] 1.55.6 and boto3 |
OAuth 2.1 grants, chat sessions | assistant/Dockerfile, node:24-bookworm-slim, port 3013, runs as uid 1000; Deployment assistant. Also hosts the two persona servers below on loopback paths |
| flow-assistant (engine persona) | flow-assistant/ |
Node.js 24 | Same stack as the assistant; cortex MCP read-only plus the paired Flow project's MCP | none | node:24-bookworm-slim, port 3014, uid 1000 |
| analyst (analytics persona) | analyst/ |
Node.js 24 | Same stack as the assistant; analytics MCP only | none | node:24-bookworm-slim, port 3015, uid 1000 |
| Accounts (auth for deployed apps) | accounts/ |
Node.js 24 | Fastify, node:test |
account rows | Dockerfile.accounts, node:24-alpine, port 3020, user node |
| Agent fleet (remote workers) | remote-agent/ |
Node.js 22 plus Python 3 dispatcher | Claude Code CLI, OpenAI Codex CLI 0.154.0, Playwright 1.49.1 with Chromium, tmux, git | none (claims jobs from the backend queues) | remote-agent/Dockerfile, node:22-bookworm; Deployment cortex-agents on a dedicated node; not restarted by a cortex deploy |
| Transcriber | transcriber/ |
Python 3.11 | faster-whisper, CPU int8 |
none | python:3.11-slim, port 8080 |
Flow engine (web, rpc, endpoints-flow, exporter, ai-assistant) |
engine/server/src/js/ |
TypeScript 4.7 on Node.js 24, run via tsx 4.19 |
RxJS 7.8, Express 4, Fastify 4.18, mongodb 5.8, redis 4.7 and ioredis 5.2, pg 8.5, ajv 8, zod 3.24, @aws-sdk/client-{s3,ses,acm,ecr,route-53} 3.665, prom-client 15 (/metrics), Jest 29.7 |
Flow catalog in MongoDB; dispatch in Redis | engine/Dockerfile.engine, node:24-bookworm-slim with postgresql-client-16 and default-mysql-client for exports; one image behind Deployments flow-engine, web, rpc, exporter, ai-assistant |
| Service manager | engine/server/src/js/modules/rpc/serviceManager/ |
Same engine code base | @kubernetes/client-node 0.20 (Kubernetes adapter), dockerode and Docker CLI with Compose 2.24.5 (compose adapter), kaniko for in-cluster image builds |
services and appServices collections in MongoDB |
engine/Dockerfile.service-manager, node:24-bookworm-slim; Deployment service-manager |
| Function services (per project) | generated by the service manager | Node.js 20.18 (node:20.18.0-bookworm-slim) or Python 3.11 (python:3.11-slim) |
Project-owned handlers behind /rpc. Shared Python services on the core fork: the record pipeline (pyarrow, pandas), the ML service (scikit-learn 1.5.2, statsmodels 0.14.4, scipy), the RAG service (PyMuPDF, python-docx, psycopg2) |
project data | built by kaniko, one Deployment per service |
| Shared libraries | shared/ |
JavaScript, no framework | access-policy.js (authorisation, fail closed), viewer-companions.js, requirement-sources.js, app-sdk/cortex-app-sdk.js, embed-bridge/cortex-embed-bridge.js, guide-pdf/render.mjs (Playwright), test-engine/ (runner.mjs, server.mjs, bundle/) |
none | copied into the images that use them; the test runner also ships inside customer archives |
| Rust runtime (in progress) | separate repo cortex-rust |
Rust 1.95, 21 crates, edition 2021 | tokio 1.53, axum 0.8, sqlx 0.8 (Postgres and MySQL), mongodb 3, redis 0.29, aws-sdk-s3 1, rquickjs 0.9 (JavaScript sandbox for Flow node bodies), bollard 0.18, kube 0.98, jsonwebtoken 9, rustls 0.23 | the same stores as the JS stack | rust:1.95-bookworm build, debian:bookworm-slim runtime, one process on port 3005 serving /api, /rpc, /flow, /accounts, /mcp. Running on a separate stand. Not the production runtime. Live parity against the JS engine on real forks: 240 of 267 cases identical, every difference classified |
Report PDFs are rendered with Typst from a generated manifest (backend/modules/reports/manifest_template.js). Guide PDFs and screenshot captures use Playwright (shared/guide-pdf/render.mjs).
Data stores
| Store | Image or service | Engine version | What it holds | Notes |
|---|---|---|---|---|
| Dolt | dolthub/dolt-sql-server |
MySQL wire protocol, port 3306 | One database per project: data sources, targets, data elements, mappings, processing rules, pipeline nodes and links, reference lists | Every write is a commit attributed to the caller. Branchable. The Dolt history is the audit trail of a project's configuration |
Postgres cortex_ops |
postgres:16-alpine locally; Postgres 16 on the cluster |
16 | Users, organisations, projects, roles, app registry, requirement chain (materials, features, tasks, evidence), tests and health verdicts, job queues (pg-boss), fleet sessions |
Backend only |
| Postgres targets | Postgres 16 | 16 | Pipeline output per project, workflow tables (wf_*), app data |
One database per project target. Apps read it through guarded endpoints, never directly from the browser |
| pgvector | pgvector/pgvector:pg16 |
16 | RAG indexes, one schema per knowledge-base source | Shared database, per-source pg_schema |
| MongoDB | mongo:7 |
7 | The Flow catalog: forks, endpoints, services, app services, export configuration, vault pages | Engine only |
| Redis | redis:7-alpine |
7 | Studio WebSocket fan-out, RPC dispatch, engine caches | Ephemeral |
| S3 | AWS S3; MinIO locally | n/a | Uploads, requirement source originals, RAG documents, generated reports, export bundles | Bucket CORS lists both front-end domains |
Model access and AI vendors
Model access is vendor-agnostic by design. The same code paths reach a model through one of three routes, chosen per environment by configuration, not by code:
| Route | How it is wired | Where it is used |
|---|---|---|
| Amazon Bedrock | The assistant image runs a LiteLLM proxy (litellm[proxy] 1.55.6, assistant/litellm-config.yaml) that maps model names to bedrock/us.anthropic.* in us-east-1. Credentials come from the pod's IAM role (IRSA); no API key is stored. ANTHROPIC_BASE_URL is pointed at the proxy |
Production default for the in-product chat and the persona sub-agents |
| OpenAI-compatible gateway | The same LiteLLM instance exposes an OpenAI-compatible endpoint; any client that speaks that protocol can use it | Any environment that wants one gateway in front of several vendors |
| Vendor API | @anthropic-ai/sdk 0.32 or @anthropic-ai/bedrock-sdk 0.29 directly, or a Claude Code subscription token |
The dev environment's chat runs on a subscription through the Claude Code CLI; local development uses the developer's own key |
The agent fleet drives a coding CLI rather than calling a model API itself. The CLI is pluggable: two are installed today, the Claude Code CLI (2.1.266 in the assistant image) and the OpenAI Codex CLI (0.154.0 in the fleet image). Each queued job runs in an isolated CLI session with the repository's skills mounted.
Tools are exposed to AI clients over the Model Context Protocol. The assistant uses @modelcontextprotocol/sdk 1.29; the bundled agent runtime uses 1.0. External MCP paths (/mcp, /mcp/p/<project>, /mcp/ro/p/<project>, /mcp/orch/p/<project>) require OAuth 2.1 bearer tokens with PKCE; the assistant publishes /.well-known/oauth-authorization-server. Any MCP client, including an agent runtime outside cortex, can call the same typed tools the product UI uses.
Infrastructure
| Concern | What is used |
|---|---|
| Compute | One AWS EKS cluster (flow-demo-2), region us-east-1. Two namespaces: cortex-demo-2 (production, git branch prod) and cortex-demo-2-dev (development, branch dev). The agent fleet is pinned to a dedicated node |
| Images | Amazon ECR, registry 743091428862.dkr.ecr.us-east-1.amazonaws.com, one repository per image (cortex-demo-2-backend, cortex-demo-2-assistant, cortex-demo-2-flow-engine, ...) |
| In-cluster builds | kaniko Jobs (job-type: kaniko-build) build project-owned images from a shared services PVC; a failed Job fails the build |
| Ingress | AWS Load Balancer Controller, internet-facing ALBs with IP targets. Platform hosts cortex-demo-2-dev.tiva-ai.com and cortex-demo-2.tiva-ai.com. Generated app services get one Ingress each in an ALB ingress group (cortex-apps, cortex-apps-prod) at https://<name>-<projectId>.apps.<env-domain>, or a customer-supplied domain |
| Certificates and DNS | AWS Certificate Manager (wildcards for *.apps.<env-domain>), Route53 zones tiva-ai.com and mindshine.com. Both environments answer on mindshine.com twins (cortex-demo-2-dev.mindshine.com, cortex-demo-2.mindshine.com, <service>-<projectId>.apps.<env>.mindshine.com) through additional host rules on the same ALBs |
| Infrastructure as code | Terraform in the operations repository on a jumpbox (~/eks/infra-demo-2: cluster, DNS, certificates, S3 and CloudFront static sites, IAM). Kubernetes overlays with kustomize (~/eks/k8s/overlays/). No manual kubectl edit or console changes; every infrastructure change is an overlay or Terraform edit followed by an apply |
| Other AWS services | S3, SES (email), Bedrock (models), IAM roles for service accounts (IRSA), CloudFront (static sites) |
| Observability | prom-client /metrics on the engine; project health transitions post to Slack #cortex-alerts; a test watchdog runs every project's suite every 15 minutes |
| Local development | docker-compose.yml with Dolt, Postgres 16, MongoDB 7, Redis 7, MinIO and the vendored engine; the backend, assistant and Vite run on the host |
CI/CD
Bitbucket Pipelines (bitbucket-pipelines.yml, base image debian:12-slim).
- Verify (
scripts/ci-verify.sh,node:22-slim): engine unit tests (Jest), accounts and backend unit tests (node:test),npm auditat level critical for every package directory, secret hygiene scan of the tree. - Build: nine images in parallel (
scripts/ci-build.sh <key>): backend, assistant, flow-assistant, analyst, accounts, client, flow-engine, service-manager, agents. Each build pulls the previous image for layer cache and pushes to ECR tagged with the commit and the branch. - Roll (
scripts/ci-roll.sh):kubectl rolloutfor every Deployment that consumes a rebuilt image: backend, assistant, flow-assistant, analyst, accounts, cortex-client, flow-engine, ai-assistant, web, rpc, service-manager, exporter. The fleet Deployment is rolled separately.
dev deploys on every push to the dev branch. Production deploys from the prod branch. After a deploy the backend re-runs every project's test suite (tests-after-deploy); a project promotion script ends with a test gate that refuses a red target.
Every project's Flow fork also has a private Bitbucket repository; the exporter pushes the fork's endpoints, services and app services to it as ordinary source.
Security posture summary
| Control | Implementation |
|---|---|
| Container hardening | Non-root users in every image (node, uid 1000); read-only root filesystems in the cluster overlays with writable /tmp where a process needs it (the assistant keeps the CLI configuration under /tmp for this reason) |
| Authentication | JWT bearer tokens issued by the backend; OpenID Connect through openid-client; OAuth 2.1 with PKCE on every externally reachable MCP path; loopback-only MCP paths carry no token and are reachable only inside the assistant pod |
| Authorisation | shared/access-policy.js: fail closed. A missing project row, an unknown role or a null role grants nothing. Project shares open exactly the route surface of the shared app and the companions its owner switched on |
| Secrets | Per-project secrets are injected into a project's containers from the project's own environment; platform secrets (flow-config, flow-secrets) are never mounted into a project-owned container. Model access on the cluster uses IAM roles, not stored keys. Customer archives mint their own credentials and are scrubbed of platform passwords before handover |
| Audit trail | Every configuration write is a Dolt commit attributed to the caller and diffable. cortex_ops keeps an audit log and a timeline per project |
| Network | ALB in front of everything; project services reach each other by cluster DNS on the Flow network; app services must opt in to a public Ingress (public: false keeps a service internal) |
| Supply chain | npm audit critical gate and a secret scan before every image build; pinned CLI versions in the images |
| Compliance | SOC 2 readiness programme with an automated evidence register per project (the platform runs its own auditor over each project's source and configuration). Trust center: trust.tiva-ai.com |
Where the code lives
One repository (cortex, Bitbucket) holds the whole platform. The Rust runtime is a separate repository (cortex-rust) and the infrastructure Terraform and Kubernetes overlays are in an operations repository on the jumpbox.
| Directory | Contents |
|---|---|
backend/ |
Fastify API; modules/ = agents, apps, audit, auth, authz, components, deployments, docs, feed, fleet, guides, models, reports, requirements, rules, search, templates, tests, versions, workflows |
frontend/src/ |
React SPA (Vite, Tailwind) |
assistant/, flow-assistant/, analyst/ |
MCP servers and persona prompts; assistant/agent/ = the bundled agent runtime |
accounts/ |
Auth service for deployed applications |
engine/ |
The Flow engine (TypeScript) and its Dockerfiles: server/src/js/modules/rpc/serviceManager/ (compose and Kubernetes adapters, app services), server/src/js/modules/rpc/exporter/ (git export, local bundles, customer archive, delivery) |
remote-agent/ |
The agent fleet image and dispatcher |
transcriber/ |
Whisper worker |
shared/ |
Libraries used by more than one component, including the portable test engine |
scripts/ |
CI build, verify and roll scripts; project push/pull tooling |
tests/e2e/ |
Playwright end-to-end tests against a running environment |
.claude/skills/ |
The fleet's executable skills (build a project, build an app service, write tests, audit) |
docs/ |
Design notes for each subsystem |