Charlotte, NC
ProjectsSeptember 21, 2026

Obsidian Vault RAG

Tap image to enlarge
Obsidian Vault RAG makes Markdown project notes searchable from a terminal or an AI agent. It combines keyword and optional semantic retrieval, returns excerpts with file-and-line citations, and checks source hashes before reading the text behind a result. I built it because my working context spans several vaults and machines. The notes were useful locally, but an agent in another environment needed a consistent way to find the relevant project history without searching every vault or maintaining its own copy of the index. The tool supports a local SQLite CLI and a shared PostgreSQL-backed service with HTTP and MCP access. It reads existing vault files directly. There is no Obsidian plugin to install, and answer generation stays with the calling agent. A project accumulates more context than its code can explain. Decisions, review findings, deployment order, and unresolved follow-ups often sit in notes outside the repository. That context needs to survive individual agent conversations and remain available from the machines where the work happens. Putting every note into every prompt doesn't scale well. It also mixes unrelated projects. A shared retrieval service needs to know which sources belong in a request before it starts ranking them, and the results need to point back to text I can inspect. Each vault owns a .vault-rag.toml manifest with a stable ID, file-selection rules, and an embedding egress policy. A separate registry maps local paths and groups vaults into named profiles. Machine-specific paths don't need to travel with the notes. Profiles define the retrieval scope. A project can search its own vault, or include a shared reference vault when the work needs it. The retrieval layer applies that scope before lexical or dense ranking. Optional filters narrow it by vault, path prefix, source type, and manifest-selected frontmatter. The CLI stores its index in SQLite with FTS5 for keyword search. It compares content hashes to update added or changed files and remove deleted sources. Unchanged, fully embedded content does not need another embedding request. The Markdown parser preserves titles, heading context, selected frontmatter, and source line ranges. Those details matter for project notes: a result needs to identify the relevant section and give the reader a way back to the original text. The keyword-only path needs no Docker, database server, or API key. Indexing is explicit rather than file-watched, so the user runs it again after changing notes. Workers fetch only server-configured Git repositories and refs. They build indexed revisions in PostgreSQL, then promote a revision for the API to serve. The database stores source text as well as search data, so API replicas don't depend on a workstation or a persistent worker checkout. I run this path centrally for multiple clients. Git handles synchronization from the machines where notes are edited. The service sees pushed, indexed revisions, not unsaved files or arbitrary remote folders. Commit identity in results makes that distinction visible. The service supports lexical, dense, and hybrid search. Hybrid retrieval combines the two rankings with Reciprocal Rank Fusion. Recognized exact identifiers, such as a complete commit hash or a qualified PR reference, take priority over ordinary ranked matches. MCP clients use four read-only tools:
  • vault_profiles lists available retrieval scopes.
  • vault_search returns matching excerpts, citations, and recommended reads.
  • vault_read returns source text after checking the expected hash.
  • vault_status reports readiness, active revisions, and degradation.
The agent searches, passes a hit's complete recommended_read object to the read tool, and builds its answer from the returned text. If the source hash no longer matches, the read fails with stale_source. The agent searches again rather than dropping the hash check. The service does not generate answers, edit notes, or expose arbitrary repository access through MCP. That keeps the same retrieval path useful to different clients without coupling it to their model or conversation state. Filtering the candidate sources first keeps a project's retrieval focused. A broad query cannot expand its profile's vault list, and an optional filter can only narrow it. Profiles are not user permissions. The service currently has no application authentication, and every reachable client can choose any configured profile. My deployment stays on a trusted private network; mutually untrusted users would need separately enforced access boundaries. Project notes contain paths, identifiers, and exact terms that keyword search handles well. Embeddings add another retrieval method without making a provider call mandatory for every query. When semantic search is unavailable, hybrid responses can return lexical results with explicit degradation information. Keeping source text in PostgreSQL lets an API read the indexed revision without depending on a worker's checkout. It also makes the database sensitive: its contents and backups need the same protection as the original notes. The manifest defines both what is indexed and whether selected text may use a remote embedding route. Remote embeddings send note text and queries to the provider. A locally hosted proxy is still a remote data path when it forwards those requests upstream.
  • Python 3.12+ for the CLI, indexing pipeline, workers, and API
  • SQLite FTS5 for local lexical retrieval
  • PostgreSQL and pgvector for shared source revisions and vector storage
  • OpenAI-compatible embedding APIs for optional semantic search
  • MCP over Streamable HTTP for agent discovery, search, and source reads
  • Docker Compose and Helm for local service demos and Kubernetes deployment
  • GitHub Actions and GHCR for validation and container publication
The project is MIT licensed on GitHub. The installation guide starts with the local CLI and a synthetic demo before moving on to a user's own vault. HTTP and MCP require a separately deployed service. I wrote about the note-taking and agent handoff workflow behind it in Using Obsidian as a shared work brain for AI coding agents.

Related projects

Garmin MCP Server

Open-source MCP server that exposes 34 Garmin Connect health and fitness tools to any AI assistant, with parallel fetching and Docker support.

blakemccarn.dev

Portfolio and blog built with Next.js 16, deployed to AWS via SST v4 with Cloudflare DNS, staging environments, and full IaC.

Charlotte Wire & Cable

Full-stack business website for a specialty wire distributor: searchable catalog, admin dashboard, and serverless AWS infrastructure via SST.

Paperless OCR Enhanced

Open-source Paperless-ngx companion service that uses LLM vision models to repair weak OCR and improve downstream document search.

Paperless Knowledge Graph

Document intelligence system that combines Paperless-ngx, Neo4j, pgvector, Strands Agents, cited answers, and an interactive graph UI.

RapidEPR

Founded and built an AI SaaS product that helps service members across five military services write evaluations, performance statements, and award narratives.