aedificium-template
Enables a personal learning notebook and lexicon with Claude-native chat, supporting markdown notes, definitions, PDFs, math rendering, wiki-links, and git auto-commit.
README
aedificium — a personal learning notebook + lexicon, Claude-native
A card-grid UI on http://localhost:8788 for notes, definitions (a lexicon),
and PDFs, with a chat pane bridged to Claude Code via MCP. Math renders
first-class (KaTeX). Everything on disk is plain markdown, auto-committed to
git, and (optionally) auto-pushed to GitHub.
This is the open-source template. Fork it, clone your fork next to a
sibling scriptorium/ code lab, and start writing.
What you get
- Card grid + reader — notes on the left, chat with Claude on the right.
- First-class math —
$e^{i\pi}+1=0$inline,$$…$$display, KaTeX server-side. Renders in the card grid and in the reader. - Lexicon — one definition per file (
lexicon/eigenvalue.md), rendered as a dictionary entry with headword + synonyms + domain label. - PDF library — drop a PDF into
pdfs/; a sidecar discussion card appears automatically. No embedded viewer — the browser's native one is better. Deep-link into pages with#page=N. - Chat is Claude Code — you type in the browser, Claude answers, and your
current card selection travels along as context (
refs=…). - Wiki-links —
[[slug]]in any note becomes a click-to-open link in the reader, with/note/<slug>deep-links via the History API. - Git-native — writes auto-commit (debounced ~3 s) and, if
originis set, auto-push. LFS pre-configured for PDFs so GitHub handles large binaries cleanly.
Prerequisites
Developed and tested on macOS (arm64). Linux should work with the equivalent package installs.
- bun — the JavaScript runtime the server uses.
brew install oven-sh/bun/bun. - git-lfs — for PDFs.
brew install git-lfs. - Claude Code — the CLI the chat pane talks to. This is what makes the notebook interactive.
Setup
# Fork on GitHub first, then:
git clone git@github.com:clausd/aedificium.git
cd aedificium
bun install
git lfs install
Launching
One flag matters and it is easy to miss. Claude Code needs
--dangerously-load-development-channels server:aedificium for the browser →
Claude direction of the channel to work. Without it, the reply /
commit_chat tools still work (Claude → browser), but nothing you type into
the chat pane reaches Claude. Silence looks like a bug and isn't.
claude --dangerously-load-development-channels server:aedificium
Claude Code will spawn bun server.ts automatically (per .mcp.json). Then
open http://localhost:8788.
Consider aliasing:
alias claude-aed='claude --dangerously-load-development-channels server:aedificium'
The "don't nohup bun" rule
Do not start bun yourself with nohup / disown. If you do, bun becomes
an orphan process detached from Claude Code's MCP stdio pipe — the browser
still works, but Claude loses reply and commit_chat, and no future
Claude Code session can bind port 8788 either (the orphan is holding it).
If you need to pick up a server.ts change:
kill $(lsof -tiTCP:8788 -sTCP:LISTEN) # or just kill the pid you see
# then exit + re-enter Claude Code; the harness respawns a fresh bun child.
Layout
notes/ YYYY-MM-DD-HHMM-slug.md — free-form notes
lexicon/ <slug>.md — one term per file, dictionary style
pdfs/ PDFs + auto-generated sidecar .md discussion cards
assets/ pasted / dropped images referenced from cards
files/ misc non-PDF uploads
archive/ archived cards (preserves original subdir)
data/chat.jsonl durable chat transcript (tracked + searchable)
server.ts the Bun app (single file, ~2500 lines)
CLAUDE.md the design doc + Claude Code project instructions
.mcp.json MCP config (Claude Code reads this to spawn bun)
.gitattributes LFS routing for *.pdf
Conventions in one page
- Card kinds are inferred, not declared: files in
notes/are notes, files inlexicon/are lexicon entries, PDFs get sidecar cards. - Math:
$x$inline (dollars hug content),$$…$$display. SeeCLAUDE.mdfor edge cases. - Machine tags in the body:
#area:calculus,#see:other-slug, or a bare#question. The UI hides them from the prose and renders them as chips. - Wiki-links:
[[some-slug]](optionally[[some-slug|display text]]) resolve server-side and open in the reader.
Full spec: CLAUDE.md.
Optional — the sibling code lab
If you want a companion Python repo for models, notebooks, and figures, use scriptorium-template as a sibling checkout:
your-workspace/
aedificium/ # this repo
scriptorium/ # from scriptorium-template
The scriptorium aedificium.py bridge lets notebook cells render aedificium
prose inline and save matplotlib figures directly into aedificium/assets/.
Set AEDIFICIUM_DIR (in scriptorium) or AED_SCRIPTORIUM_DIR (here) if the
two aren't siblings.
GitHub setup
Push to GitHub as usual once you have LFS installed locally:
git remote set-url origin git@github.com:clausd/aedificium.git
git push -u origin main
Auto-push runs after each auto-commit (5 s debounce). Disable with
AED_NO_PUSH=1. GitHub LFS free tier is 1 GB storage / 1 GB bandwidth per
month per account — comfortably enough for a personal PDF library up to a
few hundred papers.
Environment knobs
| Var | Default | Effect |
|---|---|---|
AED_PORT |
8788 |
HTTP + WebSocket port. |
AED_NO_GIT |
unset | Disable all auto-commit. |
AED_NO_PUSH |
unset | Auto-commit but never auto-push. |
AED_NO_CHAT_CHECKPOINT |
unset | Disable chat-log checkpointing. |
AED_PUSH_DEBOUNCE_MS |
5000 |
Coalesce commits into one push. |
AED_CHAT_IDLE_MS |
300000 |
Idle time before a chat checkpoint. |
AED_CHAT_MAX_MS |
900000 |
Max chat age before a forced checkpoint. |
AED_SCRIPTORIUM_DIR |
../scriptorium |
Where #code: tags resolve. |
AED_EDITOR_URL |
vscode://file/{path} |
Card "open in editor" URL scheme. |
Troubleshooting
- "I type in the chat pane and nothing happens." Almost always the
missing
--dangerously-load-development-channels server:aedificiumflag. Restart Claude Code with it. - "Claude says the
replytool is unavailable." Bun got orphaned. Kill the process on port 8788, exit and re-enter Claude Code. - "
git pushrefuses a PDF (exceeds 100 MB)." LFS wasn't active when the PDF was added. Rungit lfs install, thengit lfs migrate import --include="*.pdf" --everything, thengit push --force-with-lease(only safe when you're the sole clone). - "Auto-commit stopped." Check bun's stderr. Most common cause is a
merge conflict on
data/chat.jsonlbetween machines — the conflict is usually the union of the two sides (chat.jsonl is append-only).
License
MIT. Adapt freely — the point is that you own your notebook.
Credits
Original concept, architecture, and implementation by Claus Dahl. The two-repo split (prose ↔ code) is inspired by the way medieval scriptoria fed monastic libraries — hence the names.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
Neon Database
MCP server for interacting with Neon Management API and databases
E2B
Using MCP to run code via e2b.
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.