Skip to main content

AI-assisted code review tool for GitHub pull requests.

Project description

🛡️ GitOwl

AI-assisted code review for GitHub pull requests.

GitOwl combines a traditional static analyser (Semgrep) with an AI reasoning layer that contextualises findings, filters false positives, flags risky changes, and scores overall PR risk — so human reviewers focus on what matters.

PR opened → GitHub Action → Semgrep scans diff → AI filters + reasons
          → risk score (Low/Medium/High) → structured PR comment

License: MIT · Public, solo-maintained, open to contributions. See CONTRIBUTING.md and PROJECT_BRAIN.md.


Add GitOwl to your repo (3 steps)

Get automated AI review comments on every pull request:

  1. Copy the workflow — save examples/gitowl-review.yml into your repo at .github/workflows/gitowl-review.yml. It runs pip install gitowl.
  2. Add your key — in your repo, go to Settings → Secrets and variables → Actions and add a secret AI_API_KEY (your OpenRouter or OpenAI key).
  3. Open a PR — GitOwl reviews the diff and posts a comment automatically.

Defaults to OpenRouter + openai/gpt-4o-mini. Override with repo variables AI_PROVIDER / AI_MODEL / AI_BASE_URL. Want static analysis too? Use pip install "gitowl[semgrep]" in the workflow.


Quick start (local)

python -m venv .venv
.venv\Scripts\activate            # Windows  (macOS/Linux: source .venv/bin/activate)
pip install -r requirements.txt
pip install -r requirements-dev.txt

cp .env.example .env              # then edit .env with your provider + key

Review a diff locally

# From a saved diff
python -m gitowl.cli review-diff my.diff

# From git, piped in
git diff main...HEAD | python -m gitowl.cli review-diff -

# Skip static analysis (AI only)
python -m gitowl.cli review-diff my.diff --no-semgrep

Review a GitHub PR

# Print the review
python -m gitowl.cli review-pr MarutiDubey/GitOwl 42

# Post/update the review as a PR comment
python -m gitowl.cli review-pr MarutiDubey/GitOwl 42 --post

# ...and post committable fixes as inline suggestions (GitHub's one-click
# "Commit suggestion" button). Only findings whose fix lands on a changed
# line are posted; the rest stay in the summary comment.
python -m gitowl.cli review-pr MarutiDubey/GitOwl 42 --post --suggest

Describe a PR (auto-generated description)

Generate a clear PR description (title + summary + change list) from a diff:

# From a diff (file or stdin) — prints the description
python -m gitowl.cli describe-diff my.diff
git diff main...HEAD | python -m gitowl.cli describe-diff -

# From a GitHub PR — print it
python -m gitowl.cli describe-pr MarutiDubey/GitOwl 42

# ...or write it into the PR body (between GitOwl markers, preserving your text)
python -m gitowl.cli describe-pr MarutiDubey/GitOwl 42 --post

--post only replaces GitOwl's own marked section, so any description you wrote by hand stays intact.

List AI providers

python -m gitowl.cli providers

AI providers

GitOwl is provider-agnostic. Set AI_PROVIDER in .env:

AI_PROVIDER Notes
openrouter Default. One key, many models. Set AI_API_KEY.
openai Direct OpenAI API. Set AI_API_KEY.
ollama Local, free, offline. Run ollama serve first — no key needed.

See gitowl/ai_client/README.md to add a provider.

⚠️ Never commit your .env or API keys. .env is git-ignored by default.


Configuration (.gitowl.toml)

Drop a .gitowl.toml file at your repo root to set project-wide review policy. It's committed to the repo, so the whole team shares the same rules.

[review]
# Hide findings below this level. One of: info | warning | error.
# Default "info" reports everything.
min_severity = "warning"

# Glob patterns for files GitOwl should not report findings on.
# Matches nested paths (e.g. "*.md" also matches "docs/x.md").
ignore_paths = ["tests/**", "**/*.md", "vendor/**"]

[ai]
# Optional: pin the model for this repo (env AI_MODEL still overrides).
model = "openai/gpt-4o-mini"

[pricing]
# Optional: override or add model prices, as [input, output] USD per 1M tokens.
# GitOwl ships prices for common models; add your own for anything else.
"my-org/private-model" = [2.0, 8.0]

Precedence (lowest to highest): built-in defaults → .gitowl.toml → environment variables. So the repo file sets the baseline, and a CI secret or a shell export can always override it for a single run. API keys are never read from this file — they stay in .env / environment only.

Everything is optional; with no file present, GitOwl behaves exactly as before (reports every finding, ignores nothing).

Cost & latency

Each review call's token usage, estimated cost, and latency are logged and shown in a small footer line on the PR comment, e.g.:

Generated by GitOwl · openai/gpt-4o-mini · 1,560 tok · ~$0.0004 · 1,834ms

Cost is estimated from the built-in price table plus any [pricing] overrides; an unpriced model shows cost unknown rather than a wrong number.

Fix suggestions

When the model is confident of a concrete fix, it includes drop-in replacement code, rendered under the finding as a suggestion block:

  • 🔴 Weak password hash (auth.py:12, ai) MD5 is broken; use SHA-256.
    ```suggestion
    return hashlib.sha256(pw.encode()).hexdigest()
    ```
    

The code is kept verbatim so you can copy it straight in. (Posting these as inline, one-click-committable review comments is a planned follow-up.)


GitHub Action

.github/workflows/gitowl-review.yml runs GitOwl on every PR (opened / synchronize / reopened) and posts a review comment.

Configure in your repo settings:

  • Secret AI_API_KEY — your provider key.
  • Variables (optional) AI_PROVIDER, AI_MODEL, AI_BASE_URL — default to OpenRouter + gpt-4o-mini.

GITHUB_TOKEN is provided automatically by Actions.


Eval harness

Measure GitOwl's review quality against a corpus of diffs with known seeded bugs — precision / recall / F1. Runs offline and deterministically by default.

python -m gitowl.eval                  # mock provider (offline, no key)
python -m gitowl.eval --live           # score the real provider from .env
python -m gitowl.eval --json           # machine-readable output
python -m gitowl.eval --fail-under 0.9 # exit non-zero if aggregate F1 < 0.9

The corpus ships 12 cases (weak hash, eval, hardcoded secret, SQL injection incl. f-string, unsafe pickle, a multi-bug diff, plus benign/clean cases and a few categories the offline mock intentionally can't catch). The mock baseline is precision 1.00 / recall 0.73 / F1 0.84 — deliberately below 1.0 so the scoring math is genuinely exercised (a real provider via --live should do better). Cases live in gitowl/eval/cases/ as <name>.diff + <name>.expected.json pairs — add your own to grow the corpus.

Development

pytest --cov=gitowl          # tests
ruff check gitowl tests      # lint
black . && isort .             # format
mypy gitowl                  # types
pre-commit run --all-files     # all hooks

Roadmap and phases live in CONTRIBUTING.md §1.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

gitowl-0.1.0.tar.gz (55.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

gitowl-0.1.0-py3-none-any.whl (51.5 kB view details)

Uploaded Python 3

File details

Details for the file gitowl-0.1.0.tar.gz.

File metadata

  • Download URL: gitowl-0.1.0.tar.gz
  • Upload date:
  • Size: 55.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for gitowl-0.1.0.tar.gz
Algorithm Hash digest
SHA256 462458b16e3a3a438c9b32fed5452a3c87f2811700860068ac6060efe409900d
MD5 e909f5266688a4265526f4186834dfd3
BLAKE2b-256 54dfad12e4d74fb6d685ff256d623078fddffa1c611ae4142c9d1dae63616acb

See more details on using hashes here.

Provenance

The following attestation bundles were made for gitowl-0.1.0.tar.gz:

Publisher: publish.yml on MarutiDubey/GitOwl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file gitowl-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: gitowl-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 51.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for gitowl-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b59ef6c77d16f593fb8373424fbe94f5b732ad0b49c08de7bf3c3537311f5537
MD5 bc84e7e4355f4099f268051929a750a6
BLAKE2b-256 864ad9ebcc20cd7c15f182c86ca8e491558d984f42352a03c22dca4b6678efa2

See more details on using hashes here.

Provenance

The following attestation bundles were made for gitowl-0.1.0-py3-none-any.whl:

Publisher: publish.yml on MarutiDubey/GitOwl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page