obsidian-axi
August 11, 2026 ยท View on GitHub
A command line tool that lets coding agents work with your Obsidian notes.
It reads and writes the vault folder directly. No plugin to install, no server to run, no API key, and Obsidian does not even have to be open.
$ npx -y @andershoffmann/obsidian-axi
bin: ~/.local/bin/obsidian-axi
description: Agent ergonomic CLI for Obsidian vaults - read, search, write, and link notes.
vault:
name: My Vault
path: ~/Documents/My Vault
notes: 214
source: obsidian.json (open)
recent[5]{path,modified,ago}:
Projects/Roadmap.md,2026-08-10,1d
Inbox/Idea.md,2026-08-09,2d
...
help[3]:
obsidian-axi search <query>
obsidian-axi ls --recursive
obsidian-axi tags list
Built to the AXI standard, which is a set of design rules for CLIs that agents drive.
Why not an MCP server?
An MCP server loads its tool definitions into the model's context on every single turn, and
that cost adds up. A CLI does not, and it pipes into grep and head like anything else.
The Obsidian MCP servers also need real setup: a community plugin, a bearer token, and a running Obsidian. The most popular one does not currently install on a fresh machine, and four of its tools no longer work with the current plugin.
The trade is that anything needing a live Obsidian is out of scope here. No Dataview, no Templater, no semantic search, no command palette. In exchange it works everywhere, right away.
Install
Nothing to install. Just run it:
npx -y @andershoffmann/obsidian-axi <command>
If you want the setup hooks and update commands too, install it properly:
npm i -g @andershoffmann/obsidian-axi
obsidian-axi setup hooks
setup hooks wires a SessionStart hook into Claude Code, Codex and OpenCode, so an agent
session opens with your vault summary already loaded. Running it twice is safe, and it does
not touch your other settings.
The package also ships an agent skill at skills/obsidian-axi/SKILL.md. It is generated
from the CLI's own help text, so it cannot drift out of date.
Needs Node 20 or newer.
Getting started
Run it with no arguments to see where you are:
obsidian-axi # your vault and its recent notes
obsidian-axi ls -r --sort modified # every note, newest first
obsidian-axi read Notes/Roadmap.md # one note, trimmed to 1000 characters
obsidian-axi read a.md b.md --metadata # just frontmatter and counts
obsidian-axi search cosmosdb --context 2
obsidian-axi recent --days 7 # changed this week
obsidian-axi vault list # every vault Obsidian knows about
Every command takes --help.
One rule to remember: flags go after the command.
obsidian-axi vault info --vault "My Vault" # yes
obsidian-axi --vault "My Vault" vault info # no
Search
Search takes a query, some filters, or both.
obsidian-axi search TODO --tag project --context 2
obsidian-axi search --tag work --modified-since 7d # filters only, no query
obsidian-axi search --frontmatter status=active
obsidian-axi search "^## " --regex --path "Notes/**"
--tag project also matches #project/axi. You can repeat --tag and --frontmatter, and
everything you pass has to match.
Writing
obsidian-axi write Inbox/idea.md --content "# Idea"
obsidian-axi append Notes/log.md --content "- [ ] ship it"
echo "- piped note" | obsidian-axi append Inbox/log.md
obsidian-axi rm Inbox/draft.md # goes to .trash, so you can get it back
obsidian-axi mv Inbox/draft.md Notes/final.md
patch changes one part of a note without rewriting the whole thing. It can target a
heading's section, a block reference, or a frontmatter field.
obsidian-axi patch a.md --target-type heading --target Tasks --content "- [ ] new"
obsidian-axi patch a.md --target-type heading --target "Tasks::Today" --op prepend --content "- [ ] first"
obsidian-axi patch a.md --target-type frontmatter --target status=done --op replace
obsidian-axi patch a.md --target-type block --target abc123 --op delete
Two things worth knowing about patch:
- When you append to a heading, the text lands in that section only. It will not slip into a
nested subsection below it. To write inside
### Today, name it:--target "Tasks::Today". Using--op deleteon a heading removes the heading and everything under it. - Your line endings and trailing newline are left alone, so editing the middle of a note gives you a one line diff and nothing else.
Re-running a write is safe. Appending text a note already ends with, deleting a note that is already gone, and moving a note onto itself all do nothing and exit 0.
Links and tags
obsidian-axi links "Roadmap.md" # what it links to, and what links back
obsidian-axi links --broken # links pointing at notes that do not exist
obsidian-axi links --orphans # notes nothing links to
obsidian-axi tags # every tag, with a note count
obsidian-axi tags files project/axi
Links are resolved the way Obsidian resolves them: exact path first, then relative to the
note doing the linking, then a matching filename anywhere in the vault, then frontmatter
aliases. Attachments count too, so ![[Pasted image.png]] is not flagged as broken.
Tag counts roll up. #project includes notes tagged only #project/axi.
What Obsidian had open
obsidian-axi active # the note Obsidian last had focused
obsidian-axi open "Roadmap.md" # ask Obsidian to jump to a note
active reads .obsidian/workspace.json. Obsidian only writes that file when the layout
changes, not on every tab switch, so treat it as the last saved state rather than live. The
output tells you how old it is.
Picking a vault
First match wins:
--vault <name|path>OBSIDIAN_VAULT=<name|path>- a
.obsidian/folder in the current directory or above it defaultVaultin~/.config/obsidian-axi/config.json- the vault Obsidian has open
- the vault opened most recently
vault info tells you which rule applied, so you can check it picked the one you meant.
Output
Output is TOON, a compact format that writes lists as a header
plus rows, using roughly 40% fewer tokens than JSON. Lists come with a count: line, long
note bodies are trimmed to 1000 characters (use --full for all of it), and an empty result
says so in words instead of printing nothing.
Errors go to stdout too, with a code you can match on and a hint for what to try next:
error: Note not found `Notes/Roadmap.md`
code: NOTE_NOT_FOUND
help[2]:
obsidian-axi ls Notes
obsidian-axi search Roadmap
Exit codes: 0 worked (including "nothing to do"), 1 something went wrong, 2 you typed
it wrong.
If you use Obsidian Sync
Obsidian picks up outside edits and reloads the note. But if you have that note open with unsaved changes, Obsidian may overwrite what this tool just wrote. There is no way to detect that from the filesystem, so save or close the note first if it matters.
Writes go to a temp file and get renamed into place, so a note can never end up half
written. And rm moves notes to .trash unless you pass --permanent.
Status
Under active development, but all 16 commands work: the dashboard, ls, read, search,
recent, write, append, patch, rm, mv, links, tags, active, open, vault
and setup, plus update from the AXI SDK.
It is fast because it does the simple thing. No cache, no index, everything synchronous. On a 103 note vault a full recursive listing takes about 88ms and a full text search about 120ms, both including Node startup.
Does it actually save tokens?
npm run bench measures each command against the shell command an agent would otherwise
reach for. On a 103 note vault it returns 18% fewer characters overall, but that average
hides most of the story:
| task | obsidian-axi | plain shell | |
|---|---|---|---|
| search for a term | 5764 | 13406 | 43% |
| read a note's metadata | 111 | 512 | 22% |
| read a note | 651 | 512 | 127% |
| list every note | 8369 | 6218 | 135% |
| list tags | 637 | 502 | 127% |
Searching is the real win, since grep returns every matching line and this does not. Reading a typical note actually costs more, because the median note here is shorter than the 1000 character trim limit, so nothing gets trimmed and the metadata is overhead. On a long note the same command lands near 5%. Listing costs more too, because each row carries more than a path.
And when it does cost more, it is often answering a better question. links --broken
resolves real wikilinks, which no grep one liner can do.
bench/README.md has the full table, the caveats, and why a fair comparison against the Obsidian MCP servers is not possible right now.
License
MIT