Metadata-Version: 2.4
Name: gitowl
Version: 0.1.0
Summary: AI-assisted code review tool for GitHub pull requests.
Author: GitOwl maintainers
License: MIT
Project-URL: Homepage, https://github.com/MarutiDubey/GitOwl
Project-URL: Repository, https://github.com/MarutiDubey/GitOwl
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Quality Assurance
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: httpx==0.28.1
Requires-Dist: python-dotenv==1.0.1
Requires-Dist: unidiff==0.7.5
Provides-Extra: semgrep
Requires-Dist: semgrep==1.97.0; extra == "semgrep"
Dynamic: license-file

﻿# 🛡️ 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](CONTRIBUTING.md) and [PROJECT_BRAIN.md](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`](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)

```bash
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

```bash
# 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

```bash
# 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:

```bash
# 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

```bash
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`](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.

```toml
[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.

```bash
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/`](gitowl/eval/cases/) as
`<name>.diff` + `<name>.expected.json` pairs — add your own to grow the corpus.

## Development

```bash
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](CONTRIBUTING.md#1-development-roadmap).
