┌─────────────────────────────────────────────────────────┐
│ SCHEDULE (cron / trigger) │
│ ┌─────────────────────────────────────────────────┐ │
│ │ READ STATE (~/.hermes/loops/state/<name>.json) │ │
│ │ ┌───────────────────────────────────────────┐ │ │
│ │ │ EARLY-EXIT CHECK │ │ │
│ │ │ ┌─────────────────────────────────────┐ │ │ │
│ │ │ │ MAKER SUB-AGENT │ │ │ │
│ │ │ │ (implement, build, scan, write) │ │ │ │
│ │ │ └─────────────────────────────────────┘ │ │ │
│ │ │ ┌─────────────────────────────────────┐ │ │ │
│ │ │ │ CHECKER SUB-AGENT │ │ │ │
│ │ │ │ (verify, score, find flaws) │ │ │ │
│ │ │ └─────────────────────────────────────┘ │ │ │
│ │ │ ┌─────────────────────────────────────┐ │ │ │
│ │ │ │ RESOLUTION │ │ │ │
│ │ │ │ Pass → complete/record │ │ │ │
│ │ │ │ Fail → iterate or escalate │ │ │ │
│ │ │ └─────────────────────────────────────┘ │ │ │
│ │ └───────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────┘ │
│ WRITE STATE │
└─────────────────────────────────────────────────────────┘
The single most important safety primitive. Never let the implementer validate its own work.
- Maker — a task-oriented sub-agent that does the work (scan, fix, write, build)
- Checker — a separate sub-agent (ideally a different model family) that reviews the maker's output
Configuration in state file:
{
"maker": {
"provider": "deepseek",
"model": "deepseek-chat"
},
"checker": {
"provider": "gemini",
"model": "gemini-3.5-flash",
"threshold": 7
}
}When the maker and checker use different model families, they have different blind spots. DeepSeek may miss UI issues that Gemini catches, and vice versa.
Every loop run costs tokens even when there's nothing to do. The early-exit guard detects this and bails in ~3,000 tokens instead of 80,000+.
Rules:
- Read
last_hashorlast_commitfrom state - Compare current state of target (git log, file timestamps, API response)
- If nothing changed since last run → write
last_checktimestamp, return "no-op" - Keep state compact (no accumulated noise)
State field:
{
"last_scan_hash": "abc123def456",
"last_scan_result": "no_changes"
}Never deploy a loop at full autonomy. Phase in:
| Level | What the Loop Does | Human Involvement |
|---|---|---|
| L1: Report-Only | Observes, analyses, writes report to state file | Human reads, decides |
| L2: Assisted Fixes | Proposes changes (drafts PRs, writes to branch) | Human reviews, approves |
| L3: Unattended | Fully autonomous within allowlisted boundaries | Exception-only |
Patterns specify a recommended start level.
For loops that modify files, use Git worktrees to prevent parallel agents from conflicting:
git worktree add ../fix-auth-env fix/auth-env
cd ../fix-auth-env
# ... agent makes changes ...
git add -A && git commit -m "fix: auth env timeout"
cd ../original-repo
git worktree remove ../fix-auth-envEvery loop stores its state at ~/.hermes/loops/state/<name>.json.
Required fields:
{
"name": "string",
"type": "deterministic|adversarial|self-critique|post-merge|dependency-sweep",
"iteration": 0,
"max_iterations": 10,
"status": "active|completed|max_iterations_reached|failed|paused",
"maker": { "provider": "...", "model": "..." },
"checker": { "provider": "...", "model": "...", "threshold": 7 }
}Pattern-specific fields are documented in each pattern's markdown file.
The repo is provider-agnostic. Set any model for any role:
{
"maker": { "provider": "openrouter", "model": "anthropic/claude-sonnet-4" },
"checker": { "provider": "deepseek", "model": "deepseek-chat" }
}For adversarial patterns, different provider families are recommended (different training data = different blind spots).
For self-critique patterns, a single provider is used with different system prompts per phase.
| Pitfall | Mitigation |
|---|---|
| No max_iterations | Default 5 in every state template |
| Same model for maker/checker | Enforce different providers in checker config |
| Loop runs on empty target | Early-exit guard per pattern |
| State file corruption | JSON schema validation on read; write atomically |
| Token burn on no-ops | Early-exit targets <5k no-op cost |
| Loop keeps trying on same failure | Escalate-to-human after 2 consecutive same-failure iterations |
| Worktree conflicts with parallel agents | Worktree isolation or serialise per-repo loops |