286 lines
8.4 KiB
Markdown
286 lines
8.4 KiB
Markdown
---
|
|
sidebar_position: 5
|
|
title: "Scheduled Tasks (Cron)"
|
|
description: "Schedule automated tasks with natural language, manage them with one cron tool, and attach one or more skills"
|
|
---
|
|
|
|
# Scheduled Tasks (Cron)
|
|
|
|
Schedule tasks to run automatically with natural language or cron expressions. Hermes exposes cron management through a single `cronjob` tool with action-style operations instead of separate schedule/list/remove tools.
|
|
|
|
## What cron can do now
|
|
|
|
Cron jobs can:
|
|
|
|
- schedule one-shot or recurring tasks
|
|
- pause, resume, edit, trigger, and remove jobs
|
|
- attach zero, one, or multiple skills to a job
|
|
- deliver results back to the origin chat, local files, or configured platform targets
|
|
- run in fresh agent sessions with the normal static tool list
|
|
|
|
:::warning
|
|
Cron-run sessions cannot recursively create more cron jobs. Hermes disables cron management tools inside cron executions to prevent runaway scheduling loops.
|
|
:::
|
|
|
|
## Creating scheduled tasks
|
|
|
|
### In chat with `/cron`
|
|
|
|
```bash
|
|
/cron add 30m "Remind me to check the build"
|
|
/cron add "every 2h" "Check server status"
|
|
/cron add "every 1h" "Summarize new feed items" --skill blogwatcher
|
|
/cron add "every 1h" "Use both skills and combine the result" --skill blogwatcher --skill find-nearby
|
|
```
|
|
|
|
### From the standalone CLI
|
|
|
|
```bash
|
|
hermes cron create "every 2h" "Check server status"
|
|
hermes cron create "every 1h" "Summarize new feed items" --skill blogwatcher
|
|
hermes cron create "every 1h" "Use both skills and combine the result" \
|
|
--skill blogwatcher \
|
|
--skill find-nearby \
|
|
--name "Skill combo"
|
|
```
|
|
|
|
### Through natural conversation
|
|
|
|
Ask Hermes normally:
|
|
|
|
```text
|
|
Every morning at 9am, check Hacker News for AI news and send me a summary on Telegram.
|
|
```
|
|
|
|
Hermes will use the unified `cronjob` tool internally.
|
|
|
|
## Skill-backed cron jobs
|
|
|
|
A cron job can load one or more skills before it runs the prompt.
|
|
|
|
### Single skill
|
|
|
|
```python
|
|
cronjob(
|
|
action="create",
|
|
skill="blogwatcher",
|
|
prompt="Check the configured feeds and summarize anything new.",
|
|
schedule="0 9 * * *",
|
|
name="Morning feeds",
|
|
)
|
|
```
|
|
|
|
### Multiple skills
|
|
|
|
Skills are loaded in order. The prompt becomes the task instruction layered on top of those skills.
|
|
|
|
```python
|
|
cronjob(
|
|
action="create",
|
|
skills=["blogwatcher", "find-nearby"],
|
|
prompt="Look for new local events and interesting nearby places, then combine them into one short brief.",
|
|
schedule="every 6h",
|
|
name="Local brief",
|
|
)
|
|
```
|
|
|
|
This is useful when you want a scheduled agent to inherit reusable workflows without stuffing the full skill text into the cron prompt itself.
|
|
|
|
## Editing jobs
|
|
|
|
You do not need to delete and recreate jobs just to change them.
|
|
|
|
### Chat
|
|
|
|
```bash
|
|
/cron edit <job_id> --schedule "every 4h"
|
|
/cron edit <job_id> --prompt "Use the revised task"
|
|
/cron edit <job_id> --skill blogwatcher --skill find-nearby
|
|
/cron edit <job_id> --remove-skill blogwatcher
|
|
/cron edit <job_id> --clear-skills
|
|
```
|
|
|
|
### Standalone CLI
|
|
|
|
```bash
|
|
hermes cron edit <job_id> --schedule "every 4h"
|
|
hermes cron edit <job_id> --prompt "Use the revised task"
|
|
hermes cron edit <job_id> --skill blogwatcher --skill find-nearby
|
|
hermes cron edit <job_id> --add-skill find-nearby
|
|
hermes cron edit <job_id> --remove-skill blogwatcher
|
|
hermes cron edit <job_id> --clear-skills
|
|
```
|
|
|
|
Notes:
|
|
|
|
- repeated `--skill` replaces the job's attached skill list
|
|
- `--add-skill` appends to the existing list without replacing it
|
|
- `--remove-skill` removes specific attached skills
|
|
- `--clear-skills` removes all attached skills
|
|
|
|
## Lifecycle actions
|
|
|
|
Cron jobs now have a fuller lifecycle than just create/remove.
|
|
|
|
### Chat
|
|
|
|
```bash
|
|
/cron list
|
|
/cron pause <job_id>
|
|
/cron resume <job_id>
|
|
/cron run <job_id>
|
|
/cron remove <job_id>
|
|
```
|
|
|
|
### Standalone CLI
|
|
|
|
```bash
|
|
hermes cron list
|
|
hermes cron pause <job_id>
|
|
hermes cron resume <job_id>
|
|
hermes cron run <job_id>
|
|
hermes cron remove <job_id>
|
|
hermes cron status
|
|
hermes cron tick
|
|
```
|
|
|
|
What they do:
|
|
|
|
- `pause` — keep the job but stop scheduling it
|
|
- `resume` — re-enable the job and compute the next future run
|
|
- `run` — trigger the job on the next scheduler tick
|
|
- `remove` — delete it entirely
|
|
|
|
## How it works
|
|
|
|
**Cron execution is handled by the gateway daemon.** The gateway ticks the scheduler every 60 seconds, running any due jobs in isolated agent sessions.
|
|
|
|
```bash
|
|
hermes gateway install # Install as a user service
|
|
sudo hermes gateway install --system # Linux: boot-time system service for servers
|
|
hermes gateway # Or run in foreground
|
|
|
|
hermes cron list
|
|
hermes cron status
|
|
```
|
|
|
|
### Gateway scheduler behavior
|
|
|
|
On each tick Hermes:
|
|
|
|
1. loads jobs from `~/.hermes/cron/jobs.json`
|
|
2. checks `next_run_at` against the current time
|
|
3. starts a fresh `AIAgent` session for each due job
|
|
4. optionally injects one or more attached skills into that fresh session
|
|
5. runs the prompt to completion
|
|
6. delivers the final response
|
|
7. updates run metadata and the next scheduled time
|
|
|
|
A file lock at `~/.hermes/cron/.tick.lock` prevents overlapping scheduler ticks from double-running the same job batch.
|
|
|
|
## Delivery options
|
|
|
|
When scheduling jobs, you specify where the output goes:
|
|
|
|
| Option | Description | Example |
|
|
|--------|-------------|---------|
|
|
| `"origin"` | Back to where the job was created | Default on messaging platforms |
|
|
| `"local"` | Save to local files only (`~/.hermes/cron/output/`) | Default on CLI |
|
|
| `"telegram"` | Telegram home channel | Uses `TELEGRAM_HOME_CHANNEL` |
|
|
| `"discord"` | Discord home channel | Uses `DISCORD_HOME_CHANNEL` |
|
|
| `"telegram:123456"` | Specific Telegram chat by ID | Direct delivery |
|
|
| `"discord:987654"` | Specific Discord channel by ID | Direct delivery |
|
|
|
|
The agent's final response is automatically delivered. You do not need to call `send_message` in the cron prompt.
|
|
|
|
## Schedule formats
|
|
|
|
The agent's final response is automatically delivered — you do **not** need to include `send_message` in the cron prompt for that same destination. If a cron run calls `send_message` to the exact target the scheduler will already deliver to, Hermes skips that duplicate send and tells the model to put the user-facing content in the final response instead. Use `send_message` only for additional or different targets.
|
|
|
|
### Relative delays (one-shot)
|
|
|
|
```text
|
|
30m → Run once in 30 minutes
|
|
2h → Run once in 2 hours
|
|
1d → Run once in 1 day
|
|
```
|
|
|
|
### Intervals (recurring)
|
|
|
|
```text
|
|
every 30m → Every 30 minutes
|
|
every 2h → Every 2 hours
|
|
every 1d → Every day
|
|
```
|
|
|
|
### Cron expressions
|
|
|
|
```text
|
|
0 9 * * * → Daily at 9:00 AM
|
|
0 9 * * 1-5 → Weekdays at 9:00 AM
|
|
0 */6 * * * → Every 6 hours
|
|
30 8 1 * * → First of every month at 8:30 AM
|
|
0 0 * * 0 → Every Sunday at midnight
|
|
```
|
|
|
|
### ISO timestamps
|
|
|
|
```text
|
|
2026-03-15T09:00:00 → One-time at March 15, 2026 9:00 AM
|
|
```
|
|
|
|
## Repeat behavior
|
|
|
|
| Schedule type | Default repeat | Behavior |
|
|
|--------------|----------------|----------|
|
|
| One-shot (`30m`, timestamp) | 1 | Runs once |
|
|
| Interval (`every 2h`) | forever | Runs until removed |
|
|
| Cron expression | forever | Runs until removed |
|
|
|
|
You can override it:
|
|
|
|
```python
|
|
cronjob(
|
|
action="create",
|
|
prompt="...",
|
|
schedule="every 2h",
|
|
repeat=5,
|
|
)
|
|
```
|
|
|
|
## Managing jobs programmatically
|
|
|
|
The agent-facing API is one tool:
|
|
|
|
```python
|
|
cronjob(action="create", ...)
|
|
cronjob(action="list")
|
|
cronjob(action="update", job_id="...")
|
|
cronjob(action="pause", job_id="...")
|
|
cronjob(action="resume", job_id="...")
|
|
cronjob(action="run", job_id="...")
|
|
cronjob(action="remove", job_id="...")
|
|
```
|
|
|
|
For `update`, pass `skills=[]` to remove all attached skills.
|
|
|
|
## Job storage
|
|
|
|
Jobs are stored in `~/.hermes/cron/jobs.json`. Output from job runs is saved to `~/.hermes/cron/output/{job_id}/{timestamp}.md`.
|
|
|
|
The storage uses atomic file writes so interrupted writes do not leave a partially written job file behind.
|
|
|
|
## Self-contained prompts still matter
|
|
|
|
:::warning Important
|
|
Cron jobs run in a completely fresh agent session. The prompt must contain everything the agent needs that is not already provided by attached skills.
|
|
:::
|
|
|
|
**BAD:** `"Check on that server issue"`
|
|
|
|
**GOOD:** `"SSH into server 192.168.1.100 as user 'deploy', check if nginx is running with 'systemctl status nginx', and verify https://example.com returns HTTP 200."`
|
|
|
|
## Security
|
|
|
|
Scheduled task prompts are scanned for prompt-injection and credential-exfiltration patterns at creation and update time. Prompts containing invisible Unicode tricks, SSH backdoor attempts, or obvious secret-exfiltration payloads are blocked.
|