knowledge mode of /context solves it with the same pull-first pattern as persistent memory: the conversation receives only an index card (what the base covers), and content is retrieved on demand — automatically each turn and, in the agent, iteratively via the @knowledge tool.
How it works
Native JSONL ingestion (docs-flatten)
Each JSONL line becomes a virtual document preservingsource, title and provenance (repoUrl/commit) — instead of arriving as one opaque text blob. Malformed lines are counted and skipped, never fatal. Plain directories also become knowledge bases (normal scanner, up to 100MB).
@docs-flatten accepts three sources for the same JSONL: root=<dir> (local folder), repo=<git-url> (shallow clone) and url=<site> (a bounded same-host crawl for docs that only exist as an HTML site, with no Markdown repo).
Code and infrastructure (kind=code)
Beyond documentation, @docs-flatten ingests source-code, Terraform and GitOps (Kubernetes/Argo) repositories — into the same JSONL schema, so knowledge mode changes nothing downstream. The kind parameter controls what enters and how it is sliced:
The slicing is language-agnostic — it doesn’t rely on a per-language keyword list, so it doesn’t break when you switch stacks:
The title is best-effort metadata: if the heuristic doesn’t recognize the language, it falls back to the cleaned signature line — content is always indexed and searchable, a missed title never costs recall. Noise is skipped by default (
vendor/, node_modules/, .terraform/, lockfiles, minified assets, binaries) and files above 1 MiB are ignored.
@knowledge search fans out across all of them (each hit tagged by its source base), so the model connects the layers: “the checkout-api Rollout won’t go ready — connect the Argo manifest, the Terraform node group and the service health check in code”.
You do not need to classify the repo manually. The default is
docs for safety, but the agent picks kind=code on its own: from intent (the tool schema documents the use), from the autonomous pipeline guidance (below), and from a self-correcting hint — running the default docs on a repo with no Markdown returns “looks like a code repo, re-run with kind=code”, and it recovers in the same turn.The index card (what enters the prompt)
Knowledge bases are also nodes in the knowledge graph (
kbcontext kind, linked by their tags): @memory map counts them, @memory neighbors can walk into them, and they ride the persisted graph cache. See Bootstrap and Memory › Knowledge graph.Hybrid retrieval (keyless-first)
Each turn, the passages relevant to the question are injected into a volatile block (outside the cached prefix):- Pure-Go BM25 — always available, no API key, pt/English neutral. That’s the floor. The tokenizer splits
snake_case,kebab-caseandcamelCase/PascalCaseinto sub-words (keeping the whole token), so an identifier likegetUserNameoraws_eks_clusteris found byuser,eks, etc. — code recall without losing exact match. - Embeddings (Voyage/OpenAI/Bedrock, when configured) — semantic boost, fused by normalized ranking (0.55/0.45). An embedding failure degrades to lexical with a warning; it never breaks the turn.
- Union, fused by rank — the vector index’s own top-k (over every passage embedded so far) joins the BM25 pool, and the union is fused by reciprocal rank fusion (ranks are comparable across corpora, so a single-hit corpus no longer scores 1.0 by construction); a passage that says it in other words surfaces even when BM25 has other results. The query is embedded once per turn and reused across every attached corpus; the LLM reranker sends its instruction once as the system message and books its usage as background spend.
- BM25 floor — lexical hits under 5% of the best hit’s score are dropped from the candidate pool, so a query that barely matches the corpus returns a short, honest list instead of k passages of noise.
- Optional rerank stage (
CHATCLI_KNOWLEDGE_RERANK, defaultoff) — reorders the head of the fused pool (up to 24 passages) before truncation.mmris keyless: maximal marginal relevance over token overlap, so the passages returned cover different parts of the corpus instead of near-duplicates of the best hit.llmasks the compaction model (CHATCLI_COMPACT_MODEL, else the session client) for a listwise order, bounded by an 8 s timeout; any failure keeps the fused order. - Corpus weights —
/context attach <name> --weight 1.5scales that base’s scores when hits from several attached bases are merged (1.0is neutral). The weight is persisted with the session’s attachments. - Accent folding and light stemming (opt-in) —
CHATCLI_KNOWLEDGE_NORMALIZE=foldmakesconfiguraçãoandconfiguracaothe same term;stemalso folds common pt/en endings (configurações → configuracao,deploys → deploy,queries → query,rapidamente → rapida) while leaving short identifiers such ass3oroauth2untouched. Defaultoffkeeps ranking byte-exact; changing the mode reindexes the corpus (the mode is part of the index fingerprint), and@recall-style searches over the transcript use the same tokenizer. - Local, keyless embeddings —
CHATCLI_EMBED_PROVIDER=ollamauses a local Ollama server (OLLAMA_HOST, defaulthttp://localhost:11434; modelCHATCLI_EMBED_MODEL, defaultnomic-embed-text, dimension learned on first use) for the semantic boost with no API key and no cost. - Warm-up, not first-query latency — attaching a knowledge base (or
--rag) and every refresh that changed something embed the missing passages in the background, in batches, so the first question after them does not pay the corpus embedding in the turn. Passage ids are content hashes: a refresh embeds only what changed. The vector index is written with an fsync’d atomic rename. Retrieval and warm-up share one bounded loop (64 passages per provider request) behind a per-context single-flight, so a question that lands during a warm-up waits for it instead of embedding the same ids twice. A batch the provider rejects is skipped and the rest still lands; the vector cache keeps every chunk that came back before a failure. Binary content (NUL bytes, invalid UTF-8) and minified bundles never reach the embedder, an over-long line is cut rune-safe at a hard cap, and truncated passages keep their citation line range true. - One budget per turn — the retrieved passages of all attached bases share a budget (~24 K characters, priority order); passages already emitted by a higher-priority base (same id, or the same content at the same place) are dropped, and the last base gets what is left rather than nothing.
- Structured citations — every passage header ends with
cite as [path:start-end]and the block asks the model to reference passages that way, so an answer can be traced back to the exact lines. - Embedding cost is visible — every embedding call is metered (tokens estimated from characters at the provider’s list rate) and shown by
/costasEmbeddings: N call(s) · ~T tokens · $x; Ollama meters at $0. - Structure-aware passages — contexts created from now on cut passages at headings, blank lines and declarations (
func,def,class, …) inside the last part of the window, and the boundary line opens the next passage. Existing contexts keep their fixed-window passages and their vectors; nothing is re-embedded behind your back.
The @knowledge tool — the agent investigates the base
In agent and coder modes, the index cards enter the system prompt and the @knowledge tool enables iterative investigation — search, read whole documents in pages, walk the structure:
The use case that closes the loop — authoring skills from the docs with the
@skill tool:
Autonomous pipeline — the agent builds the base itself (@context)
The steps above (flatten → create → attach) the agent does for you. When it hits a knowledge gap — a library, framework or API it doesn’t know — instead of guessing or stopping to ask, it builds the base itself:
1
Discover the source
@websearch for the official documentation (preferably the project’s Markdown repo), or use a repo/URL/path you pointed it at.2
Flatten
@docs-flatten with root=<dir>, repo=<git> or url=<site> → produces the JSONL corpus. For a code/infra repo, it adds kind=code (one base per layer: app, infra, gitops).3
Create and attach
@context create … --mode knowledge → @context attach ….4
Query
@knowledge search/get to ground the answer in the retrieved passages.@context tool gives the agent the same self-service power it already has for skills, but for knowledge:
The tool mirrors the full
/context surface, so the agent handles contexts end to end. The inspecting subcommands (list, status, show, inspect, metrics) are read-only.
You stay in control: everything the agent attaches shows up in /context attached and @context status; remove it with /context detach or just ask (“detach the react docs”). attach auto-detects embeddings — knowledge mode uses keyless BM25 + vectors when configured, and reports which mode is active. In /agent the agent does all of this on its own; in /coder, state-changing operations go through the policy confirmation.
In chat too (read-only exception)
Chat stays tool-less by design — but querying the knowledge base is the second sanctioned exception (next toask_user), for the same reason: it executes nothing, only reads what you attached. Attach the base and talk normally; when the auto-retrieved passages aren’t enough, the model pulls more on its own (up to 4 pulls per turn: search → get → next page) before answering.