Schedule

Scheduler management for automated agent execution

The schedule command manages scheduled agent execution.

Usage

bash
praisonai schedule [OPTIONS] COMMAND [ARGS]...

Commands

CommandDescription
addAdd a scheduled job (supports --once for auto-removal after one fire)
startStart scheduled agent execution
runPoll and fire store-backed jobs in the foreground (no gateway required)
stopStop scheduled job(s)
listList scheduled jobs (merges store-backed jobs and daemon schedulers)
runsShow past run history for a store-backed schedule
pausePause a store-backed schedule (stops firing, keeps it)
resumeResume a paused store-backed schedule
updateUpdate a store-backed schedule’s cadence / message
removeRemove a store-backed schedule (run history is retained)
logsView scheduler logs
restartRestart a scheduled job
deleteDelete a scheduled job β€” now finds store jobs first, falls back to daemon
describeShow job details β€” now prefers store, falls back to daemon
statsShow scheduler statistics
blueprintCreate a job from a blueprint template
blueprint-listList available blueprints
suggestionsList pending automation suggestions
suggestion-acceptAccept a suggestion and create the job
suggestion-dismissDismiss a suggestion
suggestion-proposePropose a blueprint as a suggestion

Adding Jobs

bash
praisonai schedule add "job-name" \
  --schedule "cron:0 9 * * *" \
  --message "Good morning! Check tasks." \
  --agent support \
  --channel telegram \
  --channel-id 12345

Options

OptionShortDescription
--schedule-sWhen to run: hourly, daily, weekly, */30m, cron:..., at:..., in 20 minutes, at 9am, every day at 9am, weekdays at 9am, every monday 9am, every mon,wed,fri at 9am. Naive at: / cron: times resolve per Timezones.
--tzIANA timezone for cron: or naive one-shot at: times (e.g. America/New_York). See Timezones.
--message-mPrompt text to deliver
--agent-aAgent ID to execute this job (default: first registered)
--deliver-dDelivery token: origin, telegram, all, or platform:chat_id[:thread_id]. See Scheduler Delivery for the full token grammar and Python/YAML equivalents.
--continuable / --no-continuableDefault --continuable. Seed a resumable session on delivery so a reply resumes the job with context. Use --no-continuable for fire-and-forget notifications (pure alerts). Applied only when a delivery target is configured.
--pre-runCheap pre-run gate command: exit 0 + output β†’ run (output seeds the prompt); non-zero β†’ skip (no model tokens, no delivery)
--conditionNatural-language / expression alias for the pre-run gate (advisory)
--command / --scriptNo-LLM action: run this shell command on schedule and deliver its stdout verbatim (no agent, no model turn).
--command-timeoutMax seconds the --command may run before it is killed (default 60).
--backendExternal coding-CLI backend action: run the message as one headless turn via a registered backend (see praisonai backends), e.g. claude-code, codex-cli. No native agent, no in-process model turn. Mutually exclusive with --command.
--monitor-urlRun the agent only when the response body at this public HTTP(S) URL changes. Mutually exclusive with --monitor-command, --pre-run, --command, --backend. Trusted human-only surface β€” not exposed to the LLM.
--monitor-commandRun the agent only when this shell command’s stdout changes. Mutually exclusive with --monitor-url, --pre-run, --command, --backend. Trusted human-only surface β€” not exposed to the LLM.
--backend-cwdWorking directory for the --backend turn (default: the scheduler process cwd).
--backend-timeoutMax seconds the --backend turn may run (default: the backend’s own timeout, 300s).
--modelPin this job to a specific model (e.g. openai/gpt-4o-mini). Snapshotted so unattended runs stay stable and drift fails closed.
--pin / --no-pinDefault --pin. Enforce the model snapshot so drift fails closed (only takes effect once --model captures one). --no-pin follows whatever the default becomes.
--onceOne-shot job: auto-remove after its single successful fire (maps to delete_after_run). A failed fire leaves the job listed but disabled (visible in praisonai schedule list); a crash mid-run records an abandoned row and retries the job once. Ideal for at: / in ... reminders so a spent job does not linger in listings.
--channel[Legacy] Delivery platform: telegram, discord, slack, whatsapp
--channel-id[Legacy] Target chat/channel ID
--session-idSession ID to preserve conversation context
--jsonOutput JSON

Examples

Add a daily reminder bound to a specific agent

bash
praisonai schedule add "morning-hello" -s daily -m "say hello" --agent support

Add a weekly digest

bash
praisonai schedule add "weekly-digest" -s weekly -m "Summarise the week's activity" --deliver telegram

weekly runs every 7 days (604800 seconds).

Natural-language schedules

Plain English clock times and day names work anywhere --schedule is accepted.

bash
# Weekday standup β€” Mon–Fri at 09:00
praisonai schedule add "standup" -s "weekdays at 9am" -m "post the standup summary"

# One-shot reminder β€” fires once at the next 17:00, then auto-removes
praisonai schedule add "eod" -s "at 5pm" -m "wrap up the day" --once

# Specific weekdays β€” Mon, Wed, Fri at 09:00
praisonai schedule add "reports" -s "every mon,wed,fri at 9am" -m "send the report"

A bare clock time (at 5pm) is a one-shot at the next matching local time; any recurring form (every …, daily …, or a day-of-week name) becomes a cron schedule. See Async Agent Scheduler β†’ Natural language for the full grammar.

Timezones and portability

A naive at: timestamp is stored with the resolved zone attached (per-date DST-correct). Adding praisonai schedule add "x" -s "at:2026-07-01T09:00:00" in Europe/London stores 2026-07-01T09:00:00+01:00; the same command on a December date stores +00:00. Because the stored value carries the offset, the job fires at the same wall-clock time on any runner β€” you do not need to include an offset in the input unless you want to override the resolved zone.

Set a process-wide default with PRAISONAI_SCHEDULE_TIMEZONE. It resolves after any explicit tz/-s offset but before the machine’s local zone, and an unknown zone name is now rejected at add time:

bash
# Store an aware string derived from a chosen zone
PRAISONAI_SCHEDULE_TIMEZONE=Europe/London \
  praisonai schedule add "brief" -s "at:2026-07-01T09:00:00" -m "morning brief"

# Unknown zone β†’ ValueError at add time, not a silent never-fires job
PRAISONAI_SCHEDULE_TIMEZONE=Not/A/Zone \
  praisonai schedule add "x" -s "at:2026-07-01T09:00:00"

See Schedule Tools β†’ Timezones for the full precedence ladder.

Fire-and-forget alert

bash
praisonai schedule add "backup-alert" -s "cron:0 3 * * *" -m "Backup ok" \
  --deliver "slack:C012345" \
  --no-continuable

A reply in #C012345 lands as a brand-new turn instead of resuming the maintenance job’s conversation. Without --no-continuable, a delivered result is continuable by default β€” a reply resumes the job’s conversation with the brief in context.

Deliver via home channel

bash
praisonai schedule add "news" -s daily -m "summarise AI news" --deliver telegram

Set the platform’s home channel first β€” either by exporting TELEGRAM_HOME_CHANNEL=<chat_id> before you run this command, or by adding an explicit --deliver telegram:<chat_id> argument. See Scheduler Delivery for the full precedence ladder.

Deliver into a thread

Append a third :thread_id segment to thread the outbound message β€” a Slack thread ts, a Telegram forum topic id, or a Discord thread id:

bash
praisonai schedule add "standup" -s "cron:0 9 * * 1-5" -m "post the standup summary" \
  --deliver slack:C0123456:1728987654.001234

The router preserves the thread segment end-to-end, so the message lands in the Slack thread rooted at message ts 1728987654.001234. Adapters without thread support silently ignore the segment. See Scheduler Delivery β†’ Thread semantics.

Fire-and-forget notice

bash
praisonai schedule add "backup-notice" -s daily \
  -m "post the backup-complete notice" \
  --deliver slack:C0123456 \
  --no-continuable

--no-continuable opts out of session seeding, so a reply starts a fresh session instead of resuming the job. See Continuable Delivery.

Fan-out to all home channels

bash
praisonai schedule add "ops-digest" -s "cron:0 * * * *" -m "incident digest" --deliver all

Deliver back to origin chat

bash
praisonai schedule add "stretch" -s "*/2h" -m "time to stretch" \
  --deliver origin --channel telegram --channel-id 12345

origin requires --channel and --channel-id so the executor can resolve the creating chat.

Blueprints & Suggestions

Create jobs from reusable templates, or accept consent-first suggestions β€” the same engine that powers the /automations and /blueprint chat commands. See Automation Suggestions for the concepts.

blueprint

Create a schedule from a blueprint template.

OptionDescription
--hourDelivery hour (0-23)
--minuteDelivery minute (0-59)
--weekdaysDays: mon-fri, daily, weekends, or a single day
--focusFocus area
--intervalInterval in minutes (for interval-based blueprints)
--keywordsPriority keywords (for important-mail)
--deliver / -dDelivery target
--agent / -aAgent ID
--jsonOutput JSON

blueprint-list

List available blueprints (built-in + user YAML).

OptionDescription
--category / -cFilter by category
--jsonOutput JSON

suggestions

List pending automation suggestions.

OptionDescription
--jsonOutput JSON

suggestion-accept

Accept a suggestion and create the schedule job.

Argument / OptionDescription
<id>Suggestion ID to accept
--deliver / -dOverride delivery target

suggestion-dismiss

Dismiss a suggestion without creating a job.

ArgumentDescription
<id>Suggestion ID to dismiss

suggestion-propose

Propose a blueprint as a suggestion (manual/CLI trigger).

OptionDescription
--reason / -rWhy this is being suggested
--hourDelivery hour (0-23)
--minuteDelivery minute (0-59)
--weekdaysDays: mon-fri, daily, weekends, or a single day
--focusFocus area
--intervalInterval in minutes
--keywordsPriority keywords (for important-mail)
--deliver / -dSuggested delivery target

Examples

Create from a blueprint
praisonai schedule blueprint morning-brief \
  --hour 8 --weekdays mon-fri --deliver telegram
Accept a suggestion
praisonai schedule suggestions
# copy the [sug_...] id from the output, then:
praisonai schedule suggestion-accept sug_abc123 --deliver telegram

Add with delivery target [Legacy]

bash
praisonai schedule add "tg-reminder" \
  -s "cron:0 9 * * *" \
  -m "check email" \
  --agent support \
  --channel telegram \
  --channel-id 12345

Start scheduler

bash
praisonai schedule start

schedule start runs the agents.yaml engine (daemon scheduler). It does not poll store-backed jobs created by schedule add β€” use schedule run for those.

Run the store poller standalone (no gateway)

bash
praisonai schedule add "brief" -s daily -m "morning brief" --deliver telegram
praisonai schedule run          # foreground: polls + fires store jobs (Ctrl-C to stop)
praisonai schedule run --poll 5 # poll every 5 seconds instead of the default 15s

schedule run hosts the store poller in the foreground β€” no messaging gateway or UI host required. Use it when you added jobs via schedule add and just want them to fire from a plain terminal or a systemd unit.

Flags

OptionShortTypeDefaultDescription
--poll-pfloat15.0Seconds between store polls

The CLI maps --poll to ScheduleLoop.run_forever(poll_seconds=…), the foreground counterpart to ScheduleLoop.start().

List scheduled jobs

list merges store-backed jobs (created with schedule add) and daemon schedulers in one view. Store jobs are tagged [store].

bash
praisonai schedule list
praisonai schedule list --json

Store jobs print as [store] <name> (id: <id>) [enabled|paused] β€” <cadence> β€” last run: <ts>:

text
Store schedules (1):
  [store] morning-brief (id: sch_a1b2c3) [enabled] β€” cron: 0 8 * * 1-5 β€” last run: 2026-03-01 08:00

list --json returns a single document splitting the two sources:

json
{"store": [...], "daemon": [...]}

View logs

bash
praisonai schedule logs
praisonai schedule logs --tail 100 --follow

Stop a job

bash
praisonai schedule stop job-123
praisonai schedule stop all

Delete a job

delete finds store jobs first (by id, then by name) and removes them; it falls back to the daemon PID handler for legacy jobs.

bash
praisonai schedule delete morning-brief --yes
praisonai schedule delete sch_a1b2c3 --yes

Skip the model turn when there are no new emails

bash
praisonai schedule add "inbox-watch" \
  -s "*/5m" \
  -m "Summarise new emails" \
  --pre-run "scripts/new_mail.sh" \
  --deliver telegram

--pre-run runs scripts/new_mail.sh before each tick. Exit 0 + stdout β†’ agent runs with that stdout appended to the message. Non-zero exit β†’ tick is skipped, no tokens spent, no Telegram ping.

No-LLM command action

bash
praisonai schedule add "disk-watch" -s hourly --command "df -h /" --deliver telegram:-100123
praisonai schedule add "uptime" -s "*/5m" --command "uptime" --deliver slack:C012345 --no-continuable

--command runs the shell command on schedule and delivers its stdout verbatim β€” model-free, so there is no agent turn, no tokens, and no --message needed. --command and --script are aliases for the same flag. See Scheduler Command Action for the full feature page.

Backend action

bash
praisonai schedule add "nightly-refactor" \
  -s "cron:0 2 * * *" \
  -m "tidy utils.py, run tests" \
  --backend claude-code \
  --backend-cwd ~/proj \
  --deliver telegram

--backend runs the message as one headless turn through a registered CLI backend (see praisonai backends) β€” no native agent, no in-process model turn. It is mutually exclusive with --command. See Scheduler Backend Action for the full feature page.

Wake only when a page changes

bash
praisonai schedule add "price-watch" \
  -s "*/15m" \
  -m "Summarise the change" \
  --monitor-url "https://example.com/api/price" \
  --deliver telegram

--monitor-url probes the URL on every tick, hashes the response, and only runs the agent when the hash changed. An unchanged source records no_change β€” zero tokens, no delivery. See Scheduler Monitor for the full feature page and reliability guarantees.

Wake only when a shell command’s stdout changes

bash
praisonai schedule add "unread-watch" \
  -s "*/5m" \
  --monitor-command "curl -sf https://api.example.com/unread | jq '.count'" \
  -m "Summarise what changed" \
  --deliver telegram

--monitor-command is the stateful sibling of --pre-run: it remembers the last-seen hash across ticks and only runs the agent when the source moves.

Validation errors:

  • --command and --backend together β†’ --command and --backend are mutually exclusive: a job runs exactly one model-free action. Configure one or the other.
  • Invalid timeout β†’ --backend-timeout must be a finite, non-negative number of seconds.
  • Missing praisonai-code β†’ CLI backend '<id>' unavailable: <e>. Backend jobs require the praisonai-code package (pip install praisonai-code).
  • A duplicate schedule name now exits non-zero (previously it substring-matched Error and could misclassify).

Pin a scheduled job to a specific model

bash
praisonai schedule add "daily-brief" \
  -s "cron:0 9 * * *" \
  -m "summarise the day" \
  --model "openai/gpt-4o-mini"

--model snapshots the model onto the job so unattended runs stay on it β€” and fail closed if the default drifts. --no-pin follows whatever the default becomes:

bash
praisonai schedule add "flex-brief" -s daily -m "summarise" --no-pin

See Scheduler Model Pin for the full feature page.

Managing store-backed schedules

A store-backed schedule is a job authored by schedule add, persisted in ~/.praisonai/config.yaml, and managed from the CLI without hand-editing YAML. list, delete, and describe are now unified across store and daemon jobs, and five subcommands manage the store surface end to end. The agent-callable equivalents live in Schedule Tools.

Diagram

βž• add

πŸ“‹ list

⏸️ pause

▢️ resume

✏️ update

πŸ—‘οΈ remove

πŸ”Ž runs

Which command should I use?

Store subcommands and daemon subcommands overlap, so pick by how the job was created.

Diagram

schedule add

schedule start

Not sure

How was the job created?

Store-backed
pause / resume / update / remove

Daemon scheduler
stop / restart / delete

Run schedule list β€”
store jobs are tagged [store]

Store-backed jobs (created with schedule add) manage state via pause / resume / update / remove β€” but they must be actively fired by a running poller. Pick how they fire:

Diagram

Gateway / UI host running

Plain terminal / systemd

OS cron / CI

You added a job via schedule add.
How will it fire?

Gateway hosts the poller
(nothing extra to do)

praisonai schedule run
(foreground poller, Ctrl-C to stop)

praisonai schedule tick
(single tick, then exit)

Add a one-shot reminder

bash
# One-shot reminder that auto-cleans after firing
praisonai schedule add "standup-ping" \
  --schedule "in 20 minutes" \
  --message "Time for standup" \
  --deliver telegram --once

Pause and resume

bash
# Pause and resume without losing state
praisonai schedule pause morning-brief
praisonai schedule resume morning-brief

Update cadence or message

bash
# Change cadence without remove + re-add
praisonai schedule update morning-brief -s "cron:0 8 * * 1-5"

# Change only the message
praisonai schedule update morning-brief -m "Send the updated morning brief"

Show past runs

bash
# Show past runs (status, duration, delivered, error)
praisonai schedule runs morning-brief --limit 10
praisonai schedule runs morning-brief --json

Remove a store-backed schedule

bash
# Remove by id or name (id resolves first, so duplicate names are safe)
praisonai schedule remove morning-brief --yes

See Also