on_due whenever a tick should occur, and the shared runner and store claim and fire due jobs.
Which Provider?
Pick in-process when one host runs all the time; pick an external provider when firing should come from elsewhere.Quick Start
How It Works
The provider owns the trigger; the runner and store own the firing.on_due is the seam: the provider calls it whenever its trigger fires, and everything downstream — claiming due jobs and firing them — happens in the runner and store.
| Piece | Owns |
|---|---|
Provider (SchedulerProviderProtocol) | When a tick happens |
ScheduleRunner + store | What is due and how it fires |
Provider Options
Two ways to drive firing — one always-on, one event-driven.| Provider | When to use | Always-on thread? |
|---|---|---|
InProcessScheduleProvider (default, alias for ScheduleLoop) | Single always-on process | Yes (daemon) |
| External (webhook / systemd / cron / K8s CronJob / APScheduler) | Multi-host, serverless, or delegate to existing scheduler | No |
start(on_due, store=...) and stop() satisfies SchedulerProviderProtocol.
User Interaction Flow
A reminder set through the agent still fires even when a cloud scheduler drives the tick.Configuration Options
Providers are protocol-only — see the auto-generated SDK reference for full signatures.Scheduler Protocols
SchedulerProviderProtocol, ScheduleStoreProtocol, JobConditionProtocol, GateResultSchedule Tools
Agent-callable
schedule_add / schedule_list / schedule_removeCommon Patterns
Cloud webhook
Cloud Scheduler, EventBridge, or a GitHub Actions cron posts to an HTTP handler that callsfire_due().
systemd / launchd timer
A timer unit runs a short command on schedule; the command fires one tick and exits.Kubernetes CronJob
A short-lived pod runsfire_due() and exits — no long-running scheduler pod.
Best Practices
Never call start() twice on the same loop
Never call start() twice on the same loop
start() on a running loop is a no-op by design. Treat one loop as one provider — don’t try to reconfigure it mid-run.Use fire_due() directly for serverless
Use fire_due() directly for serverless
In webhook, cron, or systemd handlers call
engine.fire_due() and never call start() — you get one tick’s work with no daemon thread.Concurrency is safe by default
Concurrency is safe by default
fire_due() runs its claim + fire step under a per-instance lock, so an external caller and the loop thread can’t double-fire on non-atomic stores.Pair external providers with claim_due stores
Pair external providers with claim_due stores
When firing from multiple hosts, use a store that implements
claim_due for cross-host at-most-once delivery.Related
Background Tasks — ScheduleLoop
The in-process poll loop and combined recipes
Schedule Tools
Let agents create schedules via tool calls
Scheduled Run Policy
Safety gate for unattended scheduled runs
Scheduler Pre-Run Gate
Skip ticks cheaply before spending tokens

