EndPRs
An agent that turns pull request review comments into commits.
reviewer commented on src/profile.ts
user can be null after logout. Handle it?
endprs pushed 1 commit
- const name = user.name; + const name = user?.name ?? "Guest";
fix: handle signed-out user in profile header
"Rename this", "handle the null case", "fix this type": most review comments are mechanical, but each one costs a context switch. EndPRs watches your pull requests, writes the fix with Claude and pushes it back as a commit, so you only review the result.
Measured
- GitHub API quota used while nothing changes
- 0
- ways to generate a fix: agent edits or patches
- 2
- test files across the worker and API
- 21
Problem
An agent like this lives or dies on three things: it must not burn the GitHub rate limit by polling, it must not process the same comment twice, and it needs enough of the codebase in context to make a correct change.
Architecture
- External
- Worker
- Interface
- Storage
- Service
- Model
A poller checks open pull requests every 10 seconds with conditional requests and queues a job when a new comment appears. A worker pool picks jobs up by priority, gives Claude the comment plus relevant code, applies the fix and commits and pushes it with git. A Next.js dashboard shows jobs, generation modes and token usage.
Decisions
ETag polling instead of webhooks
It works for any repo without installing an app. Every request sends If-None-Match, and a 304 response costs no quota, so polling every 10 seconds stays inside GitHub's limits.
Deterministic job ids
Each job id is built from the repo, PR number and update time, so re-polling an unchanged pull request can never queue a duplicate fix.
Two ways to generate a fix
Agent SDK mode lets Claude read and edit the checkout directly with a restricted tool set. API mode generates a patch with retrieved code context. A flag switches between them, so they can be compared on cost and quality.
Priority queue
Priority comes from keywords in the comment and the PR's age, plus a per-repo boost, so urgent fixes jump ahead.
Hard parts
Rate limits everywhere
GitHub rate-limit responses become typed errors with a reset time and exponential backoff. The worker pool runs at most 100 jobs a minute, and embedding calls back off on their own limits.
Context that fits
Code is chunked, embedded and stored in pgvector with a cosine index. Retrieval is filtered by similarity and trimmed to a token budget before it goes into the prompt.
Secrets at rest
Secrets stored by the API are encrypted with AES-256-GCM, using keys derived with PBKDF2.
Quality
- 21 test files and about 500 test cases across the worker and the API.
- A Docker sandbox module with CPU, memory, process and time limits is built and unit-tested.