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

Foldertype:RoleGranularity
sources/SourceURL + why-saved + short summary. Never full article text.One per URL or meeting
extracts/ExtractEvidence layer. What one source said, claim by claim, each with a verbatim quote. Never hand-curated.One per deep-extracted source
atoms/AtomConcept-level synthesis. Holds claims, links sources, connects to other atoms.One concept per file
glossary/Glossary TermPrecise term definitions. Lighter than atoms.One term per file
topics/concepts/Concept MapDomain map — aggregates atoms, provides broad entry point.One domain per file
topics/projects/ProjectBrainstorm workspace for active work.One project per file
topics/research/Research QuestionCross-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)

FieldMeaning
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)

FieldMeaning
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

FieldMeaning
cites::References a source as evidence (affirmative or neutral)
rebuts::References a source as counter-evidence

Structural (atom → atom)

FieldMeaning
extends::Builds on / specializes another concept
uses::Applies or depends on another concept
part-of::Component of a broader concept

Epistemic (atom → atom)

FieldMeaning
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

FieldMeaning
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

PluginKindWhyInstall name
DataviewCommunityThe only hard dependency. Powers every _meta/index.md catalog and every relationship query.dataview
CanvasCoreOnly 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)

PluginKindWhyInstall name
BacklinksCoreSidebar pane showing what links here. Convenience only — Dataview's file.inlinks reads Obsidian's metadata cache and works whether or not this is enabledbuilt-in
Graph viewCoreVisualize the knowledge graph; see the group colouring belowbuilt-in
PropertiesCoreFrontmatter sidebar pane. In-document property editing is built into the editor and does not depend on itbuilt-in
TagsCoreTag pane. The vault reads tags through Dataview, never through the panebuilt-in
TemplaterCommunityOnly if you hand-author notes in the Obsidian UI. Core Templates covers everything the shipped templates use — see belowtemplater-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 2500ms or 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 haveWhat to saySkill
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

TaskWhat to saySkill
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

TaskWhat to saySkill
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-connect to 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-audit on that topic
  • Monthly: run bash _meta/lint.sh; run memex-stale; run reconcile; run review on one active topic
  • Before sharing research: run reconcile → trust-audit → conflicts → compose

Claude Code Skills Reference

SkillPhaseTrigger phrases
memex-saveCapture"quick save", "just bookmark", "save this", "I've read this", "mark as read"
memex-ingestCapture"ingest this", "add to wiki with atoms", "full ingest"
memex-meetingCapture"log this meeting", "save meeting notes", "record this discussion"
memex-connectStructure"process my inbox", "wire up my notes"
memex-deep-extractStructure"deep extract [source]", "what did [paper] actually say", "promote the claims in [extract]"
memex-topic-initStructure"create topic map", "start a new topic", "initialize [domain]"
memex-topic-emergeStructure"what topics are emerging", "discover clusters", "find natural groupings", "suggest topic maps"
memex-refactorStructure"refactor atom", "split [atom]", "merge [A] and [B]", "revise [atom]"
memex-reconcileMaintain"reconcile my vault", "check graph integrity", "fix bidirectional links"
memex-trust-auditMaintain"audit confidence", "trust audit [topic]", "are my atoms overconfident", "sign off on [atom]"
memex-conflictsMaintain"find conflicts", "what's in tension", "surface contradictions"
memex-staleMaintain"find stale notes", "decay check", "what's been sitting unread"
memex-composeCompose"compose [topic]", "write up my notes on", "export my research on"
memex-searchNavigate"what do I know about", "find sources on", "search my wiki"
memex-reviewNavigate"review this topic", "audit my concept map"
memex-log-queryNavigate"what did I ingest this week", "show unprocessed sources", "log stats"
memex-glossarySupport"scan this note for jargon", "what terms need defining", "build glossary from [atom]"
memex-candidatesSupport"show pending candidates", "what's waiting to be applied", "recover my session"
memex-initSupport"initialize my vault", "set up this vault", "specialize this template", "I just forked this"
memex-tendSupport"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:

SectionWhat it controls
Domain NameFree-text label used in exports and scaffolding
Domain TagsSubject-matter tags — replaced wholesale on a fork
Type TagsWhat kind of thing a note is (foundational, survey, …)
Stage TagsWorkflow flags for human review (needs-review, stale)
Source TypesValid medium: values; each needs a sources/<medium>/ folder
OKF TypesFolder → 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 domain
  • sources/<medium>/ folders — add or remove to match your Source Types
  • README.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

TypePatternExample
Sources (non-meeting)YYYY-MM-DD-kebab-title.md2026-04-27-attention-is-all-you-need.md
MeetingsYYYY-MM-DD-kebab-context.md2026-04-27-rag-architecture-sync.md
Atomskebab-concept-name.mdtransformer-architecture.md
Glossaryterm.mdself-attention.md
Concept mapskebab-domain.mddeep-learning.md
Projectsproj-kebab-name.mdproj-rag-pipeline.md
Research notesrq-kebab-question.mdrq-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:

  1. Save full text through the normalizer:
    <fetch> | bash _meta/normalize.sh > .archive/YYYY-MM-DD-slug.md
    
  2. Add raw:: .archive/YYYY-MM-DD-slug.md to 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

How to Install

  1. Download the ZIP or clone the repository
  2. Open the folder as a vault in Obsidian (File → Open Vault)
  3. Obsidian will prompt you to install required plugins

Stats

Stars

0

Forks

0

License

MIT

Last updated 1mo ago