CortexDB Docs
Self-Hosting

Self-Hosting Quickstart

Run your own CortexDB server with one docker run, then store and recall your first memory against localhost — the recommended way to start.

Self-hosting is the recommended way to run CortexDB. You get the same server the cloud runs, your data never leaves your infrastructure, and there's no per-token cost. This page takes you from nothing to a running server with a stored-and-recalled memory in about five minutes.

Prerequisites

  • A container runtime — Docker (or Podman). CortexDB ships as a single image, cortexdb/cortexdb.
  • An embedding provider — vector recall needs one, or the server falls back to mock embeddings and recall is meaningless. Either an OpenAI-compatible API key (used only for embeddings) or a local Ollama (fully local, no external calls — see Fully local below).
  • ~2 GB RAM and a data volume. A single node handles ~10M events on commodity hardware; everything persists under /data.
  • Optional, only if you want them: an answer lane (CORTEX_ANSWER_*) to enable /v1/answer, and enrichment to populate the Facts/Beliefs/Understanding layers — both off by default. See Self-hosting defaults.

1. Start the server

docker run -d \
  --name cortexdb \
  -p 127.0.0.1:3141:3141 \
  -v cortexdb-data:/data \
  -e CORTEX_INSECURE_NO_AUTH=1 \
  -e OPENAI_API_KEY=$OPENAI_API_KEY \
  cortexdb/cortexdb:latest

That's the whole install. The container ships with every field at its compiled default: single-node, the v1 API on :3141, data persisted to the cortexdb-data volume.

Why the OPENAI_API_KEY?

It's used only for embeddings (vector recall needs a real embedding provider — without one the server runs on mock embeddings and recall is meaningless). It is not used for answers or extraction here. Prefer to keep everything local? Point embeddings at a local Ollama instead — see Fully local, no external keys below.

Auth: CORTEX_INSECURE_NO_AUTH is dev-only

CORTEX_INSECURE_NO_AUTH=1 makes the server serve every request as user:local with no token — the frictionless path for local development, and the -p 127.0.0.1:... binds it to loopback only. Before exposing the port, drop that flag and set -e CORTEX_API_KEY=<a strong secret> instead; the value itself becomes your bearer credential (Authorization: Bearer <secret>). Note: if you set neither on a network-exposed bind, the server refuses to serve open — it auto-generates a key and prints it in the boot log, and every request needs it. See Security & Compliance.

2. Confirm it's healthy

curl http://localhost:3141/v1/admin/health
# {"status":"healthy","version":"v0.9.9"}

curl http://localhost:3141/v1/admin/ready
# ... "degraded": false  →  real embeddings are working (not mock)

If ready reports "degraded": true, the server is on mock embeddings (recall would be meaningless) — check that your embedding provider/key is set.

Readiness is outcome-based — gate deploys on it, not health

/v1/admin/ready reports what real provider calls actually did. Its embeddings check distinguishes mock, failing (a configured key returning 401 on every call), and healthy — so a dead key marks the server degraded and surfaces the provider's error text instead of silently returning empty recall. health only tells you the process is up; always gate container healthchecks and deploys on ready.

3. Store and recall your first memory

No token is needed because the server was started with CORTEX_INSECURE_NO_AUTH=1 (dev mode). Pick your surface — on a keyed server, add -H "Authorization: Bearer $CORTEX_API_KEY" (curl) or bearer=… (SDK):

curl

# Capture
curl -sfS -X POST http://localhost:3141/v1/experience \
  -H "X-Cortex-Actor: user:local" -H "Content-Type: application/json" \
  -d '{
    "scope": "org:demo/user:local",
    "modality": "conversation",
    "content": { "kind": "message", "role": "user",
                 "text": "We migrated the payments service to CockroachDB. Timeline is Q2 2026." },
    "context": { "observed_at": "2026-05-16T10:42:00Z" },
    "idempotency_key": "decision-payments-001"
  }'

# Recall
curl -sfS -X POST http://localhost:3141/v1/recall \
  -H "X-Cortex-Actor: user:local" -H "Content-Type: application/json" \
  -d '{ "scope": "org:demo/user:local", "view": "holistic",
        "query": "What database are we using for payments?", "diagnostics": "none" }'

Python

pip install cortexdbai
from cortexdb.v1 import V1Client

# Point at your self-hosted server. In local no-auth mode, no bearer token is needed.
client = V1Client(api_url="http://localhost:3141", actor="user:local")

scope = "org:demo/user:local"

client.experience(
    scope=scope,
    text="We migrated the payments service to CockroachDB. Timeline is Q2 2026.",
    observed_at="2026-05-16T10:42:00Z",
    idempotency_key="decision-payments-001",
    wait="indexed",           # block until it's searchable, for a clean first recall
)

pack = client.recall(scope=scope, view="holistic",
                     query="What database are we using for payments?", diagnostics="none")
print(pack.get("context_block", ""))

TypeScript

npm install cortexdbai
import { V1Client } from "cortexdbai/v1";

const client = new V1Client({ apiUrl: "http://localhost:3141", actor: "user:local" });
const scope = "org:demo/user:local";

await client.experience(scope, {
  content: { kind: "message", role: "user",
             text: "We migrated the payments service to CockroachDB. Timeline is Q2 2026." },
  context: { observed_at: "2026-05-16T10:42:00Z" },
  idempotency_key: "decision-payments-001",
}, { wait: "indexed" });

const pack = await client.recall(scope, { view: "holistic",
  query: "What database are we using for payments?", diagnostics: "none" });
console.log(pack.context_block);

4. Verify it — and where things live

A quick "did it actually work?" checklist:

  1. Readiness, not liveness. curl http://localhost:3141/v1/admin/ready"degraded": false. If it's true, you're on mock embeddings — fix the embedding provider before trusting recall.
  2. Read-your-writes. The recall in step 3 should return your text in context_block. (It used wait="indexed", so the event is searchable by the time the write returns.)
  3. Where your data lives. Everything — WAL, RocksDB, indexes, blobs — is under /data, persisted to the cortexdb-data Docker volume. Back it up with a verified cold backup.
  4. Boot diagnostics / logs. docker logs cortexdb shows the pinned embedding provider, the auth posture, and the config_lint dump (what actually loaded). Grep it when something's off:
    docker logs cortexdb 2>&1 | grep -iE "embedding|auth|answer|degraded"
  5. The Admin Console. Open http://localhost:3141/ in a browser — CortexDB ships a built-in operator UI (Overview, Memories, Observability, Logs, Settings, …). See Admin Console.

Common first-run issues

degraded: true → no real embedding provider (set a key or point at Ollama). 401 MISSING_TOKEN on a write → the server isn't in no-auth mode; start it with CORTEX_INSECURE_NO_AUTH=1 (dev) or send Authorization: Bearer $CORTEX_API_KEY. Empty facts() / no /v1/answer → expected on a content-only instance; enable enrichment / the answer lane (defaults).

What you get by default

Your instance runs in content-only mode out of the box: event capture, episodes, BM25 + vector + RRF recall, and blob extraction are all on. The LLM-derived layers (Facts, Beliefs, Understanding), the knowledge graph, cross-encoder rerank, and /v1/answer are opt-in — see Self-hosting defaults for exactly what's on and how to enable the rest.

Fully local, no external keys

To run with no external API calls at all, point embeddings at a local Ollama:

# On the host: ollama pull nomic-embed-text
docker run -d --name cortexdb \
  -p 127.0.0.1:3141:3141 -v cortexdb-data:/data \
  -e CORTEX_EMBEDDING_PROVIDER=ollama \
  -e CORTEX_EMBEDDING_URL=http://host.docker.internal:11434 \
  -e CORTEX_EMBEDDING_MODEL=nomic-embed-text \
  -e CORTEX_EMBEDDING_DIMS=768 \
  -e CORTEX_EMBEDDING_API_KEY=ollama \
  cortexdb/cortexdb:latest

To also get natural-language answers (/v1/answer) and the Facts/Beliefs layers locally, wire the answer lane and enrichment to Ollama too — see LLM & Answer and Self-hosting defaults.

Upgrading

CortexDB upgrades are a container image swap against the same data volume — your data lives in the volume, not the image:

docker pull cortexdb/cortexdb:latest      # or pin a version, e.g. :v0.9.9
docker rm -f cortexdb
docker run -d --name cortexdb -p 127.0.0.1:3141:3141 -v cortexdb-data:/data \
  -e CORTEX_INSECURE_NO_AUTH=1 -e OPENAI_API_KEY=$OPENAI_API_KEY \
  cortexdb/cortexdb:latest                # same flags + the SAME volume

Most releases are drop-in — no data migration, and existing data directories work as-is. Check the release notes at cortexdb.ai/changelog for anything that isn't (and for what each version changes). Take a verified cold backup before a major upgrade, and re-check GET /v1/admin/ready after.

Next steps

On this page