QuickAdd CLI
QuickAdd hooks into Obsidian’s own command-line interface, so you can run a
choice from a terminal, a shell script, or a scheduled job - no link-building or
extra plugins. Point the obsidian command at a vault and a choice, and it
runs.
obsidian vault=dev quickadd choice="Daily log"QuickAdd registers these CLI handlers automatically on any Obsidian version that supports plugin CLI commands.
What you need
Section titled “What you need”- Obsidian
1.12.2or newer (the plugin CLI handler API arrived in1.12.2). - QuickAdd enabled in the target vault.
The commands
Section titled “The commands”Run a choice: quickadd / quickadd:run
Section titled “Run a choice: quickadd / quickadd:run”Run a QuickAdd choice from the CLI, by name or by id:
obsidian vault=dev quickadd choice="Daily log"obsidian vault=dev quickadd:run id="choice-id"List your choices: quickadd:list
Section titled “List your choices: quickadd:list”List every QuickAdd choice (including nested choices inside multis):
obsidian vault=dev quickadd:listobsidian vault=dev quickadd:list type=Captureobsidian vault=dev quickadd:list commandsSee what a choice still needs: quickadd:check
Section titled “See what a choice still needs: quickadd:check”Check which inputs are still missing before a non-interactive run:
obsidian vault=dev quickadd:check choice="Daily log"Create a note from a template: quickadd:run-template
Section titled “Create a note from a template: quickadd:run-template”Create a new note from a template file, with no dedicated Template choice required. This is the scriptable form of the New note from template command.
obsidian vault=dev quickadd:run-template \ path="Templates/Meeting.md" \ value-value="2026-06-14 Standup"path=is the template file (vault-relative). A leading slash is allowed and a missing.mdextension is added, matching how Template choices resolve paths. If no file resolves there, the command returns{"ok":false}up front.- The new note’s name comes from
{{VALUE}}- pass it asvalue-value=.... A non-interactive run with an empty or missing name returnsmissingFlagsinstead of creating an unnamed note. The note is created in Obsidian’s “Default location for new notes”. - The picker (interactive command) only lists templates inside your configured template folder(s);
path=here is explicit, so any vault file resolves. - Like
quickadd:run, name collisions on the target note still prompt interactively (the file-exists choice is not a pre-collected input).
Introduced in QuickAdd 2.14.0.
Pass variables to a choice
Section titled “Pass variables to a choice”QuickAdd’s CLI accepts variables three ways:
value-<name>=...(the same form the URI uses)- extra
key=valueargs vars=<json-object>for structured values
obsidian vault=dev quickadd \ choice="Daily log" \ value-project="QuickAdd" \ mood="focused"
obsidian vault=dev quickadd \ choice="Daily log" \ vars='{"project":"QuickAdd","sprint":42}'Values are passed through exactly as provided. If a choice should ignore an
accidental leading or trailing space for a specific placeholder, use |trim in
that format string, for example {{VALUE:project|trim}}.
Names the CLI reserves
Section titled “Names the CLI reserves”The bare key=value form (pattern 2) ignores names that a command already uses
as flags or selectors: choice, id, vars, ui, verify (on quickadd /
quickadd:run), fields (on quickadd:check), and path (on
quickadd:run-template). If a choice has a variable named after one of these
(for example {{VALUE:verify}}), pass it with the value- prefix or via
vars instead - neither is ever treated as a flag:
obsidian vault=dev quickadd choice="My choice" value-verify="a value"obsidian vault=dev quickadd choice="My choice" vars='{"verify":"a value"}'What happens when inputs are missing
Section titled “What happens when inputs are missing”By default, quickadd and quickadd:run are non-interactive. If QuickAdd finds
missing inputs, it returns a JSON payload with missing fields and
missingFlags suggestions instead of opening prompts.
Pass a returned missingFlags entry back exactly as shown. Some generated flags
fill internal runtime selections, such as a preselected capture target file.
Add ui to allow interactive prompts:
obsidian vault=dev quickadd choice="Daily log" uiIn a scheduled job,
only add ui when the job runs while you are logged in and able to answer the
prompts.
Answer run-time prompts from outside: quickadd:interactive
Section titled “Answer run-time prompts from outside: quickadd:interactive”Some choices prompt at run time for inputs that can’t be gathered up front -
a macro’s quickAddApi.suggester over data it just fetched, an inputPrompt,
yesNoPrompt, checkboxPrompt, and so on. quickadd:interactive runs a choice
and forwards those prompts to you over a local HTTP bridge, so an external
front end (Raycast, a script) can render them and send back answers, instead of
the prompts opening in Obsidian.
obsidian vault=dev quickadd:interactive choice="Import from Readwise"# -> {"ok":true,"host":"127.0.0.1","port":51789,"sessionId":"…","token":"…","capabilities":["abort"]}The command returns connection details immediately and runs the choice in the background. Attach to the session and drive it:
GET http://127.0.0.1:<port>/poll?session=<id>&token=<token>- long-polls for the next event:{"kind":"prompt","requestId":…,"prompt":{…}},{"kind":"done","result":…},{"kind":"error","error":…}, or a periodic{"kind":"idle"}keepalive (just poll again).POST http://127.0.0.1:<port>/reply?session=<id>&token=<token>with body{"requestId":…,"value":…}to answer, or{"requestId":…,"cancelled":true}to cancel (which ends the run - except on aninfopanel, see below).POST http://127.0.0.1:<port>/abort?session=<id>&token=<token>- end the run. Answers{"ok":true,"interrupted":<n>}, wherenis how many pending prompts it rejected;409if the run had already finished (benign - poll for the terminal event);404for an unknown session or token, or for any method other thanPOST.
Prompt types and the value you reply with: suggester/input/date →
string, confirm → boolean, checkbox → string array, info →
acknowledgement, form → an object mapping each field’s id to its string
value (date fields use the @date:ISO format). The run’s outcome arrives as the
done/error poll event.
Cancelling, and ending a run
Section titled “Cancelling, and ending a run”{"cancelled":true} is how you say the user dismissed this prompt. It ends the
run exactly as pressing Escape on the in-app dialog does.
info is the exception, because the in-app dialog is: GenericInfoDialog resolves
on every close path and has no way to abort anything, so the same choice run in
Obsidian continues past the panel. Escape is the only gesture an info panel affords,
so cancelling one just closes it and the run carries on - matching the app.
To end a run deliberately, POST /abort. It rejects whatever the run is blocked on
and makes its next prompt fail too, so the run unwinds and delivers its real
outcome - usually {"kind":"error","error":"Input cancelled by user"}, but done if
it had nothing left to interrupt and simply finished. /abort never fabricates a
terminal event; keep polling until one arrives. The interrupted count tells you
whether it stopped anything.
When a reply is rejected
Section titled “When a reply is rejected”/reply answers 400 and leaves the prompt pending when it cannot honour
what you sent, so you can correct the reply and POST again. Two cases:
cancelledis present but is not a boolean ("true",1,"no"). QuickAdd will neither abort on a flag it does not recognise nor quietly answer the prompt on the user’s behalf, so it asks you to fix the flag. Use the literaltrue;falseand omitting it both mean “this is a real answer”.- a
confirmreply whosevalueis nottrue/false. The user never answered, and QuickAdd will not invent a “No” for them.
Every other prompt type accepts whatever you send, including an empty answer:
"" and [] are things a user genuinely submits in the app (the Skip buttons,
optional fields), so they must stay legal here too.
A 409 from /reply means nothing was waiting on that requestId.
Good to know:
- Desktop only. The bridge binds to
127.0.0.1, is gated by the per-sessiontoken, rejects browser (Origin/Referer) and non-loopbackHostrequests, and the server is ephemeral - it starts on the first session and stops when the last one ends. - Concurrency. Each run gets its own
sessionId+token; many can run at once without interfering. - If no client attaches within ~30s the run is aborted so a prompt can’t hang forever.
Introduced in QuickAdd 2.16.0.