Documentation menu
Getting Started

Advanced install

The Quickstart commits to one path: the reference stack with local embeddings, ready in one command. This page is for when you want to go the other way — step by step, from the minimum: run just the engine against your own Postgres, build the image from source, verify the supply chain, and know every knob. Pick the pieces you need.

Platform-only — your own Postgres, the minimum

The leanest footprint: clone the engine on its own and start it with Docker Compose. This is the right choice when you already run Postgres, or simply want the smallest possible thing on disk. Either way the stack is Node 20 + Fastify + PostgreSQL 16 + pgvector, and the database migrations run automatically on first boot.

git clone https://github.com/KvendraAI/kvendra-platform
cd kvendra-platform && docker compose up -d

Verify it is healthy:

curl http://localhost:7777/healthz   # {"status":"ok","schema_version":"v1.0"}

The Platform-only compose ships with EMBEDDINGS_PROVIDER=mock (deterministic stub vectors) so it boots with no external dependency. That is fine for a first health check, but search is non-semantic until you point it at a real provider — see Environment variables below.

Reading the auth token — two different commands

The engine bootstraps a bearer token at /data/auth.token (mode 0600) on first boot, and gates every tools/call on it. Where you read it from depends on how /data is mounted — and the two supported stacks differ:

  • Platform-only (bind-mount): the kvendra-platform compose file mounts ./data:/data, so the token is a real file on your host. Read it directly:
    cat ./data/auth.token
  • Reference stack (named volume): the reference stack mounts a named Docker volume at /data, so there is no ./data/auth.token on the host to cat. Read it out of the running container instead:
    docker exec kvendra-ref-platform cat /data/auth.token

Then register the Platform with your agent — the same step as Quickstart step 3:

TOKEN=$(docker exec kvendra-ref-platform cat /data/auth.token)   # reference stack
# Platform-only (bind-mount): TOKEN=$(cat ./data/auth.token)

claude mcp add --transport http kvendra-platform http://localhost:7777/mcp \
  -H "Authorization: Bearer $TOKEN"

Or add the equivalent block to .mcp.json at your project root (it holds your token, so keep it out of version control):

{
  "mcpServers": {
    "kvendra-platform": {
      "type": "http",
      "url": "http://localhost:7777/mcp",
      "headers": { "Authorization": "Bearer <your token>" }
    }
  }
}

Restart Claude Code (or reconnect it from /mcp) to activate it, then confirm by calling whoami. Once connected, the agent gains 14 MCP tools: entity_get, entity_create, entity_update, entity_archive, entity_related, entity_query, entity_search, txn_create, txn_activate, txn_cancel, txn_check_interrupted, whoami, config_get and help.

Build from source

There is no separate compile-from-source toolchain to learn: building Kvendra Platform means building its Docker image. The image itself is a multi-stage Node 20 build (install production deps, compile TypeScript, assemble a minimal runtime), so a plain docker build against the cloned repo is the from-source build:

git clone https://github.com/KvendraAI/kvendra-platform
cd kvendra-platform && docker build -t kvendra-platform:local .

The reference stack wraps exactly this for regulated environments that must compile every Kvendra-controlled component from public source before running anything. Its scripts/build-from-source.sh clones kvendra-platform, runs docker build, and writes a docker-compose.override.yml pointing the kvendra-platform service at your locally-built image — so the usual ./scripts/up.sh picks it up with no registry pull of the Kvendra bits:

cd kvendra-reference-stack
./scripts/build-from-source.sh
./scripts/up.sh   # uses the override automatically

The upstream base images (node:20-alpine, pgvector/pgvector:pg16, ollama/ollama, postgres:16-alpine) are still pulled from their public registries — they are themselves open-source projects, not Kvendra builds. Rebuilding those from source too is a rarely-needed extra step documented in the reference stack's troubleshooting notes.

Published Docker images are signed

You do not have to build from source to trust the images. Each released Kvendra image is signed with Sigstore/cosign keyless (via GitHub Actions OIDC — there is no long-lived signing key to manage or leak), and each release also attaches a signed SBOM attestation (SPDX JSON, generated by Syft). The Fulcio certificate ties every signature to the KvendraAI/kvendra-platform GitHub Actions workflow, and the signature lands in Sigstore's transparency log (Rekor). Signing has covered every release from the first published tag onwards.

The reference stack ships a one-shot verifier:

cd kvendra-reference-stack
./scripts/verify.sh   # fails if any pinned image signature does not check out

Or verify by hand with cosign (brew install cosign on macOS):

IMG=docker.io/kvendra/kvendra-platform:<version>

# 1. image signature
cosign verify "$IMG" \
  --certificate-identity-regexp '^https://github.com/KvendraAI/kvendra-platform/' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com

# 2. SBOM attestation
cosign verify-attestation "$IMG" \
  --certificate-identity-regexp '^https://github.com/KvendraAI/kvendra-platform/' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  --type spdxjson

Both commands exit 0 with a JSON payload when the signature is valid. The SBOM is also attached as a GitHub Release asset for archival and compliance.

Environment variables

Everything is configured through environment variables (the reference stack reads them from .env; the Platform-only compose sets them inline or via its own .env). Most have sane defaults. The full surface:

Embeddings

The provider is resolved at startup. Allowed values are openai-compatible and mock — a third, bedrock, is intentionally not available in the open-core Platform. With openai-compatible you can point at Ollama, vLLM, llama.cpp or any other OpenAI-compatible /embeddings endpoint; what you point it at decides whether anything leaves your infrastructure. Vectors are validated as 1024-dim, so use a 1024-dim model (e.g. mxbai-embed-large); other dimensions fail at request time.

The reference stack's .env.example already points at the local Ollama container, which ./scripts/up.sh starts by default. If you run the engine on its own, or against an existing Ollama you manage, point embeddings at it by hand:

# in .env
EMBEDDINGS_PROVIDER=openai-compatible
EMBEDDINGS_BASE_URL=http://kvendra-ollama:11434/v1
EMBEDDINGS_MODEL=mxbai-embed-large

To use your own embeddings provider instead of running a model locally, point the same openai-compatible provider at any OpenAI-compatible /embeddings endpoint and supply a key if it needs one. The engine sends only the model and the input — it does not request a dimensions size — so the model must return 1024-dimension vectors natively (for example mxbai-embed-large or bge-large-en-v1.5 served by vLLM or TEI, or mistral-embed), or sit behind a gateway such as LiteLLM that pins the output to 1024. With the reference stack, start it with ./scripts/up.sh --no-ollama so the local container is skipped.

# in .env — your own OpenAI-compatible provider
EMBEDDINGS_PROVIDER=openai-compatible
EMBEDDINGS_BASE_URL=https://<your-provider>/v1
EMBEDDINGS_MODEL=<a 1024-dim model>
EMBEDDINGS_API_KEY=<your key>

After editing .env, re-run the stack (or restart the Platform container) so the provider is picked up.

Embeddings are model-specific: vectors are not portable across models (a property of embedding spaces, not a Kvendra limitation). Pick a model and stay on it — switching models or providers, even between two 1024-dim ones, means re-embedding the corpus.

VariableDefaultNotes
EMBEDDINGS_PROVIDER mock (Platform-only) openai-compatible or mock.
EMBEDDINGS_BASE_URL — Required for openai-compatible. E.g. http://kvendra-ollama:11434/v1.
EMBEDDINGS_MODEL — Required for openai-compatible. E.g. mxbai-embed-large (1024-dim).
EMBEDDINGS_API_KEY unset Bearer token. Omit for local Ollama, which needs no auth.
EMBEDDINGS_TIMEOUT_MS 30000 Per-request timeout in milliseconds.

Postgres & engine

VariableDefaultNotes
POSTGRES_USER kvendra Reference-stack Postgres user.
POSTGRES_PASSWORD kvendra Change it for anything beyond local.
POSTGRES_DB kvendra_platform Database name.
DATABASE_URL — Platform-only connection string, e.g. postgres://kvendra:kvendra@db:5432/kvendra_platform.
PORT 7777 Port the engine listens on inside the container.
PLATFORM_HOST_PORT 7777 Reference-stack host-side mapping. Change it if 7777 is taken on your host.
HOST 0.0.0.0 Listen address.
AUTH_TOKEN_FILE /data/auth.token Where the bearer token is generated and read from.
LOG_LEVEL info trace | debug | … | fatal.
STAGE local local | staging | prod.
PG_POOL_MAX 10 Postgres connection-pool size.

Backup sidecar & Ollama (reference stack)

VariableDefaultNotes
BACKUP_CRON 30 3 * * * Cron schedule for the pg_dump sidecar (daily 03:30).
BACKUP_RETENTION_DAYS 14 How many days of dumps to keep before pruning.
OLLAMA_MODELS_PRELOAD mxbai-embed-large Comma-separated models up.sh pulls on first run (skipped with --no-ollama). The default is just the embedding model; add more models (e.g. a chat model) if you need them.
OLLAMA_HOST_PORT 11434 Host-side port for the Ollama container.

Volumes

  • Platform-only bind-mounts ./data:/data (so the token is a host file) and keeps Postgres data in a named volume kvendra_platform_pgdata.
  • Reference stack uses named volumes throughout — kvendra_ref_platform_data (engine /data, incl. the token), kvendra_ref_pgdata (Postgres) and kvendra_ref_ollama_models (Ollama weights) — plus a host ./backups directory for the sidecar's dumps.

Just want it running? Go back to the Quickstart — one command, local embeddings, no signup.