Everything that controls how OpenKB talks to your LLM lives in two places:
.openkb/config.yaml (model, language, tuning) and a .env file (your API key).
pip install openkbOpenKB pins a pre-release of its PageIndex dependency
(pageindex==0.3.0.dev3), which some installers skip by default. If an install
can't resolve pageindex, allow pre-releases:
uv tool install openkb --prerelease=allow # uv
pip install --pre openkb # pipIf openkb isn't found after a successful install, the console-script directory
isn't on your PATH (e.g. pip --user installs to ~/.local/bin) — add it to
PATH.
mkdir my-kb && cd my-kb
openkb initinit is interactive in a terminal and prompts for three things:
- Model — in LiteLLM
provider/modelformat. OpenAI models can drop the prefix (gpt-5.4); others need it (anthropic/claude-sonnet-4-6,gemini/gemini-3-flash-preview). - LLM API key — hidden input; if you provide one it's written to
.envwith0600permissions. Press Enter to skip and set it later. - Language — the output language for your wiki. Any language works; e.g. the
six official UN languages:
en(English),zh(Chinese),es(Spanish),fr(French),ar(Arabic),ru(Russian).
Skip the prompts entirely with flags — handy in scripts:
openkb init --model anthropic/claude-sonnet-4-6 --language en
openkb init -m gpt-5.4 -l zhNon-interactive (pipes/CI): prompts are gated on a TTY. When stdin isn't a terminal,
inituses the defaults instead of hanging, soprintf 'gpt-5.4\n\nen\n' | openkb initworks in a script.
init creates: raw/, wiki/{summaries,concepts,entities,sources/images},
wiki/AGENTS.md, wiki/index.md, wiki/log.md, and .openkb/config.yaml.
The file init writes is small; everything else is optional. This is the shipped
config.yaml.example, verbatim:
model: gpt-5.4 # LLM model (any LiteLLM-supported provider)
language: en # Wiki output language
pageindex_threshold: 20 # PDF pages threshold for PageIndex
# Optional: cap concurrent LLM calls during ingest (PageIndex indexing and
# concept/entity compilation — they never overlap, so one setting covers
# both). Lower it if you hit provider rate limits or "too many open files" on
# large PDFs. Omit to let each stage apply its own default.
# concurrency: 5
# Optional: whether the LLM agents (query, chat, lint, skill) may call tools
# in parallel. Leave it UNSET (commented out) to keep OpenKB's per-agent
# defaults. Setting it applies the SAME value to every agent:
# true allow parallel tool calls
# false force sequential tool calls
# null don't send the setting at all (use the provider default) — REQUIRED
# for Amazon Bedrock Claude, which rejects the request when
# parallel_tool_calls is sent at all (any value). See #175.
# parallel_tool_calls: null
# Optional: override the entity-type vocabulary used for entity pages.
# Omit this key to use the default 7 types
# (person, organization, place, product, work, event, other).
# entity_types:
# - person
# - organization
# - dataset
# - model
# Optional: LLM / LiteLLM tuning. Keys are forwarded to LiteLLM; `timeout` and
# `extra_headers` apply per request, the rest are set as litellm.<key>.
# litellm:
# timeout: 1200 # per-request timeout (s); raise for slow local backends (Ollama)
# drop_params: true # let LiteLLM drop params a provider rejects (e.g. Ollama)
# num_retries: 3
# extra_headers: # extra HTTP headers some providers need (e.g. GitHub Copilot)
# Editor-Version: vscode/1.95.0
# Copilot-Integration-Id: vscode-chat| Key | Default | What it does |
|---|---|---|
model |
gpt-5.4 |
LLM used for all compile/query/chat work. |
language |
en |
Language the wiki is written in. |
pageindex_threshold |
20 |
PDFs with this many pages or more take the long-doc (PageIndex) path; shorter ones go through the short-doc path. See pageindex-cloud/. |
concurrency |
null |
Caps concurrent LLM calls OpenKB makes during ingest — both PageIndex's indexing of a long document and OpenKB's own concept/entity compilation. The two never run at once for the same document, so one setting covers both. Lower it if you hit provider rate limits or "too many open files" on large PDFs. null lets each stage apply its own default. |
parallel_tool_calls |
unset | Whether the LLM agents (query, chat, lint, skill) may call tools in parallel. Unset keeps OpenKB's per-agent defaults; true/false force allow/sequential for every agent; null omits the setting (provider default). Amazon Bedrock needs null (see below). |
entity_types |
7 defaults | Custom vocabulary for entity pages. other is always kept. |
litellm: |
– | A pass-through block for LiteLLM. See below. |
OpenKB forwards this block to LiteLLM so you can tune anything LiteLLM supports — you set it, LiteLLM uses it. Two keys are special:
timeoutandextra_headersare applied per request (they're needed on every call).- Every other key (
drop_params,num_retries,ssl_verify, …) is set on thelitellmmodule as a process-wide global.
Local inference can be slow — on a Mac running LM Studio, a single compile
call can take minutes, and the default request timeout will abort it (this is
the usual cause of failures with local runtimes). Raise timeout (in seconds).
Add drop_params for backends that reject OpenAI-only params (e.g. Ollama):
model: ollama/llama3.1 # or your LM Studio / llama.cpp model id
language: en
litellm:
drop_params: true
timeout: 1200 # raise further (e.g. 3600) for large local modelsThese need extra headers and use OAuth (no API key):
model: github_copilot/gpt-4o
language: en
litellm:
extra_headers:
Editor-Version: vscode/1.95.0
Copilot-Integration-Id: vscode-chatWhen your model is an openrouter/* model, you can opt into OpenRouter's
Response Caching:
identical-payload requests come back in ~80–300 ms with zero token billing.
That's a direct win on the compile-retry path (a failed add re-runs every
summary/plan/concept call with the same prompts) and on repeated lint / dev
iteration. Send the cache headers via extra_headers:
model: openrouter/anthropic/claude-sonnet-4.5
language: en
extra_headers: # top-level, or nested under `litellm:` — both work
X-OpenRouter-Cache: "true"
X-OpenRouter-Cache-TTL: "600" # optional, 1–86400s (OpenRouter default 300)It's opt-in by design: responses are stored on OpenRouter, so leave it off for
zero-data-retention / regulated content. Only openrouter/* models read these
headers; other providers ignore them.
Set one universal key and OpenKB routes it to the right provider based on your
model. The shipped .env.example:
# OpenAI: LLM_API_KEY=sk-...
# Anthropic: LLM_API_KEY=sk-ant-...
# Gemini: LLM_API_KEY=AIza...
LLM_API_KEY=your-key-here-
Provider auto-detection:
model: anthropic/claude-sonnet-4-6→ yourLLM_API_KEYis exported asANTHROPIC_API_KEYautomatically. -
OAuth providers (
chatgpt/*,github_copilot/*) need no key — OpenKB won't warn about a missing one. -
PageIndex Cloud uses a separate
PAGEINDEX_API_KEY(seepageindex-cloud/). -
Amazon Bedrock (
model: bedrock/...) authenticates with AWS credentials, notLLM_API_KEY. Put them in<kb>/.env(LiteLLM/boto3 read them from the environment);LLM_API_KEYisn't needed:# <kb>/.env AWS_ACCESS_KEY_ID=... AWS_SECRET_ACCESS_KEY=... AWS_REGION_NAME=eu-central-1# <kb>/.openkb/config.yaml model: bedrock/eu.anthropic.claude-sonnet-4-6 parallel_tool_calls: null # REQUIRED for Bedrock Claude: sending # parallel_tool_calls at all (any value) makes # LiteLLM send a malformed tool_choice that Bedrock # rejects (#175). null tells OpenKB to omit it. # Write it as bare `null` — not `None` or "null".
Where keys are read from (first match wins, existing env always respected):
- your shell environment
<kb>/.env~/.config/openkb/.env(a global key shared across all your KBs)
Most commands need to know which KB they act on. Resolution order:
--kb-dir /path/to/kb(orOPENKB_DIR=/path/to/kb) — explicit override.- Walk up from the current directory looking for a
.openkb/folder. - The global default registered by
openkb use <path>(stored in~/.config/openkb/global.yaml).
# Run a query against a specific KB from anywhere
openkb --kb-dir ~/research-kb query "what changed in v2?"
# Make one KB the default, then forget about paths
openkb use ~/research-kb
openkb status # now resolves ~/research-kb from any directoryNext: commands/ — the everyday ingest-and-query loop.