I run Claude Code on top of an Obsidian vault. Have done for months — 24,000+ files, daily notes, project folders, task management, the lot. It works. But every vault operation has a tax.
Want to append a line to today’s daily note? Claude has to find the file (Glob), read its contents (Read), then edit it with the new line (Edit). Three tool calls, three round-trips, and Claude needs to hold the entire file in context just to add a line at the bottom.
Want to search the vault for something? Grep works, but it’s raw text search — no awareness of Obsidian’s link structure, tags, or metadata. And it returns file paths, not the content around the match, so Claude usually needs a follow-up Read call to see what it found.
Want to check today’s tasks? Parse the daily note’s markdown looking for - [ ] patterns. Hope the regex handles edge cases. Hope there aren’t tasks in nested callouts or embedded templates that break the pattern.
None of this is broken. It’s just expensive — in tool calls, in tokens, in context window space.
Obsidian 1.12 Grew a CLI
Obsidian 1.12 shipped a command-line interface. Not a separate binary — the CLI talks to the running Obsidian app via IPC. It has access to Obsidian’s full internal API: the file index, the link graph, the tag database, the plugin system. Everything the desktop app knows, the CLI can query.
For Claude Code users, this means vault operations go from multi-step tool chains to single bash commands.
Three Calls Becomes One
Here’s what common operations look like with and without the CLI:
Append to daily note:
| Without CLI | With CLI | |
|---|---|---|
| Steps | Glob to find file, Read contents, Edit with appended text | obsidian append file="20260228" content="\n## Log entry" |
| Tool calls | 3 | 1 |
| Context cost | Entire file loaded into context | Zero — append is blind |
Search vault with context:
| Without CLI | With CLI | |
|---|---|---|
| Steps | Grep for pattern, Read each matching file | obsidian search:context query="API integration" limit=5 |
| Tool calls | 1 + N (one per file you want to read) | 1 |
| Index | Raw text scan | Obsidian’s indexed search |
List today’s incomplete tasks:
| Without CLI | With CLI | |
|---|---|---|
| Steps | Find daily note path, Read file, Parse markdown for - [ ] | obsidian tasks todo daily |
| Tool calls | 2-3 | 1 |
| Reliability | Regex parsing, breaks on edge cases | Obsidian’s task parser |
Read a note by name:
| Without CLI | With CLI | |
|---|---|---|
| Steps | Glob with pattern guess, Read by path | obsidian read file="Project Kickoff" |
| Tool calls | 2 | 1 |
| Resolution | Exact path required | Wikilink-style name resolution |
Across the board: operations that required 2-3 tool calls collapse to one, path guessing gets replaced by wikilink resolution, and anything that required loading an entire file into context can now be done blind.
Setup: Five Minutes
Three steps. You need Obsidian 1.12 or later on macOS, Windows, or Linux.
1. Enable the CLI in Obsidian
Open Obsidian. Go to Settings, then General, then Command line interface. Toggle it on.
This registers a CLI handler so the obsidian binary (which already exists inside the app bundle) starts accepting commands instead of just launching the GUI.
2. Verify it works
Open a terminal:
obsidian vault list
You should see your vault name, path, file count, and size. If you see the GUI launching instead, the toggle didn’t take — restart Obsidian and try again.
3. Tell Claude Code to use it
Add this to your project’s CLAUDE.md or your global ~/.claude/CLAUDE.md:
## Obsidian CLI (Prefer for Vault Operations)
Use `obsidian <command> vault=<VaultName>` instead of Read/Edit/Write
for vault note operations. Requires Obsidian app running.
Key commands:
- `obsidian read file="NoteName"` — read by wikilink name
- `obsidian append file="NoteName" content="text"` — append without reading first
- `obsidian search:context query="text" limit=N` — search with context
- `obsidian tasks todo daily` — today's incomplete tasks
- `obsidian backlinks file="NoteName"` — incoming links
- `obsidian tags file="NoteName"` — tags for a file
When to still use Read/Edit/Write:
- Complex multi-edit operations
- Frontmatter YAML modifications
- Files outside the vault
- When Obsidian isn't running
That’s it. Claude Code will now prefer CLI commands for vault operations because the instructions tell it to. No plugins, no MCP servers, no API keys.
The Commands That Matter
The CLI has dozens of commands. These are the ones that actually change how Claude Code works with your vault:
read and append — The daily drivers. read file="NoteName" resolves names like wikilinks — no path guessing. append adds content without Claude needing to read the file first. For daily notes, session logs, inbox captures, this is the single biggest improvement.
search:context — Vault search that returns the matching line and its surroundings, not just file paths. One command replaces Grep + Read. The path= parameter scopes it to a folder, and limit= caps results.
tasks todo daily — Returns today’s incomplete tasks from your daily note. No markdown parsing, no regex. Also supports tasks todo path="03 Workbench/Project" to scope by project folder, and tasks todo verbose to group by file with line numbers.
task done — Mark a task complete by line number: task daily line=5 done. Claude can now check off tasks programmatically instead of doing a surgical Edit on a specific checkbox character.
backlinks and tags — Obsidian’s link graph and tag database, queryable from the terminal. backlinks file="Meeting Notes" shows every file that links to it. tags counts sort=count shows your most-used tags. These have no equivalent in raw file tools — you’d need to scan every file in the vault.
eval — Execute JavaScript inside Obsidian’s runtime. This is the escape hatch. Need to query Dataview? Check a plugin’s configuration? Modify settings programmatically? eval code="app.plugins.plugins['dataview']?.api?.pages('#project').length" runs inside Obsidian and returns the result.
Performance on a Real Vault
Timing on my vault (24,773 files, 5.1 GB):
| Command | Time |
|---|---|
read file="20260228" | 0.73s |
append (to daily note) | 0.25s |
search:context (scoped to folder) | 0.27s |
tasks todo daily | 0.25s |
These aren’t fast by CLI standards — the IPC overhead to the Electron app is real. But the comparison isn’t raw speed. It’s total operation cost: one 0.25s bash call versus three tool calls that each require an API round-trip, context loading, and token processing.
One thing to watch: vault-wide scans without scope filters are slow. tags counts across 24K files takes tens of seconds. tasks todo without daily or path= will crawl through everything. Always scope your queries with file=, path=, or daily.
What It Doesn’t Replace
The CLI isn’t a complete replacement for file tools. Use Read/Edit/Write when you need:
Complex multi-edit operations. The Edit tool lets Claude do precise string replacements at specific locations. The CLI has append and prepend but nothing equivalent to “replace this exact block of text with this other block.”
Frontmatter modifications. YAML frontmatter edits need structured manipulation. Appending to a file’s YAML block via CLI would be fragile. Edit tool is better here.
Files outside the vault. The CLI only sees what Obsidian sees. Config files, code repos, anything outside your vault root still needs the standard tools.
When Obsidian isn’t running. The CLI is an IPC client, not a standalone tool. If Obsidian’s closed, the commands won’t work. For headless or CI environments, stick with file tools.
Vault as Programmable Surface
Obsidian’s CEO kepano put it plainly: install 1.12, enable CLI, now any AI agent can use Obsidian. For me that’s the useful frame — not “Obsidian got a CLI” but “Obsidian became programmable.” Claude Code gets to work with the vault the way Obsidian understands it — through its index, its link graph, its plugin API — instead of treating it as a bag of markdown files.
In practice: my sessions do less file juggling. The context window stays cleaner. Operations that used to require holding an entire file in memory now happen in a single blind command. Fewer tool calls, less context overhead — and those savings compound across a working day.
I write about building with AI tools — the systems, the failures, and what actually works — over at Signal Over Noise.