vaultdb
WHAT IT IS
vaultdb treats a folder of .md files as a relational database. Each folder is a table, each note is a row, every YAML frontmatter field becomes a queryable column, and [[wiki-links]] form a citation graph you can traverse and join across.
It's a CLI: no daemon, no cache, no state files. Every command reads the current files directly. That means you can edit notes in Obsidian and query them with vaultdb in the same second; they don't fight each other.
WHY I BUILT IT
Obsidian's graph view is pretty, but it doesn't answer questions. I wanted to ask things like "which of my AI notes are orphans," "what tags do I actually use," "which notes link to anything tagged topic/concept," or "walk the graph from BERT two hops out and show me what's within reach." Once I had a few hundred notes, the graph view stopped scaling and I started writing one-off shell scripts. vaultdb is the unified version of those scripts.
The design constraint was peaceful coexistence with Obsidian. No proprietary database, no schema migrations, no "import your vault." Every operation is a pure read or a careful in-place edit, with --dry-run on every mutation so you can see exactly what would change.
HOW IT WORKS
Filesystem is the schema
Folder = table. .md = row. frontmatter = columns. [[wiki-links]] = relations. Virtual fields like _backlink_count and _path come for free.Expressive where syntax
tags contains topic/ai, year > 2020, status exists, director matches ^Den. Multiple --where AND, || for OR within one.Graph traversal
--links-to-where "tags contains topic/ai" for cross-table queries on the link graph.Safe mutations
[[wiki-link]] updates across the vault. --dry-run on everything before commit.QUICK START
# Install from crates.io cargo install vaultdb # Use it inside any Obsidian vault cd ~/Documents/my-vault # What do my AI notes look like? vaultdb query 3-Notes \ --where "tags contains topic/ai" \ --select "_name,_backlink_count" \ --sort _backlink_count --desc --limit 5 # Find orphans vaultdb query 3-Notes \ --where "_backlink_count = 0" \ --where "_link_count = 0"