Skip to content

Writing Tasks

Tasks are the core of Leo's scheduling system. Each task is a prompt file that tells the assistant what to do when cron triggers it.

Anatomy of a Task

A task has two parts:

  1. Configuration in leo.yaml — schedule, model, channels, routing
  2. Prompt file in the task's workspace — instructions for the assistant

Configuration

tasks:
  daily-briefing:
    schedule: "0 7 * * *"
    timezone: America/New_York
    prompt_file: reports/daily-briefing.md
    model: opus
    max_turns: 20
    channels: [plugin:telegram@claude-plugins-official]
    notify_on_fail: true
    enabled: true
    silent: true

Prompt File

The prompt file is a plain markdown file with instructions:

# Daily Briefing

Check the following and compile a morning briefing:

1. Scan my inbox for anything urgent
2. Check today's calendar for meetings
3. Review any open PRs that need my attention
4. Check for breaking news in my industry

Format as a concise message. Deliver it via the configured channel plugin
using its MCP messaging tool.

What Leo Adds

When leo run <task> executes, it assembles the final prompt. You write the prompt file; Leo adds a silent preamble if silent: true and nothing else.

Silent Preamble (if silent: true)

Leo prepends instructions telling the assistant to:

  • Work without narration or progress updates
  • Only deliver output via a configured channel if there's something meaningful
  • Output NO_REPLY if there's nothing to report

Channels

Leo passes the task's channels: list to the spawned Claude process via the LEO_CHANNELS environment variable. The agent picks up its configured channels and uses whatever MCP tool the channel plugin exposes (e.g. the Telegram plugin's reply tool) to send its final message. Leo does not hardcode any channel-specific protocol.

Examples

Periodic Check

A task that runs every 30 minutes during waking hours and only messages when something needs attention:

# leo.yaml
tasks:
  checks:
    schedule: "0,30 7-22 * * *"
    prompt_file: prompts/checks.md
    model: sonnet
    max_turns: 10
    channels: [plugin:telegram@claude-plugins-official]
    enabled: true
    silent: true      # silent: only report if something needs attention
<!-- prompts/checks.md -->
# Periodic Check

Run through this checklist. Only report items that need my attention.

- [ ] Unread messages that are urgent or time-sensitive
- [ ] Calendar events in the next 2 hours
- [ ] Pending tasks or reminders that are due
- [ ] Any alerts or notifications that need action

If everything is clear, output NO_REPLY.
If something needs attention, deliver a concise summary via your configured channel.

Weekly Report

A longer-running task that compiles a weekly summary:

tasks:
  weekly-report:
    schedule: "0 9 * * 1"           # Monday at 9 AM
    prompt_file: reports/weekly.md
    model: opus                      # use opus for deeper analysis
    max_turns: 30
    channels: [plugin:telegram@claude-plugins-official]
    enabled: true
<!-- reports/weekly.md -->
# Weekly Report

Compile a summary of the past week:

1. Key accomplishments and milestones
2. Open items and blockers
3. Upcoming deadlines this week
4. Recommendations or suggestions

Format for easy reading on mobile.

Custom Monitoring

A task that monitors something specific:

tasks:
  repo-monitor:
    schedule: "0 */4 * * *"         # every 4 hours
    prompt_file: reports/repo-monitor.md
    model: sonnet
    max_turns: 15
    enabled: true
    silent: true
<!-- reports/repo-monitor.md -->
# Repository Monitor

Check the following repositories for activity:

- github.com/myorg/main-app
- github.com/myorg/api-service

Look for:
- New PRs that need review
- Failed CI builds
- Security advisories
- Dependency updates

Only report if there's something actionable.

Task with Custom Workspace

A task that operates in a specific project directory:

tasks:
  project-check:
    schedule: "0 9 * * 1-5"
    workspace: ~/projects/my-app     # use this directory instead of default
    prompt_file: .leo/daily-check.md
    model: sonnet
    max_turns: 10
    enabled: true
    silent: true

Best Practices

  • Keep prompts focused — one clear objective per task
  • Use silent mode for frequent checks to avoid notification spam
  • Set appropriate max_turns — simple checks need fewer turns than complex analysis
  • Choose the right model — use sonnet for routine tasks, opus for tasks requiring deeper reasoning
  • Include output format guidance — tell the assistant how to format its final message for your channel
  • Test manually first — run leo run <task> before relying on the schedule

Creating a New Task

# 1. Write your prompt file
vim ~/.leo/workspace/reports/my-task.md

# 2. Add the task interactively
leo task add

# 3. Verify it's loaded
leo task list

Or edit leo.yaml directly and run leo service reload to pick up the changes in the running daemon.

See Also