Files
hans-tools/gh-monitor/design.md

159 lines
4.0 KiB
Markdown

# gh-monitor — Design Doc
**Status:** Pending Andrew's review
**Repo:** coding-with-hans-heinemann/hans-tools
**Author:** Hans Heinemann
---
## What It Does
Polls the GitHub API for activity on watched repositories and fires OpenClaw
system events to wake Hans when action is needed. Hans can then read the PR,
respond to comments, push fixes, or request changes — all without a public
webhook endpoint.
---
## Scope
Initial scope: PRs only. Issues, CI, and deployments out of scope for v1.
Events monitored:
- New review submitted (approved, changes requested, commented)
- New PR review comment posted
- New PR issue comment posted
- PR merged or closed
Events NOT monitored in v1:
- CI/check status
- Issue activity
- Dependabot alerts
---
## Architecture
```
cron (every 5 min)
└── gh-monitor/poll.py
├── reads config/watched.yaml (repos + filter rules)
├── reads state/last_seen.json (per-repo event cursor)
├── calls GitHub API via gh CLI (no extra credentials)
├── diffs against last_seen
├── for each new event:
│ └── fires openclaw system event (text summary)
└── writes updated last_seen.json
```
Hans receives OpenClaw system event → session wakes → Hans reads + acts.
---
## Config — watched.yaml
```yaml
repos:
- owner: coding-with-hans-heinemann
repo: the-agency
notify_on:
- review_submitted
- review_comment
- issue_comment
- pr_closed
```
Multiple repos supported. Per-repo filter rules.
---
## State — last_seen.json
Tracks the timestamp of the last processed event per repo. On each poll,
only events newer than this cursor are processed. Prevents duplicate alerts.
```json
{
"coding-with-hans-heinemann/the-agency": {
"last_event_at": "2026-03-15T17:00:00Z"
}
}
```
On first run (no state file), cursor is set to now — no backfill of old events.
---
## Notification Format
OpenClaw system event text:
```
[gh-monitor] PR #1 "feat: Phase 2" — Andrew left a review comment:
"The escalation retry logic looks good but can you add a test for the blocked case?"
https://github.com/coding-with-hans-heinemann/the-agency/pull/1#discussion_r12345
```
One event per notification. If multiple events arrive in one poll cycle, they
fire as separate system events in sequence.
---
## GitHub API Access
Uses `gh` CLI (already installed, already authenticated as hansheinemann).
No new credentials needed. All API calls go through `gh api`.
Endpoints used:
- `GET /repos/{owner}/{repo}/pulls/{pull_number}/reviews`
- `GET /repos/{owner}/{repo}/pulls/{pull_number}/comments`
- `GET /repos/{owner}/{repo}/issues/{pull_number}/comments`
- `GET /repos/{owner}/{repo}/pulls` (list open PRs)
Rate limit: 5,000 requests/hour for authenticated requests. At 5-min poll
intervals across a handful of repos, this is nowhere near the limit.
---
## Cron Schedule
Every 5 minutes via OpenClaw cron:
```
{ "kind": "every", "everyMs": 300000 }
```
Payload: systemEvent → injects wake text into main session.
Can be paused/resumed via OpenClaw cron management without touching the code.
---
## Error Handling
- GitHub API errors: log to `state/errors.log`, skip that repo for this cycle
- Malformed API response: log and skip
- Missing state file: create fresh with cursor = now
- `gh` CLI not found: exit with error message
Errors do NOT fire system events (avoid alert fatigue from transient API blips).
If errors persist for >3 consecutive cycles, fire one alert to Hans.
---
## Security
- No webhook endpoint — nothing exposed to the internet
- No secrets stored in the repo — `gh` CLI handles auth via its own keychain
- State files excluded from git via .gitignore
- Read-only GitHub API access needed (no write scopes required for polling)
---
## Out of Scope (v1)
- Filtering by PR author
- Filtering by comment author
- Digest mode (batch multiple events into one notification)
- Slack/email delivery (OpenClaw system event only)
- CI/check status monitoring