PullWise ✈️
Stop writing PR descriptions. Let AI do it.
📦 GitHub Action:
albertusreza/pr-pilot· PyPI:pullwise
pr-pilot is a GitHub Action + CLI that analyzes your diff and commit history, then automatically writes a clear, structured PR description — with a summary, change list, test plan, and labels.
# .github/workflows/pr-description.yml
- uses: albertusreza/pr-pilot@main
with:
openai-api-key: ${{ secrets.OPENAI_API_KEY }}
That's it. Every new PR gets a description like this:
Add rate limiting to upload endpoint
Summary
Adds per-IP rate limiting to
/api/uploadusing a sliding window algorithm. Without this, a single client could saturate the server with concurrent uploads.Changes
- Add
RateLimitermiddleware with configurable window and max requests- Apply limiter to
/api/uploadroute (100 req/min default)- Return
429 Too Many RequestswithRetry-Afterheader- Add unit tests for edge cases (burst, reset, concurrent)
Test Plan
- Run
pytest tests/test_rate_limiter.py- Send 101 rapid requests to
/api/upload— 101st should return 429- Wait 60 seconds — requests should succeed again
Labels:
feature,security
Install
As a GitHub Action (zero-config)
name: PR Pilot
on:
pull_request:
types: [opened, reopened]
jobs:
describe:
runs-on: ubuntu-latest
permissions:
pull-requests: write
contents: read
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: albertusreza/pr-pilot@main
with:
openai-api-key: ${{ secrets.OPENAI_API_KEY }}
Add OPENAI_API_KEY to your repo secrets and you're done. Works with any language, any repo size.
As a CLI
pip install pullwise
export OPENAI_API_KEY=sk-...
# Generate a description for your current branch
pr-pilot describe
# Diff against a different base
pr-pilot describe --base develop
# Get a quick code review
pr-pilot review
# Save description as markdown
pr-pilot describe --markdown pr_description.md
Features
| Command | What it does |
|---|---|
pr-pilot describe |
Generate a structured PR description from your diff |
pr-pilot review |
Get a senior-engineer-style code review in the terminal |
pr-pilot comment |
Post an AI review as a GitHub PR comment (updates on re-run, no spam) |
pr-pilot changelog |
Generate a CHANGELOG.md entry from commits since last tag |
pr-pilot reviewers |
Suggest reviewers based on git blame of changed files |
pr-pilot standup |
Generate a daily standup update from your recent commits |
pr-pilot todos |
Scan for TODO/FIXME comments and create GitHub issues from them |
pr-pilot commit |
Generate a Conventional Commit message from staged changes |
pr-pilot release |
Full release: changelog + git tag + GitHub release in one command |
pr-pilot docs |
Generate docstrings for functions in changed files |
pr-pilot branch |
Suggest a git branch name from a plain-English task description |
pr-pilot explain |
Explain what a file or function does in plain English |
pr-pilot test |
Generate unit tests for a file or function |
pr-pilot security |
Scan the diff for security vulnerabilities, post as a PR comment |
Usage
# Generate PR description (terminal)
pr-pilot describe --base main
# Get a quick code review in the terminal
pr-pilot review --base main
# Post review as a GitHub PR comment
pr-pilot comment --repo owner/repo --pr 42
# Generate CHANGELOG entry (print to stdout)
pr-pilot changelog
# Write directly into CHANGELOG.md
pr-pilot changelog --output CHANGELOG.md
# Generate tests for a whole file
pr-pilot test src/auth.py
# Generate tests for one function and write to file
pr-pilot test src/auth.py --function authenticate --write
# Scan the diff for security vulnerabilities
pr-pilot security --base main
# Scan and post the report as a PR comment (exits 1 if critical/high found)
pr-pilot security --post --repo owner/repo --pr 42
# Generate docstrings for all functions changed vs main
pr-pilot docs
# Document a specific file
pr-pilot docs src/auth.py
# Suggest a branch name from a task description
pr-pilot branch "add rate limiting to upload endpoint"
# Create the branch immediately
pr-pilot branch "fix login timeout on mobile" --checkout
# Explain what a file does
pr-pilot explain src/auth.py
# Explain a specific function
pr-pilot explain src/auth.py --function authenticate
# Generate a commit message from staged changes
pr-pilot commit
# Run git commit directly with the generated message
pr-pilot commit --commit
# Full release: bump version + write changelog + create GitHub release
pr-pilot release --repo owner/repo
# Preview release without publishing
pr-pilot release --repo owner/repo --dry-run
# Suggest reviewers for your current branch
pr-pilot reviewers --base main
# Post suggestion as a comment + assign on GitHub
pr-pilot reviewers --post --assign --repo owner/repo --pr 42
# Generate a standup from yesterday's commits
pr-pilot standup
# Generate from the last 3 days and copy to clipboard
pr-pilot standup --days 3 --copy
# Scan for TODO/FIXME and preview issues
pr-pilot todos
# Actually create GitHub issues from them
pr-pilot todos --create --repo owner/repo
Auto-comment on every PR (GitHub Action)
# .github/workflows/pr-review.yml
- uses: actions/checkout@v4
with:
fetch-depth: 0
- run: pip install pullwise
- run: pr-pilot comment --repo ${{ github.repository }} --pr ${{ github.event.pull_request.number }}
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
GITHUB_TOKEN: ${{ github.token }}
The comment updates itself on every new push — no duplicate comments.
Options
| Input | Default | Description |
|---|---|---|
openai-api-key |
— | Required. Your OpenAI API key |
model |
gpt-4o |
OpenAI model to use |
skip-labels |
false |
Skip adding labels to the PR |
update-title |
false |
Also rewrite the PR title |
How it works
- On PR open, checks out the branch with full history
- Runs
git diff <base>...HEADto get the full diff - Collects commit messages with
git log --oneline - Sends both to GPT-4o with a structured prompt
- Parses the JSON response and updates the PR body + labels via GitHub API
- Skips update if the PR already has a substantial description (>100 chars)
Why
Over 60% of PRs are merged with descriptions like "fix bug", "WIP", or nothing at all. This makes code review harder, changelogs meaningless, and git history useless for future maintainers.
pr-pilot takes 30 seconds to set up and runs on every PR automatically — no discipline required.
Cost
Each PR description costs roughly $0.01–0.03 with gpt-4o depending on diff size. For a team of 5 opening ~20 PRs/week, that's about $1–3/month.
Self-hosted / private repos
Works with private repos. Just add the secret and the workflow file — no data leaves your GitHub Actions runner except the diff sent to OpenAI.
Contributing
git clone https://github.com/albertusreza/pr-pilot
cd pr-pilot
pip install -e ".[dev]"
pytest
License
MIT
Metadata
Release files for pullwise 0.7.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pullwise-0.7.0.tar.gz | 31.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pullwise-0.7.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 56.3 kB
Release files / pullwise-0.7.0.tar.gz
| Download URL | pullwise-0.7.0.tar.gz |
|---|---|
| Size | 31.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8d24389c4ab0d4739af88c78f1d92ac5a4395f605912a8bc0140fd147b68929e
|
|
BLAKE2b-256 checksum How to use checksums |
cfac053ac3630b4194130e90f0ed95e40682607a86ccf4bdaa4654b8c5db9b1e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.9.13
|
Release files / pullwise-0.7.0-py3-none-any.whl
| Download URL | pullwise-0.7.0-py3-none-any.whl |
|---|---|
| Size | 24.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
990eb03660c43fab0656697b6c3d8fd1381d6532a2d2262d1be9e0389ced39d2
|
|
BLAKE2b-256 checksum How to use checksums |
5babe4f4ab112dcac59936f8878208c0b29160f9589b4d98ef6a5ae426572501
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.9.13
|