
Obsidian
- 1.2k installs
- 1.6k repo stars
- Updated August 3, 2026
- bitbonsai/mcpvault
obsidian provides documented workflows for >
About
The obsidian skill > # Obsidian Skill ## Routing Policy Use the backend that best matches user intent: 1. **MCP (default for vault data operations)** - Read/write/patch/move/search notes - Frontmatter and tag updates - Metadata and batch note operations 2. **Obsidian CLI/App context (only when app context is needed)** - Open a note in Obsidian from URI - Trigger app/plugin workflows that MCP cannot perform 3. **CLI git (sync/backup workflows)** - Initialize repo, configure remote, commit, pull, push - Periodic or manual vault backup/sync requests When a request is ambiguous, pick MCP first unless the user explicitly asks for sync/backup/git/app behavior. **patch_note rejects multi-match by default.** With `replaceAll: false`, if `oldString` appears more than once the call fails and returns `matchCount`. Set `replaceAll: true` only when you mean it, or add surrounding context to make the match unique. **patch_note matches inside frontmatter.** The replacement runs against the full file including the YAML block.
- **MCP (default for vault data operations)**
- Read/write/patch/move/search notes
- Frontmatter and tag updates
- Metadata and batch note operations
- **Obsidian CLI/App context (only when app context is needed)**
Obsidian by the numbers
- 1,229 all-time installs (skills.sh)
- +25 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #426 of 3,282 Productivity & Planning skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
obsidian capabilities & compatibility
- Capabilities
- **mcp (default for vault data operations)** · read/write/patch/move/search notes · frontmatter and tag updates · metadata and batch note operations · **obsidian cli/app context (only when app contex
- Use cases
- documentation
What obsidian says it does
# Obsidian Skill ## Routing Policy Use the backend that best matches user intent: 1.
**MCP (default for vault data operations)** - Read/write/patch/move/search notes - Frontmatter and tag updates - Metadata and batch note operations 2.
npx skills add https://github.com/bitbonsai/mcpvault --skill obsidianAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1.2k |
|---|---|
| repo stars | ★ 1.6k |
| Security audit | 3 / 3 scanners passed |
| Last updated | August 3, 2026 |
| Repository | bitbonsai/mcpvault ↗ |
How do I use obsidian for the task described in its SKILL.md triggers?
>
Who is it for?
Teams invoking obsidian when the user request matches documented triggers and prerequisites.
Skip if: Skip when cached docs are missing, the request is a negative trigger, or another sibling skill owns the workflow.
When should I use this skill?
>
What you get
Step-by-step guidance grounded in obsidian documentation and reference files.
- Synced git remote for vault
- Committed markdown backup
By the numbers
- Runs a 6-step git preflight checklist before vault setup or sync
- Separates three operation routes: MCP note tools, CLI git, and Obsidian URI actions
Files
Obsidian Skill
Routing Policy
Use the backend that best matches user intent:
1. MCP (default for vault data operations)
- Read/write/patch/move/search notes
- Frontmatter and tag updates
- Metadata and batch note operations
2. Obsidian CLI/App context (only when app context is needed)
- Open a note in Obsidian from URI
- Trigger app/plugin workflows that MCP cannot perform
3. CLI git (sync/backup workflows)
- Initialize repo, configure remote, commit, pull, push
- Periodic or manual vault backup/sync requests
When a request is ambiguous, pick MCP first unless the user explicitly asks for sync/backup/git/app behavior.
Gotchas
1. patch_note rejects multi-match by default. With replaceAll: false, if oldString appears more than once the call fails and returns matchCount. Set replaceAll: true only when you mean it, or add surrounding context to make the match unique.
2. patch_note matches inside frontmatter. The replacement runs against the full file including the YAML block. A generic string like title: will match frontmatter fields. Include enough context to target the right occurrence.
3. patch_note forbids empty strings. Both oldString and newString must be non-empty and non-whitespace. To delete text, use newString with a single space or restructure the note with write_note.
4. search_notes returns minified JSON. Fields are abbreviated: p (path), t (title), ex (excerpt), mc (matchCount), ln (lineNumber), uri (obsidianUri). Hard cap of 20 results regardless of limit.
5. search_notes multi-word queries score terms individually AND as a phrase. Each term is OR-matched, so a document matching any term appears in results. The full phrase gets an additional scoring boost.
6. write_note auto-creates directories. Parent folders are created recursively. In append/prepend mode, if the note doesn't exist it's created. Frontmatter is merged (new keys override) in append/prepend; replaced entirely in overwrite.
7. delete_note requires exact path confirmation. confirmPath must be character-identical to path. No normalization, no trailing-slash tolerance. Mismatch silently fails with success: false.
8. move_file needs double confirmation. Both confirmOldPath and confirmNewPath must exactly match their counterparts. Use move_note for markdown renames (text-aware, no confirmation needed); use move_file only for binary files or when you need binary-safe moves.
9. manage_tags reads from two sources but writes to one. list merges frontmatter tags + inline #hashtags. add/remove only modify the frontmatter tags array. Inline tags are never touched.
10. read_multiple_notes never rejects. Uses allSettled internally. Failed files appear in the err array; successful ones in ok. Always check both. Hard limit of 10 paths per call.
Error Recovery
| Error | Next step |
|---|---|
| patch_note "Found N occurrences" | Add surrounding lines to oldString to make it unique, or set replaceAll: true |
| delete_note / move_file confirmation mismatch | Re-read the note path with read_note or list_directory, then retry with the exact string |
| search_notes returns 0 results | Try single keywords instead of phrases, toggle searchFrontmatter, or broaden with partial terms |
read_multiple_notes partial err | Verify failed paths with list_directory, fix typos or missing extensions, retry only failed ones |
Git Sync Mode
When the user asks to "sync", "backup", or "store my vault with git", use CLI git with this behavior:
1. Run a preflight before changing anything:
gitavailable- current directory is a git repo (or prompt to initialize)
git config user.nameandgit config user.emailare set- at least one remote exists for push/pull sync
2. If preflight is incomplete, ask exactly one targeted question with a recommended default.
- Use askuserquestion for decisions that materially change behavior.
- Good examples:
- "No git repo found. Initialize one in this vault now? (Recommended: Yes)"
- "No remote configured. Set up GitHub remote now via gh if available, or provide remote URL? (Recommended: Set up via gh)"
- "Local and remote diverged. Try
git pull --rebasenow? (Recommended: Yes)"
3. Safe sync sequence (never force push by default):
git add -Agit commit -m "vault sync: YYYY-MM-DD HH:mm"(skip commit if no changes)git pull --rebasegit push
4. gh is optional:
- Use
ghonly for remote bootstrapping (create repo / set origin) when requested. - Do not require
ghfor normal sync once remote is configured.
5. Stop on conflicts and report clear next steps.
- Do not auto-resolve merge conflicts silently.
- Explain what failed and what user should run next.
Obsidian CLI Mode
When the user asks for app-context operations (active file, open in editor, daily notes with templates, backlinks), use the Obsidian CLI directly via shell commands.
1. Run a preflight before first CLI use:
- Resolve the CLI binary using the first match from these candidates:
| Priority | macOS | Linux | Windows |
|---|---|---|---|
| 1 | obsidian (PATH) | obsidian (PATH) | obsidian.exe or Obsidian.com (PATH) |
| 2 | /Applications/Obsidian.app/Contents/MacOS/obsidian-cli | — | — |
| 3 | /Applications/Obsidian.app/Contents/MacOS/Obsidian | — | — |
Obsidian 1.12.7+ installer bundles a dedicated obsidian-cli binary (~10xfaster than the legacy Electron-based CLI: ~25ms vs ~250ms per call). On macOS,
after installing the 1.12.7+ installer, disable then re-enable the CLI in
Settings > General > Advanced to update PATH registration. This replaces the old
~/.zprofilePATH entry with a/usr/local/bin/obsidiansymlink pointing to
obsidian-cli.>
On Linux, PATH registration creates a symlink at /usr/local/bin/obsidian(or ~/.local/bin/obsidian as fallback). On Windows, the installer places anObsidian.comterminal redirector alongsideObsidian.exe.
>
Note: The priority table and stale PATH check are verified on macOS only.
Linux and Windows may also bundle obsidian-cli with the 1.12.7+ installer,but this has not been confirmed. Contributions welcome via issue or PR.
- Stale PATH check (macOS): If priority 1 resolved
obsidianon PATH, check
whether it points to the fast binary or the slow Electron launcher:
| Resolved path | Meaning | Action |
|---|---|---|
/usr/local/bin/obsidian → obsidian-cli | 1.12.7 symlink registration | None — fast binary |
/Applications/.../MacOS/obsidian | Old ~/.zprofile entry (pre-1.12.7 registration or 1.12.7 installer without re-registering) | Check if obsidian-cli exists in the bundle |
If obsidian resolves to the MacOS directory (not /usr/local/bin) AND /Applications/Obsidian.app/Contents/MacOS/obsidian-cli exists, tell the user: _"Obsidian 1.12.7+ is installed but PATH still points to the slower Electron binary. In Obsidian, go to Settings > General > Advanced and disable then re-enable the CLI to update PATH registration."_ Continue with whichever priority matched — this is advisory, not blocking.
- Check Obsidian is running:
pgrep -xiq obsidian(macOS/Linux) ortasklist /FI "IMAGENAME eq Obsidian.exe" /NH(Windows) - If either fails, tell the user and fall back to MCP tools +
obsidian://URIs
2. Vault targeting: obsidian vault="VaultName" <command>. The vault name is the folder basename unless OBSIDIAN_VAULT_NAME is set.
3. Key commands:
# Read the currently active file
obsidian read
# Read a specific file
obsidian read file="My Note"
# Open a file in Obsidian
obsidian open path="Notes/example.md"
# Open today's daily note
obsidian daily
# Append to daily note
obsidian daily:append content="- [ ] New task"
# Search (Obsidian's own search, different from MCP's BM25)
obsidian search query="meeting notes" limit=10
# List all tags with frequency
obsidian tags sort=count counts
# Get backlinks for a note
obsidian backlinks file="My Note"
# Find unresolved links
obsidian unresolved4. Run obsidian help for the full command reference. The CLI evolves with Obsidian releases.
5. When to use CLI vs MCP:
- MCP for reads/writes/search/tags/frontmatter (sandboxed, validated, works headless)
- CLI for active file, daily notes with template expansion, backlinks, open in editor, plugin commands
- If unsure, prefer MCP
Resources
Load these only when needed, not on every invocation.
- Tool Patterns - read when you need a tool's response shape, mode details, or the move_note vs move_file decision
- Obsidian Conventions - read when creating/writing note content (link syntax, frontmatter fields, daily note format, template variables)
- Git Sync - read when user asks for backup/sync/store-vault workflows with git/gh
Git Sync
Practical playbook for handling user requests like:
- "sync my vault"
- "backup my vault"
- "use git to store my vault"
Routing Rule
- Use MCP tools for note/content operations.
- Use CLI git for sync/backup/versioning operations.
- Use Obsidian app/URI actions only when user needs editor/plugin behavior.
Preflight Checklist
Run these checks before setup or sync:
1. git --version 2. git rev-parse --is-inside-work-tree 3. git config user.name 4. git config user.email 5. git remote -v 6. git status --porcelain
Interpretation:
- Missing git binary: cannot continue sync.
- Not a repo: offer
git init. - Missing name/email: ask user to set identity.
- No remote: sync can commit locally, but cannot push until remote is configured.
AskUserQuestion Patterns
Use a single targeted question when a decision changes behavior.
1. Repo missing:
- "No git repo found in this vault. Initialize one now?"
- Recommended default: Yes
2. Remote missing:
- "No remote is configured. Do you want GitHub auto-setup via
gh, or provide a remote URL?" - Recommended default: GitHub auto-setup via gh (if
gh auth statuspasses)
3. Diverged history / rebase needed:
- "Local and remote branches diverged. Run
git pull --rebasenow?" - Recommended default: Yes
4. Identity missing:
- "Git user.name/email are not configured. Configure now for this repo?"
- Recommended default: Yes (repo-local config)
Standard Sync Action
Use this order for safe, transparent sync:
1. git add -A 2. git commit -m "vault sync: YYYY-MM-DD HH:mm" (skip if nothing to commit) 3. git pull --rebase 4. git push
Safety defaults:
- Never use
push --forceunless user explicitly requests it. - Never use destructive reset commands.
- If conflicts occur, stop and explain exactly what needs manual resolution.
Setup Flows
A) Existing repo + remote (fast path)
- Preflight passes -> run Standard Sync Action.
B) Not a repo yet
1. git init 2. git add -A 3. git commit -m "chore: initialize vault repository" 4. Configure remote (see C or D) 5. Run Standard Sync Action
C) Configure GitHub remote using gh (optional)
Preconditions:
gh --versiongh auth statussucceeds
Example: 1. gh repo create <name> --private --source=. --remote=origin --push 2. Set upstream if needed: git push -u origin <branch>
D) Configure remote manually (no gh)
1. git remote add origin <remote-url> 2. git push -u origin <branch>
User-Facing Success Messages
Keep output practical and clear:
- "Sync complete: 4 files changed, pushed to origin/main."
- "Vault already up to date: no local changes to commit."
- "Local commit created, but push skipped because no remote is configured."
Automation Recipes
For recurring backups, recommend platform scheduler:
- macOS: launchd
- Linux: cron
- Windows: Task Scheduler
Minimal script logic: 1. pull with rebase 2. add/commit if changes 3. push
Avoid scheduling if frequent merge conflicts are expected (multi-device concurrent edits).
Obsidian Conventions
Knowledge about Obsidian's data model and conventions that the MCP server doesn't enforce but agents should follow.
Vault Structure
A vault is a plain directory of markdown files. No database, no proprietary format.
my-vault/
.obsidian/ # App config (plugins, themes, hotkeys), not accessible via MCP
Daily Notes/ # Common convention, configurable in app
Templates/ # Template files, also configurable
Attachments/ # Images, PDFs, often set in app settings
Projects/
project-a.md
README.md.obsidian/ is blocked by the MCP server's path sandbox. You cannot read or write app config files.
Internal Links
Obsidian uses [[wikilinks]], not standard markdown links. When writing or patching note content, prefer wikilink syntax.
| Syntax | Result |
|---|---|
[[Note Name]] | Link to note |
| `[[Note Name\ | Display Text]]` |
[[Note Name#Heading]] | Link to heading |
[[Note Name#^block-id]] | Link to block |
![[Note Name]] | Embed (transclude) entire note |
![[image.png]] | Embed image |
![[Note Name#Heading]] | Embed specific section |
Standard [markdown](links) work but won't participate in Obsidian's graph view, backlinks, or rename refactoring.
Wikilinks inside Markdown tables
When an aliased wikilink appears inside a Markdown table cell, escape the alias pipe as \|. Otherwise the Markdown table parser treats the alias separator as a column separator and shifts the remaining cells.
Examples:
- Normal prose:
[[Projects/Foo/Foo|Foo]] - Table cell:
[[Projects/Foo/Foo\|Foo]]
Before writing or patching a table row, scan for [[...|...]] and convert it to [[...\|...]] inside that row.
Daily Notes
Common convention: one note per day in a Daily Notes/ folder. Default filename format: YYYY-MM-DD (e.g., 2024-03-15.md). The folder name and date format are configurable per-vault in .obsidian/daily-notes.json.
When creating daily notes via MCP, use the YYYY-MM-DD.md format unless the user specifies otherwise.
Frontmatter
YAML block delimited by --- at the top of the file. Common standard fields:
---
title: Note Title
tags:
- project
- status/active
aliases:
- alternate name
date: 2024-03-15
cssclasses:
- custom-class
---tags: array of strings, supports nested tags (parent/child)aliases: alternative names for wikilink resolutioncssclasses: Obsidian-specific stylingdate,created,modified: no enforced format, but ISO 8601 is conventional
The MCP server validates frontmatter before writing (no functions, no symbols, string keys only).
Tags
Two sources, both valid in Obsidian:
1. Frontmatter tags: tags: [foo, bar] in YAML block 2. Inline tags: #foo anywhere in the body text
Nested tags use /: #project/active, #status/done. The MCP manage_tags tool merges both sources for list but only modifies frontmatter for add/remove.
Templates
Obsidian's core Templates plugin uses these variables:
| Variable | Expands to |
|---|---|
{{title}} | Note title (filename without extension) |
{{date}} | Current date (format configurable in settings) |
{{time}} | Current time (format configurable in settings) |
{{date:FORMAT}} | Date with custom Moment.js format, e.g. {{date:YYYY-MM-DD}} |
{{time:FORMAT}} | Time with custom format |
The MCP server does not expand template variables. If you write {{date}} via write_note, it stays as literal text. Template expansion only happens when inserting templates through the Obsidian app.
Obsidian URIs
Format: obsidian://open?vault=VaultName&file=path/to/note
The MCP server includes obsidianUri in search results and read responses. These URIs only work when the Obsidian desktop app is running. They open the note in the app's editor.
URL encoding rules apply: spaces become %20, special characters are percent-encoded.
Common Folder Patterns
| Pattern | Usage |
|---|---|
Daily Notes/ | One note per day |
Templates/ | Template files for new notes |
Attachments/ or assets/ | Images, PDFs, other media |
Archive/ | Completed or inactive notes |
Inbox/ | Quick capture, unsorted notes |
These are conventions, not requirements. Every vault is different. Use list_directory to discover the actual structure before assuming folder names.
Tool Patterns
Per-tool behavioral knowledge beyond what tool descriptions provide.
read_note
Response includes content (full markdown body) and frontmatter (parsed YAML object). prettyPrint: true indents the JSON response for readability but costs extra tokens.
write_note
Modes:
overwrite(default): replaces entire file; frontmatter is set to exactly what you pass (or omitted if null)append: adds content after existing body; merges frontmatter (new keys override existing)prepend: adds content before existing body; same frontmatter merge as append
Auto-creates parent directories recursively. In append/prepend, creates the file if it doesn't exist.
Frontmatter validation runs before writing. Functions, symbols, and non-string keys are rejected. Invalid dates produce warnings but don't block the write.
patch_note
Response shape:
{ "success": bool, "path": str, "message": str, "matchCount": int }- Rejects if
oldString === newString
Recipe, safe single replacement: Include the line before and after your target text in oldString to guarantee uniqueness.
search_notes
Response fields (minified):
p: patht: title (filename without.md)ex: excerpt (context around first match, truncated with...)mc: matchCount (total occurrences across all terms + filename)ln: lineNumber (1-based, position of first match)uri: Obsidian URI
Scoring: BM25 with k1=1.2, b=0.75. Multi-word queries score each term individually plus the full phrase as a bonus term.
Limits: Default 5, hard cap 20. caseSensitive: false by default (both query and corpus lowercased).
Frontmatter/content toggle:
searchContent: true+searchFrontmatter: false(default): strips frontmatter before searchingsearchFrontmatter: true: includes YAML block in searchable text- Both false: no results
delete_note
Response: { "success": bool, "path": str, "message": str }
confirmPath must be character-identical to path. No undo. Files only; directories return "Cannot delete: path is not a file."
move_note
Text-aware move for markdown files. Reads source as UTF-8, writes to destination with wx flag (fails if target exists unless overwrite: true), then deletes source. No confirmation parameters needed.
Response: { "success": bool, "oldPath": str, "newPath": str, "message": str }
move_file
Binary-safe move. Requires double confirmation: confirmOldPath === oldPath AND confirmNewPath === newPath. Rejects directories. Falls back to copy+unlink for cross-filesystem moves.
When to use which:
- Renaming/moving
.mdfiles →move_note - Moving images, PDFs, attachments →
move_file
read_multiple_notes
Response: { "ok": [...], "err": [...] }
Hard limit: 10 paths. Uses Promise.allSettled, so it never throws on individual failures. Each ok entry has path, obsidianUri, and optionally frontmatter/content based on include flags. Each err entry has path and error message.
manage_tags
Operations:
list: returns merged set of frontmattertagsarray + inline#hashtags(deduplicated)add: appends to frontmattertagsarray onlyremove: removes from frontmattertagsarray only; if no tags remain, deletes thetagsfield
Inline #hashtag occurrences in the note body are never modified.
Response: { "path": str, "operation": str, "tags": [str], "success": bool }
update_frontmatter
merge: true(default): spreads existing frontmatter first, new values override:{...existing, ...new}merge: false: complete replacement of frontmatter
Content body is always preserved. Validates resulting frontmatter before writing. File must already exist.
get_vault_stats
Metadata-only. Returns total notes, folders, vault size, and recently modified files. No file content read. Use this for vault overview before batch operations.
get_notes_info
Metadata-only alternative to reading notes. Returns path, size (bytes), modified (ms timestamp), hasFrontmatter (heuristic: checks if file starts with ---\n), and obsidianUri. Failed reads are silently omitted from results.
list_directory
Returns files and directories. Non-note filenames (images, PDFs) are included. Hidden directories (.obsidian/, .git/) are filtered out.
get_frontmatter
Extracts parsed frontmatter without reading body content. Lighter than read_note when you only need YAML fields.
list_all_tags
Scans all notes in the vault for frontmatter tags arrays and inline #hashtags. Returns deduplicated list sorted by frequency descending.
Response shape:
[{"tag": "project", "count": 12}, {"tag": "status/active", "count": 5}]Tags are case-normalized (lowercase). Nested tags like status/active are preserved. No parameters required (scans the whole vault). Use this before creating or organizing notes to see what tags already exist.
Related skills
Forks & variants (1)
Obsidian has 1 known copy in the catalog totaling 273 installs. They canonicalize to this original listing.
- bitbonsai - 273 installs
How it compares
Choose obsidian when agents must both edit notes via MCP and manage git sync; use plain git skills when notes live outside Obsidian.
FAQ
What does obsidian do?
>
When should I use obsidian?
>
What are common prerequisites?
--- name: obsidian description: > Activate when the user mentions their Obsidian vault, notes, tags, frontmatter, daily notes, backup, or sync.
Is Obsidian safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.