docker compose exec gerhard hermes cron list --all
docker compose exec gerhard hermes cron create "every 1d""Your self-contained prompt here" --name "Daily reflection" --deliver local
```
## Schedule formats
Hermes accepts:
-`30m` — one-shot in 30 minutes
-`2h` — one-shot in 2 hours
-`every 30m` — recurring interval
-`every 2h` — recurring interval
-`0 9 * * *` — cron expression
-`2026-02-03T14:00:00` — one-shot timestamp
## Desired job format
Add entries to `desired-jobs.json` like this:
```json
{
"version":1,
"jobs":[
{
"name":"Daily conceptual hygiene",
"schedule":"0 8 * * *",
"deliver":"local",
"prompt":"Review Glitch University knowledge graph notes. Identify one concept that is vague, one relation that needs evidence, and one useful next action. Write concise output in Gerhard voice.",
"skills":[],
"enabled_toolsets":["file","terminal"],
"workdir":"/workspace"
}
]
}
```
Important:
- Prompts must be self-contained. Cron jobs run without chat context.
- Avoid secrets in prompts.
- Use `deliver: local` unless the target platform/channel is intentionally configured.
- Use absolute `workdir` values. In Gerhard's container, the mounted workspace is `/workspace`.
- Keep runtime outputs under `cron/output/`, not in Git.
## Gerhard gutask identity
The hourly orientation job expects the Gerhard container to have gutask credentials in its environment:
-`API_URL`
-`CONTENT_API_KEY`
-`AGENT_ID`
-`AGENT_NAME`
-`AGENT_PASSWORD`
The Gerhard compose service uses `env_file: .env`, so these values come from the host-local `.env` on Omega13. Do not put the password, content API key, or tokens in Git.
The Gerhard compose service also mounts the sibling checkout read-write so Gerhard can improve the tool and push changes when asked:
Gerhard has a wrapper at `/opt/data/bin/gutask` that runs `/opt/gutasktool/gutasktool/cli.py`. Cron prompts should call the absolute wrapper path, for example:
```bash
/opt/data/bin/gutask orient --agent "$AGENT_ID"
```
When modifying gutasktool, Gerhard should work in `/opt/gutasktool`, commit normally, and push to the configured Gitea `origin` remote. Secrets stay in environment/SSH config, never in Git.
## Future improvement
Add a small bootstrap/sync script that reads `desired-jobs.json` and reconciles it into `jobs.json` by stable job name.
That lets Omega13 do:
```bash
git pull
docker compose up -d gerhard gerhard-dashboard
# optional: docker compose exec gerhard python /opt/data/cron/sync_desired_jobs.py
```
For now, `desired-jobs.json` is the version-controlled schedule manifest.