OBSIDIAN · CLAUDE CODE · KARPATHY LLM WIKI

I built a second brain that runs on Claude Code.

A personal knowledge management system that captures every conversation, transcript, and note into an Obsidian vault, then curates it into a wiki an LLM can read directly. Drop files in, run /ingest, ask the wiki anything with /query. A nightly cron keeps it current while you sleep.

01 · OVERVIEW

The pattern, end-to-end

The system is a working implementation of the LLM Wiki pattern Andrej Karpathy has talked about. Source notes stay raw and untouched; a curated layer above them does the synthesis, the linking, and the attribution. Every claim points back to where it came from.

Architecture diagram: raw/ flows through /ingest into wiki/. The capture hook feeds raw/. /log, /query, and /lint operate on wiki/.

RAW IS RAW

Conversations, transcripts, articles, notes — every source lands in raw/ and never gets edited again. It's the audit trail.

WIKI IS CURATED

Claude promotes raw sources into structured wiki pages with frontmatter, cross-links, and source attribution. One idea per page.

FEEDS ITSELF

A capture hook saves every Claude Code session into raw/. A nightly cron runs /ingest and /lint at 02:00.

02 · THE VAULT

Two domains, one rule

The vault has exactly two top-level concerns: read-only intake and curated output. Everything else — agents, content drafts, journal — is optional scaffolding you grow into.

second-brain/
├── raw/                       # read-only intake — never edited by hand
│   ├── claude-exports/
│   │   └── auto/             # written by the SessionEnd hook
│   ├── chatgpt-exports/
│   ├── articles/
│   ├── notes/
│   ├── voice-memos/
│   └── youtube-transcripts/
├── wiki/                      # Claude's domain — curated output
│   ├── index.md              # master catalog
│   ├── log.md                # append-only activity log
│   ├── concepts/
│   ├── projects/
│   └── people/
├── agents/                    # optional persona files
├── content/                   # optional drafts
└── .claude/
    ├── settings.json         # hook config
    ├── commands/             # /ingest /log /query /lint
    ├── hooks/                # capture-session.py
    └── scripts/              # nightly-ingest.ps1 / .sh
03 · CONVENTIONS

The contract Claude reads on every session

One file at the vault root — CLAUDE.md — defines structure, frontmatter rules, link syntax, and style. The same six frontmatter fields show up on every wiki page.

WIKI/CONCEPTS/HOME-SERVER.MD
---
title:        "Home Server"
type:         concept          # concept | source-summary | project | person
sources:
  - raw/articles/2026-04-18-proxmox-setup.md
  - raw/claude-exports/auto/2026-04-19-103044-session-end.md
related:
  - "[[proxmox]]"
  - "[[atlas]]"
created:      2026-04-18
last-updated: 2026-05-01
---

# Home Server
## Overview
2-paragraph summary of the home-server stack...
## Key Points
- Proxmox 8.2 on the [[atlas]] machine, three VMs running...
## Sources
- (source: articles/2026-04-18-proxmox-setup.md)

FRONTMATTER · 6 FIELDS

title, type, sources, related, created, last-updated. /lint catches you the first time you forget one.

WIKI-LINKS · NATIVE OBSIDIAN

Cross-link with [[slug]]. Open the vault in Obsidian and the graph view + backlinks panel come for free.

04 · SLASH COMMANDS

Four commands. The whole loop.

Each command is a Markdown prompt at .claude/commands/. Drop them in, type the slash, Claude does the rest.

PROMOTE /ingest Reads unread files in raw/, creates wiki pages with frontmatter, cross-links related pages with [[wiki-links]], updates the index, appends to the log. Emits a sentinel footer the cron parses. batch · 5–10 sources per run
CAPTURE /log "thought" Appends a timestamped note to wiki/log.md. If the note mentions a page that already exists, also appends to that page's "Log Entries" section and bumps last-updated. one-liner · seconds
RECALL /query "question" Answers grounded only in the wiki, with citations to specific pages. Surfaces contradictions explicitly. Refuses to invent — tells you when the wiki doesn't know. cited · auditable
VERIFY /lint Read-only health check — missing frontmatter, broken wiki-links, orphan pages, stale pages, contradictions, index mismatches. Reports first, asks before fixing. read-only · ask-to-fix
05 · CAPTURE HOOK

The system feeds itself

A single Python file, ~150 lines, hooked to Claude Code's SessionEnd and PreCompact events. Every session you run lands in raw/ as a Markdown snapshot.

Hook flow: session ends, SessionEnd fires, capture-session.py reads the transcript JSONL and writes a Markdown snapshot to raw/claude-exports/auto/.
.CLAUDE/HOOKS/CAPTURE-SESSION.PY · EXCERPT
# Fires on SessionEnd and PreCompact. Never raises.
# One file per hook firing — vault-relative, local I/O only.
def main():
    payload = json.loads(sys.stdin.read())
    transcript_path = payload.get("transcript_path")
    event = payload.get("hook_event_name", "unknown")

    vault_root = Path(__file__).resolve().parent.parent.parent
    out_dir = vault_root / "raw" / "claude-exports" / "auto"
    out_dir.mkdir(parents=True, exist_ok=True)

    messages = read_transcript_jsonl(transcript_path)
    rendered = render_transcript(messages)

    now = datetime.now()
    filename = f"{now:%Y-%m-%d-%H%M%S}-{event.lower()}-{short_id}.md"
    (out_dir / filename).write_text(frontmatter + body, encoding="utf-8")
06 · NIGHTLY AUTO-INGEST

Lock · snapshot · run · report

A clean PowerShell wrapper (or bash equivalent) that runs /ingest then /lint at 02:00 every night. Concurrency-locked, snapshots wiki/ first, writes a structured status JSON.

Cron flow: Task Scheduler triggers nightly-ingest.ps1, which acquires a lock, snapshots wiki/, runs /ingest and /lint, writes status JSON, releases the lock.
.CLAUDE/STATE/NIGHTLY-STATUS.JSON · EXAMPLE
{
  "startedAt":   "2026-05-02T02:00:00Z",
  "completedAt": "2026-05-02T02:04:18Z",
  "vault":       "/home/you/second-brain",
  "overall":     "ok",
  "backupPath":  ".claude/backups/nightly-ingest/20260502-020000-wiki.zip",
  "ingest": {
    "status":    "ok",
    "processed": 5,
    "created":   3,
    "updated":   4,
    "remaining": 12
  },
  "lint": { "status": "ok", "issuesFound": 0 }
}
07 · SETUP

Six steps to a working second brain

30–45 minutes from git clone to a vault that captures itself. Full templates and prose in GUIDE.md.

01

SCAFFOLD THE VAULT

Single shell command creates raw/, wiki/, agents/, content/, journal/, .claude/ — and the suggested raw/ subfolders.

Read step 1 →
02

INSTALL CLAUDE.MD

Copy the conventions template to the vault root. Edit Section 4 (Domain Context) for your life.

Read step 2 →
03

INIT INDEX + LOG

Two seed files — index.md (catalog) and log.md (activity). Both grow as you use the system.

Read step 3 →
04

INSTALL THE COMMANDS

Drop /ingest, /log, /query, /lint into .claude/commands/. Sanity-check with one test source.

Read step 4 →
05

WIRE THE CAPTURE HOOK

capture-session.py + a SessionEnd block in settings.json. Verify by ending a session and looking in raw/claude-exports/auto/.

Read step 5 →
06

SCHEDULE THE CRON

Run nightly-ingest.ps1 -DryRun to verify, then register the daily 02:00 task. Bash + cron equivalent included.

Read step 6 →
08 · THE STACK

Everything required, nothing exotic

Plain Markdown, a Python script, a PowerShell or bash wrapper, and Claude Code. No cloud, no database, no API keys beyond Claude.

CLAUDE CODE
runs the commands
OBSIDIAN
vault editor
MARKDOWN
storage format
PYTHON 3
capture hook
POWERSHELL / BASH
cron wrapper
TASK SCHEDULER · CRON
nightly trigger

BUILD ONE OF YOUR OWN

The full setup walkthrough, drop-in templates, and lessons learned live in the repo. Fork it, follow GUIDE.md, and message me when something breaks — feedback sharpens the templates for the next person.