CodeBook
An agentic RAG workspace that answers questions across a book, its docs and its code at once, with every claim cited to the page, section or line.
01The problem
Learning a codebase usually means reading two things side by side: the prose that explains an idea, like a book chapter or a framework guide, and the code that implements it. Switching between them is slow, and asking a chatbot about either one gives answers you can't check.
CodeBook puts both in one workspace. Add a PDF, a public GitHub repository or a docs site, then ask questions. An agent decides how to look for each answer, and every claim points to the page, section or file:line it came from, which opens beside the chat.
Around that core I built study tools (quizzes, flashcards, mind maps), long-term memory, a public demo workspace that needs no account, and usage limits so it runs on free model tiers.
02Architecture
Ingestion
PDFs, GitHub repos and docs sites are parsed in background Inngest jobs: page-accurate text and a table of contents for books, Tree-sitter chunks and a code graph for repos, readable sections for sites.
Index
Parent and child chunks with a short model-written context note each, embedded and stored in Postgres with pgvector, a full-text index and the code graph, swapped in with one transaction.
Retrieval
Vector search on an HNSW index and keyword search on tsvector, fused with weighted reciprocal rank fusion. A MiniLM cross-encoder reranker can be switched on.
Agent
A streamed, multi-step loop that picks tools per question: hybrid search, exact code search, reading pages or lines, browsing a book's contents, and walking the call graph.
Citations
Every numbered note in an answer must point to a passage the model was actually shown; it opens the exact page, section or file:line beside the chat.
Reliability
Per-model and per-key circuit breakers, fallbacks across free-tier models, daily token budgets, rate limits and an admin view of failures.
03Key decisions
An agent with tools, not one vector index
Different questions need different ways of looking. “Who calls this function?” needs the call graph, “what does chapter 5 say?” needs the book's structure, and an error message needs exact text search. A single similarity search over one index does badly on all three, so the model gets each as a tool and chooses per question, retrying when the first results are weak.
Hybrid search, with keywords weighted down
Vector search alone misses exact identifiers; keyword search alone misses paraphrases. Fusing both catches function names without letting keyword noise dominate, so the keyword list is weighted at a quarter in the fusion.
Reranking is opt-in
A MiniLM cross-encoder improves results on book passages, but it was trained on web text rather than code and costs around two seconds of CPU per search, so it stays off by default and can be enabled where it helps.
Context notes on every chunk
Before embedding, each chunk gets a short model-written note about where it sits in the document or repository. A function body alone often doesn't say what it is for; the note does.
Citations are checked before saving
Models sometimes cite things they never saw. Each answer's references are validated against the passages returned to the model during that turn, and tool output and source text are passed as tagged data that the prompt never treats as instructions.
Cached, transactional ingestion
Each ingestion step caches its output, so a retry or resync only pays for what changed, and the new index replaces the old one in a single transaction. A source stays searchable while it re-indexes.
One service, one origin
The Express API also serves the built web app, so the browser talks to a single origin: the session cookie stays first-party and answers stream over server-sent events without cross-origin setup. Long work runs as Inngest functions, so requests only queue it.