| name | ObsidianCLI |
| version | 0.1.0 |
| description | Official Obsidian CLI (1.12+) — list files, search content, manage properties, query bases, navigate links, create/read/rename/delete notes. USE WHEN listing vault files, searching vault, managing frontmatter properties, querying bases, checking backlinks, creating notes via Obsidian, renaming with backlink updates, or any vault operation that benefits from Obsidian's internal index. |
ObsidianCLI
Reference for the official Obsidian CLI (1.12+). Communicates with the running Obsidian desktop app via named pipe. Returns structured data to stdout.
Falls back to file-system operations (Glob, Grep, safe-read, safe-write) when unavailable.
Setup
The CLI ships inside Obsidian 1.12+. Add to PATH (one-time):
export PATH="$PATH:/Applications/Obsidian.app/Contents/MacOS"
Or use the full path directly. Verify with make check in the module root.
Parameter Syntax
- Key-value pairs:
key=value
- Spaces in values:
content="Hello world"
- File targeting:
file=<name> (wikilink resolution) or path=<exact/path.md>
- Vault targeting:
vault=<name> or inferred from CWD or active vault
Output Formats
All commands support: format=json|csv|tsv|md|paths|text|tree|yaml
Default is text. For programmatic consumption use format=json or format=paths.
File Operations
List files
obsidian files
obsidian files folder=Resources ext=md
obsidian files format=paths
obsidian files format=json
Read file content
obsidian read file="Security"
obsidian read path="Topics/Security.md"
Create a note
obsidian create name="New Note" content="---\ntitle: New Note\n---\n\nContent here."
obsidian create name="From Template" template=Daily
Append / Prepend
obsidian append file="Daily" content="- New item"
obsidian prepend path="Topics/Security.md" content="## Update\n\nNew section."
prepend inserts after frontmatter.
Move / Rename
obsidian move file=Recipe to=Archive/
obsidian rename file="Old Name" to="New Name"
rename updates all wikilinks and markdown links across the vault. This is the only reliable way to rename with backlink tracking — file-system mv breaks links.
Delete
obsidian delete file=OldNote
obsidian delete file=OldNote permanent
Properties (Frontmatter)
Set property
obsidian property:set file="Note" property=status value=active
Atomic update — avoids the Obsidian Linter race condition that affects read-modify-write cycles with safe-write edit.
Scalar values only. Cannot set arrays (tags, comments, sources) or nested objects. For complex field types, use eval with processFrontMatter (see Developer section).
Remove property
obsidian property:remove file="Note" property=obsolete_key
Read property
obsidian property:read file="Note" property=status
obsidian property:read file="Note" property=status format=json
Stdout contamination. Like base:query, property:read can mix extraneous output into stdout. Redirect to temp file for reliable parsing, or use eval with processFrontMatter for programmatic reads.
Rename property key (vault-wide)
obsidian property:rename old=old_key new=new_key
Search
Full-text search
obsidian search query="forge-tlp"
obsidian search query="forge-tlp" format=json
Property filter syntax: [tag:project], [rating:>4], [status:active].
Search with context
obsidian search:context query="forge-tlp"
Links & Graph
Backlinks (incoming links)
obsidian backlinks file="Security"
obsidian backlinks file="Security" format=json
Outgoing links
obsidian links file="Security"
Orphans and unresolved
obsidian orphans
obsidian unresolved
Bases
Query a Base view
obsidian base:query path="Resources/Books.base" format=json > /tmp/base-out.json 2>&1
cat /tmp/base-out.json
command rm -f /tmp/base-out.json
obsidian base:query path="Resources/Books.base" format=paths
When CLI is unavailable, use the standalone obsidian-base binary (see /ObsidianBase).
Daily Notes
obsidian daily
obsidian daily:read
obsidian daily:append content="- [ ] Task"
obsidian daily:prepend content="## Morning"
obsidian daily:path
Developer / Escape Hatch
Execute JavaScript in the running Obsidian context:
obsidian eval code="app.vault.getFiles().length"
obsidian eval code="app.vault.getMarkdownFiles().map(f => f.path).join('\n')"
Has access to app, vault, workspace, plugins. Use for operations the CLI doesn't expose natively.
processFrontMatter (batch frontmatter)
The primary tool for vault-wide frontmatter migrations. Handles arrays, nested values, field deletion, and atomic read-modify-write — everything property:set cannot.
Single file:
obsidian eval code="
const file = app.vault.getAbstractFileByPath('path/to/Note.md');
await app.fileManager.processFrontMatter(file, fm => {
fm.tags = ['type/memory/insight'];
fm.comments = ['Context: what prompted this'];
delete fm.oldField;
});
"
Batch (filter + loop):
obsidian eval code="
const files = app.vault.getMarkdownFiles().filter(f => f.path.startsWith('Archives/Memory/Ideas/'));
for (const file of files) {
await app.fileManager.processFrontMatter(file, fm => {
if (fm.spark) { fm.context = fm.spark; delete fm.spark; }
if (fm.idea) { fm.description = fm.idea; delete fm.idea; }
});
}
console.log('Done: ' + files.length + ' files');
"
Key rules:
- Always
await — processFrontMatter is async. Without await, changes silently don't persist.
- Use
for...of, never forEach — forEach doesn't await async callbacks.
delete fm.field removes a key. Setting fm.field = undefined leaves a stale key.
- The
fm object is the live frontmatter — mutate it directly, don't return anything.
- Field insertion order is preserved — add fields in the order you want them in YAML.
console.log() output appears in stdout — use it for progress/verification.
Fallback Matrix
| CLI operation | When CLI unavailable |
|---|
files | Glob tool or find "$FORGE_USER_ROOT" -name '*.md' |
search | Grep tool |
read | safe-read or Read tool |
create / append / prepend | safe-write write or Write tool |
property:set (scalar) | safe-write edit (read-modify-write) |
property:set (arrays/complex) | safe-write edit — property:set can't handle arrays either |
property:remove | safe-write edit (read-modify-write) |
move / rename | command mv (lossy — no backlink updates) |
backlinks / links | Grep for [[filename]] patterns |
orphans / unresolved | No direct equivalent |
base:query | obsidian-base binary (works offline, see /ObsidianBase) |
daily:* | Resolve path from defaults.yaml journal pattern |
delete | command rm (no trash) |
Constraints
- Requires Obsidian 1.12+ desktop app running (named pipe communication)
- Catalyst license ($25) required during Early Access period
- No headless/remote operation — for that use the Local REST API plugin (see
/ObsidianREST)
base:query and property:read have stdout contamination — extraneous output mixes into results. Use temp file redirect for reliable parsing.
property:set is scalar-only — cannot set arrays, objects, or nested values. Use eval + processFrontMatter for complex field types.
- TLP access control (
safe-read / safe-write) is a separate concern — CLI bypasses TLP
- 1.12.2 renamed
all parameter to active and silent to open — pin to 1.12.2+ syntax
!dispatch skill-load forge-obsidian