- Add scripts/lib/common.sh (ORG/BOT/FORGE_BACKEND, logging, process_running) - discover.sh: dedupe review-requested+assignee PRs; JSON+summary formats - discover.sh: FORGE_BACKEND=forgejo via Forgejo API + stoke token - Fix poll-loop process detection (basename, not install path) - health-check: jq-safe JSON; backend-aware auth (gh or stoke) - install-live: require rsync/jq/tmux; soft-warn missing gh/stoke - self-test.sh offline smoke; restore/poll-once use shared config - Docs: Forgejo table, watcher.env, OPERATIONS troubleshooting
166 lines
5.5 KiB
Markdown
166 lines
5.5 KiB
Markdown
# heavy-duty-watcher
|
|
|
|
**Org-wide review agent** for the [heavy-duty](https://github.com/heavy-duty) organization
|
|
(GitHub by default; optional [Forgejo](https://forgejo.heavyduty.builders) backend via [stoke](https://forgejo.heavyduty.builders/heavy-duty/stoke)).
|
|
|
|
Runs as bot **`grok-bot-andresmgsl`**. Every 15 minutes it discovers open Issues/PRs where this bot is **assignee** or **requested reviewer** across **all** `heavy-duty/*` repos, reads the full discussion, and posts structured reviews until it **agrees** (Approve) or still has blockers (Request changes).
|
|
|
|
> Not a drive-by bot. No unsolicited comments. No merge/close/reassign unless an operator asks.
|
|
|
|
---
|
|
|
|
## Features
|
|
|
|
- **Org-wide scope** — one watcher for every repo under `heavy-duty`
|
|
- **Dual forge backends** — `FORGE_BACKEND=github` (default) or `forgejo`
|
|
- **Strict collaboration rules** — clear Verdict/Status, specific, non-redundant, blockers vs nits
|
|
- **Stateful de-dupe** — tracks per-item head SHA and last action (`owner/repo#pr:N`)
|
|
- **Deduped discovery** — PRs that are both review-requested and assigned appear once
|
|
- **Dual durability** — Grok durable schedulers **and** local tmux loops
|
|
- **Reboot recovery** — `scripts/restore.sh` rebuilds tmux + resumes the agent
|
|
- **Hourly health watchdog** — verifies poll loop, auth, freshness; self-heals
|
|
- **Offline self-test** — `scripts/self-test.sh` (`bash -n` + structure checks)
|
|
|
|
---
|
|
|
|
## Quick start
|
|
|
|
```bash
|
|
git clone https://github.com/grok-bot-andresmgsl/heavy-duty-watcher.git
|
|
# or from Forgejo: https://forgejo.heavyduty.builders/grok-reviewer-andresmgsl/heavy-duty-watcher.git
|
|
cd heavy-duty-watcher
|
|
gh auth status # bot account with org access (GitHub backend)
|
|
./scripts/self-test.sh # optional offline smoke
|
|
./scripts/install-live.sh
|
|
./scripts/restore.sh # after reboot: always this
|
|
```
|
|
|
|
### Forgejo backend
|
|
|
|
```bash
|
|
cp config/watcher.env.example config/watcher.env
|
|
# set FORGE_BACKEND=forgejo and BOT_LOGIN=<forgejo-bot>
|
|
stoke auth login
|
|
FORGE_BACKEND=forgejo ./scripts/discover.sh
|
|
```
|
|
|
|
Arm durable schedulers from a live Grok session using prompts in [`docs/SCHEDULER_PROMPTS.md`](docs/SCHEDULER_PROMPTS.md).
|
|
|
|
---
|
|
|
|
## Repository layout
|
|
|
|
```text
|
|
heavy-duty-watcher/
|
|
├── README.md
|
|
├── POLL_INSTRUCTIONS.md ← authoritative review rules (read every cycle)
|
|
├── config/
|
|
│ ├── state.template.json
|
|
│ └── watcher.env.example
|
|
├── scripts/
|
|
│ ├── lib/common.sh ← shared env + helpers
|
|
│ ├── discover.sh ← org-wide actionable list (github|forgejo)
|
|
│ ├── poll-once.sh ← one headless poll (Grok)
|
|
│ ├── poll-loop.sh ← every 15m
|
|
│ ├── health-check.sh
|
|
│ ├── health-loop.sh ← every 1h + self-heal
|
|
│ ├── restore.sh ← reboot recovery (tmux)
|
|
│ ├── install-live.sh ← deploy under ~/heavy-duty-watcher
|
|
│ └── self-test.sh ← offline smoke
|
|
├── docs/
|
|
│ ├── ARCHITECTURE.md
|
|
│ ├── OPERATIONS.md
|
|
│ ├── ORG_SCOPE.md
|
|
│ ├── SCHEDULER_PROMPTS.md
|
|
│ └── REVIEW_PLAYBOOK.md
|
|
└── logs/ ← runtime (gitignored)
|
|
```
|
|
|
|
---
|
|
|
|
## How a poll works
|
|
|
|
```text
|
|
discover (org search / forgejo API)
|
|
→ for each match
|
|
read ALL comments + reviews + diff + checks
|
|
compare head SHA / prior bot comments (state.json)
|
|
if material change:
|
|
post Verdict: Request changes | Comment | Approve
|
|
else:
|
|
silent
|
|
→ update state.json + logs/poll.log
|
|
```
|
|
|
|
Full rules: [`POLL_INSTRUCTIONS.md`](POLL_INSTRUCTIONS.md).
|
|
|
|
---
|
|
|
|
## Configuration
|
|
|
|
Copy `config/watcher.env.example` → `config/watcher.env` (gitignored):
|
|
|
|
| Variable | Default | Meaning |
|
|
|----------|---------|---------|
|
|
| `ORG` | `heavy-duty` | GitHub/Forgejo org |
|
|
| `BOT_LOGIN` | `grok-bot-andresmgsl` | Bot account login |
|
|
| `FORGE_BACKEND` | `github` | `github` or `forgejo` |
|
|
| `FORGEJO_URL` | `https://forgejo.heavyduty.builders` | Forge base URL |
|
|
| `POLL_INTERVAL_SEC` | `900` | tmux poll-loop sleep |
|
|
| `HEALTH_INTERVAL_SEC` | `3600` | health-loop sleep |
|
|
| `STALE_POLL_MINUTES` | `45` | health WARN threshold |
|
|
|
|
---
|
|
|
|
## Day-to-day commands
|
|
|
|
```bash
|
|
./scripts/discover.sh # JSON (default)
|
|
FORMAT=summary ./scripts/discover.sh # human table
|
|
./scripts/health-check.sh
|
|
./scripts/self-test.sh
|
|
tail -f logs/poll.log logs/health.log
|
|
tmux attach -t heavy-duty-watcher
|
|
```
|
|
|
|
---
|
|
|
|
## Documentation map
|
|
|
|
| Doc | Audience |
|
|
|-----|----------|
|
|
| [POLL_INSTRUCTIONS.md](POLL_INSTRUCTIONS.md) | Agent — must follow every cycle |
|
|
| [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) | Design / durability model |
|
|
| [docs/OPERATIONS.md](docs/OPERATIONS.md) | Humans operating the watcher |
|
|
| [docs/SCHEDULER_PROMPTS.md](docs/SCHEDULER_PROMPTS.md) | Copy-paste durable task prompts |
|
|
| [docs/REVIEW_PLAYBOOK.md](docs/REVIEW_PLAYBOOK.md) | Review style examples |
|
|
| [docs/ORG_SCOPE.md](docs/ORG_SCOPE.md) | Org repo notes |
|
|
|
|
---
|
|
|
|
## After reboot
|
|
|
|
```bash
|
|
~/heavy-duty-watcher/scripts/restore.sh
|
|
```
|
|
|
|
| Window | Role |
|
|
|--------|------|
|
|
| `grok` | Interactive agent (resume session when possible) |
|
|
| `poll-loop` | Headless 15m polls |
|
|
| `health-loop` | Hourly health + self-heal |
|
|
| `tools` | Manual shell |
|
|
|
|
---
|
|
|
|
## Safety
|
|
|
|
- Only comments when **assigned** or **review-requested**
|
|
- Never merges, closes, force-pushes, or reassigns by default
|
|
- Secrets are **not** stored in this repo — use `gh auth` / `stoke auth login` on the host
|
|
|
|
---
|
|
|
|
## License
|
|
|
|
MIT — see [LICENSE](LICENSE).
|