Skip to content

Durable Objects

Notewright’s stateful work runs in Cloudflare Durable Objects. Each one is an agent: it owns its own SQLite-backed state, registers its own cron schedule on start, and exposes a uniform status contract that the CLI reads.

BindingClassContributed byRole
FOLLOW_UP_AGENTFollowUpAgentcoreRuns the follow-up extraction pipeline; records runs, task mappings, and failures.
SPEAKER_CONTEXT_AGENTSpeakerContextAgentcoreResolves and caches per-meeting speaker identities.
GRANOLA_SYNC_AGENTGranolaSyncAgentGranola providerRuns notes sync on a schedule and on demand.

The two core bindings and their migrations (v2 for FollowUpAgent, v3 for SpeakerContextAgent) are already declared in wrangler.jsonc. The Granola provider contributes its own binding and the granola-v1 migration through its runtime fragment.

Each agent is driven by its own cron schedule and on-demand HTTP routes; SpeakerContextAgent has no cron and is invoked only by the pipeline:

flowchart LR
    CRON[Cron schedules] --> GSA[GranolaSyncAgent]
    CRON --> FUA[FollowUpAgent]
    HTTP[On-demand HTTP<br/>/sync · /follow-ups/run · /follow-ups/backfill] --> GSA
    HTTP --> FUA
    FUA -.->|resolve speakers| SCA[SpeakerContextAgent]

    GSA --> D1[(D1)]
    FUA --> SINK[Follow-up sink]

    class SINK external

A Durable Object only registers its cron schedule the first time it starts. After a fresh deploy, an agent has not started yet, so its schedule is not registered. Run notewright start to wake every DO at once and see the schedules each registered. (A /health call does not work here: /health is a core-owned Worker route and never reaches the provider Durable Objects.)

  • Granola sync registers the cron 0 0 * * 2-6 (weekday evenings).
  • Follow-up extraction registers a backstop cron that re-scans recent meetings so nothing is missed between on-demand runs.
  • Speaker context registers no cron; it is invoked on demand by the pipeline.

See Monitoring health for inspecting the registered schedules with notewright schedules.

Every Notewright agent extends a shared base class that exposes a plain, Promise-returning status method. The Worker’s /status and /start routes enumerate every DO binding and call that method, which is how the CLI reports per-DO health and registered schedules. The base class is part of the public API, so a third-party DO host that extends it participates in /status and /start automatically. See Writing a provider.