memex-vault
A template structure for Obsidian to coodinate local knowledge bases with LLMs
memex-vault
A personal template memex for accumulating and connecting knowledge from web articles, videos, academic papers, technical documentation, and meetings. A memex is a memory-extension machine — it ingests, indexes, and recombines knowledge. Inspired by Andrej Karpathy's LLM wiki concept.
This specific name - other than being a cool reference - was adjusted based on some now deleted comments here that rightly pointed out that a core aspect of a "wiki" is community consensus between people. So a mostly LLM derived knowledge graph of notes is decidedly not an interpersonal consensus.
Concept
This vault is a layered knowledge graph, not a flat bookmark list. Sources are never searched directly — instead, they feed upward into concept atoms, which feed upward into topic maps. Search flows top-down:
topics/concepts/ → atoms/ → extracts/ → sources/ → .archive/
(broad domain) (concept) (claim) (document) (raw text)
Every connection between notes is typed (e.g., extends::, supports::, refutes::), making the graph navigable by relationship kind — not just by link existence.
Density rises left to right and curation falls. atoms/ and above are
hand-curated: one concept per atom file, written by a human. That bounds what a
single atom holds, not what a single source yields — one article routinely feeds
three or four atoms, and the arrows above are fan-in. extracts/ is the
evidence layer — what a source actually said, claim by claim, each claim
carrying a verbatim quote that _meta/lint.sh checks against the archived text.
It is optional and selective; a vault with no extracts works exactly as before,
its atoms simply capped at confidence: medium. Nothing is ever promoted from
extracts/ to atoms/ automatically.
Folder Structure
vault/
├── VERSION # Template release this vault was built from — never edited by a fork
├── CHANGELOG.md # What changed between template releases
│
├── _templates/ # Templater input templates (not indexed)
│ ├── source-digital.md # All digital sources (web, video, paper, docs)
│ ├── source-meeting.md # Meeting notes (no URL; different schema)
│ ├── atom.md
│ ├── glossary.md
│ ├── extract.md
│ ├── topic-concept.md
│ ├── topic-project.md
│ └── topic-research.md
│
├── _meta/ # Infrastructure
│ ├── index.md # Live Dataview catalog of all notes
│ ├── log.md # Append-only ingest history
│ ├── schema.md # Relationship types, naming conventions (authoritative)
│ ├── domain.md # Instance vocabulary — tags, node types (edit on fork)
│ ├── lint.sh # Programmatic health checks
│ └── normalize.sh # Archive text normalizer — every .archive/ write pipes through it
│
├── sources/ # One file per URL or meeting — summary only
│ ├── web/
│ ├── video/
│ ├── paper/
│ ├── docs/
│ └── meeting/
│
├── extracts/ # Evidence layer — one file per deep-extracted source,
│ # quote-grounded claims addressed as [[ext-slug#^c07]]
├── atoms/ # One concept per file (Wikipedia stub granularity)
├── glossary/ # One term definition per file
│
├── topics/
│ ├── concepts/ # Domain-level maps linking atoms
│ ├── projects/ # Project brainstorm workspaces
│ └── research/ # Research synthesis across multiple sources
│
├── canvas/ # Optional visual maps (.canvas files)
├── _exports/ # Gitignored; composed topic export documents
└── .archive/ # Gitignored; optional full-text source backups
Node Types
| Folder | type: | Role | Granularity |
|---|---|---|---|
sources/ | Source | URL + why-saved + short summary. Never full article text. | One per URL or meeting |
extracts/ | Extract | Evidence layer. What one source said, claim by claim, each with a verbatim quote. Never hand-curated. | One per deep-extracted source |
atoms/ | Atom | Concept-level synthesis. Holds claims, links sources, connects to other atoms. | One concept per file |
glossary/ | Glossary Term | Precise term definitions. Lighter than atoms. | One term per file |
topics/concepts/ | Concept Map | Domain map — aggregates atoms, provides broad entry point. | One domain per file |
topics/projects/ | Project | Brainstorm workspace for active work. | One project per file |
topics/research/ | Research Question | Cross-source synthesis for a specific research question. | One question per file |
_exports/ | — | Composed topic export — generated by memex-compose. Gitignored. | One per compose session |
Every curated note carries type: — the one field that survives the folder
layout being flattened, and the only field the Open Knowledge
Format makes
mandatory. medium: is the subtype of a source (web, video, paper,
docs, meeting), so a paper is type: Source + medium: paper.
Workflow position is stage:, not status: — see _meta/schema.md § Stage
Values for why that distinction is load-bearing. Provenance is generated:
(who made this note) and verified: (who has since checked it). verified: is
append-only, written by memex-trust-audit on an explicit human yes and never
inferred — and signing off deliberately does not bump updated:, because
checking a note is not revising it.
Extract filenames carry an ext- prefix (extracts/ext-2026-04-27-lewis-rag.md
for sources/paper/2026-04-27-lewis-rag.md). Obsidian resolves wikilinks by
filename, so without the prefix every cites:: [[2026-04-27-lewis-rag]] already
written on an atom would go ambiguous the moment the extract appeared.
Relationship Taxonomy
Connections are Dataview inline fields written in note bodies, not frontmatter:
extends:: [[Other Atom]]
cites:: [[source-filename]]
Affirmative (source → atom)
| Field | Meaning |
|---|---|
supports:: | Source provides evidence for a claim in this atom |
introduces:: | Source is where this concept first appeared in the vault |
demonstrates:: | Source shows a concrete worked example |
Skeptical (source → atom)
| Field | Meaning |
|---|---|
challenges:: | Source questions or weakens a claim; describe the tension in the atom body |
refutes:: | Source provides direct counter-evidence; stronger than challenges:: |
Any note → source
| Field | Meaning |
|---|---|
cites:: | References a source as evidence (affirmative or neutral) |
rebuts:: | References a source as counter-evidence |
Structural (atom → atom)
| Field | Meaning |
|---|---|
extends:: | Builds on / specializes another concept |
uses:: | Applies or depends on another concept |
part-of:: | Component of a broader concept |
Epistemic (atom → atom)
| Field | Meaning |
|---|---|
contradicts:: | Direct logical conflict; document tension in both atoms |
challenges:: | Weakens or questions without direct contradiction |
supersedes:: | Replaces or obsoletes in modern understanding |
limits:: | Defines where the target breaks down or partially applies |
contrasts-with:: | Alternative approach to the same problem |
Navigational
| Field | Meaning |
|---|---|
related:: | Loosely connected; fallback only — refine monthly |
defines:: | Any note → glossary term |
Topic membership is derived, not written
A topic does not list its atoms. Each atom declares part-of:: [[Topic]], and the
topic surfaces its membership with a Dataview query:
LIST FROM "atoms"
WHERE contains(row["part-of"], this.file.link)
There is one source of truth and nothing to keep in sync. Outside Obsidian, the
same set is recovered with grep -rlE "^part-of::.*\[\[<topic>\]\]" atoms/.
Full taxonomy with decision tree for skeptical relations: _meta/schema.md
Obsidian Plugins
Exactly one plugin is load-bearing. Everything else is convenience: the vault is
readable, writable, and checkable without any of them, because _meta/lint.sh
answers in plain text what _meta/index.md answers in Dataview.
Required
| Plugin | Kind | Why | Install name |
|---|---|---|---|
| Dataview | Community | The only hard dependency. Powers every _meta/index.md catalog and every relationship query. | dataview |
| Canvas | Core | Only if you keep canvas/. Disabling it makes that folder dead. | built-in |
Dataview is not replaceable by Bases. Core Bases reads YAML frontmatter
properties; this vault's typed relations (cites::, part-of::, supports::,
contradicts:: …) are Dataview inline fields in the note body, which Bases
cannot see. The frontmatter-only catalogs in _meta/index.md would port to a
Base; the link-graph queries — orphan detection, topic membership, unpromoted
extracts — would not. Enable Bases if you want it, but not instead of Dataview.
Optional (quality-of-life)
| Plugin | Kind | Why | Install name |
|---|---|---|---|
| Backlinks | Core | Sidebar pane showing what links here. Convenience only — Dataview's file.inlinks reads Obsidian's metadata cache and works whether or not this is enabled | built-in |
| Graph view | Core | Visualize the knowledge graph; see the group colouring below | built-in |
| Properties | Core | Frontmatter sidebar pane. In-document property editing is built into the editor and does not depend on it | built-in |
| Tags | Core | Tag pane. The vault reads tags through Dataview, never through the pane | built-in |
| Templater | Community | Only if you hand-author notes in the Obsidian UI. Core Templates covers everything the shipped templates use — see below | templater-obsidian |
Deliberately not required
Folder Notes and Graph Analysis were listed as requirements through
Phase 4 and have been removed. Nothing in _meta/, _templates/, or any skill
referenced either, and the vault contains no folder notes. Graph Analysis has
additionally had no release since January 2022, and the job it does —
co-citation and link prediction — is covered here by memex-connect and
memex-candidates, which write their results to disk rather than into a pane
that disappears. Install either if you like them; neither is part of the vault
contract.
Obsidian Configuration
1. Templates
The shipped templates in _templates/ use exactly two Templater substitutions:
<% tp.date.now("YYYY-MM-DD") %> and <% tp.file.title %>. Both have core
equivalents, so either plugin will do.
With Templater (Settings → Templater):
- Template folder location:
_templates - Enable Trigger Templater on new file creation (optional but recommended)
- Set a hotkey for Create new note from template (e.g.,
Ctrl+T)
With core Templates instead (Settings → Templates): set the same template
folder, then in your local copies swap <% tp.date.now("YYYY-MM-DD") %> for
{{date:YYYY-MM-DD}} and <% tp.file.title %> for {{title}} — core Templates
does not understand <% %> and will leave it in the note verbatim. You lose
apply-on-creation: create the note first, then run Insert template.
Either way, all digital sources use source-digital.md; set medium: manually
after creation.
Neither plugin is on the skill path. memex-ingest, memex-save,
memex-meeting, memex-topic-init, and memex-deep-extract copy the template
structure and fill the placeholders themselves, so template syntax never
reaches a generated note.
2. Dataview setup
Settings → Dataview:
- Enable Inline queries — required for
extends::,cites::, etc. to be queryable - Enable Dataview JS queries (optional; needed only for advanced index queries)
- Set Refresh interval to
2500msor lower for responsive live tables
3. Exclude archive from indexing
Already configured in .obsidian/app.json. The .archive/ folder will not appear in file explorer, graph, or search results.
4. Graph view coloring (optional but recommended)
Settings → Graph view → Groups:
- Add group:
path:sources/→ color orange - Add group:
path:extracts/→ color grey - Add group:
path:atoms/→ color blue - Add group:
path:glossary/→ color green - Add group:
path:topics/→ color purple
Grey for extracts is deliberate: they are evidence, not curated knowledge, and should read as background in the graph rather than as nodes to navigate by.
Using the Skills
Skills live in skills/ and are invoked by talking to Claude Code naturally — there's no special syntax. Claude reads the skill's description to decide when to load it, then follows the workflow instructions inside.
To trigger a skill: just describe what you want. Examples that work:
- "quick save this: https://..." → capture
- "what do I know about attention mechanisms?" → search
- "reconcile my vault" → reconcile
If Claude doesn't pick up the right skill, name it explicitly: "use memex-ingest to save..."
Skill Lifecycle
The skills follow a natural progression from raw input to composed output:
CAPTURE ─────────────────────────────────────────────────
save URL → fetched title + summary draft; branches on read stage;
optional collaborative summary session
ingest URL → fully processed note + atoms
meeting meeting notes → structured source note
STRUCTURE ───────────────────────────────────────────────
connect inbox notes → enrich metadata + wire connections
deep-extract source → quote-grounded claims (mode A); claims → atoms (mode B)
topic-init create a new topic map (top-down)
topic-emerge discover emerging topic clusters from atoms (bottom-up)
refactor revise / split / merge existing atoms
MAINTAIN ────────────────────────────────────────────────
reconcile fix dangling part-of; promote stale related:: to typed relations
trust-audit audit confidence against the claim rubric; record human sign-off
conflicts surface and document unacknowledged tensions
stale read-only decay audit (unread age, stale atoms, underconfident topics)
COMPOSE ─────────────────────────────────────────────────
compose topic → structured Markdown export in _exports/
NAVIGATE ────────────────────────────────────────────────
search query the graph top-down by topic or concept
review semantic validity audit of one topic map
log-query query ingest history (recency, medium, atom)
SUPPORT ─────────────────────────────────────────────────
glossary scan a note for terms needing glossary definitions
candidates review and apply pending writes from dropped sessions
Run reconcile before trust-audit; run both before compose. The output quality of compose depends directly on graph integrity (reconcile) and trustworthy confidence signals (trust-audit).
deep-extract is the exception to "run it regularly": it is by far the most
expensive skill here, so it is user-invoked, one source at a time, never
automatic and never vault-wide. Reach for it when a source is dense enough that a
document-level summary loses what it said, or when stale / trust-audit names
a specific source as under-extracted. Ingest first, then extract — it does not
replace ingest (which summarizes) or connect (which wires whole sources).
Workflow Patterns
Saving new knowledge
| What you have | What to say | Skill |
|---|---|---|
| A URL to save (read or unread) | "save this: [url]" | save |
| A URL ready to process with atoms | "ingest this: [url]" | ingest |
| Meeting notes | "log this meeting" | meeting |
Building and maintaining the graph
| Task | What to say | Skill |
|---|---|---|
| Process inbox notes into the graph | "process my inbox" | connect |
| Start a new domain area | "create a topic map for [domain]" | topic-init |
| Discover topics from accumulated atoms | "what topics are emerging?" | topic-emerge |
| Update an atom's body | "revise atom [name]" | refactor |
| Atom covers two things | "split [atom] into [A] and [B]" | refactor |
| Merge redundant atoms | "merge [A] and [B]" | refactor |
| Read one dense source claim by claim | "deep extract [paper]" | deep-extract |
| Ground an atom's confidence in real quotes | "promote the claims in [extract]" | deep-extract |
| Fix graph drift after bulk ingest | "reconcile my vault" | reconcile |
| Review confidence levels | "trust audit [topic]" | trust-audit |
| Record that you checked an atom | "sign off on [atom]" | trust-audit |
| Find undocumented tensions | "find conflicts in my vault" | conflicts |
Searching and synthesizing
| Task | What to say | Skill |
|---|---|---|
| Find what you know about X | "what do I know about [topic]?" | search |
| Audit a topic's structure | "review my [topic] concept map" | review |
| Export a topic as a document | "compose [topic]" | compose |
| Check recent ingest activity | "what did I ingest this week?" | log-query |
| Decide what maintenance to do | "what should I run now?" | tend |
Maintenance cadence
Ask memex-tend — "what should I run now?" It runs _meta/lint.sh once,
routes the findings to the skills that can act on them, and proposes them in
dependency order. It reports before it runs anything, and never invokes
memex-deep-extract.
The cadence it encodes, if you would rather drive by hand:
- After each ingest session: run
memex-connectto close any inbox items - Weekly: open
_meta/index.md— scan orphan atoms and stale unread sources - After 5+ new sources in an area: run
trust-auditon that topic - Monthly: run
bash _meta/lint.sh; runmemex-stale; runreconcile; runreviewon one active topic - Before sharing research: run
reconcile→trust-audit→conflicts→compose
Claude Code Skills Reference
| Skill | Phase | Trigger phrases |
|---|---|---|
memex-save | Capture | "quick save", "just bookmark", "save this", "I've read this", "mark as read" |
memex-ingest | Capture | "ingest this", "add to wiki with atoms", "full ingest" |
memex-meeting | Capture | "log this meeting", "save meeting notes", "record this discussion" |
memex-connect | Structure | "process my inbox", "wire up my notes" |
memex-deep-extract | Structure | "deep extract [source]", "what did [paper] actually say", "promote the claims in [extract]" |
memex-topic-init | Structure | "create topic map", "start a new topic", "initialize [domain]" |
memex-topic-emerge | Structure | "what topics are emerging", "discover clusters", "find natural groupings", "suggest topic maps" |
memex-refactor | Structure | "refactor atom", "split [atom]", "merge [A] and [B]", "revise [atom]" |
memex-reconcile | Maintain | "reconcile my vault", "check graph integrity", "fix bidirectional links" |
memex-trust-audit | Maintain | "audit confidence", "trust audit [topic]", "are my atoms overconfident", "sign off on [atom]" |
memex-conflicts | Maintain | "find conflicts", "what's in tension", "surface contradictions" |
memex-stale | Maintain | "find stale notes", "decay check", "what's been sitting unread" |
memex-compose | Compose | "compose [topic]", "write up my notes on", "export my research on" |
memex-search | Navigate | "what do I know about", "find sources on", "search my wiki" |
memex-review | Navigate | "review this topic", "audit my concept map" |
memex-log-query | Navigate | "what did I ingest this week", "show unprocessed sources", "log stats" |
memex-glossary | Support | "scan this note for jargon", "what terms need defining", "build glossary from [atom]" |
memex-candidates | Support | "show pending candidates", "what's waiting to be applied", "recover my session" |
memex-init | Support | "initialize my vault", "set up this vault", "specialize this template", "I just forked this" |
memex-tend | Support | "what should I run now", "tend my vault", "vault health check", "weekly maintenance" |
Specializing This Template
This repo is a template. Forking it for a different subject — law, medicine, a company's internal docs — means editing one file.
Run memex-init and it edits that file for you: five questions, then it
rewrites the vocabulary, scaffolds the folders that vocabulary implies, seeds one
topic to enter at, and leaves the vault passing _meta/lint.sh. Everything below
describes what it writes, and what to change by hand if you would rather.
That file is _meta/domain.md. It holds everything instance-specific:
| Section | What it controls |
|---|---|
| Domain Name | Free-text label used in exports and scaffolding |
| Domain Tags | Subject-matter tags — replaced wholesale on a fork |
| Type Tags | What kind of thing a note is (foundational, survey, …) |
| Stage Tags | Workflow flags for human review (needs-review, stale) |
| Source Types | Valid medium: values; each needs a sources/<medium>/ folder |
| OKF Types | Folder → type: mapping; rename Atom to Note here and nowhere else |
_meta/lint.sh reads all of it from that file, so extending a vocabulary never
means editing a script.
What you keep: _meta/schema.md (relation types, stage values, naming
patterns), all 20 skills, all 8 templates, _meta/lint.sh, and
_meta/normalize.sh. These are the structure every memex-vault shares.
Paths need no editing. Every skill resolves the vault root at run time —
VAULT="${MEMEX_VAULT:-$(git rev-parse --show-toplevel)}" — so a fork works at any
path with no search-and-replace. Set MEMEX_VAULT only if the vault is not a git
repository, or if you run the skills from outside it.
What you should also change, in practice:
topics/concepts/getting-started.md— rewrite the Overview for your domainsources/<medium>/folders — add or remove to match your Source TypesREADME.md— this file
Sanity check after a fork:
bash _meta/lint.sh # must exit 0
A renamed type that lint does not know about fails immediately, so a half-done
rename cannot go quiet. The source-type vocabulary is read from _meta/domain.md
too: add hearing to § Source Types and lint applies every naming and frontmatter
check to sources/hearing/, and warns if the folder is missing — or if a folder
under sources/ was never declared, whose notes would otherwise go unchecked.
Which template version is this fork on?
GitHub's Use this template starts your repository at a single fresh commit. None
of the template's history, tags, or releases come with it, so git log cannot tell
you what you forked from.
Root VERSION can. It is one line naming the template release, it comes across
with the copy, and a fork never edits it — it records provenance, not the
vault's own version. memex-init reads it and writes template:: v<version> into
its _meta/log.md entry, so the answer survives even if the file is later lost.
To see what has changed upstream since, compare that version against
CHANGELOG.md in the template repository. To actually take the
changes:
git remote add template git@github.com:bcmcpher/memex-vault.git
git fetch template
git diff v<your-version> template/main -- skills/ _meta/schema.md _meta/lint.sh
Merge selectively. _meta/domain.md, README.md, and getting-started.md are
yours and will conflict by design; the skills, the constitution, and the scripts
are the parts worth pulling. Re-run memex-init afterwards to log the new version.
Naming Conventions
| Type | Pattern | Example |
|---|---|---|
| Sources (non-meeting) | YYYY-MM-DD-kebab-title.md | 2026-04-27-attention-is-all-you-need.md |
| Meetings | YYYY-MM-DD-kebab-context.md | 2026-04-27-rag-architecture-sync.md |
| Atoms | kebab-concept-name.md | transformer-architecture.md |
| Glossary | term.md | self-attention.md |
| Concept maps | kebab-domain.md | deep-learning.md |
| Projects | proj-kebab-name.md | proj-rag-pipeline.md |
| Research notes | rq-kebab-question.md | rq-scaling-laws-llms.md |
Source Text Archival
Full article/transcript text is not stored in the vault by default. The .archive/ folder provides an opt-in escape hatch:
- Save full text through the normalizer:
<fetch> | bash _meta/normalize.sh > .archive/YYYY-MM-DD-slug.md - Add
raw:: .archive/YYYY-MM-DD-slug.mdto the source note
The archive is gitignored and excluded from Obsidian's indexer.
Always pipe through _meta/normalize.sh. It folds ligatures, smart quotes,
dashes and exotic spaces to ASCII, rejoins words split across line breaks, and
unwraps each paragraph onto one line. memex-deep-extract grounds every claim by
running grep -F for its verbatim quote against this file, and _meta/lint.sh
section 12 FAILs on a miss — raw pdftotext output would fail that check on
almost every multi-line quote and turn the anti-fabrication guarantee into noise.
The script is deterministic and idempotent, so bringing a legacy archive up to
standard is safe:
bash _meta/normalize.sh --in-place .archive/YYYY-MM-DD-slug.md
When to use archival: High-value sources at risk of link rot; long-form
content you expect to re-read in full; papers you need offline. It is also a hard
prerequisite for memex-deep-extract — a claim with no checkable quote is not a
claim, so the skill refuses to run without an archive.
Because .archive/ is gitignored, the grounding guarantee is local-only. On a
fresh clone the archive is simply absent, and both the archive-mismatch check and
the grounding check SKIP rather than fail — unverifiable is not fabricated.
That is stated plainly rather than pretended around: grounding cannot run in CI.
Extract quotes themselves are committed, unlike the archives they come from. They are short attributed excerpts — ordinary citation, and the reason the guarantee is auditable by anyone reading the repo. Keep them that way: quote the sentence that carries the claim, not the paragraph around it.
Optional MCP Integrations
The memex-connect skill can fetch most URLs natively via WebFetch, but two source types benefit from dedicated MCP servers: YouTube transcripts and PDFs.
YouTube Transcripts
The memex-connect skill extracts video title and channel from the YouTube page, but cannot retrieve full transcripts without an API. A transcript MCP enables structured ## Key Points with timestamps.
Option: mcp-youtube — wraps the youtube-transcript Node package; no API key needed for public videos.
To install:
npm install -g @anaisbetts/mcp-youtube
Then add to .claude/settings.local.json:
"mcpServers": {
"youtube": {
"command": "mcp-youtube"
}
}
PDF Text Extraction
PDFs cannot be fetched as text via WebFetch. A PDF MCP lets the connect skill extract title, authors, abstract, and body text from local or remote PDF files.
Option: mcp-pdf or a local wrapper around pdftotext (part of poppler-utils).
A minimal approach using pdftotext (already installed on most Linux/macOS systems):
# Install poppler if needed
apt install poppler-utils # Linux
brew install poppler # macOS
Then add a shell MCP wrapper to .claude/settings.local.json:
"mcpServers": {
"pdf": {
"command": "bash",
"args": ["-c", "pdftotext \"$1\" -", "--", ""]
}
}
Note: test specific MCP server stability before committing to one — the ecosystem is still maturing. The skills degrade gracefully without these integrations (PDFs prompt for manual metadata; videos leave Key Points empty).
Further Reading
- Karpathy's original LLM wiki concept
- Extended memory hierarchy discussion
- llm-atomic-wiki (linting patterns)
- llm-wiki-compiler
- claude-obsidian (Obsidian integration)
_meta/ccm-mapping.md— how this vault's design lines up with PaperGuru's Capital Chunk Memory (CCM) architecture
How to Install
- Download the ZIP or clone the repository
- Open the folder as a vault in Obsidian (File → Open Vault)
- Obsidian will prompt you to install required plugins
Stats
Stars
0
Forks
0
License
MIT
Last updated 1mo ago