Charlotte, NC
BlogSeptember 21, 2026

Using Obsidian as a shared work brain for AI coding agents

Blake McCarn
Using Obsidian as a shared work brain for AI coding agents
I want to start a coding session without explaining the project again. What changed last time? Which approach did we rule out? Is that pull request waiting for review, or did it merge while I was working on something else? The code answers some of those questions. The rest tends to live in terminal conversations, scattered notes, and whatever I remember to mention in the next prompt. I use Obsidian to keep that working context outside the conversation. Agents read the relevant notes before starting, then update them as the work changes. The files stay useful when I switch providers, move to another machine, or come back to a project after a break. Once I had several vaults, I needed a way to search them from those different environments. That became Obsidian Vault RAG, a retrieval service that indexes selected notes and exposes them through project-scoped profiles. I wrote about managing coding agents with Herdr because keeping terminals, repositories, and long-running sessions organized had become its own problem. Persistent sessions help with that. They don't decide which parts of a conversation the next agent needs to know. A transcript can contain the original plan, three abandoned approaches, a test failure, a correction, and the final result. All of it happened. Only some of it describes the current project. I don't want a new agent to read the entire transcript and guess which statements still apply. I want it to find the current state, understand why we got there, and check the underlying system before making another change. That is the job of the vault. It holds the project record that needs to survive a particular session. Provider-specific memory can still hold preferences and small reminders, but I keep ongoing project state in files that both the agent and I can inspect. The useful part of Obsidian is that its vault is a folder of files. I can edit a note in the application, an agent can update the same Markdown through its file tools, and Git can show me the diff. Links connect a project note to its open PRs, deployment sequence, and relevant reference material. Frontmatter gives those notes enough structure for dashboards without making every paragraph a database field. I can browse the work in Obsidian while an agent reads the underlying files. A folder of notes doesn't tell an agent how to maintain it. I keep that agreement in AGENTS.md, next to the notes it governs. It defines what to read at the start of a session, where new information belongs, and what has to be written back before the session ends. Different agents can use the same contract instead of each inventing a filing system. The main principle is one fact, one home. The project note owns the current project state. A PR note owns its review findings. Other notes link to that information instead of copying it. The journal preserves the sequence of events, including mistakes and corrections, while the owning note reflects what I currently know. Evidence matters more than a confident paragraph. The contract separates editing a note from verifying its claims. Before an agent marks work complete or acts on an old status, it checks the primary source. Closing a note needs an outcome with evidence another session can inspect. If a claim hasn't been checked, the note should say so. I also keep the authority limits explicit. A deployment sequence describes the steps; it doesn't grant permission to run them. A follow-up records work that remains; it doesn't override an approval requirement. Secrets stay outside the vault. Keeping useful context should not mean copying credentials into searchable notes. These are instructions for the agents I configure to use this vault, not behavior Obsidian enforces. Each environment needs to load the contract and connect any supporting hooks. Retrieving a paragraph through Vault RAG is not the same as loading the full operating instructions. HOME.md answers a different question: where should I look now? It points a new reader to AGENTS.md, then brings together the project, PR, deployment, and review views. A short callout can direct attention to a blocker or a note worth reading first, with the details left in the owning note. I don't want to maintain a second status report in that file. The embedded views use the notes' metadata, and the follow-up search finds tasks where they already live. When I correct a project note, I shouldn't also have to remember to correct a paragraph on the home page. At startup, the agent reads the contract, uses HOME.md to locate relevant work, and opens recent journal entries and the owning notes. It still checks live evidence before consequential action. That gives it a starting point without treating the dashboard as either a complete history or proof that every status is current. I separate notes by the job they do. A daily log and a project note can describe the same work, but they should answer different questions. These are the folder roles I use, not a required Obsidian layout. Most of the value comes from knowing which file owns a fact. journal/ has one Markdown file per day. Each session appends a timestamped block describing the work, the decisions, and the reason for them. It links to the project or PR notes that changed. Several agents can contribute separate blocks to the same day's record. I don't rewrite an earlier block when a conclusion changes. I append a correction and fix the current-state note. That leaves the investigation understandable without making an old conclusion look current. The journal is also where I record a native agent session reference when one is available. It helps me find the original conversation while the provider still retains it. The useful handoff has to be in the note itself, though. A session ID is not a durable substitute for the decision and its evidence. A note in projects/ follows a workstream, which may span several repositories. It holds the goal, current state, important decisions, and remaining follow-ups. Its short milestone log points into the journal instead of copying every session. prs/ is narrower. If I work on a pull request and it remains open when the session ends, it gets a note with its review findings, blockers, and merge or deployment state. A PR opened and merged in one session can stay in the journal. I don't need a permanent tracking file for every small change. For a change spread across several PRs, one note owns the shared decisions and ordering. Companion notes keep their own status and link back. That avoids three copies of the same blocker drifting apart. deployments/ holds the rollout sequence when order matters. The note records preconditions, checks between steps, and a rollback plan. Merged and deployed are separate states. A merged PR is evidence that the source changed, not that the running service did. Follow-ups are checkboxes in the note that owns the work. I link to them from the journal rather than copying them into a second task list. When work is complete, I record the outcome and close the note through its metadata. The file stays in place so old links and search results still work. notes/ holds a reusable fact or gotcha that deserves its own explanation. A project can link to it without bringing along the entire investigation. inbox/ is for a useful capture whose destination isn't clear yet. It needs later triage; leaving everything there would recreate the pile of disconnected notes I was trying to avoid. templates/ gives each note type a consistent starting structure. A project starts with current state and follow-ups. A deployment starts with preconditions and a sequence. attachments/ holds supporting files that aren't Markdown. The operating rules live in AGENTS.md. Reusable maintenance procedures live in skills/, and hooks/ contains checks that configured agent tools can invoke. Keeping those files with the vault lets them travel with Git. They still need to be wired into each agent environment. A file in a folder does not enforce a rule by itself. Obsidian Bases is a core plugin for viewing and editing properties of vault files. The data remains in the Markdown notes and their properties. A .base file defines the views, filters, and sorting. I embed those views in HOME.md, so a new session has one place to find unfinished projects, open PRs, and pending deployments. The dashboard is a view of the notes, not another record of their status. For example, this is an illustrative project's frontmatter. The dates and blocker are synthetic: The type puts it in the project view. status and blocked-on explain why it isn't moving. A project marked done or dropped leaves the unfinished-work view but remains available in the closed view and in the vault. A parked project is still unfinished; it should not disappear just because I have stopped working on it for now. I keep the view filters explicit about note types and exclude templates. Otherwise a template or an agent skill can look like an unfinished record with missing metadata. The corresponding trade-off is that a new note type needs a deliberate view update or the dashboard will omit it. The review queue uses verified, sorted oldest first, to help me find facts that need another check. updated tells me when someone edited the note. verified tells me when someone checked its claims against a primary source. Rewording a paragraph should not make a stale deployment claim look fresh. Open follow-ups use a separate embedded Obsidian search query over unchecked tasks. That is not a Bases table. The checkboxes stay in their owning files, and the dashboard helps me find them without maintaining a global copy. Bases is the browsing layer I use in Obsidian. A file-only agent reading HOME.md sees embed references, not the rendered table rows. It needs to read the underlying notes or inspect the view definitions to find the matching files. Vault RAG retrieves selected note text; it does not need to render the dashboard or reproduce its live views. Suppose a fictional application needs a database migration. The project note owns the goal and the decision to make the change in two stages. The PR note records the code review. The deployment note owns the order of operations and the checks needed before the second stage. If testing finds a compatibility problem, the journal records what was tried and what failed. The project note gets the current blocker. The follow-up goes in the note responsible for resolving it, and the other notes link there. At the next session, the agent reads that current state rather than reconstructing it from yesterday's transcript. After the fix lands, it still verifies the rollout before marking the deployment done. The closed notes remain searchable, while the dashboard stops presenting them as unfinished work. That is the division I want. The journal explains how I got here. The state notes tell me what to do next. The dashboard helps me find them. My vault instructions make the start and end of a session explicit. At the start, the agent reads AGENTS.md, follows HOME.md to the relevant notes, and reads recent journal entries. Those are known files, so direct reads are enough. There is no reason to run a semantic search to find a file whose name is already in the instructions. At the end of meaningful work, the agent appends a journal entry and updates the notes it affected. A PR that is still open gets a persistent record of its state. A resolved blocker gets corrected in the owning note. The changes go through Git so another machine can pick them up. Before merging or deploying, the agent checks the repository, deployment, or issue tracker again. A note helps it find the right evidence; it doesn't replace that evidence. Only an actual check justifies changing verified. A local folder is enough while all the work happens on one machine. My setup spans different machines and project directories, so I also need shared retrieval. I could maintain an index beside every checkout. That would mean each client has its own embedding configuration, indexing schedule, and potentially different view of the same notes. Instead, I run Vault RAG centrally and let clients query the same indexed revisions. The shared path looks like this: Each vault has a .vault-rag.toml manifest. It declares a stable vault ID, include and exclude rules, and an embedding egress policy. Machine-specific paths stay outside that manifest. The same vault can live in different folders without changing its identity. On the server, I configure which Git repositories and refs the workers may fetch. Workers build a new revision before promoting it. The API reads the active revision from PostgreSQL, including the indexed source text, so it doesn't need to reach into a workstation's filesystem. This also sets the freshness limit. The shared service sees pushed Git state after a worker indexes it. It cannot see an uncommitted note on another machine. Search results report commit identity, and I use a local read when I need work that hasn't reached the shared index yet. The central service adds a database and workers to operate. In return, adding another client doesn't mean building another copy of the retrieval stack on that client. I don't want a question about one application to search every note I own. A profile names the vaults that belong in a retrieval request. One project might need only its own vault. Another might also need shared operations notes. Cross-project research can use a broader profile, but that has to be a deliberate choice. For example, these illustrative entries show the membership part of a registry: The names are examples, not deployment identifiers. The service applies the selected profile's vault list before ranking results. A caller can narrow it further by vault, relative path prefix, or selected frontmatter fields. A filter cannot add a vault that the profile doesn't include. This gives me a useful middle ground between a separate search service for every project and one search over everything. Shared reference material is available where it is relevant, without becoming the default context for unrelated work. There is an important limit. Profiles are retrieval scopes, not user permissions. The current service has no application authentication, and any client that can reach it can select any configured profile. I run it on a trusted private network. Separating mutually untrusted users would need an additional authorization design or separately protected deployments. That fits the private operations model I described in Tailscale First, Cloudflare Tunnel Still in the Stack. A private retrieval service doesn't need a public application route just because its source code is public. Vault RAG returns source text and citations. The agent that asked the question writes the answer. I wanted to keep those jobs separate. My personal knowledge graph has a more involved query and synthesis pipeline. Here, the caller is already an agent with its own model and task context. Adding another answer generator inside the retrieval service would duplicate that role. The MCP interface has four tools. vault_profiles helps a client find the right scope. vault_search returns candidate excerpts. vault_read retrieves the source behind a hit. vault_status reports readiness and freshness when something needs diagnosing. A hit includes a recommended_read object with the source hash. The agent passes it to vault_read unchanged. If the source no longer matches, the service returns stale_source, and the agent searches again. That prevents a search of one version from silently turning into a citation of another. The hash doesn't prove the note is correct. It proves the read matches the source version the search found. The agent still needs to check whether that note supports the answer and whether the underlying fact needs fresh verification. Exact words matter in project notes. A file path, a commit hash, or a PR reference is often a better starting point than a broad natural-language question. Vault RAG supports lexical, dense, and hybrid search. Hybrid search combines the lexical and embedding results, while recognized exact identifiers get their own priority. I keep lexical search available because a useful lookup shouldn't disappear just because the embedding provider is unavailable. If a hybrid request falls back to lexical results, the response reports the degraded semantic state. I want the caller to know that happened. Quietly returning fewer kinds of evidence would make failures harder to diagnose. Embeddings also have a privacy cost. A remote provider receives selected note text and queries. Sending the request through a local proxy doesn't change that if the proxy forwards it upstream. The vault's file selection and egress policy need to reflect where the text actually goes. For one local vault, the SQLite CLI can run keyword search without an API key or a database server. The central PostgreSQL deployment earns its complexity when multiple clients need the same indexed sources. It isn't a prerequisite for keeping useful project notes. The weakest part of this setup is still the quality of the handoff. If an agent finishes the code but leaves the project note unchanged, the next session starts with stale information. If it copies the same status into several notes, those copies can disagree. Search will happily retrieve them with valid citations. I keep the writeback rules small enough to follow: update the owning note, append the session history, and link the evidence. More elaborate retrieval doesn't compensate for skipping those steps. There is also a limit to what belongs in the vault. Shared repository documentation still belongs with the code. The vault holds my working context around it, not a private replacement for documentation other contributors need.
  • Obsidian, Bases, and Markdown for project notes and property-based dashboard views
  • Git for synchronization and reviewable note history
  • Python for the Vault RAG CLI, indexer, and service
  • SQLite FTS5 for local keyword retrieval
  • PostgreSQL and pgvector for the shared index and source revisions
  • An OpenAI-compatible embedding endpoint for optional semantic search
  • MCP and HTTP for read-only client access
  • Kubernetes and Helm for my central deployment
Obsidian Vault RAG is MIT licensed. The repository includes a local installation guide and a no-key demo, so trying it doesn't require reproducing my infrastructure. The improvement I care about is at the next session. I want the agent to find the relevant project state, check it, and continue the work without asking me to reconstruct the previous conversation.
Share this post: