Skip to main content

Zeno proactive-trigger scheduler: one-shot, heartbeat, and cron triggers.

Project description

zeno-scheduler

Proactive-trigger scheduler for Zeno.

Fires agent turns autonomously — the assistant doesn't have to wait for the user to send a message. Supports one-shot reminders, periodic heartbeats, and cron-style recurring schedules. Triggers are persisted to SQLite so they survive process restarts. Built-in @tools let the agent itself schedule and cancel its own reminders.

Install

uv add 'zeno-framework[scheduler]'
# or, without the AI package:
uv add zeno-scheduler

Features

  • One-shot triggers (schedule_once) — fire at a specific datetime or after a timedelta
  • Heartbeat triggers (schedule_heartbeat) — fire every N seconds
  • Cron triggers (schedule_cron) — standard 5-field cron expression with timezone support
  • Built-in tools so the agent can self-schedule from natural-language reminders: schedule_once, schedule_heartbeat, schedule_cron, list_triggers, cancel_trigger, cancel_trigger_by_name
  • (user_id, name) upsert semantics — re-running a seed call with the same name updates the existing row instead of duplicating it
  • Missed-fire policies (OnMissed.SKIP / RUN_ONCE / RUN_ALL) for triggers that lapse while the process was down

Minimal usage

import asyncio
from datetime import timedelta
from pathlib import Path

from zeno.agent import Agent
from zeno.app import ZenoApp
from zeno.channels.cli import CliChannel
from zeno.scheduler import Scheduler, SqliteScheduleStore
from zeno.scheduler.tools import schedule_once, list_triggers, cancel_trigger
from zeno.testing import FakeProvider

async def main() -> None:
    store = SqliteScheduleStore(Path("./scheduler.db"))
    scheduler = Scheduler(store)

    # Pre-seed a one-shot reminder. The agent could also call this via
    # the `schedule_once` tool at runtime (which accepts string deltas
    # like "30m" — handy when the model produces them).
    await scheduler.schedule_once(
        user_id="local",
        thread_key=None,
        channel="cli",
        prompt="Reminder: stand up and stretch.",
        delta=timedelta(minutes=30),
        name="stretch-reminder",
    )

    app = ZenoApp(
        agent=Agent(
            name="root",
            instructions="You are a proactive assistant. Schedule reminders when asked.",
            tools=[schedule_once, list_triggers, cancel_trigger],
        ),
        channels=[CliChannel()],
        provider=FakeProvider(),
        scheduler=scheduler,  # ← wires the scheduler into ZenoApp's lifecycle
    )
    await app.run()

asyncio.run(main())

ZenoApp starts and stops the scheduler alongside its other tasks. When a trigger fires, the scheduler calls channel.inbound_put(...) on the matching channel, which delivers the prompt as a synthetic inbound message — the agent processes it through the same turn path as a real user message.

Testing

uv run pytest packages/zeno-scheduler

Tests use an in-memory ScheduleStore and a virtual clock — no real sleep or filesystem I/O.

Caveats

Single-process only. The scheduler runs an in-process loop that scans SqliteScheduleStore for due triggers and fires them locally. There is no leader election or distributed lock. Running two ZenoApp instances against the same SQLite database will cause double firing — both loops will see the same row as due and call channel.inbound_put(...) independently. For now: run exactly one process per scheduler.db. A multi-process / leader-elected backend (e.g. Postgres SELECT … FOR UPDATE SKIP LOCKED) is on the roadmap.

Part of the Zeno framework. See apps/zeno-example-scheduler for a runnable end-to-end reference wiring.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

zeno_scheduler-1.1.0.tar.gz (40.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

zeno_scheduler-1.1.0-py3-none-any.whl (29.2 kB view details)

Uploaded Python 3

File details

Details for the file zeno_scheduler-1.1.0.tar.gz.

File metadata

  • Download URL: zeno_scheduler-1.1.0.tar.gz
  • Upload date:
  • Size: 40.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for zeno_scheduler-1.1.0.tar.gz
Algorithm Hash digest
SHA256 a769701f9bdf20e14544a86bc083c5c2c13e013f7c447984c975fcc302366acf
MD5 3fbbda36c0c27e89cbfbf654baf8d319
BLAKE2b-256 65dbdec5ad009ac1fe737e97aa6272597fa1e1db183eff1f811121f4ef6fc2b3

See more details on using hashes here.

Provenance

The following attestation bundles were made for zeno_scheduler-1.1.0.tar.gz:

Publisher: publish.yml on nkootstra/zeno

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file zeno_scheduler-1.1.0-py3-none-any.whl.

File metadata

  • Download URL: zeno_scheduler-1.1.0-py3-none-any.whl
  • Upload date:
  • Size: 29.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for zeno_scheduler-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ddbbd8394af8e6dba80fe097e32b91ddc7db73dd99c95ff386f073715b2f5d98
MD5 6aa03a868be2e02bf3777692fe5c5fc8
BLAKE2b-256 0d288648e2a5cf78837d08d55fb24ed51bc108d924acc4b6412ae36ef74a485f

See more details on using hashes here.

Provenance

The following attestation bundles were made for zeno_scheduler-1.1.0-py3-none-any.whl:

Publisher: publish.yml on nkootstra/zeno

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page