---
name: cronjob
description: Create, manage, update, run, and troubleshoot Hermes Agent cronjobs — scheduling, scripts, prompts, delivery, and state management.
version: 1.0.0
tags: [Cronjob, Automation, Scheduling]
---

# Cronjob System

## Core Concepts

Cronjobs can be of two types:
1. **Agent jobs** — run via an agent with a prompt, model, and skills (use a `skill` or `skills` parameter)
2. **Direct script jobs** (`no_agent: true`) — execute a shell/Python script directly

## Script Jobs: THE CRITICAL PATH RULE

**`script` parameter expects a FILENAME (relative to `~/.hermes/scripts/`), NOT raw shell content.**

This is the most common cronjob error. The system treats the `script` value as a path to a file under `~/.hermes/scripts/`.

```
❌ WRONG: script: "cd ~/.hermes/memory\nCHANGES=$(git diff..."  (raw multi-line content)
✅ RIGHT:  script: "memory-sync.sh"  (filename only)
```

**Always create the script file first, then reference it:**
```bash
# 1. Write the script
write_file path=~/.hermes/scripts/my-script.sh content='...'

# 2. Create the cronjob referencing the filename
cronjob action=create script=my-script.sh ...
```

## Creating Cronjobs

```bash
# Agent job (runs via an AI agent with a prompt)
cronjob action=create \
  name="My Job" \
  prompt="You are a helper. Do X." \
  schedule="0 9 * * *" \
  repeat="forever" \
  deliver="origin" \
  model="custom/llama/model.gguf" \
  skills="my-skill"

# Script job (runs a shell/Python script directly, no agent)
cronjob action=create \
  name="My Script Job" \
  script="my-script.sh" \
  schedule="0 22 * * *" \
  repeat="forever" \
  deliver="origin" \
  no_agent=true
```

## Parameters

| Parameter | Description | Required |
|-----------|-------------|----------|
| `name` | Human-readable job name | Yes |
| `prompt` | Instruction for agent (agent jobs) | Yes, unless `no_agent` |
| `script` | Filename in `~/.hermes/scripts/` (script jobs) | Yes, if `no_agent` |
| `schedule` | Cron expression (e.g. `"0 9 * * *"`) | Yes |
| `repeat` | `"forever"`, `"13/500"`, `"1/10"` | No (default: 1) |
| `deliver` | `"origin"` or `telegram:<chat_id>` | No (default: origin) |
| `model` | Model ID for agent jobs | No |
| `provider` | Provider name | No |
| `base_url` | API base URL | No |
| `skills` | Space-separated skill names for agent | No |
| `no_agent` | `true` for direct script execution | No |

## Managing Cronjobs

```bash
# List all jobs
cronjob action=list

# Update a job (change any parameter)
cronjob action=update job_id=<ID> schedule="0 6 * * *"

# Pause a job (keep it but stop scheduling)
cronjob action=update job_id=<ID> schedule=never

# Resume a paused job
cronjob action=update job_id=<ID> schedule="0 6 * * *"

# Run a job immediately (one-shot)
cronjob action=run job_id=<ID>

# Delete a job
cronjob action=remove job_id=<ID>
```

## Delivery Destinations

- `origin` — delivers results to the current conversation thread
- `telegram:<chat_id>` — delivers results directly to a Telegram chat (e.g., agent chat)

## Prompt Design for Agent Jobs

The prompt must be **fully self-contained** — it runs without user context:

```
Du bist ein [role]. Deine Aufgabe: [specific task].

Schritt 1: [action]
Schritt 2: [action]
Schritt 3: [action]

⚠️ Wichtige Hinweise: [caveats, constraints, common errors]
```

## Best Practices

1. **Start daily** for testing before switching to longer intervals
2. **Use `repeat` wisely** — `"forever"` for permanent jobs, `"N/M"` for limited runs (N=attempts, M=max runs)
3. **Include error handling** in scripts — always check return codes
4. **Log results** — output a summary so you can verify operations
5. **Keep prompts self-contained** — no references to previous conversation context
6. **Use `deliver="origin"`** for your own notifications, `telegram:<id>` for agent delegation

## Common Pitfalls

| Pitfall | Symptom | Solution |
|---------|---------|----------|
| Raw shell in `script` | "Script not found: cd ~/.hermes/..." | Write script file first, reference filename only |
| Forget `no_agent=true` | Agent tries to run script as a prompt | Set `no_agent: true` for direct script execution |
| Missing script file | "Script not found: my-script.sh" | Ensure file exists at `~/.hermes/scripts/my-script.sh` |
| Script not executable | Permission denied | `chmod +x ~/.hermes/scripts/my-script.sh` |
| Cronjob runs too often | Rate limits, performance issues | Use `every 15m` minimum, or daily schedule |
| Wrong deliver target | Results go to wrong chat | `origin` = this chat, `telegram:<id>` = target chat |
| Script path is absolute | Works in test, fails in cron | Use relative filename, not absolute path |
| JSON parsing fails in prompt | Non-JSON noise from tools | Use regex fallback (e.g., `[`...`]` pattern) |
| No LLM provider configured | RuntimeError: No LLM provider configured | Set model/provider via `hermes model` or `hermes config set model.provider <provider>`; then update job with `cronjob action=update job_id=<ID> model=<model> provider=<provider>` |
| **Deleting while awaiting confirmation** | User said "delete X", you asked "also delete Y?", then deleted Y BEFORE user answered | ALWAYS wait for explicit user confirmation before executing any destructive action (delete, remove, stop). Never fire off a destructive tool call while a confirmation question is pending. |
| Script outputs nothing in Telegram | Cronjob runs but message is empty | Script MUST print to stdout — anything printed becomes the delivered message body. Log messages to stderr; user-facing output to stdout. |
| **Response truncated due to output length limit** | Agent cronjob fails with `RuntimeError: Response truncated due to output length limit` | Agent cronjobs have a hard output size limit. ALWAYS constrain the agent's output in the prompt: "max 20 lines", "compact summary only", "no explanations". For structured data, output a brief table or key-value list rather than full prose or markdown documents. |
| **Telegram group sub-names as delivery targets** | `telegram:Essensplaner` not found even though the group exists | Telegram `deliver` targets must match the actual chat/group identifier known to the system (`telegram:Schoen Inc`), NOT internal nicknames or role names used within that group. Verify available targets with `send_message(action='list')` or `cronjob action=list` and inspect `deliver` fields of existing jobs. |

## Script Job: Full Example

```bash
# 1. Write the script file
write_file path=~/.hermes/scripts/memory-sync.sh content='#!/bin/bash
cd ~/.hermes/memory
CHANGES=$(git diff --quiet HEAD 2>/dev/null; echo $?)
if [ "$CHANGES" = "0" ]; then
  exit 0
fi
git add .
git commit -m "Auto-sync: $(date +%Y-%m-%d)" --allow-empty 2>/dev/null
RESULT=$(git push origin main 2>&1)
if [ $? -eq 0 ]; then
  echo "✅ Memory synced successfully"
else
  echo "⚠️ Git push failed: $RESULT"
fi
'
```

| Pitfall | Symptom | Solution |
|---------|---------|----------|
| Raw shell in `script` | "Script not found: cd ~/.hermes/..." | Write script file first, reference filename only |
| Forget `no_agent=true` | Agent tries to run script as a prompt | Set `no_agent: true` for direct script execution |
| Missing script file | "Script not found: my-script.sh" | Ensure file exists at `~/.hermes/scripts/my-script.sh` |
| Script not executable | Permission denied | `chmod +x ~/.hermes/scripts/my-script.sh` |
| Cronjob runs too often | Rate limits, performance issues | Use `every 15m` minimum, or daily schedule |
| Wrong deliver target | Results go to wrong chat | `origin` = this chat, `telegram:<id>` = target chat |
| Script path is absolute | Works in test, fails in cron | Use relative filename, not absolute path |
| JSON parsing fails in prompt | Non-JSON noise from tools | Use regex fallback (e.g., `[`...`]` pattern) |
| **Custom provider/model mismatch** | `RuntimeError: No Anthropic credentials found` or provider-specific auth errors | When updating an agent job with a custom provider, ALWAYS set BOTH `model` AND `provider` explicitly. The provider string determines which API credentials are loaded. A model string alone does NOT select the provider. Example: `model="moonshotai/kimi-k2.6" provider="noris"` together. |

## Script Job: Full Example

```bash
# 1. Write the script file
write_file path=~/.hermes/scripts/memory-sync.sh content='#!/bin/bash
cd ~/.hermes/memory
CHANGES=$(git diff --quiet HEAD 2>/dev/null; echo $?)
if [ "$CHANGES" = "0" ]; then
  exit 0
fi
git add .
git commit -m "Auto-sync: $(date +%Y-%m-%d)" --allow-empty 2>/dev/null
RESULT=$(git push origin main 2>&1)
if [ $? -eq 0 ]; then
  echo "✅ Memory synced successfully"
else
  echo "⚠️ Git push failed: $RESULT"
fi
'

# 2. Make executable
terminal command='chmod +x ~/.hermes/scripts/memory-sync.sh'

# 3. Create the cronjob
cronjob action=create name=memory-sync-daily script=memory-sync.sh schedule="0 22 * * *" repeat=forever deliver=origin no_agent=true

# 4. Verify
cronjob action=list | grep memory-sync
```

## Skill Update History
- **2026-05-09**: Created as class-level skill. Documents the critical `script` parameter filename-only requirement, script creation workflow, and comprehensive pitfall table. Migrated and improved knowledge from container-network-recon skill.
- **2026-06-17**: Added `No LLM provider configured` pitfall and reference `session_20260617_rechnungen_organizer.md`. Lesson: always verify cronjob model/provider alignment with global config.
- **2026-06-18**: Added `Custom provider/model mismatch` pitfall and reference `session_20260618_scraper_deploy.md`. Lesson: model + provider MUST be set as a PAIR on agent jobs; for scrapers, use `no_agent` + nohup wrapper + watchdog cronjob instead of LLM-based orchestration.
