PRWATCH

Review your own pull requests with the AI agent you already pay for โ€” locally, with zero CI cost.

$ npm install -g prwatch
Read the docs โ˜… GitHub
MIT LICENSE NODE โ‰ฅ 20 CLAUDE ยท CODEX ยท OPENCODE NO CI MINUTES
Live

One daemon. Every new PR reviewed.

Pick the repos to watch, pick your agent, leave it running. New PR appears โ†’ shallow clone โ†’ your agent runs the rubric โ†’ one structured review comment โ†’ clone deleted.

prw daemon โ€” ~/.prwatch

      
๐Ÿ’ธ

Zero CI cost

Nothing runs in Actions. The review happens on your machine with the agent subscription you already have.

๐Ÿค–

Your agent, your rules

Claude Code, Codex, or OpenCode โ€” auto-detected from your PATH. The rubric is a markdown file you own.

๐Ÿงน

No backlog, no spam

Only PRs opened after you start watching. Each PR reviewed exactly once. Temp clones always deleted.


Docs

Quickstart

Three prerequisites, one install, two commands.

1. Prerequisites

  • Node.js โ‰ฅ 20
  • gh (GitHub CLI), logged in โ€” gh auth login
  • At least one agent CLI on your PATH: claude, codex, or opencode

2. Install

$ npm install -g prwatch

3. Configure, then watch

$ prw            # TUI: add repos, pick your agent, check status
$ prw daemon     # start the watcher in the foreground (tmux-friendly)

Open a PR on a watched repo. Within one poll interval (default 3 minutes) the review lands as a single comment on the PR.

How it works

  1. Poll โ€” every pollIntervalMinutes, gh lists open PRs for each watched repo.
  2. Filter โ€” PRs opened before you started watching that repo are skipped, so there is no backlog spam. Already-reviewed PRs are skipped via a local ledger plus an invisible <!-- prwatch --> marker on the posted comment, which makes reviews idempotent even if local state is lost.
  3. Clone โ€” the PR head is shallow-cloned into ~/.prwatch/cache/.
  4. Review โ€” your agent runs inside that checkout with the rubric plus the PR title/body, fenced inside <untrusted-pr-content> tags.
  5. Post & clean โ€” the agent's output is posted as one PR comment, then the temp clone is deleted. Cache is empty between reviews.

Push more commits to a PR that was already reviewed and PRWatch will not re-review it.

Commands

CommandWhat it does
prwOpens the TUI โ€” add/remove repos, choose the agent, see status.
prw daemonRuns the watcher in the foreground. Ctrl+C shuts down gracefully (no orphaned agent processes).
prw service installInstalls a login service (launchd on macOS, systemd user unit on Linux) and prints the path it wrote.

The TUI

Launched with a bare prw. Arrow keys / j k to move, Enter to select, q to quit.

ScreenPurpose
ReposAdd a repo by fuzzy-searching your GitHub repos live (type to filter, Enter to add), or remove a watched one.
AgentPick among the agents actually installed on your machine โ€” PRWatch probes claude, codex, opencode.
StatusWatched repos, selected agent, and what the daemon last did.

Configuration

~/.prwatch/config.json. The TUI writes it; editing by hand is fine. Invalid values are rejected on load rather than silently coerced.

{
  "repos": ["adisagar2003/PRWatch"],
  "agent": "claude",
  "pollIntervalMinutes": 3,
  "agentTimeoutMinutes": 10
}
KeyDefaultNotes
repos[]Array of owner/name strings.
agent"claude"One of claude, codex, opencode.
pollIntervalMinutes3Finite number > 0.
agentTimeoutMinutes10Hard timeout per review; the agent process is killed past it.

Rubric

The review prompt's checklist. Edit it freely โ€” this is where you encode what your team actually cares about.

LocationScope
~/.prwatch/rubric.mdYour default, used for every watched repo.
.prwatch/rubric.mdCommitted at a repo's root โ€” overrides the default for that repo.

Run at login

$ prw service install
service installed: ~/Library/LaunchAgents/com.prwatch.daemon.plist

macOS gets a launchd agent, Linux a systemd user unit. Prefer a foreground prw daemon in tmux while you're still tuning the rubric โ€” the log is right there.

Security

Watching a public repo means running your agent against untrusted input: the PR title and body, and the PR's own files โ€” which can include agent-instruction files like CLAUDE.md that an attacker committed specifically to steer your agent.

Recommended: only watch repos you trust, and run your agent with restrictive permissions (no auto-approved shell or network tools) whenever third-party PRs are in scope.

PRWatch fences the PR title/description inside <untrusted-pr-content> tags in the prompt it sends. That does not stop an agent from reading attacker-added files inside the checkout โ€” that mitigation has to come from your agent's own permission model.

State & logs

Everything lives under ~/.prwatch/ โ€” delete the directory to fully reset.

PathContents
config.jsonWatched repos, agent, intervals.
state.jsonWatch start times and the reviewed-PR ledger.
rubric.mdYour default review rubric.
logs/daemon.logPoll, review, and post activity โ€” first place to look.
cache/Temp shallow clones. Empty between reviews.

repo-find.sh

A standalone fzf picker for your GitHub repos, for use outside the TUI. It ships only in a source checkout (git clone) โ€” it is not in the npm package. Requires gh and fzf.

$ ./repo-find.sh          # pick a repo, print its URL
$ ./repo-find.sh open     # open it in the browser
$ ./repo-find.sh clone    # clone into the current folder
$ ./repo-find.sh view     # show details in the terminal

A live preview pane runs gh repo view on whatever you hover. The repo list is cached for 10 minutes under ${XDG_CACHE_HOME:-~/.cache}/prwatch/. Fetches up to 300 repos โ€” raise it with REPO_LIMIT=500 ./repo-find.sh.

Troubleshooting

SymptomCheck
No agents listedIs the CLI on your PATH? PRWatch resolves it with which; shell aliases and functions are invisible to it.
Nothing gets reviewedOnly PRs opened after you added the repo qualify. Open a fresh one, and confirm gh auth status is green.
Review never postsTail ~/.prwatch/logs/daemon.log. A long agent run gets killed at agentTimeoutMinutes โ€” raise it.
Same PR reviewed twiceShouldn't happen: the ledger plus the <!-- prwatch --> comment marker both guard it. If it does, file an issue.
cache/ not emptyLeftover from a hard kill. Safe to delete by hand.

Full manual end-to-end walkthrough: docs/e2e.md.