Cron Job Prompts That Stay Self-Contained: The Discipline
A Hermes cron runs in a fresh session with zero memory. Six elements make the prompt self-contained; three anti-patterns break it. Skip any and the job runs but does nothing.

The discipline in one sentence
A Hermes cron prompt runs in a fresh session that has no memory of past runs, no chat history, and no inline handoff from yesterday’s operator. The prompt body is the entire job; if the prompt does not say it, the agent does not know it. Six elements make the prompt self-contained, and three anti-patterns break it — skip any one of the six and the cron becomes a job that runs on time, exits zero, and produces nothing useful.
This guide is the discipline behind those six elements: why the fresh-session constraint is load-bearing, what each element answers, and the three patterns that look like prompts but are not.
The fresh-session constraint is load-bearing
Hermes cron jobs run on a schedule in their own session. That session has:
- No prior chat. No “the conversation we had Tuesday.” A URL, path, flag, or chat ID that exists only in the operator’s memory is invisible to the running prompt.
- No carried-over tool state. Only the tools attached at job creation load. “Last run the skill was loaded” is not a thing.
- No implicit context. The prompt is what the agent sees. If the prompt does not say it, the agent does not know it.
The mental model is a night-shift worker who arrives alone with a clipboard of today’s instructions. The clipboard is the prompt; the prompt is the entire job. Every URL, every path, every identifier, every escalation rule, every silent-exit clause must already be on the clipboard when the shift starts — because the worker has no other source of truth.
Two cheap signals that a prompt is leaking context out of session:
This is why “self-contained” is the operative word. A prompt that depends on context the operator carries in their head is not a cron prompt; it is a wish.
The six mandatory elements
Every cron prompt — agent-based or no_agent script-based — has six elements. They are short; the whole prompt body is usually under 300 words. The order matches how the agent plans, top-to-bottom.
| # | Element | What it answers |
|---|---|---|
| 1 | Goal | What is this job for, in one sentence? |
| 2 | Inputs | What URLs, scripts, paths, IDs, or commands does the agent touch? |
| 3 | Output shape | What does success look like in the response? |
| 4 | Decision boundaries | What choices is the agent allowed to make, and what must it escalate? |
| 5 | Failure behavior | What does the prompt do on error? |
| 6 | Stop conditions | When does the agent stop and exit cleanly? |
A prompt that has all six is self-contained. A prompt missing any of the bottom three is the bug class below. The first three describe what success looks like; the bottom three describe what not-success looks like, and what to do about it.
Element 1 — Goal. One sentence. The agent should be able to read this and know whether today’s run is normal. “Reboot cloudflared if its tunnel is down.” That’s the goal. “Check things” is not.
Element 2 — Inputs. The URLs, paths, identifiers, and commands the agent touches. Listed verbatim. “the script we discussed” is not an input; /usr/local/bin/cloudflared is. Every input is verified before it lands in the prompt — paste from a real ls or curl, not from memory.
Element 3 — Output shape. What success looks like in the response. “Report any anomalies” is not a shape; “one paragraph: status, action taken, final state” is. The shape is what the operator (or downstream code) parses; it has to be predictable.
Element 4 — Decision boundaries. What choices the agent is allowed to make on its own, and what must be escalated. “SIGTERM first; SIGKILL only if still alive after 5s; never delete logs” is a boundary. “Handle it however” is not.
Element 5 — Failure behavior. What the prompt does on error. The element most often left implicit, and the anti-pattern below is named after it. A failure behavior is “if probe returns non-200 three times, restart; if restart fails twice, page the operator.” Three concrete branches, not “if something is wrong, handle it.”
Element 6 — Stop conditions. When the agent exits cleanly and what it leaves behind. “After the action, log to /var/log/cron-name.log and exit” is a stop condition. “Then stop” is not — without an explicit artifact, the next operator can’t tell whether the job did anything.
The three anti-patterns
These three patterns are what a self-contained prompt is not. Each one looks like a cron prompt in isolation; each one breaks the next run because the next run starts in a fresh session with no memory of the run before.
Anti-pattern 1 — Referencing past runs
“Compare today’s count to yesterday’s count.” Yesterday’s count is not in the fresh session. The agent will either ask for it (and the job hangs on a clarifying question), or it will fabricate one. Both are silent failure shapes: the cron ran, exited cleanly, and produced nothing useful.
The fix is to make the past explicit. Either re-derive it inside the prompt (“yesterday_count=$(cat /opt/data/cron/output/<job_id>/latest.json | jq .count)” — and make sure that file actually exists), or drop the comparison. A cron prompt that depends on memory is not a cron prompt.
Anti-pattern 2 — Embedding today’s chat
“Use the chat ID we discussed earlier today.” The fresh session has no “earlier today.” Operators build prompts by pasting from a working session, and the working session carries context the cron session will not see. URLs from a browser tab, identifiers from a Slack thread, paths from a terminal scrollback — none of it crosses the boundary.
The fix is to treat the prompt as the only artifact. Every identifier must be in the prompt body, verified against the live system (curl, ls, jq) before the prompt is saved. If the identifier can only be found in chat history, the prompt is wrong.
Anti-pattern 3 — Leaving failure branches implicit
“If something is wrong, handle it.” This is the most common shape in prompts that look self-contained and aren’t. The goal is clear, the inputs are listed, the output shape is described — but the failure behavior is “handle it,” which the agent reads as a license to improvise. Improvisation in a fresh session is hallucination: the agent fills the failure branch with plausible-sounding steps that are grounded in nothing on disk.
The fix is to spell the failure tree out explicitly. Three concrete branches, in order: first retry, second retry, escalate. “If X fails, do Y; if Y fails, do Z; if Z fails, page the operator with this exact message.” The prompt owns the failure; the agent does not get to invent it.
The failure fingerprint
All three anti-patterns leave the same fingerprint on the cron store: last_status: ok, last_run_at: <recent>, and a near-empty output file. The job ran. The job exited zero. The job did nothing.
The cheap-first check is the same regardless of which anti-pattern fired: read the output file. If it is short (under 200 chars), contains a question, or contains no recognizable status, the prompt is asking the model for context it does not have. The fix is always in the prompt, never in the agent — the agent was not broken; the prompt was.
Verification checklist
# 1. Confirm the scheduler fired the job
python3 -c "import json; j=json.load(open('/opt/data/cron/jobs.json'))['jobs']; \
print([x['last_run_at'] for x in j if x['id'].startswith('<id>')])"
# 2. Read the most recent run's output
ls -t /opt/data/cron/output/<job_id>/ | head -1
cat /opt/data/cron/output/<job_id>/$(ls -t /opt/data/cron/output/<job_id>/ | head -1)
# 3. If output is short (<200 chars) or contains a question,
# the prompt is asking the model for context it does not have.
# Patch the prompt, not the agent.
# 4. Confirm the prompt body has all six elements (grep for the keywords)
grep -E "Goal:|Inputs:|Output|Shape|Boundar|Failure:|Stop:" <prompt-file>
A prompt that returns six matches on the grep above is structurally self-contained. A prompt that returns fewer is missing one of the bottom three — which is exactly where the silent failures live.
Sources
- Hermes Agent cron docs
- ABS companion: Hermes cron job management
- ABS companion: ABS regression failure modes and their cheap-first check
- ABS companion: Cron watchdogs versus cron monitors and when each fails
Last verified: 2026-07-15. Six elements and three anti-patterns checked against the canonical abs-cron-job-self-contained-prompts-the-rule post and the cloudflared watchdog (360e63a4ffc3) prompt on this VPS.



Submit a take
Have a different read on this? Drop a comment below — your email isn't published, and I read every one. Nothing leaves the site until I approve it.