Plugin protocol
Note. The common notifiers (
desktop,imessage,slack,ntfy,pushover,telegram) are now built into the daemon — they do not use this protocol. Seedocs/concepts/notifications.mdfor the[[notifiers]]shape. This protocol is the contract for preflight checks, output sinks, and third-party notifiers (Discord, Teams, custom relays) wired viadriver = "plugin".
Plugins extend dotagent without recompiling it. They handle preflight checks, output sinks, and third-party notifiers. A plugin is any binary named dotagent-plugin-<name> that speaks the protocol below — write it in Rust, Go, Python, Bash, whatever.
Discovery
dotagent searches for the binary in this order, returning the first match:
$DOTAGENT_PLUGIN_PATH(colon-separated list of directories)~/.config/dotagent/plugins//usr/local/lib/dotagent/plugins/$PATH
CLI surface
A plugin must accept exactly one positional argument: the verb.
dotagent-plugin-<name> info
dotagent-plugin-<name> validate
dotagent-plugin-<name> invokeFor validate and invoke, the JSON payload arrives on stdin. The plugin must write its JSON response to stdout and exit with 0 for success, non-zero for failure. Human-readable logs go to stderr.
Verbs
info
No stdin. Print self-describing metadata.
validate
Stdin: the same JSON object the manifest puts under config.
Stdout: {"ok": true} or {"ok": false, "error": "..."}. dotagent calls this when loading manifests so misconfigurations surface in dotagent doctor rather than at firing time.
invoke
Stdin: an InvokePayload (see schema below).
Stdout: minimum {"ok": bool}. Extra fields are forwarded into dotagent's logs and --verbose output; they do not change orchestrator behavior.
Kind-specific contracts
Notify
Receives
message(string) andevent.Returns
ok=trueafter delivery,ok=falseotherwise. Best-effort — dotagent does not retry notifications.
Preflight
Returns
ok=trueif the precondition holds,ok=falseto abort the run.May include
suggestin the response (string) — dotagent forwards it into any failure notification so the user knows what to fix.The agent will NOT be invoked if any preflight returns
ok=false. dotagent emits anattempt_failedevent with the suggestion attached.
Sink
Persists the agent's output somewhere (file, Roam, Notion, etc.).
messagecarries the captured stdout.Sinks run after a successful run; failure of a sink raises
attempt_failedbut does not roll back the agent (the run already succeeded).
Convention: keep plugins single-purpose
Cross-cutting concerns (auth refresh, retries with backoff for transient HTTP errors, etc.) belong in the plugin, not in dotagent. dotagent treats the plugin as a black box: "given this payload, did you succeed?".
Testing a plugin
If your plugin passes the three commands above, it integrates with dotagent.
Last updated
Was this helpful?