diff --git a/examples/README.md b/examples/README.md index f8d63465..e044e311 100644 --- a/examples/README.md +++ b/examples/README.md @@ -29,7 +29,7 @@ Start with [primitives-matrix.md](../docs/primitives-matrix.md) to map capabilit | 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) | [cursor/post-merge-cleanup.md](./cursor/post-merge-cleanup.md) | [windsurf/post-merge-cleanup.md](./windsurf/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) | [cursor/dependency-sweeper.md](./cursor/dependency-sweeper.md) | [windsurf/dependency-sweeper.md](./windsurf/dependency-sweeper.md) | [opencode/dependency-sweeper.md](./opencode/dependency-sweeper.md) | — | [github-actions/dependency-sweeper.yml](./github-actions/dependency-sweeper.yml) | | Changelog Drafter | [grok/changelog-drafter.md](./grok/changelog-drafter.md) | [claude-code/changelog-drafter.md](./claude-code/changelog-drafter.md) | [codex/changelog-drafter.md](./codex/changelog-drafter.md) | [openclaw/changelog-drafter.md](./openclaw/changelog-drafter.md) | [cursor/changelog-drafter.md](./cursor/changelog-drafter.md) | [windsurf/changelog-drafter.md](./windsurf/changelog-drafter.md) | [opencode/changelog-drafter.md](./opencode/changelog-drafter.md) | — | [github-actions/changelog-drafter.yml](./github-actions/changelog-drafter.yml) | -| Issue Triage | [grok/issue-triage.md](./grok/issue-triage.md) | [claude-code/issue-triage.md](./claude-code/issue-triage.md) | [codex/issue-triage.md](./codex/issue-triage.md) | [openclaw/issue-triage.md](./openclaw/issue-triage.md) | [cursor/issue-triage.md](./cursor/issue-triage.md) | [windsurf/issue-triage.md](./windsurf/issue-triage.md) | [opencode/issue-triage.md](./opencode/issue-triage.md) | — | [github-actions/issue-triage.yml](./github-actions/issue-triage.yml) | +| Issue Triage | [grok/issue-triage.md](./grok/issue-triage.md) | [claude-code/issue-triage.md](./claude-code/issue-triage.md) | [codex/issue-triage.md](./codex/issue-triage.md) | [openclaw/issue-triage.md](./openclaw/issue-triage.md) | [cursor/issue-triage.md](./cursor/issue-triage.md) | [windsurf/issue-triage.md](./windsurf/issue-triage.md) | [opencode/issue-triage.md](./opencode/issue-triage.md) | [hermes/issue-triage.md](./hermes/issue-triage.md) | [github-actions/issue-triage.yml](./github-actions/issue-triage.yml) | L2 patterns ship multi-tool skills inside one starter folder — see `starters//`. @@ -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/pr-babysitter.md](./hermes/pr-babysitter.md) (manual) | [hermes/ci-sweeper.md](./hermes/ci-sweeper.md) (manual) | — | — | — | — | +| Hermes | [hermes/daily-triage.md](./hermes/daily-triage.md) (manual) | [hermes/pr-babysitter.md](./hermes/pr-babysitter.md) (manual) | [hermes/ci-sweeper.md](./hermes/ci-sweeper.md) (manual) | — | — | — | [hermes/issue-triage.md](./hermes/issue-triage.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 82b879c8..dcc67fa6 100644 --- a/examples/hermes/README.md +++ b/examples/hermes/README.md @@ -7,6 +7,7 @@ | [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) | | [ci-sweeper.md](./ci-sweeper.md) | CI Sweeper (L1 report → L2 worktree + verifier) | +| [issue-triage.md](./issue-triage.md) | Issue Triage (L1 propose-only → L2 allowlisted labels) | 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/issue-triage.md b/examples/hermes/issue-triage.md new file mode 100644 index 00000000..61248810 --- /dev/null +++ b/examples/hermes/issue-triage.md @@ -0,0 +1,135 @@ +# Issue Triage — Hermes Agent (`hermes cron`) + +Keep the issue queue legible so humans and Daily Triage always know the top five +actionable items. Hermes runs the shared `issue-triage` skill in a fresh cron +session and keeps routine output local while the loop earns trust. + +Week one is deliberately **propose-only**: the job updates +`issue-triage-state.md` with suggested priority and labels, but never changes an +issue or repository. + +## Setup + +Install and configure [Hermes Agent](https://hermes-agent.nousresearch.com/docs), +then copy the shared state example and skill: + +```bash +hermes setup + +cp starters/issue-triage/issue-triage-state.md.example \ + issue-triage-state.md + +mkdir -p ~/.hermes/skills/issue-triage +cp templates/SKILL.md.issue-triage \ + ~/.hermes/skills/issue-triage/SKILL.md + +hermes skills list | grep issue-triage +``` + +Use `.hermes/skills/issue-triage/` instead when the skill should be available +only inside this project. The job also needs read-only access to the issue +tracker, for example through an authenticated GitHub CLI or a GitHub-capable +skill. Do not grant write access for the week-one loop. + +## Week one — propose only + +Start with a two-hour cadence on an active repository. `--workdir "$PWD"` pins +the repository and injects its `AGENTS.md`, `CLAUDE.md`, or `.cursorrules` into +the cron session. + +```bash +hermes cron create "0 */2 * * *" \ + --name "Issue triage" \ + --deliver local \ + --skill issue-triage \ + --workdir "$PWD" \ + "Run the issue-triage skill. Read issue-triage-state.md first, then scan open issues and discussions created or updated since the last run. Update Last run, backlog counts, Top 5 prioritized items, proposed labels, possible duplicates, and the needs-human bucket. Week one is report-only: propose priority and labels, but do not apply labels, comment, close, reopen, assign, or edit source files. Treat duplicates as possible duplicates for human confirmation. Escalate ambiguous items and anything touching auth, payments, security, billing, infrastructure, or public API. End with the top five and the human decisions needed." +``` + +- `--deliver local` writes output to `~/.hermes/cron/output/`; routine reports + do not enter a human chat or connected home channel. +- `--skill issue-triage` attaches the shared classifier without authorizing + GitHub writes. +- For a quieter repository, use a daily cadence such as `0 9 * * 1-5`. +- If issue reads use a separate GitHub skill, repeat `--skill` to attach it while + keeping its credentials read-only. + +Run one tick manually before relying on the schedule: + +```bash +hermes cron list +hermes cron run +hermes cron status +``` + +## State file + +The state shape matches the shared +[`issue-triage` pattern](../../patterns/issue-triage.md) and starter: + +```markdown +# Issue Triage State +Last run: 2026-08-19 09:00 UTC +Open actionable: 14 (was 17) +New since last run: 3 +Needs human: 2 + +## Top 5 (by loop score) +- #487 (bug, p1, 2d old) — "Crash on export with large files" — suggested: bug, needs-repro, area:export + +## Proposed Labels (not applied — L1) +- #487: `bug`, `needs-repro`, `area:export` + +## Possible Duplicates (human confirm) +- #488 — possible duplicate of #412 + +## Noise / Ignored +- #460 — usage question; redirect candidate for human review +``` + +Each run prunes resolved entries, keeps proposed actions concise, and records +uncertainty instead of silently deciding it away. Do not copy credentials, +private issue content, or other secrets into the state file. + +## Pairing with Daily Triage + +Issue Triage runs every two hours or daily and maintains the detailed queue in +`issue-triage-state.md`. Daily Triage reads its Top 5 and carries only issue +numbers and short summaries into `STATE.md` High Priority; it does not duplicate +full issue bodies. + +## After the reports earn trust + +Keep `--deliver local` during calibration. A human may later switch delivery to +`origin`, a configured home channel such as `slack` or `feishu`, or a specific +`platform:chat_id:thread_id` after reviewing channel `allowFrom` and mention +rules. Delivery changes where the report appears, not what the loop may do. + +L2 may apply only allowlisted labels such as `area:*`, `needs-repro`, and +`needs-info`, and only after an independent verifier passes. It still never +auto-closes issues or applies P0, P1, `security`, or `breaking-change` labels. +Pause the job before changing this boundary: + +```bash +hermes cron pause +hermes cron edit --prompt "" +hermes cron resume +``` + +## Safety and human gates + +- Week one: propose only; never label, comment, assign, close, or reopen. +- Possible duplicates always need human confirmation. +- Auth, payments, security, billing, infrastructure, and public API items remain + human-owned. +- Large bursts of new issues and unclear reproductions go to `Needs human`. +- Keep issue-tracker credentials read-only until a human explicitly approves an + L2 label allowlist and verifier. + +## References + +- [Issue Triage pattern](../../patterns/issue-triage.md) +- [Issue Triage starter](../../starters/issue-triage/) +- [Hermes Daily Triage](./daily-triage.md) +- [Safety and human gates](../../docs/safety.md) +- [Primitives matrix](../../docs/primitives-matrix.md)