Skip to content

Obsidian’s built-in CLI (enabled 2026-08-20, Settings → General → Command line interface), used as a headless render-verification harness from WSL — eval runs JS inside the running app, dev:screenshot grabs a PNG. Lets an agent confirm a Dataview/dataviewjs render matches expected output without asking Talbot to look.

  • PATH is stale in an already-open WSL/terminal session — the registry User PATH gets the entry the moment the toggle is flipped, but a shell whose ancestor process launched before that won’t see it until a fresh top-level process. Don’t fight it — call the exe directly: C:\Users\Admin\AppData\Local\Programs\Obsidian\Obsidian.exe
  • Route through PowerShell, not cmd.exe (quoting is far less fragile):
    Terminal window
    /mnt/c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe -NoProfile -Command "& \"C:\Users\Admin\AppData\Local\Programs\Obsidian\Obsidian.exe\" eval \"code=<js>\""
  • Quoting rule that matters: wrap the whole -Command in double quotes, then wrap code=<js> in double quotes too, and write the JS itself using single-quote strings only. PowerShell single-quoted strings don’t process \" escapes — a \" meant for a JS string literal survives as a literal backslash and breaks the JS parser (Error: Unexpected token '.' with no other clue). A base64-encode-then-decode-in-a-.ps1-file workaround was tried and abandoned — same failure, not worth the extra layer.
  • eval awaits a returned Promise and prints the resolved value — async IIFEs work fine ((async()=>{...})()).
  • No vault= needed when exactly one vault is open (this machine: D:\FSS\KB, registered in %APPDATA%\Obsidian\obsidian.json).
  • setTimeout inside eval code silently kills the response — the CLI’s IPC round-trip never returns (no output, no error, not even the => prefix), tested at both 500ms and 1500ms. Needing to wait for a render (setState({mode:'preview'})) means splitting into two separate eval calls: one that awaits setState alone (resolves fast, no timer), and a second call afterward that reads the DOM — the gap between two separate CLI invocations is real wall-clock delay without ever using setTimeout.

Used to verify Focus/scripts/ecco-view.js’s render (ecco-notepads-build Phase 0/1): opened Focus/proofs/ecco-view-engine-proof.md, forced the active leaf to reading mode, read back .block-language-dataviewjs elements’ innerText, and confirmed it matched the algorithm’s expected output exactly — no manual look-and-confirm needed.

  • Obsidian.exe --help also prints “installer out of date” every call — harmless, ignore (the running app is 1.13.7 regardless of what the installer stub reports; see AGENTS.md’s installer-version-lies rule).
  • Multiple leaves/tabs open on the same file render the same query more than once in the DOM — dedupe by content when reading back, don’t assume one block per query.