An AI Chat App built with Reboot that provides a shared
knowledge base humans and AIs can both read from and write to.
Users hand in raw conversation Transcripts; a background
"librarian" agent progressively distills those transcripts into
a small, well-organized set of markdown Pages linked from the
Wiki's own markdown body, which serves as a living table of
contents. Humans browse the result in embedded React UIs.
Inspired by Andrej Karpathy's "LLM Knowledge Bases" tweet: https://x.com/karpathy/status/2039805659525644595
Wiki— a knowledge base. Holds aname, adescription, and acontentfield that is a single markdown blob. The table of contents, cross-references, and any other structure all live inside that markdown, not in separate fields. Links to other state instances are embedded as URIs of the form<StateType>:<state_id>, for examplePage:abc123orTranscript:xyz789; a reader follows such a link by calling the referenced type'sgetmethod on the embedded state ID. The Wiki also holds atranscriptsmap from transcript ID to a bool flag indicating whether the librarian has ingested that transcript yet.Page— a unit of knowledge. Holds atitleand a markdowncontentbody. Pages are referenced from the wiki (and from one another) viaPage:<state_id>URIs embedded in markdown.Transcript— a raw conversation, stored as a list of{role, content}messages. A transcript belongs to exactly one wiki.User— per-user state mapping user-given wiki names (e.g.,"team knowledge base") to opaque wiki state IDs, so wikis can be looked up by name later.
The cross-state operations are:
User.create_wiki— creates aWikiand records its state ID under the given name on the user. Also schedules the wiki'singestworkflow (see below).Wiki.add_transcript— creates aTranscriptwith the given messages and records it on the wiki as not-yet-ingested, which wakes the librarian.
Both are Transactions so their state changes land atomically.
Every Wiki has a long-running ingest workflow scheduled at
creation time. That workflow is the librarian: a Pydantic
AI agent (see backend/src/servicers/wiki.py) whose job is to
watch the wiki's transcripts map for pending entries and, for
each one, fold its material into the wiki and its pages, then
mark it ingested.
The librarian is deliberately biased towards aggregation. Given a new transcript, it prefers renaming and broadening an existing page over creating a new one — so a page titled "History of the Steam Engine" may grow into "History of Inventions" and later into "History of Things" as more transcripts arrive. The goal is a small, high-signal set of pages, not one page per transcript.
The user-facing write path is therefore: call
Wiki.add_transcript with the conversation you want captured,
then let the librarian do the rest asynchronously.
Wiki.update, Page.update, and Transcript.update are
exposed too, but are intended mostly for the librarian (and
for manual fix-ups).
# Install Python dependencies and create the virtualenv.
rye sync
source .venv/bin/activate
# Install web dependencies.
cd web && npm install && cd ..
# Generate API code (Python + React bindings).
rbt generate
# Build the React UIs.
cd web && npm run build && cd ..The librarian runs on Anthropic's Claude via Pydantic AI, so the backend needs an Anthropic API key. For local development, export it in your shell:
export ANTHROPIC_API_KEY=...When deployed to Reboot Cloud, store the key as a Reboot secret instead:
rbt cloud secret set --application-name=agent-wiki ANTHROPIC_API_KEY=sk-ant-...Cloud injects each secret into the application's environment
under its given name, so naming the secret ANTHROPIC_API_KEY
is what the Anthropic SDK reads directly — the same code works
in both places.
Then run the app (each command in its own terminal, from the
project directory, with .venv activated):
# Terminal 1: start the Reboot backend.
rbt dev run
# Terminal 2: start the Vite dev server for Hot Module Replacement.
cd web && npm run devState persists between restarts under the name agent-wiki
(configured in .rbtrc). To wipe it:
rbt dev expunge --application-name=agent-wikiThe backend has an in-process test suite that exercises the
servicers and the Wiki.ingest librarian workflow without
making any real Anthropic calls (the LLM is replaced by a
scripted Pydantic AI FunctionModel).
rye sync
source .venv/bin/activate
pytest backend/mcp_servers.json is pre-configured. In another terminal:
npx @mcpjam/inspector@v2.4.0 --config mcp_servers.json --server agent-wikiTry these prompts to exercise each capability. The librarian
works asynchronously, so after an add_transcript call watch
the backend log for librarian[...] tool call ... lines to see
it read the wiki, decide where material belongs, and rewrite
pages.
Create a wiki called "Team Knowledge Base" about engineering runbooks.— exercisescreate_wiki, which also schedules the wiki'singestworkflow.List all my wikis.— exerciseslist_wikis.Attach this conversation to the Team Knowledge Base as a transcript:followed by a short back-and-forth about, say, pushing to main and smoke-testing the deploy — exercisesadd_transcript. The librarian will then create a page and edit the wiki's markdown to link to it.Show me the Team Knowledge Base.— exercisesshow_wiki; the rendered markdown is the librarian's table of contents withPage:<state_id>links.Read the Team Knowledge Base.— exercisesWiki.getand returns the raw markdown the UI renders.Follow the first page link in that wiki and show it to me.— exercisesPage.get(to read) andshow_page(to render).Attach a second transcript about our rollback runbook:followed by another conversation — exercisesadd_transcriptagain. The librarian should prefer broadening the existing page (e.g., renaming it to "Deploy and Rollback Process") rather than creating a new one.Show me the raw transcript we attached first.— exercisesTranscript.getandshow_transcript.
agent-wiki/
├── api/agent_wiki/v1/wiki.py # State models + method declarations.
├── backend/
│ ├── api/ # Generated Python bindings.
│ └── src/
│ ├── main.py # Application entrypoint.
│ └── servicers/wiki.py # User/Wiki/Page/Transcript servicers
│ # plus the Pydantic AI librarian agent.
└── web/
├── api/ # Generated React bindings.
└── ui/
├── wiki_view/ # Renders a Wiki's markdown body.
├── page_view/ # Renders a Page's markdown body.
├── transcript_view/ # Renders a raw Transcript.
└── _shared/ # Shared UI helpers (markdown, etc.).