Deadlines
A deadline is a dated obligation your agent has committed to — "renew the
certificate by March 14", "file the report before the quarter closes". It is
durable memory for the thing agents forget most: a future commitment made in one
session that a later session has to honour. You hand us a due_at and a short
summary, and we hold onto it, escalating through reminders as the date
approaches and passes, until you mark it done.
A deadline looks superficially like a schedule, but they answer different questions. A schedule fires once at its moment and forgets; a deadline tracks whether the work got done and escalates if it doesn't. Reach for a deadline when any of these hold: you want reminders before and after the due date, not a single callback; some recipients are humans (reminder emails, not just a webhook); or the thing has a completion state you would want to mark "done". If you would never mark it done, it's a schedule.
How deadlines behave
Every deadline carries a due_at and a required summary — the human-readable
label every dashboard row and reminder is keyed on. (A webhook_url is optional
and can't stand in for the summary.) Around the due date, an escalation
policy drives a series of reminders; see the next section.
A deadline's status is stored, not derived on read:
| Status | Meaning |
|---|---|
open |
Live and not yet past due. |
overdue |
Past its due_at and still not done — a periodic scan flips open rows to overdue. |
completed |
You marked the obligation done (terminal). |
cancelled |
You called it off (terminal). |
open and overdue together are the active set — the deadlines still on
your plate, and the set the stock limit counts (see Limits, below).
Reminders go to destinations that live on the deadline itself, not inside the
policy: an optional webhook_url (same shape as a schedule's) and
notify_emails, a list of zero or more human recipients. A deadline may also
carry an optional cron recurrence + IANA recurrence_tz; completing a
recurring deadline spawns its successor (see below).
Escalation policies
An escalation policy is a small JSON document listing the reminder steps,
each an offset relative to due_at and the channels it fires on. Offsets are
signed ISO-8601 durations: negative is before due, P0D is the due date
itself, positive is after. Channels are webhook, email, or both. One step
may carry "repeat": "daily" to keep nagging once a day (usually the post-due
step). This is the system default — warn at 30, 7, and 1 day out, on the due day,
then daily once it lapses:
{
"steps": [
{"offset": "-P30D", "channels": ["webhook"]},
{"offset": "-P7D", "channels": ["webhook"]},
{"offset": "-P1D", "channels": ["webhook"]},
{"offset": "P0D", "channels": ["webhook"]},
{"offset": "P1D", "channels": ["webhook"], "repeat": "daily"}
]
}
When you create the deadline, the policy is materialised up front into one
concrete reminder per (step × channel), anchored on the current due_at. Any
step whose computed time is already in the past is skipped — a deadline you
remember two days before it's due simply won't get its 30-day warning.
Two rules to internalise:
- A referenced channel must have a destination. If any step lists
webhook,webhook_urlis required; if any listsemail,notify_emailsmust be non-empty. A channel with nowhere to send is a create-time validation error, never a silently dropped reminder. - You can preview a policy before committing.
POST /v1/deadlines/escalation-preview/(and the live preview on the dashboard create form) returns the exact reminder fire-times for adue_at+ policy. It's read-only: it creates nothing and costs no quota.
Remember a deadline
Every create is idempotent: pass an idempotency key and a retried create returns the original deadline instead of a duplicate. See Idempotency for choosing keys.
Go to Deadlines → New deadline. Enter the summary and due_at, pick the
destinations (a webhook URL, one or more notification emails, or both), and edit
the escalation policy — the form seeds the default policy and shows a live
preview of every reminder it will schedule, so you can confirm the cadence
before saving. Choose Recurring to attach a cron rule and timezone.
POST /v1/deadlines/ with your API key as a Bearer token. summary and a
future due_at are required; escalation_policy, webhook_url,
notify_emails, tags, metadata, and recurrence + recurrence_tz are
optional (omit the policy to accept the system default). Pass an
Idempotency-Key header to make retries safe.
curl https://aigears.example.com/v1/deadlines/ \
-H "Authorization: Bearer aigears_live_..." \
-H "Idempotency-Key: renew-cert-2026" \
-H "Content-Type: application/json" \
-d '{
"summary": "Renew the TLS certificate",
"due_at": "2026-03-14T00:00:00Z",
"webhook_url": "https://hooks.example.com/aigears",
"notify_emails": ["[email protected]"],
"escalation_policy": {
"steps": [
{"offset": "-P7D", "channels": ["webhook", "email"]},
{"offset": "P0D", "channels": ["webhook", "email"]},
{"offset": "P1D", "channels": ["email"], "repeat": "daily"}
]
}
}'
Dry-run the policy first with POST /v1/deadlines/escalation-preview/
({"due_at": ..., "escalation_policy": ...}) — it returns the reminder
fire-times and creates nothing.
Ask the agent in plain language; it maps the phrasing onto a deadline_remember
call.
"Remember to renew the TLS cert by March 14 — warn me a week ahead and again every day if it lapses."
→
deadline_remember(summary="Renew the TLS certificate", due_at="2026-03-14T00:00:00Z", notify_emails=["[email protected]"], escalation_policy={"steps": [{"offset": "-P7D", "channels": ["email"]}, {"offset": "P1D", "channels": ["email"], "repeat": "daily"}]})
deadline_remember takes the same fields as the HTTP body — summary,
due_at, webhook_url, notify_emails, escalation_policy, tags,
metadata, recurrence/recurrence_tz, and an optional idempotency_key. A
policy naming a channel with no destination comes back as a tool error the agent
can read and fix.
Query what's due
This is the payoff for agents that span sessions. A fresh agent instance, holding none of the context that created a deadline, can ask "what did past-me commit to?" and get back everything still active. That is the whole point of making deadlines durable: the commitment outlives the conversation that made it.
The Deadlines list shows one row per deadline (recurring ones collapse to a single series row) with its due date and status. Filter by status, by a due-date window, or by tags, or search the summary. Open a row for the detail page: the full reminder timeline in fire order, each reminder's delivery status, and the audit log.
GET /v1/deadlines/ lists the team's deadlines; narrow it with ?status=open.
For the "what's on my plate" question use GET /v1/deadlines/query/, which
returns only the active set and takes a forward ?window= (a positive
ISO-8601 duration such as P30D, upper-bounding due_at) plus repeatable
?tags= (AND semantics). Already-overdue deadlines always come back, regardless
of the window. GET /v1/deadlines/{id}/ returns one deadline.
# What have I committed to in the next 30 days (plus anything already overdue)?
curl "https://aigears.example.com/v1/deadlines/query/?window=P30D" \
-H "Authorization: Bearer aigears_live_..."
deadline_query is the cross-session tool: it returns the active deadlines,
optionally bounded by a window and filtered by tags. deadline_list lists
everything (optionally by status); deadline_get(deadline_id=...) returns a
single deadline.
"Before I start — what did past-me leave on my plate for this month?"
→
deadline_query(window="P30D")
Complete, snooze, or cancel
Three actions move a live deadline. All three act only on an active (open
or overdue) deadline; calling any of them on one that is already completed or
cancelled returns a 409 — there's nothing left to act on.
- Complete — mark the obligation done. It's terminal, and it cancels any pending reminders. For a recurring deadline, completing the current occurrence advances the series: we spawn its successor at the next cron occurrence, sharing the rule, destinations, and policy.
- Cancel — call the obligation off. Also terminal; for a recurring deadline, cancelling terminates the series — no successor is spawned. This is the only way to stop a recurring deadline; there is no separate delete-series action.
- Snooze — push
due_atforward to a new time. This returns anoverduedeadline toopenand rebuilds its reminders from the policy against the new date (past-due steps skipped, exactly as at create).
Open a deadline's detail page; Complete, Snooze, and Cancel controls are offered while it is active. Snooze prompts for the new due time.
POST /v1/deadlines/{id}/complete/ (optional resolution_note),
POST /v1/deadlines/{id}/snooze/ ({"until": "..."}, a future time), and
POST /v1/deadlines/{id}/cancel/. Each returns the updated deadline, or a 409
if it was already terminal.
curl -X POST https://aigears.example.com/v1/deadlines/01J9Z8XKQR.../complete/ \
-H "Authorization: Bearer aigears_live_..."
deadline_complete(deadline_id=...), deadline_snooze(deadline_id=...,
until=...), and deadline_cancel(deadline_id=...).
"I renewed the certificate — mark that deadline done."
→
deadline_complete(deadline_id="..."), which for a recurring deadline advances the series to the next occurrence.
Notifications you receive
Each reminder that fires POSTs a deadline.escalation event to your
webhook_url (and/or sends a reminder email to notify_emails, for email
steps). Inside the standard signed envelope, the webhook data identifies the
deadline and the specific reminder:
{
"event_type": "deadline.escalation",
"data": {
"deadline_id": "01J9Z8XKQR...",
"notification_id": "01J9Z8ABCD...",
"due_at": "2026-03-14T00:00:00Z",
"fire_at": "2026-03-07T00:00:00Z",
"tags": [],
"metadata": {}
}
}
One event fires per materialised reminder — a step listing two channels yields
two notifications, one per channel. The envelope shape, the
X-AIGears-Signature header, and the retry/dead-letter rules are the same for
every primitive and are documented once in
Webhooks & signing; for standing up a
receiver and verifying the signature, see
Receiving webhooks. Delivery is
at-least-once, so make your handler idempotent on event_id.
Limits
The stock you're metered on is active deadlines — the count of open plus
overdue deadlines at any moment. Completing or cancelling a deadline frees the
slot; the reminders a deadline fires along the way are not separately metered,
and reads and previews are never metered. The per-tier caps, and what happens
when you reach one, live in Limits & tiers.