/loop: Hermes' Recurring In-Session Wakeups — Timer-Driven, Not Judge-Driven, Not Cron

The deploy script finished, but you can’t walk away — will CI go red? Will the queue back up? When is the service actually live? So you refresh the page every five minutes like a dutiful sentry.
Hermes’ newest /loop command exists to take that sentry shift off your hands: re-run a prompt on a recurring cadence inside your session, waking up each tick to work against current state. It’s Hermes’ take on Claude Code’s /loop (the /proactive alias works here too), just merged into main. This post explains it properly: what fundamentally separates it from /goal and cron, and how to actually use it.
Three commands, three drivers
| Command | Driver | Lifecycle | Typical use |
|---|---|---|---|
/goal |
Judge-driven — after every turn a judge model checks “is it done yet?”, and Hermes keeps working if not | Single session, across turns | “Fix every lint error in src/ and verify the check passes” |
/loop |
Timer-driven — wake up on cadence, do the work, until something says stop | Single session, across turns and across resumes | “Check the deploy every 5 minutes and tell me when it’s live” |
| cron | Schedule-driven — fixed timetable, no session involved | Outside all sessions, unattended | “Post a daily digest to the channel at 9am” |
/goal means “keep working until the objective is achieved,” /loop means “keep checking until something says stop,” cron means “run on schedule, unrelated to conversation.” Three non-overlapping tools.
Two cadence modes: you set the clock, or it paces itself
Fixed interval — your clock
/loop 5m check the deploy status and tell me if it's live yet
Every 5 minutes (while the session is idle) Hermes injects a real agent turn against current state — the latest CI result, the newest queue depth, the file as it is now.
Self-paced — it gets smarter the longer it waits
Omit the interval and Hermes paces itself:
/loop keep an eye on the migration and summarize progress
The mechanism is clever: it starts at the 60s floor, and while the agent’s replies stop changing it backs off exponentially (2m → 4m → 8m … up to the 15-minute ceiling). The moment a reply differs, cadence snaps back to the floor. Change detection is a local, timestamp-insensitive digest comparison — zero extra LLM cost. The calmer things are, the less it bothers you; the moment there’s progress, it leans in.
Rule of thumb: fixed interval when an external clock drives the work; self-paced when the work drives the rhythm.
Stop conditions: five exits
| Condition | How |
|---|---|
| The agent decides it’s done | Wakeup replies ending with LOOP_COMPLETE on its own line |
| A run cap | --times N (e.g. --times 30) |
| An evidence-based condition | --until <condition> — judged by the same aux judge that powers /goal (fail-open: a broken judge never wedges the loop) |
| You | /loop stop (or /loop pause to keep it around) |
| The backstop budget | loops.max_ticks (default 100; 0 = unlimited) so an unattended session can’t burn tokens forever |
/loop 2m poll CI --times 30
/loop 5m watch the queue --until "queue depth reaches zero"
Control and composition
/loop statusshows cadence, ticks fired, and time to next wakeup;/loop pause/resume/stopcover the full lifecycle (Ctrl+C during a wakeup pauses the loop, recoverable via/loop resume).- Loop a slash command just as easily:
/loop 10m /recap. - Working with
/goal: an active, non-parked goal owns the idle boundary — loop ticks defer until the goal finishes, pauses, or parks (a wait barrier). A parked goal plus a loop heartbeat composes naturally. Real user input always preempts both — the moment you type, both get out of the way.
Why it doesn’t fall over: the architecture
This is the part worth really understanding — /loop is not a while true loop:
- Ordinary user-role turn injection: every wakeup is a normal user-role message. No system-prompt mutation, no toolset swap, prompt cache stays intact — looping doesn’t destroy your cache or waste tokens.
- Persisted state: loop state lives in
SessionDB.state_metaunderloop:<session_id>, so/resumebrings the loop back, and it migrates across context compression (same mechanism as/goal, with the known hazard fixed pre-emptively). - Every surface: CLI, TUI, dashboard, desktop app, and all gateway messaging platforms — a supervised
loop_wakeup_watcherscans persisted loops and injects due wakeups into idle chats even while you’re away. That’s something Claude Code can’t do (its loop dies with the CLI session). - The Slack aside: Slack has a 50-slash-command cap, so Hermes moved
/versionto/hermes versionto free a native slot for/loop.
Compared with Claude Code’s /loop
| Claude Code | Hermes | |
|---|---|---|
| Surfaces | CLI session only | CLI, TUI, dashboard, desktop, all messaging platforms |
| Persistence | Dies with the session | Survives /resume and context compression |
| Self-paced pacing | Model-decided | Local digest backoff (free, deterministic) |
| Stop conditions | Prompt-embedded | LOOP_COMPLETE + --times + judged --until + budget backstop |
| /goal interplay | Separate features | Explicit precedence: active goal owns the idle boundary |
Which one do I want?
- Watching external state (deploy, CI, queue, error rates) →
/loop(fixed or self-paced) - One objective done right (fix all lints, get CI green) →
/goal(see Heartbeats, Refinement & Goal Gates) - Unattended scheduled jobs (daily digests, overnight runs) → cron (full guide: The Hermes Cron Automation Guide)
Release status and how to get it
/loop was merged into main on August 14, 2026 (PR #72333, with 77 new tests + 367 regression tests + 22 desktop tests, all passing). It is not in any official release yet (latest is still v0.20.1). To try it:
- Wait for the next release and run
hermes update; - Or install from main now:
hermes update --branch main(switch back once the release ships).
Optional config keys: loops.min_interval_seconds, loops.max_ticks, loops.self_paced_floor_seconds, loops.self_paced_ceiling_seconds.
Wrap-up
/loop takes “watching” out of your manual-refresh hands: fixed intervals for external clocks, self-paced cadence that gets smarter the longer it waits (back off when stable, lean in when things change — at zero LLM cost), persistence and full-platform coverage that outdo the Claude Code original, and explicit cooperation with /goal. Next deploy, hand the sentry shift to it.