
Kb
- 1 installs
- 95 repo stars
- Updated June 28, 2026
- pedronauck/kodebase-go
Builds and maintains an Obsidian knowledge base with the kb CLI, ingesting sources and inspecting codebases for complexity, coupling, and dead code.
About
Drives the kb CLI through the ingest-compile-query-lint cycle to build a cross-linked Obsidian wiki and to run code graph and metrics inspection. A developer uses it for knowledge base workflows and codebase architecture analysis.
- kb CLI ingest-compile-query-lint knowledge base pipeline
- Codebase inspection for complexity, coupling, dead code, blast radius
Kb by the numbers
- 1 all-time installs (skills.sh)
- Ranked #1,366 of 1,879 Documentation skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/pedronauck/kodebase-go --skill kbAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1 |
|---|---|
| repo stars | ★ 95 |
| Last updated | June 28, 2026 |
| Repository | pedronauck/kodebase-go ↗ |
What it does
Builds and maintains an Obsidian knowledge base with the kb CLI, ingesting sources and inspecting codebases for complexity, coupling, and dead code.
Files
kb CLI and Knowledge Base Pattern
Build and maintain a self-compiling Obsidian markdown knowledge base using the kb CLI. The LLM reads raw sources, writes cross-linked wiki articles, files Q&A results back into the corpus, and runs lint-and-heal passes. The CLI also supports codebase ingestion with deep inspection commands for code quality, architecture health, and symbol relationships.
Each topic lives in its own top-level folder (e.g. ai-harness/) with raw/, wiki/, outputs/, bases/ subtrees plus a topic-level log.md and CLAUDE.md. All topics share a single Obsidian vault at the repo root. Read references/architecture.md for the full rationale and the four-phase pipeline (ingest → compile → query → lint).
The topic's `CLAUDE.md` (symlinked to AGENTS.md) is the schema document — it tells the LLM the scope, conventions, current articles, and research gaps for that topic. Co-evolve it as the topic matures.
Prerequisites
1. Verify the kb binary is available:
kb version2. For search and index commands, verify QMD is installed:
qmd --version
# If missing: npm install -g @tobilu/qmd3. Supported source languages for codebase analysis: TypeScript (.ts), TSX (.tsx), JavaScript (.js), JSX (.jsx), Go (.go).
Pattern Overview
Based on Andrej Karpathy's LLM Wiki pattern, the KB treats the LLM as a compiler that reads raw source documents and produces a structured, cross-linked markdown wiki. The four-phase loop:
1. Ingest — Scrape/curate sources via kb CLI → raw/ (immutable staging) 2. Compile — LLM reads raw/, writes wiki/concepts/ articles (3000-4000 words, dense wikilinks) 3. Query — Q&A against wiki → file answers to outputs/queries/, promote strong answers to wiki 4. Lint — Automated structural checks + LLM-driven semantic healing
Read references/architecture.md for the full rationale, context-window vs RAG tradeoffs, and multi-topic vault design.
Related Skills
This skill orchestrates several companion skills for the LLM-driven phases:
- [obsidian-markdown](https://github.com/pedronauck/skills/tree/main/skills/obsidian-markdown) — author wiki articles with valid Obsidian Flavored Markdown (wikilinks, callouts, embeds, properties).
- [obsidian-bases](https://github.com/pedronauck/skills/tree/main/skills/obsidian-bases) — create
.basefiles under<topic>/bases/for dashboard views, filters, and formulas. - [obsidian-cli](https://github.com/pedronauck/skills/tree/main/skills/obsidian-cli) — interact with the running Obsidian vault from the command line (open notes, search, refresh indexes).
kb CLI Quick Reference
Topic management
kb topic new <slug> <title> <domain> # scaffold a new topic
kb topic list # list all topics in the vault
kb topic info <slug> # topic metadata (counts, last log entry)Ingestion (auto-generates frontmatter, auto-appends to log.md)
kb ingest url <url> --topic <slug> # scrape a web URL via Firecrawl
kb ingest file <path> --topic <slug> # convert local file (PDF, DOCX, EPUB, HTML, images w/OCR, etc.)
kb ingest youtube <url> --topic <slug> # extract YouTube transcript
kb ingest bookmarks <path> --topic <slug> # ingest a bookmark-cluster markdown file
kb ingest codebase <path> --topic <slug> # analyze a codebase into raw/codebase/Codebase inspection
kb inspect smells [--type <smell-type>] --format json
kb inspect dead-code --format json
kb inspect complexity [--top N] --format json
kb inspect blast-radius [--min N] [--top N] --format json
kb inspect coupling [--unstable] --format json
kb inspect circular-deps --format json
kb inspect symbol <name> --format json
kb inspect file <path> --format json
kb inspect backlinks <name-or-path> --format json
kb inspect deps <name-or-path> --format jsonStructural linting
kb lint [<slug>] [--save] # dead links, orphans, missing sources, format violations, stale contentIndexing and search (requires QMD)
kb index --topic <slug> # create or update QMD collection
kb search "<query>" --topic <slug> # hybrid BM25 + vector search
kb search "<query>" --lex --topic <slug> # keyword-only search
kb search "<query>" --vec --topic <slug> # vector-only searchAfter running kb ingest or kb lint --save, the CLI auto-appends entries to <topic>/log.md. Manual log entries are still needed for compile, query, promote, and split operations (Procedure 5).
Command Dispatch
Map the user's intent to the correct command:
| Intent | Command |
|---|---|
| Scaffold a new topic | kb topic new <slug> <title> <domain> |
| List all topics | kb topic list |
| Scrape a web URL | kb ingest url <url> --topic <slug> |
| Ingest a local file (PDF, DOCX, etc.) | kb ingest file <path> --topic <slug> |
| Extract a YouTube transcript | kb ingest youtube <url> --topic <slug> |
| Ingest bookmark clusters | kb ingest bookmarks <path> --topic <slug> |
| Analyze a codebase | kb ingest codebase <path> --topic <slug> --progress never |
| Find code smells | kb inspect smells --format json |
| Find dead exports and orphan files | kb inspect dead-code --format json |
| Rank functions by complexity | kb inspect complexity --format json |
| Find high-impact symbols (blast radius) | kb inspect blast-radius --min 5 --format json |
| Find unstable files (coupling) | kb inspect coupling --unstable --format json |
| Find circular imports | kb inspect circular-deps --format json |
| Look up a specific symbol | kb inspect symbol <name> --format json |
| Look up a specific file | kb inspect file <path> --format json |
| Find what depends on X (incoming refs) | kb inspect backlinks <name-or-path> --format json |
| Find what X depends on (outgoing deps) | kb inspect deps <name-or-path> --format json |
| Run structural lint | kb lint <slug> --save |
| Index vault for search | kb index --topic <slug> |
| Search the knowledge base | kb search "<query>" --topic <slug> --format json |
Codebase Analysis Workflow
For codebase-specific analysis, the kb ingest codebase command must run before any inspect command.
Workflow A -- Code Analysis (no QMD required):
kb ingest codebase <path> --topic <slug> --> kb inspect <subcommand>Workflow B -- Full Pipeline (requires QMD):
kb ingest codebase <path> --topic <slug> --> kb index --> kb search <query>The vault is stored at <path>/.kb/vault/<topic-slug>/ by default. Later commands auto-discover this vault by walking up from the current working directory.
Ingest a Codebase
kb ingest codebase <path> --topic <slug> --progress neverAlways use --progress never in agent contexts to prevent TTY progress bars from corrupting stdout.
Parse the JSON output from stdout to extract key values:
topicSlug-- the topic identifier for later commandsvaultPath-- absolute path to the vault roottopicPath-- absolute path to the topic directoryfilesScanned,filesParsed,symbolsExtracted-- summary statisticsdiagnostics-- check for warnings or errors
Stderr carries structured stage logs. Do not treat stderr content as failure evidence.
Key flags:
--output <dir>-- override vault root location--topic <slug>-- override the topic slug--include <pattern>-- re-include paths that would otherwise be ignored (repeatable)--exclude <pattern>-- exclude additional paths from scanning (repeatable)--semantic-- enable semantic analysis when adapters support it
Read references/cli-ingest-codebase.md for the full flag table and output schema.
Inspect the Vault
Run inspect subcommands to analyze code quality and architecture.
Shared flags for all inspect subcommands:
--format json-- always use JSON for programmatic parsing--vault <path>-- explicit vault root (omit to auto-discover from cwd)--topic <slug>-- explicit topic slug (omit if only one topic exists)
Tabular Subcommands
These return a list of rows sorted by the primary metric:
1. smells -- List symbols and files with detected code smells.
kb inspect smells --format json
kb inspect smells --type high-complexity --format json2. dead-code -- List dead exports and orphan files.
kb inspect dead-code --format json3. complexity -- Rank functions/methods by cyclomatic complexity. Default top 20.
kb inspect complexity --format json
kb inspect complexity --top 50 --format json4. blast-radius -- Rank symbols by transitive dependent count.
kb inspect blast-radius --format json
kb inspect blast-radius --min 10 --top 20 --format json5. coupling -- Rank files by instability (Ce / (Ca + Ce)).
kb inspect coupling --format json
kb inspect coupling --unstable --format json6. circular-deps -- List files participating in circular import chains.
kb inspect circular-deps --format jsonDetail Lookup Subcommands
These return field-value pairs for a single matched entity:
7. symbol \<name\> -- Case-insensitive substring match. Returns detail fields for a single match, or a summary table for multiple matches.
kb inspect symbol parseConfig --format json8. file \<path\> -- Exact source path lookup. Use the source-relative path as stored in vault frontmatter.
kb inspect file src/config.ts --format jsonRelation Subcommands
These return relation edges (target_path, type, confidence):
9. backlinks \<name-or-path\> -- Incoming references. Accepts a symbol name or file path.
kb inspect backlinks parseConfig --format json10. deps \<name-or-path\> -- Outgoing dependencies. Accepts a symbol name or file path.
kb inspect deps src/config.ts --format jsonRead references/cli-inspect.md for all column schemas and flag details.
Index the Vault
Index the vault content into QMD for search. This step requires QMD on PATH.
kb index --topic <slug>The command is idempotent: it checks whether the collection already exists and chooses add (create) or update (refresh) automatically.
Key flags:
--embed(default true) -- run embedding after syncing files--force-embed-- force re-embedding all documents--context <text>-- attach human context to improve search relevance--name <name>-- override the derived collection name
Read references/cli-search-index.md for the full output schema.
Search the Vault
Search indexed vault content with QMD. Requires a prior kb index run.
kb search "<query>" --topic <slug> --format jsonSearch modes:
- Hybrid (default) -- combines lexical and vector search
- Lexical (
--lex) -- BM25 keyword search only - Vector (
--vec) -- embedding-based semantic search
The --lex and --vec flags are mutually exclusive. Omit both for hybrid mode.
Key flags:
--limit N(default 10) -- maximum results--min-score N-- minimum relevance threshold--full-- return full document content instead of snippets--all-- return all matches above the minimum score
Read references/cli-search-index.md for full details.
KB Maintenance Procedures
Procedure 1: Compile a wiki article
1. Read references/compilation-guide.md to anchor on length, style, wikilink density, and sourcing rules. 2. Identify candidate sources via kb search "<topic phrase>" --topic <slug> or read <topic>/wiki/index/Source Index.md. 3. Load the candidate raw sources fully into context. 4. Load <topic>/wiki/index/Concept Index.md for orientation on existing articles and wikilink targets (including in other topics). 5. Surface takeaways BEFORE drafting. Present to the user: 3-5 key takeaways from the sources, the entities/concepts this article will introduce or update, and anything that contradicts existing wiki articles. Ask: "Anything specific to emphasize or de-emphasize?" Wait for the response. Skip this step only if the user has explicitly asked for autonomous compilation. 6. Write the article to <topic>/wiki/concepts/<Article Title>.md following the obsidian-markdown skill for wikilink, callout, and frontmatter syntax. Use the frontmatter schema from references/frontmatter-schemas.md. Target 3000-4000 words with a Sources section, wikilinks to related articles, and code or diagram blocks where applicable. 7. Backlink audit -- do not skip. Grep every existing article in <topic>/wiki/concepts/ for mentions of the new article's title, aliases, or core entities. For each match, add a [[New Article]] wikilink at the first mention (and one later occurrence). This is the step most commonly skipped -- a compounding wiki depends on bidirectional links.
grep -rln "<new article title or key term>" <topic>/wiki/concepts/8. Update the topic's indexes (Procedure 2). 9. Update <topic>/CLAUDE.md current-articles list. 10. Re-index the topic's collection: kb index --topic <slug>. 11. Append an entry to <topic>/log.md (Procedure 5) -- e.g., ## [YYYY-MM-DD] compile | <Article Title> (<word_count> words, <N> sources).
When updating an existing article (rather than writing new), use the Current / Proposed / Reason / Source diff format and contradiction-sweep workflow described in references/compilation-guide.md.
Procedure 2: Maintain topic indexes
After adding, renaming, or removing any wiki article:
1. <topic>/wiki/index/Dashboard.md -- update article count, total word count, featured sections, and any Obsidian Base embeds (use the obsidian-bases skill to author .base files and embed them). 2. <topic>/wiki/index/Concept Index.md -- insert/update the article row alphabetically with its one-line summary. 3. <topic>/wiki/index/Source Index.md -- for each new article, append rows for every source it cites, with a wikilink back to the article. 4. Optionally refresh the live view in Obsidian with the obsidian-cli skill (obsidian open <path>, obsidian search <query>).
Procedure 3: Query the wiki and file back the answer
A query has two phases: Phase A produces the answer by reading the wiki (never from general knowledge); Phase B files the answer back so the exploration compounds.
Precondition: Identify which topic(s) the question belongs to. If the question spans topics, load each topic's Concept Index.
Phase A -- Answer from the wiki
1. Read the topic's Concept Index first (<topic>/wiki/index/Concept Index.md). Scan the full index to identify candidate articles. Do NOT answer from general knowledge -- the wiki is the source of truth, even when the answer seems obvious. A contradiction between the wiki and general knowledge is itself valuable signal. 2. Locate relevant articles. At small scale (<30 articles), the index is enough. At larger scale, supplement with kb search "<phrase>" --topic <slug>. Also grep the topic for keywords: grep -rl "<keyword>" <topic>/wiki/concepts/. 3. Read the identified articles in full. Follow one level of [[wikilinks]] when targets look relevant to the question. Stop at one hop -- deeper traversal wastes context. 4. (Optional) Pull in raw sources if an article's claim is ambiguous and its sources: frontmatter points at a specific raw file worth verifying. 5. Synthesize the answer with these properties:
- Grounded in the wiki articles you just read -- every factual claim traces back to a
[[Wiki Article]]citation. - Notes agreements and disagreements between articles when they exist.
- Flags gaps explicitly: "The wiki has no article on X" or "[[Article Y]] does not yet cover Z".
- Suggests follow-up ingest targets or open questions.
6. Match format to question type:
- Factual → prose with inline
[[wikilink]]citations. - Comparison → table with rows per alternative, citations in cells.
- How-it-works → numbered steps with citations.
- What-do-we-know-about-X → structured summary with "Known", "Open questions", "Gaps".
- Visual → ASCII/Mermaid diagram, Marp deck (see
references/tooling-tips.md), or matplotlib chart.
Phase B -- File back the answer
7. Save the answer to <topic>/outputs/queries/<YYYY-MM-DD> <Question Slug>.md with frontmatter: type: output, stage: query, informed_by: ["[[Article 1]]", "[[Article 2]]"]. See references/frontmatter-schemas.md for the full schema. 8. In the body, list which wiki articles informed the answer under informed_by: (as wikilinks) and call out new insights that should be absorbed back into those articles on the next compile pass. 9. When a filed-back insight contradicts or extends an article's claims, recompile the affected articles (Procedure 1). 10. Promote to wiki when the synthesis is durable. If the answer is a first-class reference (a comparison table, a trade-off analysis, a new concept synthesized from multiple articles), copy it to <topic>/wiki/concepts/<Title>.md following Procedure 1 standards and update the indexes (Procedure 2). Karpathy's pattern treats strong query answers as wiki citizens, not secondary artifacts. 11. Append to `<topic>/log.md` (Procedure 5) -- e.g., ## [YYYY-MM-DD] query | <Question Slug> plus a second line ## [YYYY-MM-DD] promote | <Title> if promoted.
Anti-patterns to avoid:
- Answering from memory -- always read the wiki pages. The wiki may contradict what you think you know.
- No citations -- every factual claim must trace back to a
[[wikilink]]. - Skipping the save -- good query answers compound the wiki's value. Always file to
outputs/queries/; promote when durable. - Silent gaps -- surface missing coverage explicitly so the next ingest pass can fill it.
Procedure 4: Lint and heal
Run structural lint via the kb CLI:
kb lint <slug> --saveThis checks dead wikilinks, orphan articles, missing source references, format violations, and stale content, saving a dated report to <topic>/outputs/reports/. For each issue, propose the fix with a diff before applying -- do not batch-apply changes:
- Dead wikilink -- either create the missing article (Procedure 1) or rewrite the wikilink to point at an existing article.
- Orphan article -- add incoming wikilinks from at least one related article, or remove the article if it is outside the topic's scope.
- Missing source file -- an article's
sources:frontmatter references a file absent fromraw/. Either re-ingest (kb ingest url/file) or correct the reference. - Stale content -- article's
updated:date is older than its source'sscraped:date. Recompile with current sources. - Format violation -- fix missing frontmatter fields, H1 title, lead paragraph, or Sources section.
For deeper LLM-driven self-healing checks (inconsistencies across articles, missing coverage, wikilink audits, filed-back query absorption), read references/lint-procedure.md.
After the heal pass, append ## [YYYY-MM-DD] lint | <N> issues found, <M> fixed to <topic>/log.md.
Procedure 5: Append to log.md
The kb CLI auto-appends log entries for ingest and lint --save operations. Manual entries are needed for compile, query, promote, and split operations.
Format -- each entry is a single H2 heading with a consistent prefix so the log stays grep-able:
## [YYYY-MM-DD] <op> | <short description>Where <op> is one of compile, query, promote, or split (ingest and lint are handled by kb).
Examples:
## [2026-04-04] compile | Transformer Architecture (3847 words, 6 sources)
## [2026-04-04] query | 2026-04-04 flash-attention-vs-paged-attention.md
## [2026-04-04] promote | FlashAttention vs PagedAttention (from query)
## [2026-04-05] split | "Inference Optimization" → KV Cache, Speculative DecodingOptionally add a body paragraph under each entry with more context (key findings, source urls, decisions made). Keep entries terse -- the log is for skimming, not prose.
Quick recent-activity check -- the consistent prefix lets unix tools query the log:
grep "^## \[" <topic>/log.md | tail -10 # last 10 events
grep "^## \[.*compile" <topic>/log.md | wc -l # total compiles
grep "^## \[2026-04" <topic>/log.md # April 2026 eventsKeep log.md at the topic root (not inside wiki/ or outputs/) so it sits alongside CLAUDE.md as a first-class topic artifact.
Output Format Selection
All inspect and search commands support --format:
- json -- always use for programmatic parsing
- table -- human-readable aligned columns (default)
- tsv -- tab-separated for piping to Unix tools
The ingest codebase and index commands always output JSON to stdout.
Read references/output-formats.md for format examples and empty result handling.
Error Handling
CLI Errors
| Error | Recovery |
|---|---|
unable to find a vault from <path> | Run kb ingest codebase <path> --topic <slug> first |
QMD is not available | Run npm install -g @tobilu/qmd |
no topics were found | Run kb ingest codebase or kb topic new to populate the vault |
multiple topics were found | Re-run with --topic <slug> |
no symbols matched "<query>" | Use inspect smells or inspect complexity to discover valid names |
no file matched "<path>" | Use exact source-relative path from vault frontmatter (e.g. src/config.ts not ./src/config.ts) |
KB Workflow Errors
| Error | Recovery |
|---|---|
kb not found | Install the kb binary and ensure it is on PATH. Verify with kb version |
| Topic not found | Run kb topic list to see available topics, or scaffold with kb topic new |
| Article exceeds 4000 words | Extract a sub-topic into its own article and wikilink to it |
| Cross-topic wikilink ambiguity | Disambiguate with full path: `[[other-topic/wiki/concepts/Article Name\ |
log.md missing in existing topic | Create manually and backfill from git: `git log --format='## [%ad] <op> \ |
Read references/error-handling.md for the full error catalog with causes and recovery steps.
Constraints
MUST DO
- Run
kb ingest codebasebefore any inspect command on that topic - Use
--format jsonwhen parsing output programmatically - Use
--progress neverwhen runningkb ingest codebasein a non-interactive context - Parse stdout only for command output; treat stderr as diagnostics
- Use the
topicSlugfrom ingest output for subsequent--topicflags - Read
references/compilation-guide.mdbefore writing wiki articles - Run backlink audits after every article compile (Procedure 1, step 7)
- File query answers to
outputs/queries/(Procedure 3) - Append manual log entries for compile, query, promote, and split operations
MUST NOT DO
- Pass both
--lexand--vectosearch - Pass
--force-embedwith--embed=falsetoindex - Treat stderr content as failure evidence for
kb ingest codebase - Assume vault location without running ingest or checking for
.kb/vault/ - Use relative paths like
./src/config.tsforinspect file-- usesrc/config.tsinstead - Answer wiki queries from general knowledge -- the wiki is the source of truth
- Skip the backlink audit when compiling articles
- Batch-apply lint fixes without proposing diffs first
Architecture and Rationale
The Karpathy Knowledge Base Pattern treats the LLM as a compiler that reads raw source documents and produces a structured, cross-linked markdown wiki. No vector database, no embedding pipeline, no retrieval ranking — the wiki itself is the knowledge base, and at personal scale (~100 articles, ~400K words) it fits entirely in a modern context window.
Described by Andrej Karpathy in April 2026 in LLM Wiki: Knowledge Base Pattern, with conceptual roots in Vannevar Bush's Memex (1945) — a personal, curated knowledge store with associative trails between documents. Bush's unsolved problem was who does the maintenance. LLMs solve that: they don't get bored, don't forget cross-references, and can touch 15 files in one pass.
Core thesis
You never write the wiki. The LLM writes everything. You just steer, and every answer compounds.
Three converging capabilities enable the pattern:
1. 1M+ token context windows let the full wiki load into a single LLM call. 2. LLM writing quality is sufficient to produce technically rigorous reference articles. 3. Markdown + Obsidian gives inspectable, editable, scriptable, versionable, renderable files with no lock-in.
The human contributes judgment, taste, and direction. The LLM contributes exhaustive cross-referencing, consistent formatting, tireless compilation, and gap identification.
Three-op core vs four-phase extension
Karpathy's original gist frames the pattern as three operations: Ingest, Query, Lint. In his flow, ingest is active — the LLM reads the source, discusses it, writes a summary page, and updates 10-15 related wiki pages in one pass. "Compile" is folded into ingest.
This skill splits ingest into two distinct phases — ingest (scrape + stage into raw/ immutably) and compile (LLM reads raw/, writes wiki/concepts/) — for three reasons:
1. Multi-topic vaults. A source may arrive weeks before it has enough companions to compile a rigorous 3000-4000-word article. Staging decouples acquisition from synthesis. 2. Batch scraping. Tools like firecrawl and tweetsmash-api produce clusters of raw material. Staging them first lets the LLM pick the compile order. 3. Reproducibility. raw/ is immutable — a compiled article can always be re-derived from its sourced files.
The four-phase loop:
┌──────────────┐
│ 1. INGEST │ Scrape / curate → raw/ (immutable)
└──────┬───────┘
│
v
┌──────────────┐
│ 2. COMPILE │ LLM reads raw/, writes wiki/concepts/
└──────┬───────┘
│
v
┌──────────────┐
│ 3. QUERY │ Q&A against wiki → outputs/queries/, promote strong answers to wiki/
└──────┬───────┘
│
v
┌──────────────┐
│ 4. LINT │ Find gaps, fix errors, suggest articles
└──────┬───────┘
│
└──────→ back to Phase 1Every phase ends with an append to <topic>/log.md. Each phase enhances the next. The cycle runs continuously — the knowledge base is always growing, always improving.
Phase 1: Ingest
Raw source material enters through the kb CLI and is staged immutably:
kb ingest url <url> --topic <slug> # web articles, blog posts, papers → raw/articles/
kb ingest file <path> --topic <slug> # local files (PDF, DOCX, EPUB, images w/OCR) → raw/articles/
kb ingest youtube <url> --topic <slug> # YouTube transcripts → raw/youtube/
kb ingest bookmarks <path> --topic <slug> # bookmark clusters → raw/bookmarks/
kb ingest codebase <path> --topic <slug> # codebase analysis → raw/codebase/The CLI auto-generates frontmatter and appends a log entry for each ingest. Principle: capture broadly, filter later. It is better to ingest something irrelevant than to miss something valuable. Never edit files in raw/ after ingestion — if a source changes, re-scrape as a new version.
Phase 2: Compile
The LLM reads raw sources and produces structured wiki articles:
1. Load the topic's Concept Index for orientation. 2. Load the target article (if updating). 3. Load relevant raw sources. 4. Write the article with structured sections, [[wikilinks]], code examples, source attributions, technical depth suitable for senior practitioners. 5. Write to wiki/concepts/<Article Title>.md.
Compile foundational articles first so dependent articles can wikilink to them.
Phase 3: Query and enhance
With 1M+ context, load the full wiki (or a relevant subset) and answer complex cross-article queries that would challenge traditional retrieval:
- "Compare approaches to X across all frameworks discussed."
- "What are the gaps in our coverage of Y?"
- "Synthesize arguments for and against Z."
Every answer gets filed back to outputs/queries/<YYYY-MM-DD> <slug>.md. On the next compile pass, insights from filed-back queries get absorbed into the wiki articles themselves. When an answer is strong enough to stand as a first-class reference (a comparison table, a concept synthesized from multiple articles, a novel trade-off analysis), promote it to `wiki/concepts/` following Procedure 1 (Compile) standards. Karpathy's pattern treats strong query answers as equal citizens of the wiki, not secondary artifacts. This is the compounding mechanism — explorations become reusable knowledge.
Phase 4: Lint and heal
The kb CLI handles automated structural checks:
kb lint <slug> --save # dead links, orphans, missing sources, format violations, stale contentThe LLM handles deeper semantic healing that requires reading articles and applying judgment:
- Missing coverage — topics referenced in N articles but lacking their own
- Inconsistencies — contradictory claims across articles
- Filed-back query absorption — query insights not yet integrated into cited articles
The lint pass leaves the knowledge base in a better state than it found it. This is the self-healing property.
Why markdown + Obsidian
Five properties:
- Inspectable — plain text, any editor, no opaque database.
- Editable — humans can correct errors directly without an API layer.
- Scriptable — grep, sed, and programming languages process the corpus trivially.
- Versionable — git tracks every change, every compilation can be reviewed.
- Renderable — Obsidian gives graph view, backlinks, full-text search, plugin ecosystem.
No lock-in. If Obsidian disappears the files are still markdown. If the LLM changes the files are still text.
Context window vs RAG
| Concern | RAG | Karpathy KB |
|---|---|---|
| Retrieval | Embedding + vector DB + ranking | Load into context |
| Relevance | Depends on embedding quality | LLM reads everything relevant |
| Cross-article reasoning | Multi-retrieval with fusion | Natural, all in context |
| Infrastructure | Vector DB, pipeline, tuning | File system + LLM |
| Per-query cost | Low | Higher |
| Answer quality on synthesis | Medium | High |
Karpathy KB trades higher per-query cost for dramatically simpler infrastructure and higher synthesis quality. For personal/team knowledge bases with moderate query volume and a premium on answer quality, the tradeoff is favorable. For high-volume production (millions of queries/day), traditional RAG remains more cost-effective.
Target scale
A mature knowledge base: 100+ articles, 400K+ words total, dense cross-linking. At this scale, queries produce insights that combine information from articles originally compiled from completely independent raw sources. The knowledge base becomes more than the sum of its inputs.
Future direction: knowledge in weights
The pattern's trajectory: wiki → synthetic QA pairs → QLoRA fine-tune → domain-expert model. The knowledge moves from context into parameters, enabling faster inference and deployable domain expertise.
Multi-topic vaults
Each top-level folder at the vault root is a topic — a self-contained subject with its own raw/, wiki/, outputs/, bases/ subtrees plus CLAUDE.md and log.md at the topic root. All topics share one Obsidian vault at the root, so cross-topic wikilinks work naturally (e.g., an ai-harness article on embeddings can link to a rust-systems article on implementation details). Topics stay self-contained in terms of content but contribute to a unified knowledge graph.
Each topic has its own CLAUDE.md (symlinked to AGENTS.md for Codex parity) capturing topic-specific scope, current articles, and research gaps — this IS the schema document in Karpathy's terminology. The vault-root CLAUDE.md captures the shared Karpathy pattern itself.
The log.md audit trail
Every topic carries a log.md at its root — an append-only, chronological record of every knowledge-base operation. Each entry is a single H2 heading with a consistent grep-able prefix:
## [YYYY-MM-DD] <op> | <short description>Ops: ingest, compile, query, promote, split, lint. The consistent prefix means unix tools can query the log without special parsing:
grep "^## \[" log.md | tail -10 # recent activity
grep "compile" log.md | wc -l # total compilesThe log is distinct from git history. Git records what changed in the files; log.md records what the knowledge base did as a system — decisions made, insights synthesized, gaps identified. Both coexist. The log is the operational memory; git is the version control.
The wiki is a git repo
The wiki is just a directory of markdown files under git. No database, no server, no API — you get version history, branching, diffs, blame, and collaboration for free. Every compile and lint pass is a reviewable commit. If Obsidian disappears, the files are still markdown. If the LLM changes, the files are still text. This is the no-lock-in guarantee.
Ingest Codebase Command Reference
Usage
kb ingest codebase <path> [flags]The <path> argument is the root directory of the source repository to analyze (required).
Flags
| Flag | Type | Default | Description |
|---|---|---|---|
--topic | string | "" | Topic slug for the ingested codebase (derived from directory name if omitted) |
--output | string | "" | Vault root where the generated topic will be written. Defaults to <path>/.kb/vault |
--title | string | "" | Override the generated topic title |
--domain | string | "" | Override the generated topic domain |
--include | string[] | nil | Re-include a path pattern that would otherwise be ignored; repeatable |
--exclude | string[] | nil | Exclude an additional path pattern from scanning; repeatable |
--semantic | bool | false | Enable semantic analysis when the underlying adapters support it |
--progress | string | auto | Progress rendering mode: auto, always, or never |
--log-format | string | text | Stderr event format: text or json |
Non-Interactive Usage
When invoking from an agent context, always set --progress never to prevent TTY progress bars from corrupting stdout output.
kb ingest codebase /path/to/repo --topic my-project --progress neverPipeline Stages
The codebase ingestion pipeline executes these stages in order:
1. scan -- Discover source files by language 2. select_adapters -- Choose language parsers (tree-sitter for TS/JS, Go parser) 3. parse -- Extract AST nodes, symbols, and relations 4. normalize -- Merge per-file graphs into a unified snapshot, resolve imports 5. metrics -- Compute complexity, coupling, blast radius, dead code, smells 6. render -- Generate markdown documents and Base definitions 7. write -- Persist vault files to disk
Supported Languages
| Language | Extensions | Adapter |
|---|---|---|
| TypeScript | .ts | tree-sitter |
| TSX | .tsx | tree-sitter |
| JavaScript | .js | tree-sitter |
| JSX | .jsx | tree-sitter |
| Go | .go | tree-sitter |
Output Schema (GenerationSummary)
The command writes JSON to stdout. Parse the following fields:
{
"command": string, // always "generate"
"rootPath": string, // absolute path to the analyzed repository
"vaultPath": string, // absolute path to the vault root
"topicPath": string, // absolute path to the topic directory
"topicSlug": string, // topic identifier (use for --topic in later commands)
"filesScanned": int, // total files discovered
"filesParsed": int, // files successfully parsed
"filesSkipped": int, // files skipped (unsupported or excluded)
"symbolsExtracted": int, // total symbols extracted
"relationsEmitted": int, // total relation edges
"rawDocumentsWritten": int, // per-file markdown documents
"wikiDocumentsWritten": int, // concept wiki articles
"indexDocumentsWritten": int, // index pages
"timings": {
"scanMillis": int,
"selectAdaptersMillis": int,
"parseMillis": int,
"normalizeMillis": int,
"metricsMillis": int,
"renderMillis": int,
"writeMillis": int,
"totalMillis": int
},
"diagnostics": [ // structured warnings/errors
{
"code": string,
"severity": "warning" | "error",
"stage": "scan" | "parse" | "render" | "write" | "validate",
"message": string,
"filePath": string?,
"language": string?,
"detail": string?
}
]
}Vault Structure
After ingestion, the vault directory contains:
<vaultPath>/<topicSlug>/
raw-codebase/ # One markdown file per source file with frontmatter and code
wiki-concept/ # Compiled concept articles
wiki-index/ # Index pages for navigation
*.base # Obsidian Base view definitions (YAML)
CLAUDE.md # Topic marker fileDefault Path Derivation
- If
--outputis omitted: vault path defaults to<rootPath>/.kb/vault - If
--topicis omitted: topic slug is derived from the repository directory name - Full topic path:
<vaultPath>/<topicSlug>/
Inspect Command Reference
Usage
kb inspect <subcommand> [flags]Shared Flags (All Subcommands)
| Flag | Type | Default | Description |
|---|---|---|---|
--format | string | table | Output format: table, json, or tsv |
--vault | string | "" | Vault root path (auto-discovered from cwd if omitted) |
--topic | string | "" | Topic slug inside the vault (auto-detected if only one topic exists) |
Vault Auto-Discovery
When --vault is omitted, the CLI walks up from the current working directory looking for .kb/vault/. If --topic is omitted and only one topic exists, it is selected automatically. If multiple topics exist, the command fails with an error listing available slugs.
---
Subcommands
1. smells
List symbols and files with detected code smells.
kb inspect smells [--type <smell-type>] [--format json]Flags: --type (string) -- filter to a specific smell type (e.g., long-function, high-complexity, dead-export, orphan-file, god-file)
Output Columns:
| Column | Type | Description |
|---|---|---|
kind | string | "symbol" or "file" |
name | string | Symbol name or file source path |
source_path | string | Source-relative file path |
symbol_kind | string | Symbol kind (empty for files) |
smells | string[] | List of detected smell types |
---
2. dead-code
List dead exports and orphan files.
kb inspect dead-code [--format json]Output Columns:
| Column | Type | Description |
|---|---|---|
kind | string | "symbol" or "file" |
name | string | Symbol name or file source path |
source_path | string | Source-relative file path |
symbol_kind | string | Symbol kind (empty for files) |
reason | string | "dead-export" or "orphan-file" |
smells | string[] | List of detected smell types |
---
3. complexity
Rank functions by cyclomatic complexity (descending).
kb inspect complexity [--top N] [--format json]Flags: --top (int, default 20) -- maximum number of rows to return
Output Columns:
| Column | Type | Description |
|---|---|---|
symbol_name | string | Function or method name |
symbol_kind | string | "function" or "method" |
source_path | string | Source-relative file path |
cyclomatic_complexity | int | Cyclomatic complexity score |
loc | int | Lines of code |
blast_radius | int | Transitive dependents count |
smells | string[] | Detected smell types |
---
4. blast-radius
Rank symbols by blast radius (how many symbols transitively depend on a given symbol).
kb inspect blast-radius [--min N] [--top N] [--format json]Flags:
--min(int, default 0) -- minimum blast radius threshold--top(int, default 0) -- maximum rows to return (0 = all)
Output Columns:
| Column | Type | Description |
|---|---|---|
symbol_name | string | Symbol name |
source_path | string | Source-relative file path |
blast_radius | int | Count of unique transitive dependents |
centrality | float | Betweenness centrality score (0-1) |
external_reference_count | int | References from outside the symbol's module |
smells | string[] | Detected smell types |
---
5. coupling
Rank files by instability (Martin coupling metric).
kb inspect coupling [--unstable] [--format json]Flags: --unstable (bool) -- only show files with instability > 0.5
Output Columns:
| Column | Type | Description |
|---|---|---|
source_path | string | Source-relative file path |
afferent_coupling | int | Files that import this file (Ca) |
efferent_coupling | int | Files this file imports (Ce) |
instability | float | Ce / (Ca + Ce); 1.0 = completely unstable |
has_circular_dependency | bool | Participates in a circular import chain |
smells | string[] | Detected smell types |
---
6. symbol \<name\>
Lookup symbols by case-insensitive substring match.
kb inspect symbol <name> [--format json]Behavior:
- No matches: Returns error with suggestion to use
inspect smellsorinspect complexity - Single match: Returns detailed field-value pairs (see detail output below)
- Multiple matches: Returns summary table
Summary Table Columns (multiple matches):
| Column | Type | Description |
|---|---|---|
symbol_name | string | Symbol name |
symbol_kind | string | Symbol kind |
source_path | string | Source-relative file path |
start_line | int | Start line in source |
language | string | Source language |
smells | string[] | Detected smell types |
Detail Fields (single match):
| Field | Type |
|---|---|
relative_path | string |
symbol_name | string |
symbol_kind | string |
source_path | string |
language | string |
exported | bool |
start_line | int |
end_line | int |
signature | string |
loc | int |
blast_radius | int |
centrality | float |
cyclomatic_complexity | int |
external_reference_count | int |
is_dead_export | bool |
is_long_function | bool |
smells | string[] |
outgoing_relations | relation[] |
backlinks | relation[] |
Each relation entry has: target_path (string), type (string: imports|calls|references), confidence (string: semantic|syntactic).
---
7. file \<path\>
Lookup a file by its exact source path.
kb inspect file <path> [--format json]Detail Fields:
| Field | Type |
|---|---|
relative_path | string |
source_path | string |
language | string |
symbol_count | int |
symbols | string[] (name + kind pairs) |
afferent_coupling | int |
efferent_coupling | int |
instability | float |
is_orphan_file | bool |
is_god_file | bool |
has_circular_dependency | bool |
smells | string[] |
outgoing_relations | relation[] |
backlinks | relation[] |
---
8. backlinks \<name-or-path\>
Show incoming references for a symbol or file.
kb inspect backlinks <name-or-path> [--format json]Entity Resolution: Tries exact file path match first, falls back to single symbol name match.
Output Columns:
| Column | Type | Description |
|---|---|---|
target_path | string | Path of the referencing entity |
type | string | Relation type: imports, calls, references |
confidence | string | semantic or syntactic |
---
9. deps \<name-or-path\>
Show outgoing dependencies for a symbol or file.
kb inspect deps <name-or-path> [--format json]Entity Resolution: Same as backlinks (file path first, then symbol name).
Output Columns:
| Column | Type | Description |
|---|---|---|
target_path | string | Path of the dependency |
type | string | Relation type: imports, calls, references |
confidence | string | semantic or syntactic |
---
10. circular-deps
List files that participate in circular dependencies.
kb inspect circular-deps [--format json]Behavior:
- If cycles exist: returns a table of participating files
- If no cycles: returns
{"message": "no circular dependencies found"}
Output Columns (when cycles exist):
| Column | Type | Description |
|---|---|---|
source_path | string | Source-relative file path |
afferent_coupling | int | Files that import this file |
efferent_coupling | int | Files this file imports |
instability | float | Coupling instability metric |
smells | string[] | Detected smell types |
Search and Index Command Reference
Both commands require the QMD binary on PATH. Install with npm install -g @tobilu/qmd.
---
Search Command
Usage
kb search <query> [flags]The <query> argument is the search text (required, non-empty).
Flags
| Flag | Type | Default | Description |
|---|---|---|---|
--lex | bool | false | Use BM25 keyword search only |
--vec | bool | false | Use vector similarity search only |
--limit | int | 10 | Maximum number of results to return |
--min-score | float | 0 | Minimum score threshold for returned matches |
--full | bool | false | Show the full matched document content instead of snippets |
--all | bool | false | Return all matches above the minimum score threshold |
--collection | string | "" | Use an explicit QMD collection name instead of deriving from the topic |
--format | string | table | Output format: table, json, or tsv |
--vault | string | "" | Vault root path (used when deriving the collection name) |
--topic | string | "" | Topic slug (used when deriving the collection name) |
Search Modes
| Mode | Flag | QMD Command | Description |
|---|---|---|---|
| Hybrid | (default) | query | Combines lexical and vector search |
| Lexical | --lex | search | BM25 keyword search only |
| Vector | --vec | vsearch | Embedding-based semantic search |
The --lex and --vec flags are mutually exclusive. Omit both for hybrid mode.
Output Columns
| Column | Type | Description |
|---|---|---|
path | string | Vault-relative path of the matched document |
score | float | Relevance score |
preview | string | Snippet of matched content (or full content if --full is set) |
Collection Name Derivation
When --collection is omitted, the collection name is derived from the topic slug: 1. Resolve the vault and topic (same logic as inspect commands) 2. Use the topicSlug as the collection name
Example Invocations
# Hybrid search (default)
kb search "authentication middleware" --format json
# Lexical search with higher result limit
kb search "parseConfig" --lex --limit 20 --format json
# Vector search with score threshold
kb search "error handling patterns" --vec --min-score 0.5 --format json
# Full document content
kb search "auth" --full --format json
# Explicit collection name
kb search "auth" --collection my-project --format json---
Index Command
Usage
kb index [flags]Flags
| Flag | Type | Default | Description |
|---|---|---|---|
--vault | string | "" | Vault root path |
--topic | string | "" | Topic slug inside the vault |
--name | string | "" | Override the derived QMD collection name |
--embed | bool | true | Run embedding after syncing files |
--force-embed | bool | false | Force re-embedding all documents |
--context | string | "" | Attach human-written collection context to improve search relevance |
Idempotent Behavior
The index command is idempotent. It checks qmd status first and selects the operation:
- If the collection already exists: performs an update (syncs changes)
- If the collection does not exist: performs an add (creates and populates)
Run kb index repeatedly without side effects.
Output Schema (indexResultPayload)
{
"collectionName": string, // QMD collection name (= topic slug or --name override)
"embedRequested": bool, // whether --embed was true
"embedResult": { // present only if embedding was performed
"docsProcessed": int,
"chunksEmbedded": int,
"errors": int,
"durationMs": int
},
"forceEmbed": bool, // whether --force-embed was set
"status": {
"collection": { // null if collection was just created
"name": string,
"path": string,
"pattern": string,
"documents": int,
"lastUpdated": string
},
"hasVectorIndex": bool,
"needsEmbedding": int,
"totalDocuments": int
},
"topicPath": string, // absolute path to the topic directory
"topicSlug": string, // topic identifier
"updateResult": {
"collections": int,
"indexed": int,
"updated": int,
"unchanged": int,
"removed": int,
"needsEmbedding": int
},
"vaultPath": string // absolute path to the vault root
}Example Invocations
# Index with default settings (embed enabled)
kb index
# Index with custom context for search relevance
kb index --context "React application with Redux state management"
# Force re-embedding all documents
kb index --force-embed
# Index without embedding (sync files only)
kb index --embed=false
# Index with explicit vault and topic
kb index --vault /path/to/vault --topic my-project
# Index with custom collection name
kb index --name custom-collectionWiki Article Compilation Guide
Writing standards for articles in <topic>/wiki/concepts/. These are the primary output of the knowledge base and the interface the LLM answers queries against.
Target characteristics
- Length: 3000-4000 words. Split into sub-articles when exceeded.
- Audience: senior practitioners in the topic's field. Assume foundational literacy; explain domain-specific terms on first use.
- Standalone: a reader should be able to learn the topic from one article alone.
- Dense wikilinks: target 10-30
[[wikilinks]]per article, including cross-topic links where relevant. - Cited: every factual claim traces back to a file in
raw/listed undersources:frontmatter.
Voice and style
- Domain knowledge, not personal wiki. Write as a reference anyone in the field could use. No "what this means for [person]" sections. No builder profiles. No first-person narration.
- Declarative, technical, neutral. Avoid hype. Avoid hedging. State what is true, with sources backing it.
- Concrete examples. Prefer code blocks, tables, and diagrams over prose when describing structures, comparisons, or flows.
Required sections
Every wiki article has:
1. H1 title — matches the filename. 2. Lead paragraph — 2-4 sentences establishing what the topic is, why it matters, and scoping the article. 3. Core sections (H2) — the substantive body. Exact structure depends on the topic but should follow a consistent hierarchy. 4. Sources and Further Reading — bulleted list of every cited source plus related wikilinks.
Optional sections depending on topic:
- Comparison tables — when the article surveys alternatives
- Code examples — runnable snippets demonstrating the concepts
- Architecture diagrams — ASCII or Mermaid
- Trade-offs — explicit pros/cons when the topic has design tensions
- Future direction — where the field is heading, if well-established
Wikilink density
Wikilinks are the knowledge graph. Every mention of a related concept should be a wikilink on first occurrence, and ideally a second time in a later section. Examples of good density:
- Mention of another concept article →
[[Concept Name]] - Mention of a protocol, tool, or framework that has its own article →
[[Tool Name]] - Cross-topic reference →
[[other-topic/wiki/concepts/Article Name|Display Name]]
Do not wikilink every occurrence of common words. Do not wikilink authors or organizations unless they have their own article.
Sourcing rules
- Every article cites real sources. Do not write from general knowledge alone. If the corpus does not contain the claim, either ingest a new source (
kb ingest url/file) or omit the claim. - Frontmatter `sources:` lists every raw file that informed the article, as wikilinks.
- Inline attributions are allowed but not required. A Sources section at the bottom is mandatory.
- Direct quotes require quotation marks and a source reference.
Anti-patterns
- Articles that summarize a single source — instead, synthesize across multiple sources, or cite the single source as reference and link to the raw file.
- Articles with no incoming wikilinks (orphans) — every article should be reachable via the link graph.
- Articles with no outgoing wikilinks — every article should participate in the graph.
- Prose that could apply to any topic — be specific to this topic's vocabulary, patterns, and tensions.
- Restating prerequisites at length — link to the prerequisite article and move on.
When updating an existing article
1. Load the current article fully. 2. Load any new raw sources that have been added since the last compile. 3. Identify what changed in the sources (new techniques, corrections, new terminology). 4. Propose each change with a structured diff before writing. Present to the user:
Current: <quote the existing text>>
Proposed: <replacement text>>
Reason: <why this change is warranted>>
Source: <raw/ file path or URL backing the new claim>Always include Source. An edit without a source citation creates untraceability — future compile passes won't know why the change was made. Ask for confirmation per page. Do not batch-apply changes.
5. Run a contradiction sweep. If the new information contradicts something in the wiki, the contradicted claim may appear in more than one article. Before rewriting, grep every article for the contradicted claim:
grep -rln "<contradicted claim or key term>" <topic>/wiki/concepts/Update all occurrences, not just the most obvious one. Silent contradictions across articles are the worst failure mode of a multi-article wiki.
6. Check downstream effects. After identifying the primary article to update, grep for [[<Article Title>]] across the topic. For each article that links to the one being updated, ask: does the update change anything that page asserts? If yes, flag it explicitly and offer to update it with the same Current/Proposed/Reason/Source flow.
grep -rln "\[\[<Article Title>" <topic>/wiki/concepts/7. Update the article in place, preserving structure where possible. 8. Bump updated: in frontmatter. 9. Add any new sources: entries. 10. Check that existing wikilinks still resolve; add new ones for newly-introduced concepts.
Backlink audit (compounding bidirectional links)
After writing or renaming any article, run a backlink audit. A compounding wiki depends on bidirectional links — every new article needs incoming links from articles that mention its concepts.
Process:
1. Grep the topic's wiki/concepts/ for mentions of the new article's title, aliases, or core entities:
grep -rln "<new article title or key term>" <topic>/wiki/concepts/2. For each match, open the file and decide whether the mention warrants a wikilink. Add [[New Article]] at the first occurrence, and optionally at a second occurrence in a later section. 3. Skip matches that are inside code blocks or already wikilinked. 4. Skip matches that are incidental (the term appears in a different sense).
This is the step most commonly skipped when authoring articles. A wiki with one-way links is a blog; a wiki with bidirectional links is a knowledge graph.
When to split an article
Split when any of these hold:
- Word count exceeds 4000
- A single H2 section exceeds 1000 words
- The article covers two distinct sub-topics that warrant their own entries
- Multiple other articles would benefit from linking to a sub-section (that sub-section deserves its own article)
After splitting, update the parent article to wikilink to the new sub-article(s) and update the topic's indexes.
When to write a new article (vs extend an existing one)
Write new when:
- Three or more existing articles wikilink to the concept as a dead link
- A query answer keeps synthesizing the same cross-article content (that synthesis deserves its own article)
- The topic is a distinct concept with its own sources, patterns, and terminology
Extend existing when:
- The new material is a refinement, example, or sub-aspect of an existing concept
- The sub-topic would be under 500 words on its own
Error Handling Reference
Categorized error messages from the kb CLI with causes and recovery steps.
Vault Resolution Errors
These occur when inspect, search, or index cannot locate a vault or topic.
| Error Message | Cause | Recovery |
|---|---|---|
unable to find a vault from <path>. walked up looking for .kb/vault/ | No .kb/vault/ directory exists above the working directory | Run kb ingest codebase <path> --topic <slug> first to create the vault |
Vault path was not found or is not a directory: <path> | The --vault flag points to a nonexistent path | Verify the vault path exists and is a directory |
no topics were found in <path>. expected child directories containing CLAUDE.md | The vault directory exists but contains no generated topics | Run kb ingest codebase <path> or kb topic new to populate the vault |
multiple topics were found in <path>: <slug1>, <slug2> | The vault contains more than one topic and no --topic flag was provided | Re-run the command with --topic <slug> to select one |
topic name is required when topic is specified | The --topic flag was provided but with an empty or whitespace-only value | Provide a non-empty topic slug |
Topic path was not found or is not a directory: <path> | The --topic slug does not match any directory in the vault | Check available topic slugs inside the vault directory |
Inspect Lookup Errors
These occur when inspect symbol, inspect file, inspect backlinks, or inspect deps cannot resolve the target entity.
| Error Message | Cause | Recovery |
|---|---|---|
no symbols matched "<query>" | No symbol name contains the query as a case-insensitive substring | Use kb inspect smells or kb inspect complexity to discover valid symbol names |
multiple symbols matched "<query>": <name1>, <name2> | More than one symbol matched the query | Re-run with a more specific query string |
no file matched "<path>" | No file in the vault has the given source_path value | Use the exact source-relative path as stored in vault frontmatter (e.g., src/config.ts not ./src/config.ts) |
no symbol or file matched "<query>" | The query matched neither a file source path nor a symbol name | Re-run with a specific symbol name or an exact source path |
QMD Errors
These occur when search or index cannot communicate with the QMD binary.
| Error Message | Cause | Recovery |
|---|---|---|
<command>: QMD is not available to kb. Install it with 'npm install -g @tobilu/qmd' and ensure 'qmd' is on PATH | The qmd binary was not found on the system PATH | Run npm install -g @tobilu/qmd and verify with qmd --version |
<command>: <qmd error details> | QMD returned an error during execution | Read the stderr diagnostics from QMD for details; common causes include missing collections or corrupted index files |
Flag Validation Errors
These occur before any command execution when flag combinations are invalid.
| Error Message | Cause | Recovery |
|---|---|---|
choose at most one search mode flag: --lex or --vec | Both --lex and --vec were provided to search | Use only one mode selector, or omit both for hybrid mode |
--force-embed cannot be used together with --embed=false | Contradictory embedding flags on index | Remove --force-embed or set --embed=true |
--limit must be >= 1. received <N> | The --limit flag on search was set to zero or negative | Provide a positive integer for --limit |
--min-score must be >= 0. received <N> | The --min-score flag on search was set to a negative value | Provide a non-negative value for --min-score |
--top must be >= 1. received <N> | The --top flag on inspect complexity was set to zero or negative | Provide a positive integer for --top |
--min must be >= 0. received <N> | The --min flag on inspect blast-radius was set to negative | Provide a non-negative integer for --min |
invalid --format "<value>": expected one of "table", "json", "tsv" | An unsupported format string was provided | Use table, json, or tsv |
KB Workflow Errors
These occur during knowledge base maintenance operations.
| Error | Cause | Recovery |
|---|---|---|
kb not found on PATH | The kb binary is not installed or not on PATH | Install the kb binary and verify with kb version |
| Topic not found | The specified topic slug does not exist in the vault | Run kb topic list to see available topics, or scaffold with kb topic new <slug> <title> <domain> |
| Article exceeds 4000 words | A wiki article has grown beyond the recommended length | Extract a sub-topic into its own article and wikilink to it, rather than padding |
| Cross-topic wikilink ambiguity | Two topics contain articles with the same title | Disambiguate with the full path: `[[other-topic/wiki/concepts/Article Name\ |
log.md missing in existing topic | The topic was created before log.md was standard, or it was accidentally deleted | Create manually and backfill from git: `git log --format='## [%ad] <op> \ |
| Log entry conflicts with git | Apparent duplication between log.md and git history | The log is a human/LLM-readable audit trail, not a replacement for git. Let them coexist: git records what changed, log.md records what the knowledge base did |
General Errors
| Error Message | Cause | Recovery |
|---|---|---|
a search query is required | Empty or whitespace-only query passed to search | Provide a non-empty search query string |
a symbol name is required | Empty query passed to inspect symbol | Provide a non-empty symbol name |
a file path is required | Empty path passed to inspect file | Provide a non-empty source path |
a symbol name or file path is required | Empty query passed to inspect backlinks or inspect deps | Provide a non-empty symbol name or file path |
Frontmatter Schemas
All notes in the vault use YAML frontmatter for metadata. The subfolder path identifies the topic; the domain field is a shortcut for Bases and qmd queries.
Conventions:
domain: <short-slug>identifies the topic (e.g.,aiforai-harness/).createdandupdateduse ISO date formatYYYY-MM-DD.tagsalways include the domain plus the note type plus topic-specific tags.sourcesentries are wikilinks pointing at files inraw/.
---
Wiki article — <topic>/wiki/concepts/<Article Title>.md
---
title: Article Title
type: wiki
stage: compiled
domain: <topic-domain>
tags:
- <topic-domain>
- wiki
- topic-specific-tag
- another-topic-tag
created: YYYY-MM-DD
updated: YYYY-MM-DD
sources:
- "[[Source File Name]]"
- "[[Another Source]]"
---Raw article — <topic>/raw/articles/<slug>.md
---
title: Descriptive Title
type: source
stage: raw
domain: <topic-domain>
source_kind: article
source_url: https://example.com/article
scraped: YYYY-MM-DD
tags:
- <topic-domain>
- raw
- topic-specific-tag
---source_kind values: article, github-readme, documentation, paper, blog-post, whitepaper.
GitHub README — <topic>/raw/github/<slug>.md
---
title: Repository or Doc Title
type: source
stage: raw
domain: <topic-domain>
source_kind: github-readme
source_url: https://github.com/owner/repo
scraped: YYYY-MM-DD
tags:
- <topic-domain>
- raw
- github
- topic-specific-tag
---Bookmark cluster — <topic>/raw/bookmarks/<Topic> Bookmarks <Subtopic>.md
---
title: <Topic> Bookmarks <Subtopic>
type: source
stage: raw
domain: <topic-domain>
source_kind: bookmark-cluster
status: seeded
created: YYYY-MM-DD
updated: YYYY-MM-DD
source_urls:
- https://twitter.com/user/status/123
- https://twitter.com/user/status/456
tags:
- <topic-domain>
- bookmarks
- raw
- topic-specific-tag
---status values: seeded, enriched, archived.
Research output — <topic>/outputs/queries/<YYYY-MM-DD> <slug>.md
---
title: Output Title
type: output
stage: query
domain: <topic-domain>
tags:
- <topic-domain>
- output
- query
- topic-specific-tag
created: YYYY-MM-DD
updated: YYYY-MM-DD
informed_by:
- "[[Wiki Article 1]]"
- "[[Wiki Article 2]]"
---stage values for outputs: briefing, query, diagram, lint-report.
Lint report — <topic>/outputs/reports/<YYYY-MM-DD>-lint.md
---
title: Lint Report YYYY-MM-DD
type: output
stage: lint-report
domain: <topic-domain>
tags:
- <topic-domain>
- output
- lint-report
created: YYYY-MM-DD
issues_found: N
issues_fixed: M
---Topic index — Dashboard / Concept Index / Source Index
These files are human-browsed hubs, not research notes. Keep frontmatter minimal:
---
title: Dashboard
type: index
domain: <topic-domain>
updated: YYYY-MM-DD
---Quick reference
| File type | Path | type | stage |
|---|---|---|---|
| Wiki article | wiki/concepts/ | wiki | compiled |
| Raw article | raw/articles/ | source | raw |
| Raw GitHub | raw/github/ | source | raw |
| Raw bookmarks | raw/bookmarks/ | source | raw |
| Briefing | outputs/briefings/ | output | briefing |
| Query result | outputs/queries/ | output | query |
| Diagram | outputs/diagrams/ | output | diagram |
| Lint report | outputs/reports/ | output | lint-report |
| Index | wiki/index/ | index | — |
Lint and Heal Procedure
Run kb lint <slug> --save for automated structural checks (dead wikilinks, orphans, missing sources, format violations, stale content). The report is saved to <topic>/outputs/reports/ and a log entry is auto-appended.
This document covers the deeper LLM-driven checks that require reading articles and applying judgment. Run them periodically or after a batch of new content.
Check 1: Stale content
For each article:
1. Read the article's updated: date and sources: entries. 2. Check each source file's scraped: date (or file mtime). 3. If any source is newer than the article, flag it for recompilation. 4. Also flag articles where the topic has evolved rapidly (e.g., LLM model names, protocol versions) and the article has not been updated in 30+ days.
Check 2: Inconsistencies across articles
Load groups of related articles (identified via shared tags or wikilinks) and check for:
- Contradictory factual claims (e.g., "H100 has 80GB HBM3" vs "H100 has 80GB HBM2e")
- Inconsistent terminology (same concept called two different names across articles)
- Inconsistent formatting (some articles use tables, others prose, for the same kind of comparison)
Fix by picking the correct/canonical version and updating all affected articles.
Check 3: Missing coverage
Scan all articles for wikilinks and identify targets that:
- Are referenced in 3+ articles
- Do not have their own article yet
These are strong candidates for new articles. For each:
1. Check whether relevant raw sources exist in raw/. 2. If yes, write the article (Procedure 1 in SKILL.md). 3. If no, ingest sources first (kb ingest url/file) or mark as a research gap in the topic's CLAUDE.md.
Check 4: Format violations
Verify each article has:
- H1 title matching filename
- Lead paragraph
- Sources section at the bottom
- At least 5 wikilinks (outgoing)
- Frontmatter with all required fields (the
kbCLI validates these automatically viakb lint)
Fix by rewriting or adding the missing elements.
Check 5: Wikilink audit
For each article:
- Identify concepts mentioned without wikilinks that should have them
- Identify over-wikilinking (same term linked multiple times in close proximity)
- Identify wikilinks to concepts that no longer match the linked article's actual content
Check 6: Filed-back query absorption
Scan <topic>/outputs/queries/ for recent query results. For each:
1. Identify the wiki articles listed under informed_by:. 2. Check whether the synthesis in the query result adds new insights not yet in those articles. 3. If yes, flag the articles for updates and absorb the insights on the next compile pass.
This is the core compounding mechanism — query answers feeding back into the wiki.
Lint report format
When running a manual lint pass, produce a report like:
LINT REPORT — <topic>/ — YYYY-MM-DD
DEAD LINKS (N)
- [[Missing Article]] referenced in: Foo.md, Bar.md
→ SUGGEST: Create wiki/concepts/Missing Article.md
→ POTENTIAL SOURCES: raw/articles/relevant-source.md
ORPHAN ARTICLES (N)
- Token Economics.md — 0 incoming links
→ SUGGEST: Add refs from Agent Infrastructure.md, Fine-Tuning.md
STALE CONTENT (N)
- MCP article references "MCP spec v0.9" but raw/articles/mcp-spec.md is v1.2
→ UPDATE: Recompile with current spec
INCONSISTENCIES (N)
- Hardware specs disagree: Agent Infrastructure.md vs Fine-Tuning.md
→ RESOLVE: Verify against authoritative source, pick canonical
MISSING COVERAGE (N)
- "Inference Optimization" referenced in 4 articles, no article exists
→ SUGGEST: Create wiki/concepts/Inference Optimization.md
FORMAT VIOLATIONS (N)
- Prompt Engineering Techniques.md — missing Sources section
FILED-BACK INSIGHTS (N)
- outputs/queries/2026-04-02 memory vs context.md has synthesis not in Memory Systems.md
→ ABSORB: Update Memory Systems.md with the compaction tradeoffs insightHeal workflow
For each issue the lint report surfaces:
1. Dead link + source available → create the article (Procedure 1). 2. Dead link + no source → mark in topic CLAUDE.md research gaps, or rewrite the link. 3. Orphan → add incoming wikilinks, or delete if out-of-scope. 4. Stale → re-scrape source, recompile article. 5. Inconsistency → find authoritative source, fix all affected articles. 6. Missing coverage → ingest sources, write article. 7. Format violation → fix formatting. 8. Filed-back insight → update affected wiki articles.
Run the cycle regularly. Each pass leaves the knowledge base in a better state than it found it.
Output Format Reference
All inspect and search commands support three output formats via --format.
Format Selection
| Format | Flag | Use Case |
|---|---|---|
| table | --format table | Human-readable display (default) |
| json | --format json | Programmatic parsing by agents |
| tsv | --format tsv | Piping to Unix tools |
Always use --format json when parsing output programmatically.
Inspect Output (Tabular Commands)
Tabular inspect commands (smells, dead-code, complexity, blast-radius, coupling, circular-deps) return rows with typed columns.
JSON Example (inspect complexity --top 2 --format json)
[
{
"symbol_name": "parseConfig",
"symbol_kind": "function",
"source_path": "src/config.ts",
"cyclomatic_complexity": 12,
"loc": 45,
"blast_radius": 8,
"smells": ["high-complexity"]
},
{
"symbol_name": "resolveImports",
"symbol_kind": "function",
"source_path": "src/resolver.ts",
"cyclomatic_complexity": 9,
"loc": 32,
"blast_radius": 5,
"smells": []
}
]TSV Example
symbol_name symbol_kind source_path cyclomatic_complexity loc blast_radius smells
parseConfig function src/config.ts 12 45 8 high-complexity
resolveImports function src/resolver.ts 9 32 5 Inspect Output (Detail Commands)
Detail commands (symbol, file) return field-value pairs when a single entity matches.
JSON Example (inspect symbol parseConfig --format json)
[
{"field": "symbol_name", "value": "parseConfig"},
{"field": "symbol_kind", "value": "function"},
{"field": "source_path", "value": "src/config.ts"},
{"field": "loc", "value": 45},
{"field": "blast_radius", "value": 8},
{"field": "smells", "value": ["high-complexity"]},
{"field": "outgoing_relations", "value": [
{"target_path": "src/utils.ts", "type": "imports", "confidence": "syntactic"}
]},
{"field": "backlinks", "value": [
{"target_path": "src/main.ts", "type": "calls", "confidence": "semantic"}
]}
]Ingest Codebase Output
kb ingest codebase always outputs JSON to stdout (no --format flag).
{
"command": "generate",
"rootPath": "/path/to/repo",
"vaultPath": "/path/to/repo/.kb/vault",
"topicPath": "/path/to/repo/.kb/vault/my-project",
"topicSlug": "my-project",
"filesScanned": 120,
"filesParsed": 95,
"filesSkipped": 25,
"symbolsExtracted": 430,
"relationsEmitted": 1200,
"rawDocumentsWritten": 95,
"wikiDocumentsWritten": 12,
"indexDocumentsWritten": 5,
"timings": {
"scanMillis": 45,
"selectAdaptersMillis": 2,
"parseMillis": 1200,
"normalizeMillis": 80,
"metricsMillis": 150,
"renderMillis": 300,
"writeMillis": 200,
"totalMillis": 1977
},
"diagnostics": []
}Search Output
JSON Example (search "auth middleware" --format json)
[
{
"path": "raw-codebase/src/auth/middleware.md",
"score": 0.89,
"preview": "Authentication middleware that validates JWT tokens..."
}
]Index Output
kb index always outputs JSON to stdout (no --format flag).
{
"collectionName": "my-project",
"embedRequested": true,
"embedResult": {
"docsProcessed": 95,
"chunksEmbedded": 320,
"errors": 0,
"durationMs": 4500
},
"forceEmbed": false,
"status": {
"collection": {
"name": "my-project",
"path": "qmd://collections/my-project",
"pattern": "",
"documents": 95,
"lastUpdated": "2026-04-10T12:00:00Z"
},
"hasVectorIndex": true,
"needsEmbedding": 0,
"totalDocuments": 95
},
"topicPath": "/path/to/vault/my-project",
"topicSlug": "my-project",
"updateResult": {
"collections": 1,
"indexed": 95,
"updated": 0,
"unchanged": 0,
"removed": 0,
"needsEmbedding": 95
},
"vaultPath": "/path/to/vault"
}Empty Results
| Format | Empty Output |
|---|---|
| json | [] |
| table | No results. followed by newline |
| tsv | Header row only (no data rows) |
Tooling Tips
Companion tooling and Obsidian plugins that accelerate the Karpathy KB workflow. All are optional — the core pattern only requires markdown files. Add them as scale demands.
Obsidian Web Clipper (browser extension)
Converts web articles to clean markdown with a single click, writing directly into the vault. The fastest path for getting articles from browser → <topic>/raw/articles/.
- Install from the Obsidian Web Clipper page (official extension for Chrome/Firefox/Safari).
- Configure the default save location to
<topic>/raw/articles/per topic. - Configure a default template that includes
source_url,scraped, and topic tags in frontmatter (thekbCLI auto-generates correct frontmatter onkb ingest, so this is only needed for manual clips).
After clipping, verify the frontmatter matches kb conventions (the CLI auto-generates it on kb ingest, but manual clips need manual frontmatter). Then re-index with kb index --topic <slug> and append a log entry.
Image download and asset handling
LLMs cannot reliably read markdown with inline images in a single pass. The workaround: download images locally so the LLM can view them separately when needed.
Obsidian config:
- Settings → Files and links → Attachment folder path: set to
raw/assets/(or a per-topic attachments dir). - Settings → Hotkeys → search "Download" → bind "Download attachments for current file" to a hotkey (e.g., Ctrl+Shift+D).
Workflow: after clipping an article with image URLs, press the hotkey — all referenced images download to the attachment folder and the markdown is rewritten to reference local files. The LLM then reads the text first, then views specific images separately for additional context.
Dataview plugin
Runs SQL-like queries over page frontmatter. Useful when the LLM adds structured frontmatter (tags, dates, source_count) to wiki pages — Dataview turns that into dynamic tables without maintaining a separate index.
Example: list all wiki articles updated in the last 30 days, sorted by source count:
TABLE updated, length(sources) AS "Sources"
FROM "ai-harness/wiki/concepts"
WHERE date(updated) > date(today) - dur(30 days)
SORT length(sources) DESCDataview complements the static Concept Index.md — keep the static index for LLM navigation and add Dataview blocks inside Dashboard.md for live views.
Marp plugin
Converts markdown files to slide decks (PDF/HTML/PPTX). A query answer, a wiki article, or a comparison can be exported to a slide deck with zero extra authoring.
Usage:
- Add
marp: trueto the frontmatter of the file being presented. - Use
---separators between slides. - Export via Marp's CLI or the Obsidian Marp plugin.
Useful for briefings in <topic>/outputs/briefings/ that need to be shared as decks.
qmd vs naked index tradeoffs
Karpathy's original pattern notes that at small scale, the static index.md (our Concept Index.md + Source Index.md) is sufficient — the LLM reads it to find relevant pages, then drills in. qmd (hybrid BM25 + vector search with LLM re-ranking, all local) becomes worth adding as the corpus grows.
Heuristic:
| Scale | Navigation |
|---|---|
| 1-20 sources, <30 wiki articles | Concept Index + Source Index only |
| 20-50 sources, 30-80 articles | Run kb index --topic <slug>, still read indexes first |
| 50+ sources, 80+ articles | qmd primary, indexes become secondary browsing aids |
The indexes never go away — they serve as the LLM's mental model of the topic. qmd serves as its search tool.
Graph view
Obsidian's graph view is the fastest way to see the shape of a topic — what's central, what's orphan, what's overconnected. Run it after each lint pass to eyeball the structure. Orphan nodes in the graph corroborate orphan detection from kb lint.
The wiki is just a git repo
No database, no server. Every commit is a reviewable checkpoint. Branch to experiment with a restructure without risking the main wiki. git log --follow <article>.md shows the full evolution of any concept. git blame shows which compile pass introduced which claim.