Quick Start
1
Register a hook
Register one hook on the default registry for
SCHEDULE_ADD.2
Give an Agent the tool
Hand the agent the
schedule_add tool — the store fires your hook when the agent persists a job.How It Works
SCHEDULE_ADD and SCHEDULE_REMOVE are emitted by the schedule store — the one chokepoint every add/remove path funnels through — after its locks release.
Hooks fire only on a successful persist. If FileScheduleStore.add(), remove(), or remove_by_name() fails to save, the store raises OSError, reloads memory from disk, and emits nothing — a hook never sees a job that doesn’t exist on disk (PraisonAI PR #5901).
What Fires (and What Doesn’t)
Events fire only on a real change.
Retirement via any
should_retire() path (one-shot, max_runs, or until) emits the same SCHEDULE_REMOVE hook as a manual schedule_remove — the store is the single chokepoint every deletion funnels through. For a normal spent run that removal happens in ScheduleRunner.mark_run() after the run completes; claim_due() only removes a spent job when its crash retry was abandoned too or its until deadline has passed. See Crash Recovery.
Payload Reference
ScheduleAddInput (fires on SCHEDULE_ADD):
ScheduleRemoveInput (fires on SCHEDULE_REMOVE):
Both inherit
session_id, cwd, event_name, timestamp, and agent_name from HookInput (agent_name is the job’s agent_id if set, else "scheduler").
Both types are importable from
praisonaiagents.hooks:
from praisonaiagents.hooks import ScheduleAddInput, ScheduleRemoveInput.Common Patterns
Audit log
Append every add and remove to a JSONL file.Per-tenant quota
Count active schedules perprincipal.
One-shot metric
Push a metric when a spent one-shot is auto-removed.Emission Discipline
Inside a running asyncio loop, emission is fire-and-forget;asyncio.run(...) around your code works because the emitter handles both loop states.
Best Practices
Keep hooks lightweight
Keep hooks lightweight
Hooks may run inside an async event loop. Avoid blocking I/O; offload heavy work to a queue.
Filter early on principal
Filter early on principal
For multi-tenant setups, check
event_data.principal at the top of the hook and return HookResult.allow() immediately when it doesn’t match.Don't gate the mutation from a hook
Don't gate the mutation from a hook
These events are observability-only — the store proceeds regardless of
HookResult.deny(...). To control who can create schedules, gate the callers: guardrails on the tool, auth on the CLI.Use job_id as the durable key
Use job_id as the durable key
Use
event_data.job_id, not event_data.job_name, as the stable key — names can be reused.Related
Hook Events
Full event reference for every lifecycle hook.
Schedule Tools
The agent-callable tools that trigger these hooks.
Schedule CLI
The CLI that triggers these hooks.
Bot Lifecycle Hooks
Sibling gateway lifecycle events.

