pr-context-engine 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pr_context_engine-0.1.0/.env.example +30 -0
- pr_context_engine-0.1.0/.github/ISSUE_TEMPLATE/bug_report.md +24 -0
- pr_context_engine-0.1.0/.github/ISSUE_TEMPLATE/feature_request.md +16 -0
- pr_context_engine-0.1.0/.github/pull_request_template.md +15 -0
- pr_context_engine-0.1.0/.github/workflows/pr-review.yml +59 -0
- pr_context_engine-0.1.0/.github/workflows/release.yml +44 -0
- pr_context_engine-0.1.0/.gitignore +24 -0
- pr_context_engine-0.1.0/.python-version +1 -0
- pr_context_engine-0.1.0/CHANGELOG.md +22 -0
- pr_context_engine-0.1.0/CODE_OF_CONDUCT.md +27 -0
- pr_context_engine-0.1.0/CONFIG.md +80 -0
- pr_context_engine-0.1.0/CONTRIBUTING.md +60 -0
- pr_context_engine-0.1.0/LICENSE +21 -0
- pr_context_engine-0.1.0/PKG-INFO +211 -0
- pr_context_engine-0.1.0/PROJECT.md +481 -0
- pr_context_engine-0.1.0/README.md +181 -0
- pr_context_engine-0.1.0/action.yml +62 -0
- pr_context_engine-0.1.0/docs/design-decisions.md +87 -0
- pr_context_engine-0.1.0/pyproject.toml +57 -0
- pr_context_engine-0.1.0/src/__init__.py +1 -0
- pr_context_engine-0.1.0/src/analyzers/__init__.py +1 -0
- pr_context_engine-0.1.0/src/analyzers/ast_walker.py +91 -0
- pr_context_engine-0.1.0/src/analyzers/diff_parser.py +158 -0
- pr_context_engine-0.1.0/src/analyzers/risk_scorer.py +121 -0
- pr_context_engine-0.1.0/src/briefing/__init__.py +5 -0
- pr_context_engine-0.1.0/src/briefing/generator.py +229 -0
- pr_context_engine-0.1.0/src/briefing/prompt_templates.py +67 -0
- pr_context_engine-0.1.0/src/cli.py +329 -0
- pr_context_engine-0.1.0/src/config.py +118 -0
- pr_context_engine-0.1.0/src/context/__init__.py +1 -0
- pr_context_engine-0.1.0/src/context/codebase_index.py +382 -0
- pr_context_engine-0.1.0/src/context/git_history.py +225 -0
- pr_context_engine-0.1.0/src/fixes/__init__.py +1 -0
- pr_context_engine-0.1.0/src/fixes/confidence.py +60 -0
- pr_context_engine-0.1.0/src/fixes/fix_generator.py +152 -0
- pr_context_engine-0.1.0/src/github_api/__init__.py +3 -0
- pr_context_engine-0.1.0/src/github_api/comment_poster.py +95 -0
- pr_context_engine-0.1.0/src/llm/__init__.py +106 -0
- pr_context_engine-0.1.0/src/llm/anthropic_provider.py +32 -0
- pr_context_engine-0.1.0/src/llm/base.py +11 -0
- pr_context_engine-0.1.0/src/llm/gemini_provider.py +33 -0
- pr_context_engine-0.1.0/src/llm/groq_provider.py +30 -0
- pr_context_engine-0.1.0/src/llm/ollama_provider.py +41 -0
- pr_context_engine-0.1.0/tests/__init__.py +0 -0
- pr_context_engine-0.1.0/tests/eval/__init__.py +0 -0
- pr_context_engine-0.1.0/tests/eval/fixtures/01-simple-refactor.json +10 -0
- pr_context_engine-0.1.0/tests/eval/fixtures/02-auth-middleware.json +10 -0
- pr_context_engine-0.1.0/tests/eval/fixtures/03-db-migration.json +10 -0
- pr_context_engine-0.1.0/tests/eval/fixtures/04-config-update.json +10 -0
- pr_context_engine-0.1.0/tests/eval/fixtures/05-public-api-deleted.json +10 -0
- pr_context_engine-0.1.0/tests/eval/fixtures/06-hardcoded-api-key.json +15 -0
- pr_context_engine-0.1.0/tests/eval/fixtures/07-token-in-url.json +15 -0
- pr_context_engine-0.1.0/tests/eval/fixtures/08-retry-no-limit.json +15 -0
- pr_context_engine-0.1.0/tests/eval/fixtures/09-missing-null-check.json +15 -0
- pr_context_engine-0.1.0/tests/eval/fixtures/10-trivial-docfix.json +10 -0
- pr_context_engine-0.1.0/tests/eval/fixtures/11-multi-flag.json +10 -0
- pr_context_engine-0.1.0/tests/eval/fixtures/12-new-endpoint.json +10 -0
- pr_context_engine-0.1.0/tests/eval/fixtures/13-auth-bypass.json +15 -0
- pr_context_engine-0.1.0/tests/eval/fixtures/14-env-file-update.json +10 -0
- pr_context_engine-0.1.0/tests/eval/fixtures/15-dependency-update.json +10 -0
- pr_context_engine-0.1.0/tests/eval/rubric.md +95 -0
- pr_context_engine-0.1.0/tests/eval/test_briefings.py +543 -0
- pr_context_engine-0.1.0/tests/unit/__init__.py +0 -0
- pr_context_engine-0.1.0/tests/unit/test_anthropic_provider.py +39 -0
- pr_context_engine-0.1.0/tests/unit/test_ast_walker.py +100 -0
- pr_context_engine-0.1.0/tests/unit/test_briefing_generator.py +203 -0
- pr_context_engine-0.1.0/tests/unit/test_codebase_index.py +279 -0
- pr_context_engine-0.1.0/tests/unit/test_config.py +82 -0
- pr_context_engine-0.1.0/tests/unit/test_diff_parser.py +127 -0
- pr_context_engine-0.1.0/tests/unit/test_failover_provider.py +189 -0
- pr_context_engine-0.1.0/tests/unit/test_fix_generator.py +393 -0
- pr_context_engine-0.1.0/tests/unit/test_gemini_provider.py +34 -0
- pr_context_engine-0.1.0/tests/unit/test_git_history.py +319 -0
- pr_context_engine-0.1.0/tests/unit/test_groq_provider.py +34 -0
- pr_context_engine-0.1.0/tests/unit/test_ollama_provider.py +55 -0
- pr_context_engine-0.1.0/tests/unit/test_risk_scorer.py +178 -0
- pr_context_engine-0.1.0/uv.lock +1460 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Copy this file to .env for local development. .env is gitignored — never commit it.
|
|
2
|
+
|
|
3
|
+
# ── Provider selection ────────────────────────────────────────────────────────
|
|
4
|
+
# Choose: groq (default) | gemini | ollama | anthropic
|
|
5
|
+
LLM_PROVIDER=groq
|
|
6
|
+
|
|
7
|
+
# ── Provider keys (only the selected provider's key is required) ──────────────
|
|
8
|
+
|
|
9
|
+
# Free Groq API key (no credit card): https://console.groq.com/keys
|
|
10
|
+
GROQ_API_KEY=your-groq-api-key-here
|
|
11
|
+
|
|
12
|
+
# Google Gemini key (fallback): https://aistudio.google.com/apikey
|
|
13
|
+
GEMINI_API_KEY=your-gemini-api-key-here
|
|
14
|
+
|
|
15
|
+
# Anthropic Claude key (BYO): https://console.anthropic.com/settings/keys
|
|
16
|
+
ANTHROPIC_API_KEY=your-anthropic-api-key-here
|
|
17
|
+
|
|
18
|
+
# Ollama (local, no key needed — just run `ollama serve`)
|
|
19
|
+
# OLLAMA_BASE_URL=http://localhost:11434
|
|
20
|
+
# OLLAMA_MODEL=qwen2.5-coder:7b
|
|
21
|
+
|
|
22
|
+
# ── GitHub ────────────────────────────────────────────────────────────────────
|
|
23
|
+
# A GitHub token with `pull-requests: write` scope.
|
|
24
|
+
# Locally, you can generate one with: gh auth token
|
|
25
|
+
GITHUB_TOKEN=your-github-token-here
|
|
26
|
+
|
|
27
|
+
# ── Fix suggestions (opt-in) ──────────────────────────────────────────────────
|
|
28
|
+
# Set to true to generate confidence-gated patch suggestions. Default: false.
|
|
29
|
+
# See CONFIG.md for full details.
|
|
30
|
+
ENABLE_FIXES=false
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Bug report
|
|
3
|
+
about: Something isn't working
|
|
4
|
+
labels: bug
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**What happened**
|
|
8
|
+
<!-- A clear description of the bug. -->
|
|
9
|
+
|
|
10
|
+
**To reproduce**
|
|
11
|
+
```bash
|
|
12
|
+
# Command you ran
|
|
13
|
+
pr-context-engine review --pr N --repo owner/name
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
**Expected behaviour**
|
|
17
|
+
|
|
18
|
+
**Actual behaviour** (include the full error / log output)
|
|
19
|
+
|
|
20
|
+
**Environment**
|
|
21
|
+
- OS:
|
|
22
|
+
- Python version (`python --version`):
|
|
23
|
+
- Package version (`pr-context-engine --version` or `pip show pr-context-engine`):
|
|
24
|
+
- LLM provider (`LLM_PROVIDER` value):
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Feature request
|
|
3
|
+
about: Suggest an improvement
|
|
4
|
+
labels: enhancement
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**What problem does this solve?**
|
|
8
|
+
<!-- Describe the use case, not the implementation. -->
|
|
9
|
+
|
|
10
|
+
**What should the solution look like?**
|
|
11
|
+
|
|
12
|
+
**Alternatives you've considered**
|
|
13
|
+
|
|
14
|
+
**Would you be willing to open a PR?**
|
|
15
|
+
- [ ] Yes
|
|
16
|
+
- [ ] No
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
## What changed
|
|
2
|
+
|
|
3
|
+
<!-- 2-3 sentences on the intent, not the line count. -->
|
|
4
|
+
|
|
5
|
+
## Why
|
|
6
|
+
|
|
7
|
+
<!-- Link to the issue this closes, or explain the motivation. -->
|
|
8
|
+
|
|
9
|
+
## Checklist
|
|
10
|
+
|
|
11
|
+
- [ ] `uv run ruff check src/ tests/` passes
|
|
12
|
+
- [ ] `uv run pytest tests/unit/ -v` passes
|
|
13
|
+
- [ ] New behaviour is covered by a unit test
|
|
14
|
+
- [ ] `CONFIG.md` updated if new env vars were added
|
|
15
|
+
- [ ] `CHANGELOG.md` entry added under `## Unreleased`
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
name: PR Context Briefing
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
types: [opened, synchronize, reopened]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
lint:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
steps:
|
|
11
|
+
- uses: actions/checkout@v4
|
|
12
|
+
- uses: actions/setup-python@v5
|
|
13
|
+
with:
|
|
14
|
+
python-version: "3.12"
|
|
15
|
+
- name: Install uv
|
|
16
|
+
run: pip install uv
|
|
17
|
+
- name: Install dev dependencies
|
|
18
|
+
run: uv sync --group dev
|
|
19
|
+
- name: Lint
|
|
20
|
+
run: uv run ruff check src/ tests/
|
|
21
|
+
|
|
22
|
+
brief:
|
|
23
|
+
needs: lint
|
|
24
|
+
runs-on: ubuntu-latest
|
|
25
|
+
permissions:
|
|
26
|
+
pull-requests: write
|
|
27
|
+
contents: read
|
|
28
|
+
steps:
|
|
29
|
+
- uses: actions/checkout@v4
|
|
30
|
+
with:
|
|
31
|
+
fetch-depth: 50 # tradeoff: enough history for most files, fast clone; see Milestone 6 note
|
|
32
|
+
|
|
33
|
+
- uses: actions/setup-python@v5
|
|
34
|
+
with:
|
|
35
|
+
python-version: "3.12"
|
|
36
|
+
|
|
37
|
+
- name: Install uv
|
|
38
|
+
run: pip install uv
|
|
39
|
+
|
|
40
|
+
- name: Restore index cache
|
|
41
|
+
uses: actions/cache@v4
|
|
42
|
+
with:
|
|
43
|
+
path: index.db
|
|
44
|
+
key: pr-engine-index-${{ github.event.pull_request.base.sha }}
|
|
45
|
+
restore-keys: pr-engine-index-
|
|
46
|
+
|
|
47
|
+
- name: Install dependencies
|
|
48
|
+
run: uv sync
|
|
49
|
+
|
|
50
|
+
- name: Generate briefing
|
|
51
|
+
env:
|
|
52
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
53
|
+
LLM_PROVIDER: groq
|
|
54
|
+
GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
|
|
55
|
+
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }} # fallback (Milestone 7)
|
|
56
|
+
run: >
|
|
57
|
+
uv run pr-context-engine review
|
|
58
|
+
--pr ${{ github.event.pull_request.number }}
|
|
59
|
+
--repo ${{ github.repository }}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
build:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
|
|
14
|
+
- uses: actions/setup-python@v5
|
|
15
|
+
with:
|
|
16
|
+
python-version: "3.12"
|
|
17
|
+
|
|
18
|
+
- name: Install uv
|
|
19
|
+
run: pip install uv
|
|
20
|
+
|
|
21
|
+
- name: Build distribution
|
|
22
|
+
run: uv build
|
|
23
|
+
|
|
24
|
+
- name: Upload dist artifact
|
|
25
|
+
uses: actions/upload-artifact@v4
|
|
26
|
+
with:
|
|
27
|
+
name: dist
|
|
28
|
+
path: dist/
|
|
29
|
+
|
|
30
|
+
publish:
|
|
31
|
+
needs: build
|
|
32
|
+
runs-on: ubuntu-latest
|
|
33
|
+
environment: pypi
|
|
34
|
+
permissions:
|
|
35
|
+
id-token: write # required for Trusted Publishing (OIDC — no PyPI token secret needed)
|
|
36
|
+
steps:
|
|
37
|
+
- name: Download dist artifact
|
|
38
|
+
uses: actions/download-artifact@v4
|
|
39
|
+
with:
|
|
40
|
+
name: dist
|
|
41
|
+
path: dist/
|
|
42
|
+
|
|
43
|
+
- name: Publish to PyPI
|
|
44
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Byte-compiled / cached Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
|
|
5
|
+
# Packaging / build artifacts
|
|
6
|
+
build/
|
|
7
|
+
dist/
|
|
8
|
+
*.egg-info/
|
|
9
|
+
|
|
10
|
+
# Virtual environment
|
|
11
|
+
.venv/
|
|
12
|
+
|
|
13
|
+
# Local secrets — never commit (see .env.example)
|
|
14
|
+
.env
|
|
15
|
+
|
|
16
|
+
# Test / tooling caches
|
|
17
|
+
.pytest_cache/
|
|
18
|
+
.ruff_cache/
|
|
19
|
+
|
|
20
|
+
# Generated codebase index (Milestone 5)
|
|
21
|
+
index.db
|
|
22
|
+
|
|
23
|
+
# Eval run output — generated on each run, not committed
|
|
24
|
+
tests/eval/scores.jsonl
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). This project uses [semantic versioning](https://semver.org/).
|
|
6
|
+
|
|
7
|
+
## Unreleased
|
|
8
|
+
|
|
9
|
+
## 0.1.0 — 2026-05-17
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- **Milestone 1** — End-to-end skeleton: Typer CLI entrypoint (`pr-context-engine review`), Groq LLM provider, GitHub diff fetch and PR comment posting, GitHub Actions workflow.
|
|
14
|
+
- **Milestone 2** — Pluggable LLM providers: `LLMProvider` abstract base, Gemini, Ollama, and Anthropic implementations, `LLM_PROVIDER` env var switching.
|
|
15
|
+
- **Milestone 3** — Real diff analysis: `diff_parser`, `ast_walker` (function/class name extraction), `risk_scorer` with located-issue objects (`file`, `line`, `snippet`).
|
|
16
|
+
- **Milestone 4** — Senior-voice prompt and structured briefing: four-section markdown output (What changed / Blast radius / Risk flags / Questions), terse system prompt.
|
|
17
|
+
- **Milestone 5** — Codebase index (RAG): `sqlite-vec` + `fastembed` local embeddings, semantic similar-chunk retrieval, `actions/cache` integration.
|
|
18
|
+
- **Milestone 6** — Git history context: per-file commit history, recent merged PR lookup, graceful shallow-clone degradation.
|
|
19
|
+
- **Milestone 7** — Provider failover: `FailoverProvider` (Groq → Gemini on 429), provider attribution in PR comment footer, unit test for failover path.
|
|
20
|
+
- **Milestone 8** — Confidence-gated fix suggestions: `fix_generator`, confidence gate (`high`/`medium` → suggestion block, `low` → prose), collapsed `<details>` + GitHub suggestion blocks, `ENABLE_FIXES` kill switch.
|
|
21
|
+
- **Milestone 9** — Eval harness: LLM-as-judge scoring across 5 rubric dimensions + fix correctness + calibration rate, `pytest tests/eval/` scorecard.
|
|
22
|
+
- **Milestone 10** — Open-source readiness: `action.yml` for one-line GitHub Action install, `--dry-run` flag, `quickstart` command, `LICENSE` (MIT), `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, `CONFIG.md`, PyPI metadata, issue/PR templates.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Code of Conduct
|
|
2
|
+
|
|
3
|
+
## Our Pledge
|
|
4
|
+
|
|
5
|
+
We pledge to make participation in this project a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
|
6
|
+
|
|
7
|
+
## Our Standards
|
|
8
|
+
|
|
9
|
+
Examples of behavior that contributes to a positive environment:
|
|
10
|
+
|
|
11
|
+
- Using welcoming and inclusive language
|
|
12
|
+
- Being respectful of differing viewpoints and experiences
|
|
13
|
+
- Gracefully accepting constructive criticism
|
|
14
|
+
- Focusing on what is best for the community
|
|
15
|
+
|
|
16
|
+
Examples of unacceptable behavior:
|
|
17
|
+
|
|
18
|
+
- Trolling, insulting/derogatory comments, and personal or political attacks
|
|
19
|
+
- Public or private harassment
|
|
20
|
+
- Publishing others' private information without explicit permission
|
|
21
|
+
- Other conduct which could reasonably be considered inappropriate in a professional setting
|
|
22
|
+
|
|
23
|
+
## Enforcement
|
|
24
|
+
|
|
25
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting the maintainer directly. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances.
|
|
26
|
+
|
|
27
|
+
This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 2.1.
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Configuration Reference
|
|
2
|
+
|
|
3
|
+
All configuration is via environment variables or CLI flags. CLI flags take precedence over env vars.
|
|
4
|
+
|
|
5
|
+
## Minimal config (one API key is enough)
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
export GROQ_API_KEY=<your-groq-key>
|
|
9
|
+
export GITHUB_TOKEN=<your-github-token>
|
|
10
|
+
pr-context-engine review --pr 42 --repo owner/name
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Full reference
|
|
14
|
+
|
|
15
|
+
### Provider selection
|
|
16
|
+
|
|
17
|
+
| Env var | Default | Values | Description |
|
|
18
|
+
|---|---|---|---|
|
|
19
|
+
| `LLM_PROVIDER` | `groq` | `groq` \| `gemini` \| `ollama` \| `anthropic` | Primary LLM provider. |
|
|
20
|
+
|
|
21
|
+
### API keys
|
|
22
|
+
|
|
23
|
+
| Env var | Required | Notes |
|
|
24
|
+
|---|---|---|
|
|
25
|
+
| `GROQ_API_KEY` | Yes (if `LLM_PROVIDER=groq`) | Free at https://console.groq.com/keys. ~1 000 req/day. |
|
|
26
|
+
| `GEMINI_API_KEY` | No | Failover when Groq is rate-limited. Also used as primary when `LLM_PROVIDER=gemini`. |
|
|
27
|
+
| `ANTHROPIC_API_KEY` | No | Required only when `LLM_PROVIDER=anthropic`. No free tier. |
|
|
28
|
+
| `GITHUB_TOKEN` | Yes (unless `--dry-run`) | Needs `pull-requests:write`. In Actions, use `${{ secrets.GITHUB_TOKEN }}`. |
|
|
29
|
+
|
|
30
|
+
### Ollama
|
|
31
|
+
|
|
32
|
+
| Env var | Default | Description |
|
|
33
|
+
|---|---|---|
|
|
34
|
+
| `OLLAMA_BASE_URL` | `http://localhost:11434` | Ollama server URL. |
|
|
35
|
+
| `OLLAMA_MODEL` | `qwen2.5-coder:7b` | Model name to use via Ollama. |
|
|
36
|
+
|
|
37
|
+
### Fix suggestions (opt-in)
|
|
38
|
+
|
|
39
|
+
| Env var | CLI flag | Default | Description |
|
|
40
|
+
|---|---|---|---|
|
|
41
|
+
| `ENABLE_FIXES` | `--enable-fixes` / `--no-enable-fixes` | `false` | Generate confidence-gated fix suggestions. Opt-in per repo. See [ADR-5](docs/design-decisions.md). |
|
|
42
|
+
|
|
43
|
+
### Failover
|
|
44
|
+
|
|
45
|
+
Failover to Gemini is **automatic** whenever `GEMINI_API_KEY` is set, regardless of `LLM_PROVIDER`. The PR comment footer shows which provider was actually used (`via groq`, `via gemini (groq rate-limited)`, etc.).
|
|
46
|
+
|
|
47
|
+
To disable auto-failover, set `LLM_PROVIDER=gemini` explicitly — this makes Gemini the primary and there is no automatic fallback.
|
|
48
|
+
|
|
49
|
+
## CLI flags (review command)
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
pr-context-engine review [OPTIONS]
|
|
53
|
+
|
|
54
|
+
--pr INTEGER Pull request number. [required]
|
|
55
|
+
--repo TEXT Repository in owner/name form. [required]
|
|
56
|
+
--github-token TEXT GitHub token. Defaults to GITHUB_TOKEN env var.
|
|
57
|
+
--enable-fixes Generate fix suggestions (default off).
|
|
58
|
+
--no-enable-fixes Disable fix suggestions (default).
|
|
59
|
+
--dry-run Print briefing to stdout; do not post to GitHub.
|
|
60
|
+
--help Show this message and exit.
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## CLI flags (quickstart command)
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
pr-context-engine quickstart
|
|
67
|
+
|
|
68
|
+
Checks whether GROQ_API_KEY, GEMINI_API_KEY, and GITHUB_TOKEN are set and
|
|
69
|
+
whether the GitHub token has the correct scope. Prints exactly what is missing.
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## GitHub Actions example (full config)
|
|
73
|
+
|
|
74
|
+
```yaml
|
|
75
|
+
- uses: paramahastha/pr-context-engine@v1
|
|
76
|
+
with:
|
|
77
|
+
groq-api-key: ${{ secrets.GROQ_API_KEY }}
|
|
78
|
+
gemini-api-key: ${{ secrets.GEMINI_API_KEY }} # optional failover
|
|
79
|
+
enable-fixes: "true" # opt-in fix suggestions
|
|
80
|
+
```
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
## Development setup
|
|
4
|
+
|
|
5
|
+
Requires Python 3.12+ and [`uv`](https://docs.astral.sh/uv/).
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
git clone https://github.com/paramahastha/pr-context-engine
|
|
9
|
+
cd pr-context-engine
|
|
10
|
+
uv sync --group dev
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Copy `.env.example` to `.env` and fill in your API keys.
|
|
14
|
+
|
|
15
|
+
## Running tests
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# Unit tests (fast, no API calls)
|
|
19
|
+
uv run pytest tests/unit/ -v
|
|
20
|
+
|
|
21
|
+
# Eval harness (requires a provider key; uses LLM-as-judge)
|
|
22
|
+
uv run pytest tests/eval/ -v
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Lint
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
uv run ruff check src/ tests/
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Local dry-run
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
export GITHUB_TOKEN=$(gh auth token)
|
|
35
|
+
export GROQ_API_KEY=<your-key>
|
|
36
|
+
uv run pr-context-engine review --pr <N> --repo <owner/name> --dry-run
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Milestone philosophy
|
|
40
|
+
|
|
41
|
+
Each milestone is designed so the next milestone doesn't require painful refactors of the previous one. The key early decisions — CLI-core entrypoint (M1), provider abstraction (M2), and located-issue data shape in the risk scorer (M3) — exist specifically to make M7, M8, and M9 cheap. Don't skip milestones or reorder them.
|
|
42
|
+
|
|
43
|
+
## Commit message format
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
feat(milestone-N): description
|
|
47
|
+
fix(milestone-N): description
|
|
48
|
+
refactor: description
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Pull request checklist
|
|
52
|
+
|
|
53
|
+
- [ ] `uv run ruff check src/ tests/` passes
|
|
54
|
+
- [ ] `uv run pytest tests/unit/ -v` passes
|
|
55
|
+
- [ ] New behaviour is covered by a test in `tests/unit/`
|
|
56
|
+
- [ ] No new required env vars without updating `CONFIG.md`
|
|
57
|
+
|
|
58
|
+
## Reporting bugs
|
|
59
|
+
|
|
60
|
+
Open an issue using the [bug report template](https://github.com/paramahastha/pr-context-engine/issues/new?template=bug_report.md).
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Kautsar
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pr-context-engine
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: An AI tool that reads every PR and posts a senior-engineer-style briefing.
|
|
5
|
+
Project-URL: Homepage, https://github.com/paramahastha/pr-context-engine
|
|
6
|
+
Project-URL: Repository, https://github.com/paramahastha/pr-context-engine
|
|
7
|
+
Project-URL: Issues, https://github.com/paramahastha/pr-context-engine/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/paramahastha/pr-context-engine/blob/main/CHANGELOG.md
|
|
9
|
+
Author-email: Kautsar <paramahastha@gmail.com>
|
|
10
|
+
License: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: ai,code-review,github,llm,pull-request
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Environment :: Console
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Software Development :: Version Control :: Git
|
|
19
|
+
Requires-Python: >=3.12
|
|
20
|
+
Requires-Dist: anthropic>=0.40
|
|
21
|
+
Requires-Dist: fastembed>=0.4
|
|
22
|
+
Requires-Dist: google-genai>=1.0
|
|
23
|
+
Requires-Dist: groq>=0.13
|
|
24
|
+
Requires-Dist: pygithub>=2.4
|
|
25
|
+
Requires-Dist: python-dotenv>=1.0
|
|
26
|
+
Requires-Dist: requests>=2.32
|
|
27
|
+
Requires-Dist: sqlite-vec>=0.1
|
|
28
|
+
Requires-Dist: typer>=0.12
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
|
|
31
|
+
# PR Context Engine
|
|
32
|
+
|
|
33
|
+
[](https://github.com/paramahastha/pr-context-engine/actions/workflows/pr-review.yml)
|
|
34
|
+
[](https://pypi.org/project/pr-context-engine/)
|
|
35
|
+
[](LICENSE)
|
|
36
|
+
[](https://www.python.org/downloads/)
|
|
37
|
+
|
|
38
|
+
> An AI tool that reads every PR and writes the briefing — and the fixes — a senior engineer would, with the calibration data to prove it's not just guessing.
|
|
39
|
+
|
|
40
|
+
## What it does
|
|
41
|
+
|
|
42
|
+
Every PR opens with three problems for the reviewer: _what is this actually doing_, _what could it break_, and _what should I push back on_. A diff doesn't answer any of those.
|
|
43
|
+
|
|
44
|
+
PR Context Engine reads the diff plus surrounding code, recent git history, and semantically similar code from elsewhere in the repo, then posts a terse briefing written like a senior backend engineer would write it:
|
|
45
|
+
|
|
46
|
+
```markdown
|
|
47
|
+
## PR Briefing
|
|
48
|
+
|
|
49
|
+
**What changed**
|
|
50
|
+
Refactors the session token storage from an in-memory dict to Redis, adding a
|
|
51
|
+
configurable TTL. The auth middleware is updated to hit Redis on every request.
|
|
52
|
+
|
|
53
|
+
**Blast radius**
|
|
54
|
+
Any caller of `get_session()` now depends on Redis being reachable. If Redis is
|
|
55
|
+
down, all authenticated requests will 401. The previous in-memory store had no
|
|
56
|
+
such single point of failure.
|
|
57
|
+
|
|
58
|
+
**Risk flags**
|
|
59
|
+
- `modifies_auth`: src/auth/session.py line 42 — `token = generate_token(user_id)`
|
|
60
|
+
|
|
61
|
+
**Questions for the reviewer**
|
|
62
|
+
|
|
63
|
+
1. The Redis client is initialised once at import time — is there a reconnect
|
|
64
|
+
strategy if the connection drops mid-deploy?
|
|
65
|
+
2. `SESSION_TTL` defaults to 3600 but the old in-memory store had no TTL — have
|
|
66
|
+
existing sessions been migrated or will they all expire immediately after deploy?
|
|
67
|
+
3. There are no tests for the Redis-down path — is 401-on-outage the intended
|
|
68
|
+
degradation, or should it fall back to the old store?
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
No praise. No filler. No "this LGTM." Just the context a reviewer needs.
|
|
72
|
+
|
|
73
|
+
## Quickstart (5 minutes)
|
|
74
|
+
|
|
75
|
+
### Option A — GitHub Action (recommended)
|
|
76
|
+
|
|
77
|
+
1. Get a free [Groq API key](https://console.groq.com/keys) — no credit card.
|
|
78
|
+
2. Add it as a secret: **Settings → Secrets → Actions → New secret** → `GROQ_API_KEY`.
|
|
79
|
+
3. Enable write permissions: **Settings → Actions → General → Workflow permissions → Read and write**.
|
|
80
|
+
4. Add this to `.github/workflows/pr-briefing.yml`:
|
|
81
|
+
|
|
82
|
+
```yaml
|
|
83
|
+
name: PR Briefing
|
|
84
|
+
on:
|
|
85
|
+
pull_request:
|
|
86
|
+
types: [opened, synchronize, reopened]
|
|
87
|
+
jobs:
|
|
88
|
+
brief:
|
|
89
|
+
runs-on: ubuntu-latest
|
|
90
|
+
permissions:
|
|
91
|
+
pull-requests: write
|
|
92
|
+
contents: read
|
|
93
|
+
steps:
|
|
94
|
+
- uses: paramahastha/pr-context-engine@main
|
|
95
|
+
with:
|
|
96
|
+
groq-api-key: ${{ secrets.GROQ_API_KEY }}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
That's it. Every new PR gets a briefing comment automatically.
|
|
100
|
+
|
|
101
|
+
### Option B — CLI (any CI or local)
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
pipx install pr-context-engine
|
|
105
|
+
export GROQ_API_KEY=<your-groq-key>
|
|
106
|
+
export GITHUB_TOKEN=$(gh auth token)
|
|
107
|
+
|
|
108
|
+
# Check your setup first
|
|
109
|
+
pr-context-engine quickstart
|
|
110
|
+
|
|
111
|
+
# Dry-run: see the briefing without posting it
|
|
112
|
+
pr-context-engine review --pr 42 --repo owner/name --dry-run
|
|
113
|
+
|
|
114
|
+
# Post the real comment
|
|
115
|
+
pr-context-engine review --pr 42 --repo owner/name
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Switching LLM providers
|
|
119
|
+
|
|
120
|
+
Set `LLM_PROVIDER` to any of `groq` (default), `gemini`, `ollama`, or `anthropic`. Nothing downstream changes.
|
|
121
|
+
|
|
122
|
+
| Provider | Key env var | Notes |
|
|
123
|
+
|---|---|---|
|
|
124
|
+
| `groq` *(default)* | `GROQ_API_KEY` | Free, ~1 000 req/day, fast |
|
|
125
|
+
| `gemini` | `GEMINI_API_KEY` | Free-tier fallback; auto-engaged on Groq 429 |
|
|
126
|
+
| `ollama` | — | Local, offline, no rate limits |
|
|
127
|
+
| `anthropic` | `ANTHROPIC_API_KEY` | BYO key, no free tier |
|
|
128
|
+
|
|
129
|
+
**Automatic failover:** if `GEMINI_API_KEY` is set, the tool fails over to Gemini on any Groq 429 or error and notes it in the PR comment footer. See [ADR-7](docs/design-decisions.md).
|
|
130
|
+
|
|
131
|
+
## Fix suggestions (opt-in)
|
|
132
|
+
|
|
133
|
+
When `ENABLE_FIXES=true`, the tool generates confidence-gated patch suggestions for located issues. Only `high`/`medium` confidence suggestions become one-click GitHub suggestion blocks; `low` confidence produces prose notes only. Max 3 suggestions per PR.
|
|
134
|
+
|
|
135
|
+
```yaml
|
|
136
|
+
- uses: paramahastha/pr-context-engine@main
|
|
137
|
+
with:
|
|
138
|
+
groq-api-key: ${{ secrets.GROQ_API_KEY }}
|
|
139
|
+
enable-fixes: "true"
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
See [ADR-5](docs/design-decisions.md) for why this is opt-in and confidence-gated.
|
|
143
|
+
|
|
144
|
+
## Eval results
|
|
145
|
+
|
|
146
|
+
`pytest tests/eval/` produces a scorecard across five rubric dimensions (Accuracy, Blast radius, Risk flags, Question quality, Brevity) plus fix correctness and calibration rate.
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
pytest tests/eval/ -v
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Results are committed to `tests/eval/scores/` so improvements are visible in git history. The headline metrics are **fix correctness rate** and **false-confidence rate** (when the model said `high` confidence, how often was the patch actually correct).
|
|
153
|
+
|
|
154
|
+
## Architecture
|
|
155
|
+
|
|
156
|
+
```
|
|
157
|
+
Front door A: Front door B:
|
|
158
|
+
GitHub Action wrapper pipx install + run in any CI / locally
|
|
159
|
+
(paramahastha/pr-context-engine@main)
|
|
160
|
+
│ │
|
|
161
|
+
└────────────┬────────────────────┘
|
|
162
|
+
▼
|
|
163
|
+
┌─────────────────────────────────────┐
|
|
164
|
+
│ CLI core (src/cli.py + orchestrator)│
|
|
165
|
+
└─────────────────────────────────────┘
|
|
166
|
+
│
|
|
167
|
+
├──► analyzers/ diff → FileChange objects, AST symbols, risk flags
|
|
168
|
+
├──► context/ git history, sqlite-vec codebase index (RAG)
|
|
169
|
+
├──► briefing/ prompt assembly → LLM call → structured output
|
|
170
|
+
├──► fixes/ confidence-gated patch suggestions (opt-in)
|
|
171
|
+
├──► llm/ pluggable providers + FailoverProvider
|
|
172
|
+
└──► github_api/ fetch diff, post comment + suggestion blocks
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
The CLI is the product; the GitHub Action is a thin wrapper. See [docs/architecture.md](docs/architecture.md) and [docs/design-decisions.md](docs/design-decisions.md).
|
|
176
|
+
|
|
177
|
+
## Data & privacy
|
|
178
|
+
|
|
179
|
+
**What leaves your machine:**
|
|
180
|
+
|
|
181
|
+
- The PR diff and parsed metadata (file paths, function names, changed lines) are sent to the active LLM provider (Groq or Gemini by default).
|
|
182
|
+
- No source code beyond the diff is sent to any external API. The codebase index (RAG) runs entirely locally via `fastembed` + `sqlite-vec`.
|
|
183
|
+
- Git history and PR metadata are fetched from the GitHub API using your `GITHUB_TOKEN`.
|
|
184
|
+
|
|
185
|
+
**Provider data policies:**
|
|
186
|
+
|
|
187
|
+
- Groq and Gemini free tiers may use inputs for model improvement. See their respective privacy policies before using on private/sensitive repos.
|
|
188
|
+
- Use `LLM_PROVIDER=ollama` or `LLM_PROVIDER=anthropic` (with `ANTHROPIC_API_KEY`) if you need a provider with stronger data-isolation guarantees.
|
|
189
|
+
- The tool has no shared backend. Your API key, your quota, your data.
|
|
190
|
+
|
|
191
|
+
## Configuration
|
|
192
|
+
|
|
193
|
+
See [CONFIG.md](CONFIG.md) for the full reference of every env var and flag.
|
|
194
|
+
|
|
195
|
+
## Design decisions
|
|
196
|
+
|
|
197
|
+
See [docs/design-decisions.md](docs/design-decisions.md) for ADRs covering: why provider abstraction is built early, why SQLite over Pinecone, why fixes are opt-in, why MIT license, and more.
|
|
198
|
+
|
|
199
|
+
## Cost
|
|
200
|
+
|
|
201
|
+
**$0/month** for a portfolio-scale project on public repos.
|
|
202
|
+
|
|
203
|
+
- GitHub Actions: free for public repos.
|
|
204
|
+
- Groq: free tier, ~1 000 req/day.
|
|
205
|
+
- Gemini fallback: free tier (~1 500 req/day).
|
|
206
|
+
- Local embeddings (`fastembed`): $0, no API.
|
|
207
|
+
- The tool has no shared backend — your usage costs stay yours regardless of how many repos adopt it.
|
|
208
|
+
|
|
209
|
+
## Contributing
|
|
210
|
+
|
|
211
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md). Bug reports and feature requests go in [Issues](https://github.com/paramahastha/pr-context-engine/issues).
|