The renewals agent
The first five rungs each introduced one primitive. This one composes all four into a single workflow — the product's "coherent cluster" thesis shown rather than asserted. A procurement agent manages a supplier contract end to end: it watches the supplier's terms page, remembers the renewal deadline, gets human approval before committing spend, and schedules a post-renewal follow-up. Each primitive hands off to the next through a webhook, and the whole run is legible after the fact in the audit log.
The story
Acme renews its contract with a supplier every year. Nobody wants to babysit that. So a procurement agent takes it on: it keeps an eye on the supplier's terms page for changes, holds the hard renewal deadline so it never lapses, insists a human signs off before money is committed, and books a check-in a week after renewal to confirm everything went through. The agent isn't resident the whole time — it wakes only when a webhook calls it back.
The architecture
The four primitives never call each other directly. Each fires a webhook to the agent's receiver, and the agent decides the next move:
- A
watch.changedon the terms page wakes the agent → it remembers the renewal deadline. - A
deadline.escalationas the renewal date nears wakes the agent → it requests human approval. - An
approval.approveddecision wakes the agent → it commits the renewal and schedules the follow-up. - A
schedule.fireda week later wakes the agent → it confirms the renewal landed and closes the loop.
Webhooks are the glue; the agent is stateless between them, rehydrating from each event's payload.
Step 1 — Watch the supplier's terms
Watches → New watch on the supplier's terms URL, scoped with a CSS selector to the renewal-terms section, firing on any change.
POST /v1/watches/ with the terms URL and a match_rule; the change arrives as
a watch.changed webhook.
"Watch the supplier's terms page and tell me if the renewal terms change."
watch_create(
source_type="url",
url="https://supplier.example.com/terms",
css_selector="#renewal-terms",
match_rule={"kind": "any"},
webhook_url="https://hooks.example.com/aigears",
poll_interval="PT6H",
)
Step 2 — Remember the renewal deadline
Deadlines → New deadline for the renewal date, with an escalation policy that nudges the agent by webhook ahead of time.
POST /v1/deadlines/ with due_at and an escalation_policy; reminders arrive
as deadline.escalation webhooks.
"Remember the renewal is due 2027-01-01; warn me 30 and 7 days ahead."
deadline_remember(
summary="Renew the Acme supplier contract",
due_at="2027-01-01T00:00:00Z",
webhook_url="https://hooks.example.com/aigears",
escalation_policy={"steps": [
{"offset": "-P30D", "channels": ["webhook"]},
{"offset": "-P7D", "channels": ["webhook"]}]},
)
Step 3 — Gate the renewal on approval
The Approvals view shows the pending request while a human reviews the renewal terms and cost.
POST /v1/approvals/ with the action summary and a callback_url; the decision
arrives as an approval.approved (or approval.rejected) webhook.
"Get Dana's approval before we commit to the renewal."
approval_request(
approver_email="[email protected]",
action_summary="Renew the Acme supplier contract for 2027",
action_details="€48,000/yr, terms unchanged from 2026.",
timeout="P3D",
callback_url="https://hooks.example.com/aigears",
metadata={"contract": "acme-2027"},
)
Step 4 — Schedule the follow-up
Schedules → New schedule, one-shot, a week after the renewal date.
POST /v1/schedules/ with a fire_at a week out; it arrives as a
schedule.fired webhook.
"After the renewal, remind me in a week to confirm it went through."
schedule_create(
fire_at="2027-01-08T09:00:00Z",
webhook_url="https://hooks.example.com/aigears",
payload={"contract": "acme-2027", "step": "confirm-renewal"},
)
Observing the whole run
Because every surface writes to the same audit log, the entire renewal —
across four primitives, three surfaces, and however many agent instances — reads
back as one story. Each entry records who did what (actor_type distinguishes
the agent's mcp/api_key actions from the human approver's decision), every
webhook delivery, and the approver's comment. When you want to answer "how did
this contract actually get renewed?", the audit log
is the single end-to-end record.
Run it yourself
There is no single composed script — the composition is the four per-primitive scripts wired together by your own receiver. Each step's lifecycle runs on its own:
examples/python/watches_agent.py(TypeScript)examples/python/deadlines_agent.py(TypeScript)examples/python/approvals_agent.py(TypeScript)examples/python/schedules_agent.py(TypeScript)
Over MCP, the whole workflow is one agent conversation: the four prompts above, each waking the agent from the previous step's webhook. See Receiving webhooks for standing up the receiver that ties them together.