Metadata-Version: 2.4
Name: prsentinel-cli
Version: 1.5.0
Summary: Free, self-hosted AI code review for pull requests. Bring your own free or paid model.
Author-email: Kivanc <noreply@example.com>
License: MIT
Project-URL: Homepage, https://github.com/Lethe044/prsentinel
Project-URL: Repository, https://github.com/Lethe044/prsentinel
Project-URL: Issues, https://github.com/Lethe044/prsentinel/issues
Project-URL: Changelog, https://github.com/Lethe044/prsentinel/blob/main/CHANGELOG.md
Keywords: code-review,pull-request,github-actions,ai,static-analysis,devtools,llm,ci-cd
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Quality Assurance
Classifier: Topic :: Software Development :: Testing
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: click>=8.1
Requires-Dist: rich>=13.7
Requires-Dist: requests>=2.31
Requires-Dist: PyYAML>=6.0
Provides-Extra: dev
Requires-Dist: pytest>=7.4; extra == "dev"
Requires-Dist: pytest-cov>=4.1; extra == "dev"
Requires-Dist: responses>=0.24; extra == "dev"
Dynamic: license-file

# PR Sentinel

[![CI](https://github.com/Lethe044/prsentinel/actions/workflows/ci.yml/badge.svg)](https://github.com/Lethe044/prsentinel/actions/workflows/ci.yml)
[![PyPI version](https://img.shields.io/pypi/v/prsentinel-cli.svg)](https://pypi.org/project/prsentinel-cli/)
[![Downloads](https://static.pepy.tech/badge/prsentinel-cli)](https://pepy.tech/project/prsentinel-cli)
[![Python versions](https://img.shields.io/pypi/pyversions/prsentinel-cli.svg)](https://pypi.org/project/prsentinel-cli/)
[![Docker image](https://img.shields.io/badge/ghcr.io-prsentinel-blue?logo=docker)](https://github.com/Lethe044/prsentinel/pkgs/container/prsentinel)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

Free, self-hosted AI code review for pull requests and merge requests.
Point it at a free provider like Groq, Gemini, or a local Ollama model and
it reads your diff, flags real problems, and leaves comments directly on
GitHub or GitLab. No subscription, no seat-based pricing, no vendor
lock-in.

If your team has a budget for a paid model, PR Sentinel works with your own
OpenAI or Anthropic key too. Nothing here requires it.

## Why this exists

Automated PR review tools are useful, but the well known ones are paid
products with per-seat pricing. That is a real cost for a solo developer, a
student project, or a small open source repository, even when the actual
review only needs a handful of API calls per pull request. PR Sentinel is
the same idea built as a small, auditable, self-hosted tool: you choose the
model, you hold the API key (or use none at all with a local model), and
the entire pipeline runs inside your own GitHub Actions job.

## What it does

- Reads the diff for a pull request (or a local `git diff`) and reviews
  only the changed lines, using surrounding context to understand intent.
- Works on GitHub pull requests, GitLab merge requests, Bitbucket pull
  requests, and Azure DevOps pull requests.
- Flags bugs, security issues, performance problems, missing error
  handling, and missing tests, not personal style nitpicks. Where it can,
  it includes a drop-in code fix, not just an explanation.
- Posts a single summary comment on the pull request, plus inline comments
  on the specific lines with a problem, and updates that same comment on
  every push instead of piling up duplicates.
- Requests changes automatically when a critical issue is found, so it can
  act as a real merge gate if you want one.
- Also works as a [pre-commit](https://pre-commit.com) hook, reviewing
  staged changes before they are even pushed.
- Suggests a pull request title and description from a diff with
  `prsentinel summarize`, if you would rather not write one by hand.
- Reviews diff chunks concurrently, so larger pull requests finish faster,
  and retries transient rate limit or server errors automatically.
- Can write review comments in a language other than English.
- Can notify a Slack or Discord channel when something serious is found.
- Works from the command line too, so you can review a diff before you even
  open the pull request.
- Exports findings as SARIF for the GitHub Security tab, plain JSON for
  your own tooling, an HTML report, or JUnit XML for CI systems that
  render test reports.
- Caches results per diff chunk so re-running a workflow does not spend
  API quota reviewing the same lines twice.
- Automatically skips files matched by your project's own `.gitignore`,
  and `prsentinel doctor` catches common setup problems (missing git,
  missing API key, an Ollama server that isn't running) in one command.

## Quickstart: GitHub Actions

Add this workflow at `.github/workflows/pr-sentinel.yml`:

```yaml
name: PR Sentinel

on:
  pull_request:

permissions:
  contents: read
  pull-requests: write

jobs:
  review:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: Lethe044/prsentinel@v1
        with:
          provider: groq
          api-key: ${{ secrets.GROQ_API_KEY }}
```

Get a free Groq API key at [console.groq.com/keys](https://console.groq.com/keys),
add it as a repository secret named `GROQ_API_KEY`, and every new pull
request gets reviewed automatically.

## Quickstart: GitLab CI

Add this to `.gitlab-ci.yml`:

```yaml
prsentinel:
  image: python:3.12
  stage: test
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
  script:
    - pip install prsentinel-cli
    - prsentinel review --post-to-gitlab --provider groq
  variables:
    GROQ_API_KEY: $GROQ_API_KEY
```

Add `GROQ_API_KEY` and a `GITLAB_TOKEN` (a project access token with the
`api` scope) as masked CI/CD variables in your project settings, and every
merge request gets a summary note plus inline comments on the changed
lines.

## Quickstart: Bitbucket Pipelines

Add this to `bitbucket-pipelines.yml`:

```yaml
pipelines:
  pull-requests:
    '**':
      - step:
          name: PR Sentinel
          image: python:3.12
          script:
            - pip install prsentinel-cli
            - prsentinel review --post-to-bitbucket --provider groq
```

Create a repository access token with the `pullrequest:write` scope under
**Repository settings > Security > Access tokens**, then add it along with
`GROQ_API_KEY` as secured repository variables named `BITBUCKET_TOKEN` and
`GROQ_API_KEY`.

## Quickstart: Azure DevOps

Add this to `azure-pipelines.yml`:

```yaml
trigger: none
pr:
  branches:
    include:
      - '*'

pool:
  vmImage: ubuntu-latest

steps:
  - script: pip install prsentinel-cli
  - script: prsentinel review --post-to-azure --provider groq
    env:
      AZURE_DEVOPS_TOKEN: $(AzureDevOpsToken)
      GROQ_API_KEY: $(GroqApiKey)
```

Create a personal access token with Code (Read & Write) scope, add it as
a secret pipeline variable named `AzureDevOpsToken`, and add `GroqApiKey`
alongside it. Azure DevOps has no endpoint that returns a ready-made diff
the way the others do, so this fetches changed file contents and builds
the diff itself; expect it to make a few more requests per review than on
GitHub, GitLab, or Bitbucket, especially on pull requests touching many
files.

## Quickstart: pre-commit hook

PR Sentinel also works as a [pre-commit](https://pre-commit.com) hook, so
you catch problems before they are even pushed. Add this to your
`.pre-commit-config.yaml`:

```yaml
repos:
  - repo: https://github.com/Lethe044/prsentinel
    rev: v1.1.0
    hooks:
      - id: prsentinel
```

This reviews your staged changes every time you run `git commit`, using
whichever provider and API key you have configured locally.

## Quickstart: command line

```bash
pip install prsentinel-cli

export GROQ_API_KEY=your-key-here
prsentinel review --base origin/main --head HEAD
```

This prints a table of findings straight to your terminal, before you even
push. Combine it with a pre-push git hook if you want a check before code
leaves your machine at all.

## Choosing a provider

| Provider  | Cost                          | Setup                                                             |
|-----------|--------------------------------|--------------------------------------------------------------------|
| groq      | Free tier                     | API key from console.groq.com/keys, set `GROQ_API_KEY`             |
| gemini    | Free tier                     | API key from aistudio.google.com/apikey, set `GEMINI_API_KEY`      |
| ollama    | Free, fully local             | Run `ollama serve` and pull a model, no key needed                 |
| openai    | Paid, bring your own key      | Set `OPENAI_API_KEY`                                                |
| anthropic | Paid, bring your own key      | Set `ANTHROPIC_API_KEY`                                             |

Run `prsentinel providers` at any time to see this list along with the
default model used for each one.

## Configuration

Run `prsentinel init` to write a starter `.prsentinel.yml` in your
repository root. Every field is optional and falls back to a sensible
default if the file does not exist at all. Pass `--preset security`,
`--preset frontend`, or `--preset backend` to pre-fill `custom_rules` with
a ready made rule set instead of starting from an empty list.

```yaml
provider: groq
model:
severity_threshold: suggestion
fail_on: critical
max_files: 60
max_diff_lines_per_chunk: 350
ignore:
  - "*.lock"
  - "dist/**"
  - "node_modules/**"
  - "vendor/**"
include: []
respect_gitignore: true
custom_rules:
  - "Flag any hardcoded API keys or secrets"
  - "Require a docstring on every public function"
post_summary_comment: true
inline_comments: true
request_changes_on_critical: true
cache_enabled: true
max_workers: 4
show_footer: true
min_confidence: low
category_severity_floor:
  security: warning
enable_suppression_comments: true
suggested_code: true
comment_language: english
min_request_interval: 0
notify_webhook_url:
notify_webhook_format: slack
notify_on: critical
```

`custom_rules` is where PR Sentinel becomes specific to your project. Add
plain English instructions and they get appended to every review prompt,
alongside the general review.

`fail_on` controls the exit code (and therefore whether your CI check goes
red). Set it to `warning` for a stricter gate, or `suggestion` for the
strictest possible one.

`max_workers` controls how many diff chunks are reviewed at the same time.
Raising it speeds up large pull requests, at the cost of hitting a free
tier rate limit sooner.

Run `prsentinel validate-config` at any time to check a `.prsentinel.yml`
file for typos or invalid values without running a full review, useful as
a quick sanity check in CI before the real review step runs.

## Command line reference

```
prsentinel review           Review a diff and report findings
prsentinel summarize        Suggest a PR title and description from a diff
prsentinel init              Write a starter .prsentinel.yml
prsentinel validate-config   Check a .prsentinel.yml file for problems
prsentinel providers         List providers and setup instructions
prsentinel clear-cache       Delete the local review cache
prsentinel stats             Show how much is stored in the local cache
prsentinel doctor            Check your environment for common setup problems
```

Useful flags on `review`:

```
--base, --head        Git refs to diff (defaults to origin/main...HEAD)
--staged              Review staged changes instead of a branch diff
--diff-file           Review a saved unified diff file instead of running git
--provider, --model   Override the provider or model from config
--output              terminal (default), json, sarif, html, or junit
--output-file         Write json/sarif/html/junit output to a file
--post-to-github      Post results as a review on the current GitHub Actions PR
--post-to-gitlab      Post results as notes on the current GitLab CI merge request
--post-to-bitbucket   Post results as comments on the current Bitbucket Pipelines PR
--post-to-azure       Post results as comments on the current Azure DevOps PR
--only                Only review files matching this glob (repeatable)
--dry-run             Compute the review but do not post anything, just print it
--fail-on             Override the fail_on threshold for this run
--no-cache            Skip the local response cache for this run
```

## Suggesting a PR title and description

```bash
prsentinel summarize --base origin/main --head HEAD
```

Reads the same kind of diff as `review`, but instead of finding problems it
proposes a conventional-commit style title, a short summary, and a few
highlights. Handy when you are about to open a pull request and would
rather not write the description from scratch.

## Quickstart: Docker

If you would rather not install Python, a ready to use image is published
on every release:

```bash
docker run --rm -v "$(pwd):/workspace" -e GROQ_API_KEY \
  ghcr.io/lethe044/prsentinel:latest review --base origin/main --head HEAD
```

Mount your repository at `/workspace` and pass whichever provider key you
are using as an environment variable. This works the same way in any CI
system that can run a Docker image, not just GitHub Actions or GitLab CI.

## Silencing a specific finding

Sometimes a flagged line is genuinely fine for reasons the model cannot
see. Silence it the same way you would silence a linter, with a comment
near the line:

```python
eval(trusted_internal_config)  # prsentinel-ignore-line
```

```python
# prsentinel-ignore-next-line
eval(trusted_internal_config)
```

Add `# prsentinel-ignore-file` anywhere in a file to skip it entirely (for
example, a generated file that should never be reviewed). This works with
any comment syntax, since only the marker text itself is matched. Turn it
off globally with `enable_suppression_comments: false` in
`.prsentinel.yml` if you would rather not have this escape hatch at all.

## Confidence and category severity floors

Every finding also carries a confidence level (low, medium, or high),
based on how sure the model is. Set `min_confidence: high` in
`.prsentinel.yml` if you only want the findings it is fairly certain about.

`category_severity_floor` forces a minimum severity for a category no
matter what the model assigned, which is on by default for security
findings (`security: warning`) so a model having an off day never quietly
downgrades a real security issue to a suggestion.

## Focusing a review with include patterns

In a monorepo, you might only want PR Sentinel looking at one part of the
codebase. Set `include` in `.prsentinel.yml`, or pass `--only` on the
command line (repeatable):

```bash
prsentinel review --only "backend/**" --only "*.py"
```

An empty `include` list (the default) means every changed file that is
not ignored gets reviewed, same as before.

## Token usage

Since this tool is built around free tier APIs, PR Sentinel reports how
many tokens a review actually used, when the provider includes that in
its response (Groq, Gemini, OpenAI, Anthropic, and Ollama all do):

```
Tokens used: 530 (450 prompt, 80 completion)
```

This also appears in `--output json` under a `usage` key, so you can track
it over time if you want to keep an eye on a free tier quota.

## Drop-in code fixes

Where a finding maps to a small, well defined change, PR Sentinel asks the
model for a ready to paste fix alongside the explanation, shown as a code
block right under the finding. Set `suggested_code: false` in
`.prsentinel.yml` if you would rather only see explanations.

## Reviewing in another language

Set `comment_language` in `.prsentinel.yml` (for example `turkish`,
`spanish`, or `japanese`) and PR Sentinel writes every explanation,
suggestion, and the output of `prsentinel summarize` in that language.
Category and severity values stay in English internally, so filtering and
`fail_on` behave exactly the same regardless of the language you choose.

## Reliability on a free tier

Every provider automatically retries a rate limited or temporarily
unavailable request a few times with backoff, honoring the server's
`Retry-After` header when it sends one, before giving up. If you are
still hitting rate limits on a large pull request, set
`min_request_interval` in `.prsentinel.yml` to add a small pause between
the start of each chunk's request.

## Notifications

Set `notify_webhook_url` to a Slack or Discord incoming webhook URL and
PR Sentinel posts a short summary there whenever a review finds something
at or above the `notify_on` severity (critical by default). Set
`notify_webhook_format: discord` if the URL is a Discord webhook.

## CI systems without native support (JUnit XML)

Run with `--output junit --output-file results.xml` to get a JUnit XML
report, which Jenkins, CircleCI, Azure DevOps, and Bitbucket's own test
report tab all know how to render natively, without a GitHub or GitLab
integration.

## Editor autocompletion for the config file

`.prsentinel.yml` files written by `prsentinel init` include a
`yaml-language-server` schema hint, so editors with the YAML extension
(VS Code, most JetBrains IDEs) autocomplete fields and flag typos as you
type. The schema itself lives at
[`prsentinel.schema.json`](prsentinel.schema.json) in this repository.

## How review comments look

PR Sentinel posts one summary comment with a small table of counts by
severity, followed by a breakdown per file, and inline comments on the
exact lines a finding refers to. If a critical issue is found and
`request_changes_on_critical` is enabled, the review is submitted as
"Request changes" instead of a plain comment, so it behaves like a real
review a teammate would leave.

## Uploading findings to the GitHub Security tab

If you would rather see findings in GitHub's Security tab alongside your
other code scanning results, export SARIF and upload it with the
official action, as a step alongside (or instead of) the PR comment
action:

```yaml
- uses: actions/checkout@v4
  with:
    fetch-depth: 0
- run: pip install prsentinel-cli
- run: |
    prsentinel review --base origin/${{ github.base_ref }} --head HEAD \
      --output sarif --output-file results.sarif --fail-on suggestion || true
  env:
    GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
- uses: github/codeql-action/upload-sarif@v3
  if: always()
  with:
    sarif_file: results.sarif
```

`fetch-depth: 0` is needed so the base branch is available to diff
against. The `|| true` keeps the step green even when findings are
reported, since the upload step is what should reflect them, not this
one. For most people the PR comments from the main action are enough on
their own; this is for teams that already have a Security tab workflow
and want PR Sentinel findings to show up there too.

## Limitations, on purpose

PR Sentinel reviews diffs, not your entire codebase, and it does not
replace a human reviewer. Language models make mistakes, including missing
real issues and occasionally flagging something that is not actually a
problem. Treat its output the way you would treat a review from a
thorough but fallible colleague: worth reading, not worth merging blindly
on faith either way. `custom_rules` and the `severity_threshold` and
`fail_on` settings let you tune how much weight to give it in your
workflow.

## Shell completion

PR Sentinel is built on [Click](https://click.palletsprojects.com), which
provides tab completion for free. Add one of these to your shell's
startup file:

```bash
# Bash (~/.bashrc)
eval "$(_PRSENTINEL_COMPLETE=bash_source prsentinel)"

# Zsh (~/.zshrc)
eval "$(_PRSENTINEL_COMPLETE=zsh_source prsentinel)"

# Fish (~/.config/fish/completions/prsentinel.fish)
_PRSENTINEL_COMPLETE=fish_source prsentinel | source
```

Open a new shell and `prsentinel review --pro<TAB>` completes to
`--provider`.

## Contributing

Bug reports, feature requests, and pull requests are welcome. See
[CONTRIBUTING.md](CONTRIBUTING.md) for how to get set up locally, how the
provider interface works, and what a good pull request looks like here.

## License

MIT. See [LICENSE](LICENSE).
