I have about 50 projects. plugins, apps, MCPs, tools, browser extensions, static sites. each one is its own git repo with its own CLAUDE.md. I can work on gummymine for three hours, switch to zapframe for a day, come back to gummymine next week, and have no idea where I left off.
Claude Code has a memory system. it's fine for conversation-level stuff like "this user prefers terse responses" or "always register MCPs with user scope." but it doesn't track project state. it doesn't know that gummymine's Stripe integration is half-wired, or that the social marketing agent has steps 1-2 done and 3-5 remaining.
I tried a ## Next convention in project CLAUDE.md files. the idea was Claude updates it before ending a session so the next session knows what to pick up. I checked: 4 out of ~50 projects had one.
the Karpathy pattern
Andrej Karpathy posted a gist about LLM-maintained wikis. three layers: raw sources, LLM-owned wiki pages, and a schema file. three operations: ingest, query, lint. he grew one research topic to ~100 articles and 400k words without writing any of it.
the key insight: at personal scale, a structured index beats vector search. no RAG, no embeddings, no vector DB. the LLM reads an index file, knows what pages exist, and greps for what it needs. cosine similarity matches words. the LLM understands intent.
I'm well under his scale ceiling (~500 articles before context windows become a problem). so I stole the pattern.
the vault
I picked Obsidian as the frontend. it gives me graph view, tag filtering, full-text search, and a nice reading experience. Claude writes markdown files. I browse them. the vault is a git repo, so every update is a commit.
structure is one directory per project:
vault/Projects/
├── gummymine/
│ ├── gummymine.md # status, open threads, where-I'm-at
│ ├── plugin.md # the Claude Code plugin side
│ └── marketing.md # launch plan
├── zapframe/
│ └── zapframe.md
├── meta/
│ ├── infrastructure.md
│ ├── stripe.md
│ └── cloudflare.md
└── Dashboard.md
each project's main note has a "Where I'm at" section. freeform prose. this is what Claude reads when I ask "where am I at with gummymine" and it's what Claude updates after a work session.
tags in YAML frontmatter give me vertical slicing: #status/active, #needs/marketing, #type/plugin. the directory structure groups by project. tags cut across projects. wikilinks like [[zapframe]] connect related notes and make the graph view useful.
git as the temporal layer
I looked at a few approaches for tracking history. the claude-memory-compiler project uses daily log files. LLM Wiki v2 adds confidence scoring with decay (facts expire unless reinforced). both require extra maintenance machinery.
git already does this. every vault update is a commit with a descriptive message. git log --oneline reads as a project timeline:
5e76138 reddit-poster: v1.1.0 with abstract social-posting capability
306e1c3 infra: AX210 wifi drops — monitor running, AX mode disabled
4e70e59 gummymine: email-based team invites, agent self-serve API keys
git log -p -- Projects/gummymine/ shows how gummymine evolved over time. no log files, no decay scoring, no extra moving parts. the commit message discipline is the entire temporal system.
what makes it stick
the ## Next convention failed because it was optional. Claude might do it, might not.
the vault rule goes in the global ~/.claude/CLAUDE.md, so it loads in every session regardless of which project directory you're in. it tells Claude: after meaningful work, update the relevant vault note, commit with a specific message. that's it. no skill to invoke, no command to remember.
I went back through my last 5 conversations and simulated the vault updates. a gummymine session that added email-based team invites became three lines in "Where I'm at" and one line in "Decisions made." a WiFi debugging session became a meta/networking.md note documenting the AX210 firmware situation. a reddit-poster session created a new project note and a social marketing agent plan with build steps tracked.
small writes, high signal. that's the whole game.
what didn't work
I tried putting site URLs and repo links in YAML frontmatter. Obsidian renders frontmatter as plain text, not clickable links. had to move them into a ## Links section in the body with regular markdown links.
I almost forced this into my plugin capability system. the idea was a wiki capability with providers: obsidian-vault for local files, maybe confluence-wiki or github-wiki someday. but obsidian-vault has no runtime component. there's no MCP server, no tools. Claude already knows how to write files and run git. wrapping file I/O in an MCP call just to match a pattern is pointless. I dropped the abstraction.
the plugin
I packaged it as knowledge-base, a Claude Code plugin. no MCP server. just a setup skill and a rule file.
the setup skill detects Obsidian, creates the vault structure, inits git. the rule file loads every session and tells Claude the conventions: note format, tag taxonomy, commit discipline, what goes in the vault vs. what stays in CLAUDE.md.
install:
claude plugin marketplace add softwaresoftware-dev/softwaresoftware-plugins
claude plugin install softwaresoftware@softwaresoftware-plugins
claude
/softwaresoftware:install knowledge-base
/knowledge-base:setup
point it at a directory. open Obsidian. work on your projects. the vault fills itself.