CLI-Driven Vault Automation
The pattern of scripting a running Obsidian vault via Obsidian CLI (or its MCP wrappers) instead of touching the GUI: shell scripts, cron jobs, and agent wrapper scripts that treat vault operations as ordinary CLI calls with structured (format=json) output piped into jq.
Wrapper-script conventions (from two real-world examples)
Two independent GitHub projects wrapping the CLI converge on the same shape, worth treating as the default template for any new wrapper: 1. Doctor/health-check pattern (lacp-obsidian-cli, part of a larger agent-config-management CLI): a check/doctor subcommand that verifies, in order — CLI binary on PATH, Obsidian.app actually running (pgrep), vault directory exists — before any real command runs, with --json output for scripted consumption:
obs-helper.sh, titled literally “Obsidian CLI Wrapper for AI Agents”): a thin dispatch script mapping short verbs to CLI invocations, with the “Obsidian not running” guard as the very first line before anything else runs:
search+execute Code Mode pattern in Obsidian CLI REST MCP — a large underlying command surface gets collapsed to a small stable interface for the calling agent/script, whether the caller is a human’s cron job or an LLM.
Common automation shapes
- Morning/daily setup — prepend a template into today’s daily note, pull yesterday’s unfinished
- [ ]tasks forward - Inbox auto-sort — read a folder as
format=json, branch onproperties file=... format=json | jqtag values,moveinto PARA-style folders - Tag-to-publish pipeline — search
[tag:ready-to-publish]→properties:seta published date/status →publish:add - Vault health report —
files total+orphans format=json | jq length+unresolved format=json | jq length+tags sort=count→ written back as a new note - Cron-fed external data — fetch from any API (weather, HN, etc.) and
daily:append/createthe result; this is the shape that most needs the “Obsidian must be running” guard since cron runs unattended
Safety rules (apply whether the caller is a human’s script or an agent)
- Run every command manually once before wiring it into a script — a misunderstood command fails silently when automated.
- Prefer plain
delete(trash) overdelete --permanentuntil the automation has proven it targets the right notes. - Guard on “Obsidian is running” at the top of any unattended script (cron, agent loop) — start it or fail loudly rather than run partial operations.
- Treat
eval/dev:*(JavaScript-in-runtime) as the highest-risk command class — both REST/MCP bridges gate these behind a separateallowDangerousCommands/“Dangerous” flag; read generatedevalcode before running it. - Don’t over-scope a wrapper to the full command surface — both real examples above expose a handful of verbs, not the 100+ raw commands.
Related
- Obsidian CLI — the underlying command surface these scripts wrap
- Obsidian CLI REST MCP — the same “small stable interface over a big command surface” instinct, applied via MCP’s Code Mode instead of a shell wrapper
- obsidian-claude-code-mcp — the standing-connection alternative to scripting per-invocation
- Tool Design for Agents — general principle: collapse large tool/command surfaces into a small, stable, discoverable interface