Notifications
An agent that runs while the laptop is closed needs a way to say “I
finished”, “I failed”, and above all “I am waiting for you”. A run parked at
an approval nobody hears about is a run that never happens. Notifications are
one destination — an email address or a webhook URL — declared once in
AGENTS.md, and a short list of the events that should reach it.
Declaring one
notify:
email: [email protected]
events: [failed, awaiting-approval, completed]
or, for people who live in a channel rather than an inbox:
notify:
url: ${SLACK_WEBHOOK_URL} # a secret name, or a literal URL
events: [failed, awaiting-approval]
A bare string is whichever destination it looks like: notify: [email protected].
The default events are failed and awaiting-approval. completed is
opt-in on purpose: a schedule that works is the quiet kind of good news, and
a channel that pings on every success gets muted — which un-pings the
failures too. Turn it on when the run’s headline is the thing you want to
read each morning, which for a scheduled desk it usually is.
Where it is set, and the rule that bites
notify: lives in the account’s AGENTS.md and every workspace inherits it.
A workspace may declare its own — and when it does, its block replaces
the account’s whole, it does not merge. A workspace that wants the account’s
destination and events simply says nothing.
What arrives
The subject is the run’s headline — the first line of the last step’s reply — followed by its summary. Ids and costs are in the body. The subject is meant to be read on a phone: “BAD — 3 targets fell out of the top 20” is the whole message; “run-mtmv20up-oote completed” is not.
The body, and the webhook’s JSON:
{
"text": "BAD — 3 targets fell out of the top 20 · rank-desk/run-… · $1.01",
"workspace": "rank-desk", "runId": "run-…", "flow": "rankings",
"status": "completed", "summary": "…", "costUsd": 1.01,
"startedAt": "…", "finishedAt": "…",
"approveUrl": "…", "rejectUrl": "…"
}
text is what Slack, Discord and ntfy render as-is; the rest is for anything
that wants the data. A webhook URL is the one integration: those services,
and every phone-push relay, all accept a POST of that shape.
Approve and reject links
A run parked on a person sends its notification with two links. Clicking one opens a page that shows what is waiting and asks for the decision — it never decides on the GET, because inbox link-checkers follow links. The token in the link is derived from the run, never stored, so a key rotation kills every old link at once.
The links exist only when the install knows its own public address
(FOLDRUN_PUBLIC_URL). Without it the notification goes out without them and
the run is approved from the dashboard.
Email goes through the account’s Resend connection (RESEND_API_KEY), the
same one the platform’s own email tool uses. There is nothing to configure
beyond the address.