Cron Jobs

Schedule recurring agent tasks. Define jobs in config/cron.yaml or manage them via the CLI.

Quick example

# Send a morning brief to Telegram every day at 8 AM
vesper cron add morning-brief \
  --schedule "0 8 * * *" \
  --agent auto \
  --prompt "Good morning, give me the brief for {{date}}" \
  --deliver-to "telegram:@me"

Cron expression syntax

Standard 5-field crontab: minute hour day-of-month month day-of-week

FieldRangeSpecial
minute0-59* */N
hour0-23* */N
day-of-month1-31* */N
month1-12 or JAN-DEC*
day-of-week0-6 or SUN-SAT*

Shortcuts

  • @hourly โ†’ 0 * * * *
  • @daily โ†’ 0 0 * * *
  • @weekly โ†’ 0 0 * * SUN
  • @monthly โ†’ 0 0 1 * *
  • @yearly โ†’ 0 0 1 1 *

Prompt templates

Prompts support template variables interpolated at run time:

VariableValue
{{now}}ISO timestamp
{{date}}YYYY-MM-DD
{{yesterday}}Previous day (YYYY-MM-DD)
{{time}}HH:MM
{{weekday}}Monday / Tuesday / ...
{{user}}Current OS user

Delivery targets

Set deliver_to to send the agent's output somewhere:

  • telegram:@username โ€” Telegram DM
  • slack:#channel โ€” Slack channel
  • discord:#channel โ€” Discord channel
  • email:user@example.com โ€” Email
  • log โ€” append to ~/.openvesper/logs/cron.log
  • console โ€” stdout (useful for debugging)
  • none โ€” discard output

YAML config

Define jobs declaratively in config/cron.yaml:

jobs:
  - id: morning-briefing
    name: Daily morning briefing
    schedule: "0 8 * * *"
    agent: auto
    prompt: |
      Good morning. It is {{date}}. Give me:
      - Top crypto moves overnight
      - Calendar today
      - Weather
    deliver_to: "telegram:@me"
    enabled: false

  - id: friday-retro
    name: Friday weekly retro
    schedule: "0 17 * * FRI"
    agent: productivity-coach
    prompt: "Run my weekly retro for week of {{date}}"
    deliver_to: "telegram:@me"
    enabled: false

CLI commands

# List all jobs
vesper cron list

# Show summary stats
vesper cron status

# Add a job
vesper cron add daily-brief \
  --schedule "0 8 * * *" \
  --agent auto \
  --prompt "Give me my daily brief for {{date}}"

# Run a job immediately (bypass schedule)
vesper cron run daily-brief

# Enable/disable
vesper cron toggle daily-brief

# Remove
vesper cron remove daily-brief

Heartbeats โ€” per-agent autonomous mode

Each agent in .agents/<name>/ has a HEARTBEAT.md with frontmatter:

---
schedule: "0 9 * * MON"
enabled: false
---

# Heartbeat โ€” code-reviewer

## Recurring task

Weekly: list open PRs older than 3 days. Suggest which to prioritize.

To activate a heartbeat:

  1. Set enabled: true in the frontmatter
  2. Run vesper daemon start

The daemon reads all .agents/*/HEARTBEAT.md on startup and schedules each enabled one.

Running the scheduler

The scheduler runs inside the gateway daemon:

# Start the daemon (auto-loads cron.yaml + HEARTBEAT.md files)
vesper daemon start

# Check status
vesper daemon status

# Stop
vesper daemon stop

Without the daemon running, jobs do not fire on schedule. CLI commands like vesper cron run work without the daemon by triggering immediate execution.

State persistence

Job state (last run, run count, errors, next run) is stored at:

~/.openvesper/workspace/heartbeat.json

File permissions are set to 0600 on POSIX systems.

Privacy

All scheduling, execution, and state lives on your local machine. Cron output is never sent to OpenVesper servers โ€” only to the deliver_to target you configure. See Security for full details.