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-platformcompose 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.tokenon 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
/setup wizard
does all of this for you — what follows is the by-hand equivalent:
TOKEN=$(docker exec kvendra-ref-platform cat /data/auth.token)
claude mcp add kvendra-platform http://localhost:7777/mcp \
-H "Authorization: Bearer $TOKEN"
Or add the equivalent block to .mcp.json at your project root
(or ~/.claude/settings.json):
{
"mcpServers": {
"kvendra-platform": {
"type": "http",
"url": "http://localhost:7777/mcp",
"headers": { "Authorization": "Bearer <your token>" }
}
}
}
Restart Claude Code (or run /mcp reconnect kvendra-platform)
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 Quickstart's --with-ollama sets these for you. If you are
not using that flag — running the engine on its own, or against an existing
Ollama you manage — point embeddings at the local container by hand:
# in .env
EMBEDDINGS_PROVIDER=openai-compatible
EMBEDDINGS_BASE_URL=http://kvendra-ollama:11434/v1
EMBEDDINGS_MODEL=mxbai-embed-large
To use managed embeddings instead of running a model locally, point the same
openai-compatible provider at a hosted endpoint and supply a key.
For Kvendra Cloud embeddings that is the cloud base URL plus an
EMBEDDINGS_API_KEY:
# in .env — managed embeddings (e.g. Kvendra Cloud)
EMBEDDINGS_PROVIDER=openai-compatible
EMBEDDINGS_BASE_URL=https://api.kvendra.cloud/v1
EMBEDDINGS_MODEL=mxbai-embed-large
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 moving a corpus to a managed provider on a different model, means re-embedding the corpus.
| Variable | Default | Notes |
|---|---|---|
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
| Variable | Default | Notes |
|---|---|---|
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)
| Variable | Default | Notes |
|---|---|---|
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 | llama3.1:8b,mxbai-embed-large | Comma-separated models up.sh --with-ollama pulls on first
run. Includes the embedding model; trim it if you only need
embeddings. |
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 volumekvendra_platform_pgdata. - Reference stack uses named volumes throughout —
kvendra_ref_platform_data(engine/data, incl. the token),kvendra_ref_pgdata(Postgres) andkvendra_ref_ollama_models(Ollama weights) — plus a host./backupsdirectory for the sidecar's dumps.
Just want it running? Go back to the Quickstart — one command, local embeddings, no signup.