Repository navigation
Installation
You need Docker, uv and Git. If you don't have Python 3.12, uv installs it.
flowchart LR
a["1. Clone"] --> c["2. uv sync"]
c --> b["3. stratakb db up<br/>Postgres on 5433"]
b --> d["4. stratakb add<br/>a folder"]
d --> e["Connect a client"]
git clone https://github.com/boudou/StrataKB.git
cd StrataKBThe defaults match the Docker database, so on your own machine you need no settings file. To change the passwords, see Passwords.
uv syncThis also installs the stratakb command. uv run stratakb add <folder> adds a folder; uv run stratakb receipt <id> opens a receipt (--json for the tool's form); uv run stratakb (or stratakb serve, or python -m stratakb) starts the MCP server.
The server answers its client at once and, with the default local backend, loads the embedding model in the background; a search sent before the model is ready waits for it. The first start downloads the embedding model (about 420 MB) and the first strata_ask downloads the reranker (about 90 MB), both into your Hugging Face cache. After that, both load from the cache, and StrataKB works offline unless you turn on a provider listed in Where your data goes. A model setting that names a folder (EMBEDDING_MODEL=C:\models\mpnet, RERANKING_MODEL=/opt/models/reranker) loads from that folder only: a folder that is missing or holds no model fails with a message naming the setting and the folder, and nothing is downloaded. With HF_HUB_OFFLINE or TRANSFORMERS_OFFLINE set, a model missing from the Hugging Face cache fails with a message naming that variable.
uv run stratakb db upThis starts PostgreSQL 16 with pgvector in the Docker container stratakb-db, on 127.0.0.1:5433, so it doesn't collide with a PostgreSQL already running on 5432. The data lives in the Docker volume stratakb-data. The command waits until the database accepts connections and builds the schema before it returns.
- Run it again any time: a running database keeps running and gets any missing schema updates, and a stopped one is started with its data.
-
uv run stratakb db downstops the container and keeps the volume. -
--portpicks another host port when the container is first created. - If it prints a
DATABASE_URL=line, your settings point at another database: put that line where it says. - With no
dockeronPATH, or the Docker daemon not running, it exits with code 3 and says which.
It creates no strata_readonly role, so strata_db_query and strata_db_explain stay off until you apply db/03_readonly_role.sql (see Roles and Audit); the other strata_db_* tools work without it.
A checkout also has a docker-compose.yml with the same database on port 5433 (container strata-postgres), which creates the read-only role too. Run docker compose up -d, or stratakb db up, not both on the same port. On the first start of an empty volume, Docker runs these files:
| File | Creates |
|---|---|
src/stratakb/core/sql/01_init.sql |
Layers, ingestion runs, chunks with their vectors, users and the audit log |
src/stratakb/core/sql/02_learning.sql |
Interactions, feedback, and the synonyms and rewrites the server has learned |
db/03_readonly_role.sql |
The strata_readonly role used by the SQL inspection tools |
src/stratakb/core/sql/04_ingested_files.sql |
The table that tracks each ingested file |
The server applies the remaining schema changes itself (see The schema). To start again from scratch, run docker compose down -v. This deletes all data.
Any empty PostgreSQL 16 database with pgvector works as well. The server and stratakb add create the schema on first use, as long as the user in DATABASE_URL may create the vector and pg_trgm extensions. Before it creates anything, it names the database it sets up as host:port/database (never the user or password; unknown host when the URL cannot be read safely, such as a password with an unencoded /, ? or #): in the server log (setting_up_database) and on stderr in stratakb add. It refuses to set up in postgres or in a database whose name starts with template, which usually means DATABASE_URL points at the wrong database: create one for StrataKB (CREATE DATABASE strata;) and point DATABASE_URL at it. A StrataKB schema already in such a database keeps working. Use pgvector 0.8 or later for complete results: older versions work, but a filtered search can return fewer results than it asks for, and the server logs hnsw_iterative_scan_unavailable. After upgrading an existing database's image, run ALTER EXTENSION vector UPDATE;. The strata_readonly role is not created for you: apply db/03_readonly_role.sql with psql as the owner of the schemas if you want the SQL tools (see Roles and Audit).
The schema files ship inside the package. At startup, and before stratakb add writes anything, StrataKB applies every numbered migration the database is missing, in order, and records it in strata_core.schema_migrations. An existing database is brought up to date the same way, so upgrading needs no manual SQL step. If the database user may not change the schema, the error names the SQL file to apply as the database owner; a user without USAGE on the StrataKB schemas is told which privilege is missing. A schema update waits at most 30 seconds for a lock another process holds, then stops and names the lock.
uv run stratakb add path/to/docsIt creates a layer named after the folder and prints what it stored and skipped. See Layers and Presets. No documents at hand? The Python PEPs example fetches a few in seconds. Then connect a client.
Settings come from four sources, each overriding the one before:
flowchart LR
d["Defaults"] --> u["User config.env"] --> c["File named by<br/>STRATAKB_CONFIG"] --> e["Environment<br/>variables"]
| Source | Where |
|---|---|
| User config file |
%APPDATA%\stratakb\config.env on Windows; $XDG_CONFIG_HOME/stratakb/config.env, else ~/.config/stratakb/config.env, elsewhere |
STRATAKB_CONFIG |
Any file you name; a missing file is logged and skipped by the server, and refused by stratakb add
|
| Environment variables | Your shell, or the env block of your MCP client's configuration |
Copy .env.example to the user config file to start. ./.env is not read unless you set STRATAKB_CONFIG=.env; when the server finds one it does not read, it logs a warning (dotenv_not_read). Keys the server does not know, such as DB_PASSWORD, are ignored, so one file can serve both the server and Docker (see Passwords). Configuration has the full table of settings.
The server keeps the settings it started with for strata_admin_health, strata_search, strata_ask, strata_verify, strata_ingest_documents, strata_apply_preset, query rewriting, the query embedding and the raw-query audit setting: a config file edited while the server runs changes nothing for them until you restart it. The server reads STRATA_USER and STRATA_ROLE once, when it starts; changing either takes a restart.
docker compose still reads ./.env itself, for its own variables: DB_PASSWORD, READONLY_DB_PASSWORD and DB_PORT. Unless the server only runs on your own machine, change the passwords before the first docker compose up -d:
cp .env.example .env # for docker composeChange DB_PASSWORD and READONLY_DB_PASSWORD in .env, and the matching DATABASE_URL and READONLY_DATABASE_URL in your user config.env (or set STRATAKB_CONFIG=.env so the server reads the same file). The passwords apply when the data volume is created.
By default nothing leaves this machine except what you choose to send: your documents stay in PostgreSQL, and the embedding and reranking models run in-process. Each other path is off until a setting turns it on.
| Path | What leaves | Turned on by | Blocked by STRATA_LOCAL_ONLY
|
|---|---|---|---|
| PostgreSQL | Documents, chunks, stored queries, audit entries |
DATABASE_URL (always) |
No |
| Your MCP client and its language model | Retrieved text, sources | Every search and ask | No |
| Anthropic query rewriting | Questions and layer descriptions | ANTHROPIC_API_KEY |
Yes |
| Rewrite endpoint on another host | Questions and layer descriptions |
QUERY_REWRITE_PROVIDER=openai_compatible with QUERY_REWRITE_BASE_URL and QUERY_REWRITE_MODEL set |
Yes |
| OpenAI embeddings | Documents and questions |
EMBEDDING_BACKEND=openai without EMBEDDING_BASE_URL
|
Yes |
| Embedding server on another host | Documents and questions |
EMBEDDING_BACKEND=openai with EMBEDDING_BASE_URL
|
Yes |
| Hugging Face downloads | Nothing about your documents; model files come in | The first start, the first stratakb add and the first strata_ask
|
Yes |
A rewrite endpoint or embedding server on this machine (127.0.0.1, ::1 or localhost) is allowed with the switch on.
With STRATA_LOCAL_ONLY=true the server refuses to start while any blocked path is configured, and the error names each setting that caused it. strata_search, strata_ask, query rewriting, strata_ingest_documents and strata_apply_preset use the settings the server started with, so a config file edited while the server runs changes nothing for them until a restart. That includes the switch for the outbound providers: turning STRATA_LOCAL_ONLY on in a config file stops them only after a restart, though a model the server has not loaded yet is kept from downloading at once. Models load from local files only; a model that is not installed fails with a message that says how to install it. The switch does not cover the database: DATABASE_URL may point at a shared database on purpose. Every embedding path (strata_search, strata_ask, strata_ingest_documents, strata_apply_preset, stratakb add, scripts/apply_preset.py) checks its setup before any work, so strata_ask never sends a question to the rewrite provider ahead of a search that cannot run: an unknown EMBEDDING_BACKEND, openai without OPENAI_API_KEY or EMBEDDING_BASE_URL, or a blocked path fails and names the setting. stratakb add then refuses with exit 2 (reason local_only or embedding_setup in --json) and writes nothing. The OpenAI and Anthropic SDKs also read OPENAI_BASE_URL and ANTHROPIC_BASE_URL; StrataKB treats them as the destination of those paths, and STRATA_LOCAL_ONLY checks them too. Requests to EMBEDDING_BASE_URL and QUERY_REWRITE_BASE_URL never carry OPENAI_API_KEY, OPENAI_ADMIN_KEY, OPENAI_ORG_ID or OPENAI_PROJECT_ID.
strata_admin_health always lists the switch (local_only) and the active outbound providers (outbound: provider, purpose, what it sends, destination host and the setting that turns it on). The outbound list never shows keys, credentials, paths or ports. An endpoint URL that cannot be read safely (an unencoded /, ? or # in its password, or an @ in its path or query) shows as unknown host and counts as leaving the machine, so STRATA_LOCAL_ONLY refuses it even when it points at this machine; percent-encode such characters.
StrataKB cannot control what your MCP client's language model does with the retrieved text. If the client uses a cloud model, the retrieved text goes to that provider.
uv sync --extra dev
uv run pytest # the integration tests need the database running
uv run ruff check src testsSee CONTRIBUTING.md before opening a pull request.
Getting started
Using StrataKB
Reference
Help