loop-run.sh 1.6 KB

123456789101112131415161718192021222324252627282930
  1. #!/usr/bin/env bash
  2. # loop-run.sh - one tick of the pr-watch loop. RUNNER-AGNOSTIC: point any scheduler
  3. # at it. No GitHub Actions required.
  4. # cron: */10 * * * * /path/.loops/pr-watch/loop-run.sh >> tick.log 2>&1
  5. # Windows Task Scheduler: schtasks /Create /SC MINUTE /MO 10 /TN pr-watch \
  6. # /TR "bash -lc '/path/.loops/pr-watch/loop-run.sh'"
  7. # by hand: bash loop-run.sh
  8. # The scheduler is the authorizer; this runs a gated `claude -p` (dontAsk + an allowlist),
  9. # never bypassPermissions on a shared host. (github-actions.yml is one OPTIONAL scheduler.)
  10. set -uo pipefail
  11. HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
  12. cd "$HERE"
  13. # 1. Kill switch first.
  14. if [ -f PAUSED ]; then echo "pr-watch: paused (PAUSED sentinel) - skipping tick" >&2; exit 0; fi
  15. command -v claude >/dev/null 2>&1 || { echo "pr-watch: 'claude' not on PATH" >&2; exit 5; }
  16. # 2. One tick. SAME prompt every time (cache-friendly). Allowlist = exactly what an L1
  17. # report loop needs: read-only gh + Read + the STATE/run-log writes. No 'gh pr merge'.
  18. claude -p "$(cat run.md)" \
  19. --permission-mode dontAsk \
  20. --append-system-prompt "$(cat STATE.md)" \
  21. --allowedTools 'Bash(gh pr list:*)' 'Bash(gh pr view:*)' 'Bash(gh pr comment:*)' 'Read' 'Write(STATE.md)' 'Write(run-log.md)' \
  22. --max-turns 30
  23. # 3. Persist STATE + run-log if this dir lives in a git repo.
  24. if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
  25. git add STATE.md run-log.md 2>/dev/null || true
  26. git diff --cached --quiet 2>/dev/null || git commit -q -m "chore(loop): pr-watch tick" || true
  27. fi