pr-sentinel 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.
Files changed (33) hide show
  1. pr_sentinel-0.1.0/LICENSE +21 -0
  2. pr_sentinel-0.1.0/PKG-INFO +266 -0
  3. pr_sentinel-0.1.0/README.md +234 -0
  4. pr_sentinel-0.1.0/pyproject.toml +64 -0
  5. pr_sentinel-0.1.0/setup.cfg +4 -0
  6. pr_sentinel-0.1.0/src/pr_sentinel/__init__.py +1 -0
  7. pr_sentinel-0.1.0/src/pr_sentinel/agents/__init__.py +11 -0
  8. pr_sentinel-0.1.0/src/pr_sentinel/agents/base.py +64 -0
  9. pr_sentinel-0.1.0/src/pr_sentinel/agents/performance_agent.py +7 -0
  10. pr_sentinel-0.1.0/src/pr_sentinel/agents/quality_agent.py +7 -0
  11. pr_sentinel-0.1.0/src/pr_sentinel/agents/security_agent.py +7 -0
  12. pr_sentinel-0.1.0/src/pr_sentinel/agents/testing_agent.py +7 -0
  13. pr_sentinel-0.1.0/src/pr_sentinel/cache.py +130 -0
  14. pr_sentinel-0.1.0/src/pr_sentinel/chunker.py +33 -0
  15. pr_sentinel-0.1.0/src/pr_sentinel/claude_runner.py +112 -0
  16. pr_sentinel-0.1.0/src/pr_sentinel/cli.py +605 -0
  17. pr_sentinel-0.1.0/src/pr_sentinel/diff_parser.py +105 -0
  18. pr_sentinel-0.1.0/src/pr_sentinel/git_diff.py +65 -0
  19. pr_sentinel-0.1.0/src/pr_sentinel/orchestrator.py +105 -0
  20. pr_sentinel-0.1.0/src/pr_sentinel/prompts/performance.md +50 -0
  21. pr_sentinel-0.1.0/src/pr_sentinel/prompts/quality.md +48 -0
  22. pr_sentinel-0.1.0/src/pr_sentinel/prompts/security.md +48 -0
  23. pr_sentinel-0.1.0/src/pr_sentinel/prompts/testing.md +50 -0
  24. pr_sentinel-0.1.0/src/pr_sentinel/report_generator.py +292 -0
  25. pr_sentinel-0.1.0/src/pr_sentinel.egg-info/PKG-INFO +266 -0
  26. pr_sentinel-0.1.0/src/pr_sentinel.egg-info/SOURCES.txt +31 -0
  27. pr_sentinel-0.1.0/src/pr_sentinel.egg-info/dependency_links.txt +1 -0
  28. pr_sentinel-0.1.0/src/pr_sentinel.egg-info/entry_points.txt +2 -0
  29. pr_sentinel-0.1.0/src/pr_sentinel.egg-info/requires.txt +7 -0
  30. pr_sentinel-0.1.0/src/pr_sentinel.egg-info/top_level.txt +1 -0
  31. pr_sentinel-0.1.0/tests/test_chunker.py +52 -0
  32. pr_sentinel-0.1.0/tests/test_diff_parser.py +114 -0
  33. pr_sentinel-0.1.0/tests/test_report_generator.py +110 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Yarramaddi Kishor Kumar Reddy
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,266 @@
1
+ Metadata-Version: 2.4
2
+ Name: pr-sentinel
3
+ Version: 0.1.0
4
+ Summary: Local PR review tool that orchestrates Claude Code CLI agents over git diffs.
5
+ Author-email: Yarramaddi Kishor Kumar Reddy <kishor04reddy@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/kishor2004reddy/Pull-Request-Sentinel-CLI
8
+ Project-URL: Repository, https://github.com/kishor2004reddy/Pull-Request-Sentinel-CLI
9
+ Project-URL: Issues, https://github.com/kishor2004reddy/Pull-Request-Sentinel-CLI/issues
10
+ Keywords: pr-review,code-review,claude,claude-code,cli,git-diff,static-analysis
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Software Development :: Quality Assurance
21
+ Classifier: Topic :: Software Development :: Version Control :: Git
22
+ Requires-Python: >=3.11
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ Requires-Dist: click>=8.1
26
+ Requires-Dist: rich>=13
27
+ Provides-Extra: dev
28
+ Requires-Dist: pytest>=7.0; extra == "dev"
29
+ Requires-Dist: build; extra == "dev"
30
+ Requires-Dist: twine; extra == "dev"
31
+ Dynamic: license-file
32
+
33
+ # PR Sentinel
34
+
35
+ Local pull-request review tool. Reads a git diff, runs four specialized review agents over it via the Claude Code CLI, and emits a structured JSON + Markdown report so you can fix issues *before* raising the PR.
36
+
37
+ No API keys. No hosted services. PR Sentinel shells out to `claude -p` and uses your existing Claude Code authentication.
38
+
39
+ ## How it works
40
+
41
+ ```
42
+ git diff main...HEAD
43
+
44
+
45
+ [ diff_parser ] ── filters noise (lock files, build dirs, minified, generated)
46
+
47
+
48
+ [ chunker ] ── packs files into ≤60k-char chunks (hybrid batching)
49
+
50
+
51
+ [ orchestrator ] ── runs (agent × chunk) tasks in a bounded thread pool
52
+
53
+ ├── Security Agent (claude -p prompts/security.md)
54
+ ├── Code Quality Agent (claude -p prompts/quality.md)
55
+ ├── Performance Agent (claude -p prompts/performance.md)
56
+ └── Testing Agent (claude -p prompts/testing.md)
57
+
58
+
59
+ [ cache ] ── sha256(model + prompt) → response, on disk
60
+
61
+
62
+ [ report_generator ] ── merges findings, computes risk level
63
+
64
+
65
+ reports/report.json + reports/review-report.md
66
+ ```
67
+
68
+ ## Requirements
69
+
70
+ - Python 3.11+
71
+ - [Claude Code CLI](https://docs.claude.com/en/docs/claude-code) installed and authenticated. `claude --version` must work from your shell.
72
+ - Git, if you want to review live branches (not required for `--diff` mode).
73
+
74
+ ## Install
75
+
76
+ From PyPI:
77
+
78
+ ```bash
79
+ pip install pr-sentinel
80
+ ```
81
+
82
+ From source (for development):
83
+
84
+ ```bash
85
+ git clone https://github.com/kishor2004reddy/Pull-Request-Sentinel-CLI.git
86
+ cd Pull-Request-Sentinel-CLI
87
+ pip install -e .[dev]
88
+ ```
89
+
90
+ Verify:
91
+
92
+ ```bash
93
+ pr-sentinel --help
94
+ pr-sentinel agents
95
+ ```
96
+
97
+ ## Quickstart
98
+
99
+ Review your current branch against `main`:
100
+
101
+ ```bash
102
+ pr-sentinel review --base main
103
+ ```
104
+
105
+ Or review a saved diff file (works without a git repo):
106
+
107
+ ```bash
108
+ git diff main...HEAD > my.diff
109
+ pr-sentinel review --diff my.diff --out reports
110
+ ```
111
+
112
+ Open `reports/review-report.md`.
113
+
114
+ ## Commands
115
+
116
+ ### `pr-sentinel review`
117
+
118
+ | Flag | Default | Description |
119
+ |------|---------|-------------|
120
+ | `--base` | `main` | Branch to diff against. Runs `git diff <base>...<head>`. |
121
+ | `--head` | `HEAD` | Source branch/ref to review. Use with `--base` to diff arbitrary refs without checking them out. |
122
+ | `--diff PATH` | — | Review a saved diff file instead of running git. Mutually exclusive with `--staged`. |
123
+ | `--staged` | off | Review staged changes (`git diff --cached`). |
124
+ | `--repo PATH` | cwd | Path to the git repository to review. Ignored when `--diff` is used. |
125
+ | `--agents` | `security,quality,performance,testing` | Comma-separated agents to run. |
126
+ | `--out` | `./reports` | Output directory. |
127
+ | `--format` | `both` | `json`, `markdown`, or `both`. |
128
+ | `--max-file-size` | `20000` | Per-file diff size cap (chars). Larger files get truncated with a marker. |
129
+ | `--chunk-budget` | `60000` | Max combined diff size per Claude call before chunking kicks in. |
130
+ | `--model` | `haiku` | Claude model to use. Shortcuts: `sonnet`, `opus`, `haiku`. Or pass a full model ID such as `claude-opus-4-7`. |
131
+ | `--max-parallel` | `8` | Max concurrent `claude` calls across all (agent, chunk) pairs. |
132
+ | `--timeout` | `600` | Per-call timeout in seconds for each `claude` subprocess. |
133
+ | `--no-cache` | off | Bypass the response cache for this run. Successful responses are still written to the cache. |
134
+
135
+ ### `pr-sentinel agents`
136
+
137
+ Lists available agents and their implementation status.
138
+
139
+ ### `pr-sentinel cache`
140
+
141
+ Inspect and manage the on-disk response cache.
142
+
143
+ | Subcommand | Description |
144
+ |---|---|
145
+ | `cache size` | Show cache location, entry count, and disk usage. |
146
+ | `cache clear` | Wipe the entire cache (prompts for confirmation). |
147
+ | `cache prune --older-than 30d` | Delete entries older than the given age. Supports `s/m/h/d` suffixes. Add `--dry-run` to preview. |
148
+
149
+ The cache lives at `~/.pr-sentinel/cache/` by default. Override with the `PR_SENTINEL_CACHE_DIR` environment variable. Keys are `sha256(model + prompt)`, so changing the model or any prompt content invalidates the entry automatically.
150
+
151
+ ## Examples
152
+
153
+ Review current branch vs `main`:
154
+ ```bash
155
+ pr-sentinel review --base main
156
+ ```
157
+
158
+ Run only the security agent:
159
+ ```bash
160
+ pr-sentinel review --base main --agents security
161
+ ```
162
+
163
+ Review what's currently staged:
164
+ ```bash
165
+ pr-sentinel review --staged
166
+ ```
167
+
168
+ Review a feature branch without checking it out:
169
+ ```bash
170
+ pr-sentinel review --base main --head feature/new-auth
171
+ ```
172
+
173
+ Use a stronger model for higher-stakes reviews:
174
+ ```bash
175
+ pr-sentinel review --base main --model opus
176
+ ```
177
+
178
+ Force a fresh run, ignoring cached responses:
179
+ ```bash
180
+ pr-sentinel review --base main --no-cache
181
+ ```
182
+
183
+ Prune cache entries older than a week:
184
+ ```bash
185
+ pr-sentinel cache prune --older-than 7d
186
+ ```
187
+
188
+ ## Report structure
189
+
190
+ The markdown report always emits these five sections in this fixed order, regardless of findings:
191
+
192
+ 1. **Summary** — risk level, source, branch, timestamp, agents, finding counts
193
+ 2. **Merge Verdict** — deterministic verdict driven by risk level (not a separate Claude call)
194
+ 3. **Key Findings** — top blocking issues (High + Medium)
195
+ 4. **Key Recommendations** — deduplicated fixes
196
+ 5. **All Findings** — per-agent summary table + full per-issue detail
197
+
198
+ The JSON report contains the same data in a single structured object suitable for piping into other tools.
199
+
200
+ ### Risk levels
201
+
202
+ | Level | Trigger |
203
+ |-------|---------|
204
+ | **High** | Any High-severity finding, or 5+ Medium-severity findings |
205
+ | **Medium** | One or more Medium-severity findings (and fewer than 5) |
206
+ | **Low** | Only Low-severity findings |
207
+ | **None** | No findings across all executed agents |
208
+ | **Unknown** | All executed agents failed — risk could not be determined |
209
+
210
+ ## Architecture
211
+
212
+ ```
213
+ src/pr_sentinel/
214
+ ├── cli.py # Click entrypoint + Rich UI
215
+ ├── git_diff.py # git rev-parse, git diff, --staged
216
+ ├── diff_parser.py # per-file splitting + noise filter + truncation
217
+ ├── chunker.py # greedy packer to keep prompts under chunk-budget
218
+ ├── claude_runner.py # subprocess(claude -p) + JSON extraction + 1 retry
219
+ ├── orchestrator.py # parallel (agent, chunk) execution via ThreadPoolExecutor
220
+ ├── cache.py # sha256-keyed disk cache for Claude responses
221
+ ├── report_generator.py # build_report + JSON/Markdown writers
222
+ ├── agents/
223
+ │ ├── base.py # BaseAgent: load prompt, chunk, call, validate
224
+ │ ├── security_agent.py
225
+ │ ├── quality_agent.py
226
+ │ ├── performance_agent.py
227
+ │ └── testing_agent.py
228
+ └── prompts/
229
+ ├── security.md
230
+ ├── quality.md
231
+ ├── performance.md
232
+ └── testing.md
233
+
234
+ tests/
235
+ ├── test_diff_parser.py
236
+ ├── test_chunker.py
237
+ └── test_report_generator.py
238
+ ```
239
+
240
+ ## Running tests
241
+
242
+ ```bash
243
+ pip install -e .[dev]
244
+ pytest -q
245
+ ```
246
+
247
+ ## Troubleshooting
248
+
249
+ **`claude CLI not found on PATH`** — install Claude Code and confirm `claude --version` works in the same shell where you run `pr-sentinel`.
250
+
251
+ **`claude returned non-JSON output after retry`** — Claude occasionally returns prose instead of JSON. The runner retries once; if it still fails, that chunk's findings are dropped and the agent is marked failed for the run. Re-running usually succeeds.
252
+
253
+ **Slow runs** — large diffs trigger chunking. Each chunk is one Claude call per agent. Reduce scope with `--agents security` if you only want one perspective, or with `--max-file-size` to truncate huge files. The cache amortizes repeat runs against the same diff.
254
+
255
+ **Lock files / minified files showing up** — they shouldn't. If they do, add the pattern to `NOISE_PATTERNS` in [diff_parser.py](src/pr_sentinel/diff_parser.py).
256
+
257
+ ## Notes & limitations
258
+
259
+ - The Performance Agent only sees the diff. It can flag pattern-level issues (N+1 queries, sync-over-async) but cannot reason about runtime behavior or system load.
260
+ - `lineHint` is approximate — unified diffs have hunk headers, not absolute line numbers. The prompt asks Claude for a *description* of the location rather than a hallucinated number.
261
+ - Agents cannot read other files in the repo. Review depth is limited to what's visible in the diff itself.
262
+ - If any one chunk fails for an agent (timeout, exit code, unparseable JSON after retry), that agent is marked failed for the run and its partial findings are discarded. Other agents continue.
263
+
264
+ ## License
265
+
266
+ MIT
@@ -0,0 +1,234 @@
1
+ # PR Sentinel
2
+
3
+ Local pull-request review tool. Reads a git diff, runs four specialized review agents over it via the Claude Code CLI, and emits a structured JSON + Markdown report so you can fix issues *before* raising the PR.
4
+
5
+ No API keys. No hosted services. PR Sentinel shells out to `claude -p` and uses your existing Claude Code authentication.
6
+
7
+ ## How it works
8
+
9
+ ```
10
+ git diff main...HEAD
11
+
12
+
13
+ [ diff_parser ] ── filters noise (lock files, build dirs, minified, generated)
14
+
15
+
16
+ [ chunker ] ── packs files into ≤60k-char chunks (hybrid batching)
17
+
18
+
19
+ [ orchestrator ] ── runs (agent × chunk) tasks in a bounded thread pool
20
+
21
+ ├── Security Agent (claude -p prompts/security.md)
22
+ ├── Code Quality Agent (claude -p prompts/quality.md)
23
+ ├── Performance Agent (claude -p prompts/performance.md)
24
+ └── Testing Agent (claude -p prompts/testing.md)
25
+
26
+
27
+ [ cache ] ── sha256(model + prompt) → response, on disk
28
+
29
+
30
+ [ report_generator ] ── merges findings, computes risk level
31
+
32
+
33
+ reports/report.json + reports/review-report.md
34
+ ```
35
+
36
+ ## Requirements
37
+
38
+ - Python 3.11+
39
+ - [Claude Code CLI](https://docs.claude.com/en/docs/claude-code) installed and authenticated. `claude --version` must work from your shell.
40
+ - Git, if you want to review live branches (not required for `--diff` mode).
41
+
42
+ ## Install
43
+
44
+ From PyPI:
45
+
46
+ ```bash
47
+ pip install pr-sentinel
48
+ ```
49
+
50
+ From source (for development):
51
+
52
+ ```bash
53
+ git clone https://github.com/kishor2004reddy/Pull-Request-Sentinel-CLI.git
54
+ cd Pull-Request-Sentinel-CLI
55
+ pip install -e .[dev]
56
+ ```
57
+
58
+ Verify:
59
+
60
+ ```bash
61
+ pr-sentinel --help
62
+ pr-sentinel agents
63
+ ```
64
+
65
+ ## Quickstart
66
+
67
+ Review your current branch against `main`:
68
+
69
+ ```bash
70
+ pr-sentinel review --base main
71
+ ```
72
+
73
+ Or review a saved diff file (works without a git repo):
74
+
75
+ ```bash
76
+ git diff main...HEAD > my.diff
77
+ pr-sentinel review --diff my.diff --out reports
78
+ ```
79
+
80
+ Open `reports/review-report.md`.
81
+
82
+ ## Commands
83
+
84
+ ### `pr-sentinel review`
85
+
86
+ | Flag | Default | Description |
87
+ |------|---------|-------------|
88
+ | `--base` | `main` | Branch to diff against. Runs `git diff <base>...<head>`. |
89
+ | `--head` | `HEAD` | Source branch/ref to review. Use with `--base` to diff arbitrary refs without checking them out. |
90
+ | `--diff PATH` | — | Review a saved diff file instead of running git. Mutually exclusive with `--staged`. |
91
+ | `--staged` | off | Review staged changes (`git diff --cached`). |
92
+ | `--repo PATH` | cwd | Path to the git repository to review. Ignored when `--diff` is used. |
93
+ | `--agents` | `security,quality,performance,testing` | Comma-separated agents to run. |
94
+ | `--out` | `./reports` | Output directory. |
95
+ | `--format` | `both` | `json`, `markdown`, or `both`. |
96
+ | `--max-file-size` | `20000` | Per-file diff size cap (chars). Larger files get truncated with a marker. |
97
+ | `--chunk-budget` | `60000` | Max combined diff size per Claude call before chunking kicks in. |
98
+ | `--model` | `haiku` | Claude model to use. Shortcuts: `sonnet`, `opus`, `haiku`. Or pass a full model ID such as `claude-opus-4-7`. |
99
+ | `--max-parallel` | `8` | Max concurrent `claude` calls across all (agent, chunk) pairs. |
100
+ | `--timeout` | `600` | Per-call timeout in seconds for each `claude` subprocess. |
101
+ | `--no-cache` | off | Bypass the response cache for this run. Successful responses are still written to the cache. |
102
+
103
+ ### `pr-sentinel agents`
104
+
105
+ Lists available agents and their implementation status.
106
+
107
+ ### `pr-sentinel cache`
108
+
109
+ Inspect and manage the on-disk response cache.
110
+
111
+ | Subcommand | Description |
112
+ |---|---|
113
+ | `cache size` | Show cache location, entry count, and disk usage. |
114
+ | `cache clear` | Wipe the entire cache (prompts for confirmation). |
115
+ | `cache prune --older-than 30d` | Delete entries older than the given age. Supports `s/m/h/d` suffixes. Add `--dry-run` to preview. |
116
+
117
+ The cache lives at `~/.pr-sentinel/cache/` by default. Override with the `PR_SENTINEL_CACHE_DIR` environment variable. Keys are `sha256(model + prompt)`, so changing the model or any prompt content invalidates the entry automatically.
118
+
119
+ ## Examples
120
+
121
+ Review current branch vs `main`:
122
+ ```bash
123
+ pr-sentinel review --base main
124
+ ```
125
+
126
+ Run only the security agent:
127
+ ```bash
128
+ pr-sentinel review --base main --agents security
129
+ ```
130
+
131
+ Review what's currently staged:
132
+ ```bash
133
+ pr-sentinel review --staged
134
+ ```
135
+
136
+ Review a feature branch without checking it out:
137
+ ```bash
138
+ pr-sentinel review --base main --head feature/new-auth
139
+ ```
140
+
141
+ Use a stronger model for higher-stakes reviews:
142
+ ```bash
143
+ pr-sentinel review --base main --model opus
144
+ ```
145
+
146
+ Force a fresh run, ignoring cached responses:
147
+ ```bash
148
+ pr-sentinel review --base main --no-cache
149
+ ```
150
+
151
+ Prune cache entries older than a week:
152
+ ```bash
153
+ pr-sentinel cache prune --older-than 7d
154
+ ```
155
+
156
+ ## Report structure
157
+
158
+ The markdown report always emits these five sections in this fixed order, regardless of findings:
159
+
160
+ 1. **Summary** — risk level, source, branch, timestamp, agents, finding counts
161
+ 2. **Merge Verdict** — deterministic verdict driven by risk level (not a separate Claude call)
162
+ 3. **Key Findings** — top blocking issues (High + Medium)
163
+ 4. **Key Recommendations** — deduplicated fixes
164
+ 5. **All Findings** — per-agent summary table + full per-issue detail
165
+
166
+ The JSON report contains the same data in a single structured object suitable for piping into other tools.
167
+
168
+ ### Risk levels
169
+
170
+ | Level | Trigger |
171
+ |-------|---------|
172
+ | **High** | Any High-severity finding, or 5+ Medium-severity findings |
173
+ | **Medium** | One or more Medium-severity findings (and fewer than 5) |
174
+ | **Low** | Only Low-severity findings |
175
+ | **None** | No findings across all executed agents |
176
+ | **Unknown** | All executed agents failed — risk could not be determined |
177
+
178
+ ## Architecture
179
+
180
+ ```
181
+ src/pr_sentinel/
182
+ ├── cli.py # Click entrypoint + Rich UI
183
+ ├── git_diff.py # git rev-parse, git diff, --staged
184
+ ├── diff_parser.py # per-file splitting + noise filter + truncation
185
+ ├── chunker.py # greedy packer to keep prompts under chunk-budget
186
+ ├── claude_runner.py # subprocess(claude -p) + JSON extraction + 1 retry
187
+ ├── orchestrator.py # parallel (agent, chunk) execution via ThreadPoolExecutor
188
+ ├── cache.py # sha256-keyed disk cache for Claude responses
189
+ ├── report_generator.py # build_report + JSON/Markdown writers
190
+ ├── agents/
191
+ │ ├── base.py # BaseAgent: load prompt, chunk, call, validate
192
+ │ ├── security_agent.py
193
+ │ ├── quality_agent.py
194
+ │ ├── performance_agent.py
195
+ │ └── testing_agent.py
196
+ └── prompts/
197
+ ├── security.md
198
+ ├── quality.md
199
+ ├── performance.md
200
+ └── testing.md
201
+
202
+ tests/
203
+ ├── test_diff_parser.py
204
+ ├── test_chunker.py
205
+ └── test_report_generator.py
206
+ ```
207
+
208
+ ## Running tests
209
+
210
+ ```bash
211
+ pip install -e .[dev]
212
+ pytest -q
213
+ ```
214
+
215
+ ## Troubleshooting
216
+
217
+ **`claude CLI not found on PATH`** — install Claude Code and confirm `claude --version` works in the same shell where you run `pr-sentinel`.
218
+
219
+ **`claude returned non-JSON output after retry`** — Claude occasionally returns prose instead of JSON. The runner retries once; if it still fails, that chunk's findings are dropped and the agent is marked failed for the run. Re-running usually succeeds.
220
+
221
+ **Slow runs** — large diffs trigger chunking. Each chunk is one Claude call per agent. Reduce scope with `--agents security` if you only want one perspective, or with `--max-file-size` to truncate huge files. The cache amortizes repeat runs against the same diff.
222
+
223
+ **Lock files / minified files showing up** — they shouldn't. If they do, add the pattern to `NOISE_PATTERNS` in [diff_parser.py](src/pr_sentinel/diff_parser.py).
224
+
225
+ ## Notes & limitations
226
+
227
+ - The Performance Agent only sees the diff. It can flag pattern-level issues (N+1 queries, sync-over-async) but cannot reason about runtime behavior or system load.
228
+ - `lineHint` is approximate — unified diffs have hunk headers, not absolute line numbers. The prompt asks Claude for a *description* of the location rather than a hallucinated number.
229
+ - Agents cannot read other files in the repo. Review depth is limited to what's visible in the diff itself.
230
+ - If any one chunk fails for an agent (timeout, exit code, unparseable JSON after retry), that agent is marked failed for the run and its partial findings are discarded. Other agents continue.
231
+
232
+ ## License
233
+
234
+ MIT
@@ -0,0 +1,64 @@
1
+ [build-system]
2
+ requires = ["setuptools>=64", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "pr-sentinel"
7
+ description = "Local PR review tool that orchestrates Claude Code CLI agents over git diffs."
8
+ readme = "README.md"
9
+ requires-python = ">=3.11"
10
+ license = { text = "MIT" }
11
+ authors = [
12
+ { name = "Yarramaddi Kishor Kumar Reddy", email = "kishor04reddy@gmail.com" },
13
+ ]
14
+ keywords = [
15
+ "pr-review",
16
+ "code-review",
17
+ "claude",
18
+ "claude-code",
19
+ "cli",
20
+ "git-diff",
21
+ "static-analysis",
22
+ ]
23
+ classifiers = [
24
+ "Development Status :: 3 - Alpha",
25
+ "Environment :: Console",
26
+ "Intended Audience :: Developers",
27
+ "License :: OSI Approved :: MIT License",
28
+ "Operating System :: OS Independent",
29
+ "Programming Language :: Python :: 3",
30
+ "Programming Language :: Python :: 3.11",
31
+ "Programming Language :: Python :: 3.12",
32
+ "Programming Language :: Python :: 3.13",
33
+ "Topic :: Software Development :: Quality Assurance",
34
+ "Topic :: Software Development :: Version Control :: Git",
35
+ ]
36
+ dependencies = [
37
+ "click>=8.1",
38
+ "rich>=13",
39
+ ]
40
+ dynamic = ["version"]
41
+
42
+ [project.optional-dependencies]
43
+ dev = [
44
+ "pytest>=7.0",
45
+ "build",
46
+ "twine",
47
+ ]
48
+
49
+ [project.scripts]
50
+ pr-sentinel = "pr_sentinel.cli:main"
51
+
52
+ [project.urls]
53
+ Homepage = "https://github.com/kishor2004reddy/Pull-Request-Sentinel-CLI"
54
+ Repository = "https://github.com/kishor2004reddy/Pull-Request-Sentinel-CLI"
55
+ Issues = "https://github.com/kishor2004reddy/Pull-Request-Sentinel-CLI/issues"
56
+
57
+ [tool.setuptools.dynamic]
58
+ version = { attr = "pr_sentinel.__version__" }
59
+
60
+ [tool.setuptools.packages.find]
61
+ where = ["src"]
62
+
63
+ [tool.setuptools.package-data]
64
+ pr_sentinel = ["prompts/*.md"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1 @@
1
+ __version__ = "0.1.0"
@@ -0,0 +1,11 @@
1
+ from pr_sentinel.agents.performance_agent import PerformanceAgent
2
+ from pr_sentinel.agents.quality_agent import QualityAgent
3
+ from pr_sentinel.agents.security_agent import SecurityAgent
4
+ from pr_sentinel.agents.testing_agent import TestingAgent
5
+
6
+ AGENT_REGISTRY = {
7
+ "security": SecurityAgent,
8
+ "quality": QualityAgent,
9
+ "performance": PerformanceAgent,
10
+ "testing": TestingAgent,
11
+ }
@@ -0,0 +1,64 @@
1
+ from importlib import resources
2
+
3
+ from pr_sentinel import chunker, claude_runner
4
+
5
+ VALID_SEVERITIES = {"Low", "Medium", "High"}
6
+
7
+
8
+ def load_prompt(filename: str) -> str:
9
+ return resources.files("pr_sentinel.prompts").joinpath(filename).read_text(encoding="utf-8")
10
+
11
+
12
+ class BaseAgent:
13
+ name: str = ""
14
+ prompt_file: str = ""
15
+ display_name: str = ""
16
+
17
+ def __init__(self) -> None:
18
+ if not self.prompt_file:
19
+ raise ValueError(f"{type(self).__name__} missing prompt_file")
20
+ self._template = load_prompt(self.prompt_file)
21
+
22
+ def process_chunk(
23
+ self,
24
+ chunk: list[dict],
25
+ model: str | None = None,
26
+ timeout: int = 600,
27
+ use_cache: bool = True,
28
+ ) -> list[dict]:
29
+ """Process a single chunk and return validated findings.
30
+
31
+ Raises on subprocess failure or unparseable output (after retry); caller
32
+ decides whether to discard partial findings for the agent.
33
+ """
34
+ diff_block = chunker.format_diff_block(chunk)
35
+ prompt = self._template.replace("<<<DIFF>>>", diff_block)
36
+ response = claude_runner.run_json(
37
+ prompt, timeout=timeout, model=model, use_cache=use_cache
38
+ )
39
+ return self._validate_findings(response)
40
+
41
+ def _validate_findings(self, response: dict) -> list[dict]:
42
+ findings = response.get("findings", [])
43
+ if not isinstance(findings, list):
44
+ return []
45
+
46
+ cleaned: list[dict] = []
47
+ for f in findings:
48
+ if not isinstance(f, dict):
49
+ continue
50
+ severity = f.get("severity", "Low")
51
+ if severity not in VALID_SEVERITIES:
52
+ severity = "Low"
53
+ cleaned.append(
54
+ {
55
+ "agent": self.display_name,
56
+ "severity": severity,
57
+ "file": str(f.get("file", "<unknown>")),
58
+ "lineHint": str(f.get("lineHint", "")),
59
+ "issue": str(f.get("issue", "")).strip(),
60
+ "reasoning": str(f.get("reasoning", "")).strip(),
61
+ "recommendation": str(f.get("recommendation", "")).strip(),
62
+ }
63
+ )
64
+ return cleaned
@@ -0,0 +1,7 @@
1
+ from pr_sentinel.agents.base import BaseAgent
2
+
3
+
4
+ class PerformanceAgent(BaseAgent):
5
+ name = "performance"
6
+ display_name = "Performance Agent"
7
+ prompt_file = "performance.md"
@@ -0,0 +1,7 @@
1
+ from pr_sentinel.agents.base import BaseAgent
2
+
3
+
4
+ class QualityAgent(BaseAgent):
5
+ name = "quality"
6
+ display_name = "Code Quality Agent"
7
+ prompt_file = "quality.md"