Quickstart

Self-host the full NovaCortex stack in about 5 minutes with Docker Compose, then mint your admin token from a one-time bootstrap code.

This is the supported ~5-minute self-host path. It brings up the full stack (SurrealDB, Qdrant, Redis, the API, and the Web UI) from pinned images, then walks you through minting your first admin token.

Requirements: Docker and Docker Compose. Works on Unraid and any Docker host. See Installation for details.

1. Clone the repo

git clone https://github.com/Nova-Cognitive-Systems/novacortex.git
cd novacortex

2. Generate secrets

scripts/gen-env.sh writes a .env with strong random secrets (chmod 600). It refuses to overwrite an existing .env, so it is safe to run.

./scripts/gen-env.sh

This generates SURREALDB_PASS, REDIS_PASSWORD, NEXTAUTH_SECRET, and JWT_SECRET, plus sensible defaults: APPDATA=./data, API_PORT=3001, WEB_PORT=3000, and a pinned NOVACORTEX_VERSION. The self-host compose fails fast if the required secrets are missing, so don't skip this step.

Optionally edit .env before starting:

  • Data location. APPDATA=./data keeps data next to the repo. On Unraid, set APPDATA=/mnt/user/appdata/novacortex.
  • Semantic search. Set OPENAI_API_KEY to enable embeddings. Leave it unset to run with local substring search only. See Configuration.

3. Start the stack

docker compose -f docker-compose.unraid.yml up -d

This pulls pinned multi-arch images from GHCR (ghcr.io/nova-cognitive-systems/novacortex-api and -web) and starts all five services. The API waits for SurrealDB, Qdrant, and Redis to report healthy before it boots.

4. Get the bootstrap code

On first boot the API has no tokens, so it prints a one-time bootstrap code to its logs. The code starts with nc_boot_ and is valid for 1 hour.

docker logs novacortex-api 2>&1 | grep -A1 "Bootstrap code"

You'll see something like:

═══════════════════════════════════════════════════════════
  NovaCortex Setup Required
  Bootstrap code: nc_boot_xxxxxxxxxxxxxxxxxxxxxxxx
  Valid for 1 hour
  Exchange via:
    novacortex setup --url <URL> --code nc_boot_xxxxxxxxxxxxxxxxxxxxxxxx
  Or visit the /login page in the web UI
═══════════════════════════════════════════════════════════

5. Mint your admin token

Exchange the bootstrap code for an admin token (scopes admin:*, tokens:read, tokens:write). Use whichever method you prefer — both hit the same POST /setup/exchange endpoint.

Option A — Web UI

Open the Web UI at http://localhost:3000 (or http://<host-ip>:3000), go to the login page, and paste the nc_boot_… code to mint your admin token. You're in.

Option B — CLI

novacortex setup --url http://localhost:3001 --code nc_boot_xxxxxxxxxxxxxxxxxxxxxxxx

This stores the resulting token in a local profile (--profile <name>, default default). Add --json for machine-readable output.

Option C — REST

curl -X POST http://localhost:3001/setup/exchange \
  -H 'Content-Type: application/json' \
  -d '{"code":"nc_boot_xxxxxxxxxxxxxxxxxxxxxxxx"}'

Response:

{
  "token": "<your-admin-token>",
  "whoami": {
    "kind": "selfhosted",
    "name": "...",
    "scopes": ["admin:*", "tokens:read", "tokens:write"],
    "server": { "version": "1.2.1", "mode": "selfhosted" }
  }
}

This endpoint is rate-limited to 5 requests per minute. Store the returned token securely — it is the credential for all subsequent API calls.

6. Verify

The REST API is at http://localhost:3001, with interactive Swagger docs at /docs (the root / redirects there).

# Stack health (also reports namespace stats)
curl http://localhost:3001/health

# Open the API docs in a browser
open http://localhost:3001/docs

7. Store your first memory

With your admin token:

curl -X POST http://localhost:3001/memories \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"content":"The user prefers dark mode","memoryType":"semantic","namespace":"agent"}'

Or from the TypeScript SDK:

import { NovaCortexClient } from '@novacortex/sdk';

const nc = new NovaCortexClient({ baseUrl: 'http://localhost:3001', token });
await nc.memories.create({
  content: 'The user prefers dark mode',
  memoryType: 'semantic',
  namespace: 'agent',
});

const { data, mode } = await nc.search({
  query: 'what does the user like?',
  namespace: 'agent',
});

Where data lives

All state is bind-mounted under ${APPDATA} (surrealdb/, qdrant/, redis/), so it survives container and image rebuilds and is covered by Unraid appdata backups.

Next steps

  • Configuration — tune backends, embeddings, the background processor, CORS, and licensing.
  • Authentication — token scopes and minting scoped tokens beyond the bootstrap admin token.
  • Installation — compose variants, ports, volumes, and upgrades.