Skip to main content
Built-in — no extra dependencies required. Schedule tools are included in the core praisonaiagents package.
Schedule tools let your agents self-schedule reminders, recurring tasks, and one-shot jobs — all via simple tool calls. No changes to the Agent class are needed.

Quick Start

from praisonaiagents import Agent
from praisonaiagents.tools import schedule_add, schedule_list, schedule_remove

agent = Agent(
    name="assistant",
    instructions="You can set reminders and schedules for the user.",
    tools=[schedule_add, schedule_list, schedule_remove],
)

agent.start("Remind me to check email every morning at 7am")
The agent will call schedule_add with the appropriate schedule expression, and the job will be persisted to disk.

Available Tools

schedule_add

Add a new scheduled job.
ParameterTypeRequiredDescription
namestrYesHuman-readable name (e.g. "morning-email-check")
schedulestrYesWhen to run (see Schedule Expressions)
messagestrNoPrompt or reminder text to deliver when triggered
Returns: Confirmation string with the job id.

schedule_list

List all scheduled jobs. Takes no parameters. Returns: Formatted string listing every job with id, name, schedule, status, and message.

schedule_remove

Remove a scheduled job by name.
ParameterTypeRequiredDescription
namestrYesName of the schedule to remove
Returns: Confirmation or not-found message.

Schedule Expressions

FormatExampleDescription
Keyword"hourly", "daily"Predefined intervals
Interval"*/30m", "*/6h", "*/10s"Custom interval (minutes, hours, seconds)
Cron"cron:0 7 * * *"5-field cron expression
One-shot"at:2026-03-01T09:00:00"ISO 8601 timestamp
Relative"in 20 minutes"Relative to now
Seconds"3600"Raw seconds

Examples

Recurring Schedule

from praisonaiagents import Agent
from praisonaiagents.tools import schedule_add, schedule_list, schedule_remove

agent = Agent(
    name="news-bot",
    instructions="""You help users stay informed.
    When asked, create schedules for news summaries.
    Use schedule_add with cron expressions for precise timing.""",
    tools=[schedule_add, schedule_list, schedule_remove],
)

# Agent will create: schedule_add("morning-news", "cron:0 7 * * *", "Summarize AI news")
agent.start("Send me an AI news summary every morning at 7am")

One-Shot Reminder

# Agent will create: schedule_add("meeting-prep", "in 20 minutes", "Prepare for standup")
agent.start("Remind me in 20 minutes to prepare for standup")

List and Manage

# Agent will call schedule_list() and schedule_remove("old-task")
agent.start("Show me my schedules and remove 'old-task'")

Using String Tool Names

agent = Agent(
    name="scheduler",
    tools=["schedule_add", "schedule_list", "schedule_remove"],
)

Storage

Jobs are persisted to ~/.praisonai/config.yaml under the schedules key by default via ConfigYamlScheduleStore. The store is:
  • Thread-safe for multi-agent scenarios
  • Atomic writes (tmp + rename) to prevent corruption
  • Auto-created on first use
  • Auto-migrates legacy jobs.json data on first load

Custom Store (ScheduleStoreProtocol)

Swap the default file store for any backend that implements ScheduleStoreProtocol:
from praisonaiagents.scheduler import ScheduleStoreProtocol

class MyDatabaseStore:
    """Any object with these methods works."""
    def add(self, job): ...
    def get(self, job_id) -> Optional[Any]: ...
    def list(self, agent_id=None) -> list: ...
    def update(self, job): ...
    def remove(self, job_id) -> bool: ...
    def get_by_name(self, name) -> Optional[Any]: ...
    def remove_by_name(self, name) -> bool: ...

assert isinstance(MyDatabaseStore(), ScheduleStoreProtocol)  # ✅
Inject it at startup so all agent schedule_add/list/remove calls use your store:
from praisonaiagents.tools.schedule_tools import set_store

my_store = MyDatabaseStore()
set_store(my_store)  # All schedule tools now use this store
PraisonAIUI and BotOS use the same config.yaml store. You can also call set_store() to inject any custom backend.

Schedule Runner

The ScheduleRunner checks which jobs are due for execution:
from praisonaiagents.scheduler import ScheduleRunner, ConfigYamlScheduleStore

store = ConfigYamlScheduleStore()
runner = ScheduleRunner(store=store)

# Get jobs that are due right now
due_jobs = runner.get_due_jobs()

for job in due_jobs:
    print(f"Due: {job.name}{job.message}")
    runner.mark_run(job)  # Updates last_run_at

Hook Events

Schedule lifecycle events are available via the hook system:
EventWhen
SCHEDULE_ADDA new schedule is created
SCHEDULE_REMOVEA schedule is deleted
SCHEDULE_TRIGGERA scheduled job fires

Execution History

Every scheduled job execution is logged as a RunRecord for auditing:
from praisonaiagents.scheduler import FileScheduleStore

store = FileScheduleStore()

# Get last 10 executions for a job
history = store.get_history("job-abc123", limit=10)

for run in history:
    print(f"{run.job_name}: {run.status} ({run.duration:.1f}s)")
    if run.error:
        print(f"  Error: {run.error}")
FieldTypeDescription
job_idstrJob that was executed
job_namestrHuman-readable job name
statusstr"succeeded" or "failed"
resultstrAgent output (truncated)
errorstrError message if failed
durationfloatExecution time in seconds
deliveredboolWhether result was delivered to channel
timestampfloatEpoch timestamp

Executing Scheduled Jobs

Schedule tools create and persist jobs, but to actually execute them when they’re due, use ScheduleLoop:
from praisonaiagents.scheduler import ScheduleLoop

def handle_job(job):
    print(f"🔔 {job.name}: {job.message}")

loop = ScheduleLoop(on_trigger=handle_job, tick_seconds=30)
loop.start()
See Background Tasks — ScheduleLoop for the full API and combined examples with BackgroundRunner.

BotOS Integration

When using BotOS (multi-platform bot orchestrator), scheduled jobs execute automatically — no ScheduleLoop needed. BotOS runs its own 30-second schedule tick alongside all bots:
  • Agents create jobs via schedule_add during conversations
  • BotOS detects due jobs every 30 seconds
  • The originating agent processes the job message
  • Results are delivered back to the originating platform (Telegram, Discord, etc.)
# bot.yaml — schedules work out of the box
agent:
  name: assistant
  tools:
    - schedule_add
    - schedule_list
    - schedule_remove

channels:
  telegram:
    token: ${TELEGRAM_BOT_TOKEN}
praisonai bot start --config bot.yaml
# Agent can now self-schedule and BotOS executes + delivers results

Architecture

Schedule tools follow PraisonAI’s core principles:
  • Agent-centric — tools, not Agent parameters
  • Lazy-loaded — zero import cost until used
  • Protocol-drivenScheduleStoreProtocol makes stores swappable
  • No Agent bloat — the Agent class is unchanged
  • Thread-safe — safe for multi-agent workflows
  • Pluggableset_store() lets any backend replace the default file store

See Also

Background Tasks

Sync wrappers, ScheduleLoop, and combined recipes

Scheduler CLI

24/7 autonomous agent scheduling via CLI