From 33de65917b2677a9eb9f43b8cd892ff9927ffd92 Mon Sep 17 00:00:00 2001 From: Lorenzo Bosio <121148589+lorenzobosio@users.noreply.github.com> Date: Fri, 10 Jul 2026 15:13:39 +0200 Subject: [PATCH] docs(examples): add Hermes PR Babysitter example Mirrors the structure of examples/cursor/pr-babysitter.md for Hermes: week-one report-only cron job with --deliver local, pr-review-triage skill install from the starter, loop-worktree + verifier progression for week two, and filled Hermes cells in the examples tables. Closes #225 Co-Authored-By: Claude Fable 5 --- examples/README.md | 4 +- examples/hermes/README.md | 1 + examples/hermes/pr-babysitter.md | 112 +++++++++++++++++++++++++++++++ 3 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 examples/hermes/pr-babysitter.md diff --git a/examples/README.md b/examples/README.md index 42994b9..b00c48f 100644 --- a/examples/README.md +++ b/examples/README.md @@ -24,7 +24,7 @@ Start with [primitives-matrix.md](../docs/primitives-matrix.md) to map capabilit | Pattern | Grok | Claude | Codex | OpenClaw | Cursor | Windsurf | Opencode | Hermes | GH Actions | |---------|------|--------|-------|----------|--------|----------|----------|--------|------------| | Daily Triage | [grok/daily-triage.md](./grok/daily-triage.md) | [claude-code/daily-triage.md](./claude-code/daily-triage.md) | [codex/daily-triage.md](./codex/daily-triage.md) | [openclaw/daily-triage.md](./openclaw/daily-triage.md) | [cursor/daily-triage.md](./cursor/daily-triage.md) | [windsurf/daily-triage.md](./windsurf/daily-triage.md) | [opencode/daily-triage.md](./opencode/daily-triage.md) | [hermes/daily-triage.md](./hermes/daily-triage.md) | [github-actions/daily-triage.yml](./github-actions/daily-triage.yml) | -| PR Babysitter | [grok/pr-babysitter.md](./grok/pr-babysitter.md) | [claude-code/pr-babysitter.md](./claude-code/pr-babysitter.md) | [codex/pr-babysitter.md](./codex/pr-babysitter.md) | [openclaw/pr-babysitter.md](./openclaw/pr-babysitter.md) | [cursor/pr-babysitter.md](./cursor/pr-babysitter.md) | [windsurf/pr-babysitter.md](./windsurf/pr-babysitter.md) | [opencode/pr-babysitter.md](./opencode/pr-babysitter.md) | — | [github-actions/pr-babysitter.yml](./github-actions/pr-babysitter.yml) | +| PR Babysitter | [grok/pr-babysitter.md](./grok/pr-babysitter.md) | [claude-code/pr-babysitter.md](./claude-code/pr-babysitter.md) | [codex/pr-babysitter.md](./codex/pr-babysitter.md) | [openclaw/pr-babysitter.md](./openclaw/pr-babysitter.md) | [cursor/pr-babysitter.md](./cursor/pr-babysitter.md) | [windsurf/pr-babysitter.md](./windsurf/pr-babysitter.md) | [opencode/pr-babysitter.md](./opencode/pr-babysitter.md) | [hermes/pr-babysitter.md](./hermes/pr-babysitter.md) | [github-actions/pr-babysitter.yml](./github-actions/pr-babysitter.yml) | | CI Sweeper | [grok/ci-sweeper.md](./grok/ci-sweeper.md) | [claude-code/ci-sweeper.md](./claude-code/ci-sweeper.md) | [codex/ci-sweeper.md](./codex/ci-sweeper.md) | [openclaw/ci-sweeper.md](./openclaw/ci-sweeper.md) | — | — | [opencode/ci-sweeper.md](./opencode/ci-sweeper.md) | — | [github-actions/ci-sweeper.yml](./github-actions/ci-sweeper.yml) | | Post-Merge Cleanup | [grok/post-merge-cleanup.md](./grok/post-merge-cleanup.md) | [claude-code/post-merge-cleanup.md](./claude-code/post-merge-cleanup.md) | [codex/post-merge-cleanup.md](./codex/post-merge-cleanup.md) | [openclaw/post-merge-cleanup.md](./openclaw/post-merge-cleanup.md) | — | — | [opencode/post-merge-cleanup.md](./opencode/post-merge-cleanup.md) | — | [github-actions/post-merge-cleanup.yml](./github-actions/post-merge-cleanup.yml) | | Dependency Sweeper | [grok/dependency-sweeper.md](./grok/dependency-sweeper.md) | [claude-code/dependency-sweeper.md](./claude-code/dependency-sweeper.md) | [codex/dependency-sweeper.md](./codex/dependency-sweeper.md) | [openclaw/dependency-sweeper.md](./openclaw/dependency-sweeper.md) | — | — | [opencode/dependency-sweeper.md](./opencode/dependency-sweeper.md) | — | [github-actions/dependency-sweeper.yml](./github-actions/dependency-sweeper.yml) | @@ -41,5 +41,5 @@ L2 patterns ship multi-tool skills inside one starter folder — see `starters/< | Claude Code | [minimal-loop-claude](../starters/minimal-loop-claude/) | via `loop-init --tool claude` | via `loop-init --tool claude` | via `loop-init --tool claude` | via `loop-init --tool claude` | via `loop-init --tool claude` | via `loop-init --tool claude` | | Codex | [minimal-loop-codex](../starters/minimal-loop-codex/) | via `loop-init --tool codex` | via `loop-init --tool codex` | via `loop-init --tool codex` | via `loop-init --tool codex` | via `loop-init --tool codex` | via `loop-init --tool codex` | | OpenClaw | [openclaw/daily-triage.md](./openclaw/daily-triage.md) (manual) | [openclaw/pr-babysitter.md](./openclaw/pr-babysitter.md) | [openclaw/ci-sweeper.md](./openclaw/ci-sweeper.md) | [openclaw/dependency-sweeper.md](./openclaw/dependency-sweeper.md) | [openclaw/post-merge-cleanup.md](./openclaw/post-merge-cleanup.md) | [openclaw/changelog-drafter.md](./openclaw/changelog-drafter.md) | [openclaw/issue-triage.md](./openclaw/issue-triage.md) | -| Hermes | [hermes/daily-triage.md](./hermes/daily-triage.md) (manual) | — | — | — | — | — | — | +| Hermes | [hermes/daily-triage.md](./hermes/daily-triage.md) (manual) | [hermes/pr-babysitter.md](./hermes/pr-babysitter.md) (manual) | — | — | — | — | — | | Opencode | [minimal-loop-opencode](../starters/minimal-loop-opencode/) | [pr-babysitter-opencode](../starters/pr-babysitter-opencode/) | [ci-sweeper-opencode](../starters/ci-sweeper-opencode/) | [dependency-sweeper-opencode](../starters/dependency-sweeper-opencode/) | [post-merge-cleanup-opencode](../starters/post-merge-cleanup-opencode/) | [changelog-drafter-opencode](../starters/changelog-drafter-opencode/) | [issue-triage-opencode](../starters/issue-triage-opencode/) | diff --git a/examples/hermes/README.md b/examples/hermes/README.md index dd55947..7e31bdc 100644 --- a/examples/hermes/README.md +++ b/examples/hermes/README.md @@ -5,6 +5,7 @@ | Example | Pattern | |---------|---------| | [daily-triage.md](./daily-triage.md) | Daily Triage (L1 report → L2 assisted) | +| [pr-babysitter.md](./pr-babysitter.md) | PR Babysitter (L1 report → L2 worktree + verifier) | Optional **channel delivery** (Telegram, Slack, Discord, WhatsApp, SMS, Feishu) is Hermes's differentiator — the same cron job can post its summary into any connected home channel. diff --git a/examples/hermes/pr-babysitter.md b/examples/hermes/pr-babysitter.md new file mode 100644 index 0000000..ea6d0b0 --- /dev/null +++ b/examples/hermes/pr-babysitter.md @@ -0,0 +1,112 @@ +# PR Babysitter — Hermes Agent (`hermes cron`) + +This is a practical, copy-pasteable example of a PR babysitter loop using Hermes. + +Hermes ships a native scheduler on its **gateway** — map the loop to `hermes cron` +instead of a TUI `/loop`. Optional **channel delivery** (Feishu, Slack, Telegram, +Discord, WhatsApp, SMS) can ping blockers into the channel the team already watches +once you trust the output; week one stays on `--deliver local`. + +## Cron job (week one — report only) + +Isolated session each tick: reads GitHub state, updates `pr-babysitter-state.md`, +no code edits, **no merges**. + +```bash +hermes cron create "*/15 * * * *" \ + --name "PR babysitter" \ + --deliver local \ + --skill pr-review-triage \ + --workdir "$PWD" \ + "Run the pr-review-triage skill on all open PRs. Read pr-babysitter-state.md first, then update it with current CI status, review state, merge conflicts, and unanswered comments. Do not merge or push fixes in week one — report only. Flag anything ambiguous or high-risk for human review in pr-babysitter-state.md. End with the top 3 human actions." +``` + +- `--deliver local` writes output to `~/.hermes/cron/output/` only — nothing lands + in the human's chat history until you trust the output. Swap for `--deliver origin` + (current chat), a home channel name (e.g. `slack`, `feishu`), or + `platform:chat_id:thread_id` for a specific thread. +- `--workdir "$PWD"` injects `AGENTS.md` / `CLAUDE.md` / `.cursorrules` from the + project into the system prompt and pins the terminal cwd to the repo. +- Repeat `--skill` to attach multiple skills (e.g. `--skill pr-review-triage + --skill github-workflow` if PR reads go through a GitHub skill instead of `gh`). +- Operations: `hermes cron run ` for a one-off test tick, then + `pause` / `resume` / `edit` / `remove` as needed. + +## Progression + +- **Week one — report only.** Fresh isolated session each tick appends to + `pr-babysitter-state.md`. Read it yourself before acting on any suggestion. + Human gates all merges. +- **Week two — minimal fixes in worktrees.** Extend the prompt to propose fixes + in an isolated worktree for allowlisted low-risk PRs only — one worktree per + fix attempt via [`loop-worktree`](../../docs/QUICKSTART.md#l2-isolated-fix-attempts-loop-worktree) + so retries never collide on the same branch. Draft PRs only; never force-push. +- **Week two — verifier split.** A separate verifier approves before any fix is + committed: a second `delegate_task` call with a review-only prompt, or a chained + cron job via `hermes cron edit --context-from ` (the + upstream job's stdout is injected into the downstream prompt). Never let the + implementer mark its own work done. Escalate after 3 attempts per PR. +- **Add channel delivery.** Swap `--deliver local` for a home channel once the + output has earned trust; set channel `allowFrom` / mention rules first. + +Week-two worktree lifecycle (see the +[loop-worktree subsection of the QUICKSTART](../../docs/QUICKSTART.md#l2-isolated-fix-attempts-loop-worktree)): + +```bash +npx @cobusgreyling/loop-worktree create --run-id pr-217-fix-1 --pattern pr-babysitter +# fix + verifier run inside the printed worktree path +npx @cobusgreyling/loop-worktree mark --run-id pr-217-fix-1 --status rejected # verifier said no +npx @cobusgreyling/loop-worktree cleanup --older-than 24h +``` + +## Requirements + +- [Hermes Agent](https://hermes-agent.nousresearch.com/docs) installed and + configured (`hermes setup`) +- `pr-babysitter-state.md` in the repo root (from `starters/pr-babysitter/`) +- The `pr-review-triage` skill in `~/.hermes/skills/pr-review-triage/SKILL.md` + (user-scoped) or `.hermes/skills/` (project-scoped) — the `SKILL.md` format is + shared across tools, so the starter copy works unchanged + +```bash +cp starters/pr-babysitter/pr-babysitter-state.md.example pr-babysitter-state.md + +mkdir -p ~/.hermes/skills/pr-review-triage +cp starters/pr-babysitter/.claude/skills/pr-review-triage/SKILL.md ~/.hermes/skills/pr-review-triage/SKILL.md + +hermes skills list | grep pr-review-triage +``` + +## Example pr-babysitter-state.md + +```markdown +# PR Babysitter State +Last run: 2026-07-05 09:00 UTC + +## Open PRs + +### #1234 — fix: correct login redirect +- CI: green +- Reviews: 1 approval, 1 blocking comment +- Loop action: report only (week one). Needs human triage. +- Attempts: 1 / 3 +``` + +## Notes + +- Never force-push; draft PRs by default; do not resolve review threads without + approval. Security, auth, payments, infra, or public API changes always + escalate — see [docs/safety.md](../../docs/safety.md) +- Sign loop comments on PRs: `🤖 Loop Engineering — PR Babysitter` +- Webhooks (`POST /hooks/agent`) can fire a check the moment CI finishes instead + of waiting for the next tick — keep hook endpoints on loopback or a trusted tailnet +- `hermes config set approvals.mode smart` so low-risk reads don't stall the loop + on manual gateway approvals +- Most runs should no-op on an empty watchlist. Cost check: + `npx @cobusgreyling/loop-cost --pattern pr-babysitter --cadence 15m --level L1 --conservative`; + audit readiness: `npx @cobusgreyling/loop-audit . --suggest` +- See [patterns/pr-babysitter.md](../../patterns/pr-babysitter.md) and + [starters/pr-babysitter](../../starters/pr-babysitter/) for the full pattern spec + +See the [primitives matrix](../../docs/primitives-matrix.md) for how Hermes maps +to the same six-part loop shape.