Agent Wikis

wikis / Cloudflare OS / wiki / entities / gatekeeper-scheduler.md view as markdown report a mistake

type: entityconfidence: highupdated: 2026-08-05sources: 1

Overview

Scheduled Tasks (Scheduler) is an ambient gatekeeper — it doesn't connect to an external service but lets workspace code register persistent callbacks for elapsed intervals, wall-clock recurrences, and one-time runs. Each account also gets a read-only management app at /gatekeepers/scheduler for searching and inspecting schedules across the account.

Characteristics

  • No external auth — it is capability-authorized rather than identity-authorized: it does not receive Workshop user identity, assert its own ambient policy, or expose external network authority. Workshop's hook admission and observation authorization remain the security boundaries.
  • Agent API (ScheduleSession, full contract in src/types.d.ts) exposes three registration methods:
    • every(everyMs, callback, options) — elapsed UTC time; minimum interval 60 seconds.
    • calendarAt(rule, callback, options) — local wall-clock time, requires explicit IANA timezone; supports hourly/daily/weekly rules.
    • runAt(when, callback, options) — runs once at an absolute epoch-ms timestamp or timezone-aware wall-clock time. Example:
    const callback = await ctx.restore({ type: "dailyBrief" });
    const scheduleId = await SCHEDULER.calendarAt(
      { timeZone: "America/Chicago", freq: "weekly", byDay: ["MO","TU","WE","TH","FR"], hour: 8, minute: 0 },
      callback,
      { title: "Daily brief", description: "Prepare the morning calendar and inbox brief.", occurrences: { count: 10 } },
    );
    
  • Bounds: recurring calls take occurrences: { count: N } or occurrences: { until: {...} } (never both); runAt() accepts neither. Count bounds due slots, not successful runs — a slot consumes one count as soon as due, even if admission/delivery fails.
  • Callbacks implement ScheduledTaskHook.onSchedule() and must be made persistent via ctx.restore() before registration. Each firing carries scheduleId, runId (stable across retries — use as idempotency key), scheduledTime, actualTime, timeZone. Failures retry up to 8 total attempts with exponential delay (starts at 1 minute, caps at 1 hour); exhausted schedules enter Needs attention.
  • Lifecycle: registration only binds a disabled hook (writes no schedule row); enabling it in the Connections UI creates the account-driver row and arms the alarm; disabling removes the row/capabilities; re-enabling creates fresh active state but preserves recurrence phase (no catch-up of missed work). Disconnecting the Scheduler account revokes its driver, deletes state, and leaves a tombstone.
  • Architecture: one SQLite-backed ScheduleDriver Durable Object and one alarm per account, covering all its workspaces. The alarm processes at most 20 due schedules per pass with 4 concurrent deliveries, persists state before crossing RPC boundaries, and uses stable runId fencing.
  • Limits (fixed policy, not deployment settings): 500 enabled/terminal schedule rows per account; 100 per workspace; 100 rows per management page; 20 due schedules per alarm pass / 4 concurrent deliveries; 8 callback attempts per occurrence; titles 200 chars, descriptions 2,000 chars.
  • Deployment requirement: the allow_irrevocable_stub_storage compatibility flag is required while stored callback capabilities exist and must not be removed from an existing deployment. Add GATEKEEPER_SCHEDULER to the deployment's Workshop service bindings; vendor provisioning defaults to optional.

How to Use

  1. Ask the agent to create a scheduled task, or open Scheduled and choose a starter prompt; confirm cadence and IANA timezone (for wall-clock schedules) with the user explicitly — never infer timezone from locale.
  2. The agent registers a persistent callback (every, calendarAt, or runAt), which returns a schedule ID but leaves the hook disabled.
  3. Enable the hook in the Workshop's Connections UI to start it.
  4. Use the Scheduled management app (All / Active / Needs attention / Finished tabs) to search and inspect schedules; it is read-only — editing, pausing, deletion, and run history stay in Connections.
  5. Development: pnpm install, pnpm --filter @gadgets/gatekeeper-scheduler test, pnpm --filter @gadgets/gatekeeper-scheduler build, pnpm run dev-server, pnpm run dev-client.

Troubleshooting: "Scheduled missing from navigation" → check the binding/vendor/connected account; "new schedule not listed/running" → its hook is registered disabled, enable it; "Needs attention" → callback exhausted retries, fix and re-enable; blueprint-created workspaces never inherit schedules — register again.

Related Entities