agent-roast 0.10.1 → 0.12.0
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.
- package/README.md +94 -464
- package/dist/{chunk-FFKEBW6D.js → chunk-AP5Y4CH6.js} +901 -64
- package/dist/cli.js +289 -18
- package/dist/index.d.ts +163 -2
- package/dist/index.js +51 -1
- package/package.json +12 -4
package/README.md
CHANGED
|
@@ -5,518 +5,148 @@
|
|
|
5
5
|
<img src="docs/assets/logo.svg" alt="agent-roast" width="380">
|
|
6
6
|
</picture>
|
|
7
7
|
|
|
8
|
-
<h2>
|
|
8
|
+
<h2>Your AI agent made the tests pass.<br>Did it fix the code, or the tests?</h2>
|
|
9
9
|
|
|
10
10
|
<p>
|
|
11
|
-
<a href="https://github.com/Nari-Ab/agent-roast/actions/workflows/test.yml"><img src="https://github.com/Nari-Ab/agent-roast/actions/workflows/test.yml/badge.svg" alt="
|
|
11
|
+
<a href="https://github.com/Nari-Ab/agent-roast/actions/workflows/test.yml"><img src="https://github.com/Nari-Ab/agent-roast/actions/workflows/test.yml/badge.svg" alt="CI"></a>
|
|
12
12
|
<a href="https://www.npmjs.com/package/agent-roast"><img src="https://img.shields.io/npm/v/agent-roast?color=cb3837&logo=npm&logoColor=white" alt="npm"></a>
|
|
13
|
-
<a href="https://www.npmjs.com/package/agent-roast"><img src="https://img.shields.io/npm/
|
|
14
|
-
<a href="https://nari-ab.github.io/agent-roast/"><img src="https://img.shields.io/badge/site-live-1f9d55" alt="site"></a>
|
|
13
|
+
<a href="https://www.npmjs.com/package/agent-roast"><img src="https://img.shields.io/npm/dm/agent-roast?label=downloads&color=0969da" alt="downloads"></a>
|
|
15
14
|
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-0969da" alt="license"></a>
|
|
15
|
+
<img src="https://img.shields.io/badge/runs-offline%20·%20no%20tokens-1f9d55" alt="offline, no tokens">
|
|
16
16
|
</p>
|
|
17
17
|
|
|
18
18
|
</div>
|
|
19
19
|
|
|
20
|
-
**
|
|
20
|
+
**agent-roast** catches the changes that turn a red build green by weakening the *checks* instead of fixing the *code*: a
|
|
21
|
+
loosened assertion, a skipped or deleted test, a lowered coverage threshold, a CI step allowed to fail. A linter cannot see
|
|
22
|
+
these, because every new line looks fine on its own. agent-roast compares the **before and after** of each change, as an
|
|
23
|
+
agent hook, a Git hook and a pull request check. It is deterministic and offline: no model, no tokens, no network.
|
|
21
24
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
exactly these moves. It is offline, runs no project code, and needs only Git. It was built to
|
|
27
|
-
review AI-assisted changes, but it cannot tell who wrote a change, and the measurements below
|
|
28
|
-
show these moves are not specific to AI.
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
npx agent-roast review --base origin/main # a pull request
|
|
32
|
-
npx agent-roast --staged # what you are about to commit
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
| Rule | Fires when | By default |
|
|
36
|
-
| --- | --- | --- |
|
|
37
|
-
| `assertion-weakened` | an exact check is replaced by a weaker one: `toBe(42)` → `toBeDefined()`, `assert x == 1` → `assert x`, `isinstance(...)` → `is not None` | blocks |
|
|
38
|
-
| `guard-weakened` | coverage threshold lowered, `strict`/`noImplicitAny` off, lint rule downgraded, an existing CI step allowed to fail, a workflow that stops running tests or stops running on push and pull requests, a test script that cannot fail | blocks |
|
|
39
|
-
| `assertion-removed` | a test keeps its name but loses assertions | warns |
|
|
40
|
-
| `test-removed` | a test (or test file) disappears and no identical body appears elsewhere | warns |
|
|
41
|
-
| `expectation-rewritten` | an expected value changed, test inputs did not, and production code changed in the same PR | warns |
|
|
42
|
-
| `test-skip`, `test-focus`, `trivial-assert`, `swallowed-error`, `type-escape`, `stub-abandonment` | the classic shortcuts, compared before/after so old debt does not block | skip, focus and trivial-assert block |
|
|
43
|
-
|
|
44
|
-
Renames, moved tests, parametrization, assertions moved into a new helper, and formatter
|
|
45
|
-
rewraps (prettier, black) are recognized and not reported. Intentional cases can be accepted
|
|
46
|
-
one by one with an expiring, reviewed exception (see below). Policy is read from the base
|
|
47
|
-
branch, so a PR cannot switch the rules off for itself.
|
|
48
|
-
|
|
49
|
-
### How well does it work?
|
|
50
|
-
|
|
51
|
-
Measured, not promised; method, corpus and raw numbers are in
|
|
52
|
-
[docs/benchmarks.md](docs/benchmarks.md). **Short version: weakened checks are rare, usually
|
|
53
|
-
deliberate, and not specific to AI. The tool finds them; a person decides.**
|
|
54
|
-
|
|
55
|
-
- **Labeled changes** (`benchmarks/cases.mjs`): 40 cheating edits across JS/TS, Python, Go and
|
|
56
|
-
CI/config files are caught and 33 harmless look-alikes (reformat, rename, move, parametrize,
|
|
57
|
-
helper extraction, raised thresholds, CI restructuring) stay silent. The cases were written
|
|
58
|
-
together with the detector, so they guard against regressions; they do not prove accuracy.
|
|
59
|
-
Three known gaps are listed in the file and still open: mocking the module under test,
|
|
60
|
-
hardcoding the tested value, and vacuous matchers such as `expect.anything()`.
|
|
61
|
-
- **Five mature open-source projects** (commander.js, execa, click, requests, zod; 606 commits
|
|
62
|
-
that touch tests or CI/config): the blocking rules fired on 3 commits (0.5%), all of them
|
|
63
|
-
deliberate. `assertion-removed` fired on 5 (0.8%), including one real defect:
|
|
64
|
-
a refactor in `requests` dropped the `assert` keyword and left a comparison with no effect.
|
|
65
|
-
- **AI-signed commits in 166 public repositories** (signatures from Claude, Copilot, Cursor,
|
|
66
|
-
Codex, Devin and aider; 12,645 commits that touch tests or CI/config):
|
|
67
|
-
|
|
68
|
-
| | AI-signed | Other commits |
|
|
69
|
-
| --- | ---: | ---: |
|
|
70
|
-
| Repositories | 160 | 141 |
|
|
71
|
-
| Commits reviewed | 6,895 | 5,750 |
|
|
72
|
-
| Blocking rules | 0.3% (20) | 0.3% (16) |
|
|
73
|
-
| `assertion-removed` (warns) | 2.4% | 2.2% |
|
|
74
|
-
| `test-removed` (warns) | 15.4% | 12.7% |
|
|
75
|
-
| `expectation-rewritten` (warns) | 5.7% | 5.5% |
|
|
76
|
-
|
|
77
|
-
Compared inside the same repository (135 repositories with both kinds), the odds of a
|
|
78
|
-
blocking finding in an AI-signed commit are 0.81 times those of another commit (95% CI
|
|
79
|
-
0.40-1.67): no sign that AI-signed commits weaken checks more often. Claude accounts for
|
|
80
|
-
5,380 of the AI-signed commits; the other agents are too few to compare.
|
|
81
|
-
- **Hand-read precision.** Findings were read without knowing who wrote the commit (one
|
|
82
|
-
reader, an AI assistant; not independently verified). On repositories the detector had never
|
|
83
|
-
seen, the 11 blocking findings were 2 unexplained relaxations (TypeScript strictness switched
|
|
84
|
-
off in commits titled "Changes"), 7 deliberate and explained changes, and 2 false alarms. Of
|
|
85
|
-
24 `assertion-removed` warnings, 1 was an unexplained weakening, 12 deliberate, 6 unclear and
|
|
86
|
-
5 false alarms. So most findings are decisions a reviewer should see rather than mistakes,
|
|
87
|
-
and roughly one in five is a false alarm. Earlier rounds (76 findings) were used to fix the
|
|
88
|
-
detector and are not counted here.
|
|
89
|
-
|
|
90
|
-
Caveats. A signature shows a tool was involved, not how much, and unsigned AI help in the
|
|
91
|
-
"other" group would hide a difference. The repositories came from searching for those
|
|
92
|
-
signatures, so many are small personal projects. This measures what was committed, not what an
|
|
93
|
-
agent tries mid-session: a weakened check fixed before the commit is invisible. Labels are one
|
|
94
|
-
reader's opinion. Three small fixes (assertion helpers, throwing test-library queries,
|
|
95
|
-
scheduled-only workflows) were added after the labeling and have regression cases, but were not
|
|
96
|
-
re-labeled.
|
|
97
|
-
|
|
98
|
-
It is a **review aid**: it cannot prove who wrote a change or that code is correct, and it
|
|
99
|
-
reads text, not program semantics. A green result is not a quality certificate.
|
|
100
|
-
|
|
101
|
-
**Want to see what it says about your repository?** [docs/pilot.md](docs/pilot.md) has a
|
|
102
|
-
five-minute look back, an advisory workflow that never fails a pull request, and a feedback form.
|
|
103
|
-
Counts are enough; no code is needed.
|
|
104
|
-
|
|
105
|
-
### Quick start
|
|
106
|
-
|
|
107
|
-
```bash
|
|
108
|
-
# Everything that is true of the code you have now
|
|
109
|
-
npx agent-roast check
|
|
110
|
-
npx agent-roast explain swallowed-error
|
|
111
|
-
|
|
112
|
-
# Adopt in an existing project without blocking on historical debt
|
|
113
|
-
npx agent-roast check --write-baseline .agentroast-baseline.json
|
|
114
|
-
npx agent-roast check --baseline .agentroast-baseline.json
|
|
115
|
-
|
|
116
|
-
# Optional: score a repository's history
|
|
117
|
-
npx agent-roast --all --verbose
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
A finding includes its file and line, the evidence, and a concrete next step.
|
|
121
|
-
`--format json|markdown|sarif|github` are available; terminal output shows the 20 most
|
|
122
|
-
important findings (rules that block first, then the before/after rules, then the noisier
|
|
123
|
-
line patterns).
|
|
124
|
-
|
|
125
|
-
### Context review for pull requests
|
|
126
|
-
|
|
127
|
-
```bash
|
|
128
|
-
# Compare committed source at the common ancestor and candidate head
|
|
129
|
-
agent-roast review --base origin/main --head HEAD
|
|
130
|
-
agent-roast review --base origin/main --format markdown
|
|
131
|
-
|
|
132
|
-
# Export a report for tools that consume SARIF 2.1.0
|
|
133
|
-
agent-roast review --base origin/main --format sarif > agentroast.sarif
|
|
134
|
-
agent-roast check --format sarif > current-code.sarif
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
`review` compares **full contents of changed source files**, so deleting the only
|
|
138
|
-
handler inside a `catch` is detectable even when no suspicious line was added.
|
|
139
|
-
It reports new findings, existing findings, and patterns no longer detected. Only
|
|
140
|
-
new blocking findings fail the check; no manually generated baseline is required.
|
|
141
|
-
Deleting a file is reported as disappearance of a pattern, not proof of a correct fix.
|
|
142
|
-
|
|
143
|
-
Source is read directly from immutable Git blobs at the merge-base and head. The
|
|
144
|
-
worktree and index are left untouched, and project code, hooks, diff programs and
|
|
145
|
-
package scripts are never executed. Use `check` for uncommitted working files, and
|
|
146
|
-
`--staged` for the index. Source comparison and policy are pinned to the reported SHAs.
|
|
25
|
+
<p align="center">
|
|
26
|
+
<img src="docs/assets/demo-terminal.svg" alt="Terminal: npx agent-roast demo reports a skipped test, a trivial assertion, a weakened assertion, a CI step allowed to fail and two lowered coverage thresholds, and blocks the change" width="820">
|
|
27
|
+
<br><sub>Real output of <code>npx agent-roast demo</code>, shortened. The scenario is scripted; the review is not.</sub>
|
|
28
|
+
</p>
|
|
147
29
|
|
|
148
|
-
|
|
149
|
-
at the merge-base. Candidate changes to `.agentroastrc.json`, `.agentroastrc` or
|
|
150
|
-
`agent-roast.config.json` are reported and ignored for this review. Adopt policy
|
|
151
|
-
changes through separate human review. An explicit `--fail-on` overrides blocking
|
|
152
|
-
severity but does not enable rules disabled by base policy.
|
|
30
|
+
## Try it
|
|
153
31
|
|
|
154
32
|
```bash
|
|
155
|
-
#
|
|
156
|
-
agent-roast review
|
|
157
|
-
# Gate the shortcuts the team agrees matter
|
|
158
|
-
agent-roast review --base origin/main --fail-on test-skip,trivial-assert,swallowed-error
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
Matching uses rule, source snippet and occurrence count within a file pair. Line
|
|
162
|
-
shifts and Git-recognized pure renames do not turn old debt into new debt. A second
|
|
163
|
-
identical occurrence is new. This is not semantic tracking: rewritten snippets or
|
|
164
|
-
language changes can require fresh review, and Git's rename recognition is heuristic.
|
|
165
|
-
|
|
166
|
-
Limits: 1,000 changed files, 2 MiB per source blob, 50 MiB across inspected versions,
|
|
167
|
-
30 seconds per Git command. Symlinked/binary/oversized source and missing comparison
|
|
168
|
-
objects yield exit 2, never a clean pass. Partial clones and ambiguous multiple
|
|
169
|
-
merge-bases are unsupported; fetch complete local history (`fetch-depth: 0`). The
|
|
170
|
-
report counts excluded and unsupported changes explicitly. Only changed supported
|
|
171
|
-
files are compared; this is not a whole-repository safety certification.
|
|
172
|
-
|
|
173
|
-
SARIF includes rule metadata, relative locations, stable occurrence fingerprints
|
|
174
|
-
and whether the scan completed. Source snippets are omitted from SARIF. JSON and
|
|
175
|
-
Markdown reports contain evidence snippets and should be handled as source code.
|
|
176
|
-
SARIF output is generated offline; uploading it is a separate, optional operation.
|
|
177
|
-
GitHub supports SARIF ingestion, but this release has not been tested with a live
|
|
178
|
-
code-scanning upload. Some findings on unchanged lines (including deletion-only
|
|
179
|
-
regressions) may appear in the report/summary rather than as an inline PR annotation.
|
|
180
|
-
Use a separate SARIF category for introduced-findings review; it does not represent
|
|
181
|
-
a full scan of all outstanding alerts.
|
|
182
|
-
|
|
183
|
-
Install 0.10.1: `npx agent-roast@0.10.1 review --base origin/main`. For local development,
|
|
184
|
-
run `npm run build` and use `node dist/cli.js`.
|
|
185
|
-
|
|
186
|
-
### Precise exceptions (since 0.8.0)
|
|
187
|
-
|
|
188
|
-
Use `npx agent-roast@0.10.1 check --format json`, or build this checkout with
|
|
189
|
-
`npm run build` and run `node dist/cli.js`.
|
|
190
|
-
|
|
191
|
-
Some skipped integrations or abstract stubs are intentional. In 0.8.0 you can accept
|
|
192
|
-
one exact finding without switching off the rule or ignoring its whole file:
|
|
193
|
-
|
|
194
|
-
1. Run `node dist/cli.js check --format json` and inspect the evidence. Findings
|
|
195
|
-
include a stable `fingerprint` (rule, relative filename and trimmed source snippet).
|
|
196
|
-
2. Add a reviewed `exceptions` entry to the root `.agentroastrc.json`, with the
|
|
197
|
-
fingerprint, the **total** allowed occurrence count, a reason and an expiry date.
|
|
198
|
-
3. Run the check again. Accepted findings remain visible with their reason/date;
|
|
199
|
-
additional duplicate occurrences still block. Expired exceptions stop applying.
|
|
200
|
-
Use a full `check` to revisit old findings; `review` continues gating newly
|
|
201
|
-
introduced debt, so expiration does not turn unchanged old debt into a new finding.
|
|
202
|
-
|
|
203
|
-
```json
|
|
204
|
-
{
|
|
205
|
-
"exceptions": [
|
|
206
|
-
{
|
|
207
|
-
"fingerprint": "f4d1212234f00381d0eaed359e3229fe4ff47388affc9eac0d0d89daffea13d6",
|
|
208
|
-
"count": 1,
|
|
209
|
-
"reason": "Integration sandbox unavailable; restore under ENG-42",
|
|
210
|
-
"expires": "2026-11-15"
|
|
211
|
-
}
|
|
212
|
-
]
|
|
213
|
-
}
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
The example fingerprint is for `it.skip('temporary');` in `auth.test.ts`; copy the
|
|
217
|
-
fingerprint from **your** report. Expiry includes the specified day in UTC. Changing
|
|
218
|
-
the rule, path or source snippet requires review again. Counts from an exception and
|
|
219
|
-
baseline do not add together to accept extra identical occurrences.
|
|
220
|
-
|
|
221
|
-
For committed/staged context reviews the allowance must already exist in the trusted
|
|
222
|
-
base/HEAD policy. A candidate PR or unstaged config cannot approve itself; first
|
|
223
|
-
commits use built-in defaults. `check` intentionally reads the current root policy.
|
|
224
|
-
Use `--ignore-exceptions` with `check`, `review` or `--staged` to inspect accepted
|
|
225
|
-
findings again. This flag does not disable a separately supplied baseline.
|
|
226
|
-
Exceptions apply to these context/current-source workflows; historical and legacy
|
|
227
|
-
added-line audits do not apply them. A full scan can use baseline adoption for old
|
|
228
|
-
debt, while exceptions record temporary reviewed decisions about particular findings.
|
|
229
|
-
|
|
230
|
-
JSON/Markdown/terminal reports separate accepted exceptions from actionable findings.
|
|
231
|
-
SARIF retains accepted records with `suppressions` and their justification/expiry;
|
|
232
|
-
JSON and SARIF include stable occurrence identities. SARIF omits code snippets but
|
|
233
|
-
includes exception reasons, so review those before sharing reports.
|
|
234
|
-
|
|
235
|
-
An offline editor schema is included as `schema.json` in the npm package. When using
|
|
236
|
-
a local dev dependency, set `$schema` to `./node_modules/agent-roast/schema.json`.
|
|
237
|
-
Ignore policies are bounded to 1,000 patterns of at most 1,024 characters each.
|
|
238
|
-
Unknown settings, invalid severities and malformed exceptions fail with exit 2.
|
|
239
|
-
Root policy must be a regular UTF-8 file no larger than 64 KiB. Simple ignore globs
|
|
240
|
-
support `*`, `?`, `**` and directory prefixes; they are not full `.gitignore` syntax.
|
|
241
|
-
|
|
242
|
-
### Baseline adoption
|
|
243
|
-
|
|
244
|
-
A baseline explicitly accepts the findings present at adoption time. It does not fix
|
|
245
|
-
or hide new code. Fingerprints use the rule, repository-relative filename and source
|
|
246
|
-
snippet; line numbers are excluded so adding clean code above a finding does not
|
|
247
|
-
break it. Occurrence counts ensure a second identical shortcut is still new. Moving
|
|
248
|
-
a finding to another file or changing its snippet requires a fresh review. Baselines
|
|
249
|
-
contain hashes and counts, not source code. The report shows both accepted and new
|
|
250
|
-
findings and counts accepted findings no longer present.
|
|
251
|
-
|
|
252
|
-
Baseline use is explicit (`--baseline`), and writes refuse to overwrite existing
|
|
253
|
-
files. To refresh accepted debt, inspect the full scan and write a **new** baseline
|
|
254
|
-
file for review. Treat baseline changes as policy changes in code review. Do not
|
|
255
|
-
silently regenerate one in CI. Input/output baseline paths are relative to the
|
|
256
|
-
directory passed to `check` (or the current directory if omitted).
|
|
257
|
-
|
|
258
|
-
`check` scans the repository containing the supplied path, applies its root config,
|
|
259
|
-
respects Git ignores for untracked files, and excludes generated dependencies/build
|
|
260
|
-
outputs. It checks working files, while `--staged` checks the index. Git submodules
|
|
261
|
-
are not recursively scanned. A supported file that is binary, too large, unreadable
|
|
262
|
-
or a symlink makes the scan incomplete (exit 2); incomplete scans cannot create a
|
|
263
|
-
baseline. Limits are 2 MiB per source file and 50 MiB per scan. Intentional generated
|
|
264
|
-
or unsupported input should be excluded in `ignorePaths`, not silently counted clean.
|
|
265
|
-
|
|
266
|
-
History auditing remains available when you want an overview of prior shortcuts:
|
|
267
|
-
|
|
268
|
-
What a report looks like (a real repository audit, trimmed):
|
|
269
|
-
|
|
270
|
-
```text
|
|
271
|
-
agent-roast — git discipline audit (304 AI commits in Soup)
|
|
272
|
-
|
|
273
|
-
SCORE: 55 / 100 · The Panic Looper
|
|
274
|
-
Prone to rapid-fire fix and revert thrashing cycles when wrestling stubborn bugs.
|
|
275
|
-
|
|
276
|
-
INFRACTIONS DETECTED (42)
|
|
277
|
-
|
|
278
|
-
● panic-loop (15) — consecutive quick fixes < 15m apart
|
|
279
|
-
latest: 3df29a1 -> a910f21 (3m apart)
|
|
280
|
-
|
|
281
|
-
● type-escape (19) — compiler type bypasses in added lines
|
|
282
|
-
e.g. src/client.ts:42 — response.body as any
|
|
283
|
-
|
|
284
|
-
● test-skip (6) — disabled or skipped test suites
|
|
285
|
-
e.g. tests/test_outbound.py:18 — pytest.skip(...)
|
|
286
|
-
|
|
287
|
-
● trivial-assert (2) — tautological assertions faking test coverage
|
|
288
|
-
e.g. tests/auth.test.ts:31 — expect(true).toBe(true)
|
|
289
|
-
|
|
290
|
-
● stub-abandonment (1) — incomplete stubs left behind
|
|
291
|
-
e.g. src/payment.ts:18 — throw new Error("Not implemented")
|
|
292
|
-
|
|
293
|
-
● swallowed-error (2) — empty catch blocks or except: pass
|
|
33
|
+
npx agent-roast demo # ten seconds: a scripted example in a temporary repository, nothing of yours is read
|
|
34
|
+
npx agent-roast # review what you have not committed yet (on a clean tree: replay your last commits)
|
|
294
35
|
```
|
|
295
36
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
<img src="docs/assets/demo.gif" alt="agent-roast running in terminal: streaming git diff, calculating discipline score and line proofs" width="820">
|
|
299
|
-
|
|
300
|
-
---
|
|
301
|
-
|
|
302
|
-
### Configuration (`.agentroastrc.json`)
|
|
303
|
-
|
|
304
|
-
Configure custom ignore paths, rule severities, and CI thresholds with a `.agentroastrc.json` file in your repository root:
|
|
305
|
-
|
|
306
|
-
```json
|
|
307
|
-
{
|
|
308
|
-
"ignorePaths": [
|
|
309
|
-
"**/*.min.js",
|
|
310
|
-
"**/vendor/**",
|
|
311
|
-
"**/dist/**",
|
|
312
|
-
"**/fixtures/**"
|
|
313
|
-
],
|
|
314
|
-
"rules": {
|
|
315
|
-
"test-focus": "error",
|
|
316
|
-
"swallowed-error": "warn",
|
|
317
|
-
"trivial-assert": "warn",
|
|
318
|
-
"stub-abandonment": "warn"
|
|
319
|
-
},
|
|
320
|
-
"scoreThreshold": 70
|
|
321
|
-
}
|
|
322
|
-
```
|
|
323
|
-
|
|
324
|
-
---
|
|
325
|
-
|
|
326
|
-
### Check code before committing
|
|
37
|
+
## Stop your coding agent from doing it
|
|
327
38
|
|
|
328
39
|
```bash
|
|
329
|
-
|
|
330
|
-
npx agent-roast --staged
|
|
331
|
-
npx agent-roast init --hook
|
|
40
|
+
npx agent-roast hook install # Claude Code, Codex and Cursor
|
|
332
41
|
```
|
|
333
42
|
|
|
334
|
-
|
|
335
|
-
of changed files in HEAD and the Git index. It detects deletion-only empty handlers
|
|
336
|
-
and retains comment context. Existing findings do not block; additional occurrences
|
|
337
|
-
do. Unstaged edits, untracked files and `git add -N` intent-to-add entries are excluded.
|
|
338
|
-
The older 0.6.0 `--staged` command checks only added index lines. Since
|
|
339
|
-
0.8.0, it also reads Git's temporary candidate index during real `commit -a` / `--only`
|
|
340
|
-
hooks. An alternate `GIT_INDEX_FILE` outside this checkout's Git metadata is refused
|
|
341
|
-
with exit 2; it cannot silently redirect the check to a different commit.
|
|
342
|
-
|
|
343
|
-
Policy comes from HEAD. Staged/unstaged config edits cannot weaken this check and
|
|
344
|
-
are reported; adopt policy changes in a separately reviewed commit. With no HEAD,
|
|
345
|
-
the first commit uses built-in defaults; use `--fail-on` for an explicit override.
|
|
346
|
-
For example: `node dist/cli.js review --staged --fail-on test-skip,test-focus,swallowed-error`.
|
|
347
|
-
Source is pinned by Git blob IDs. If HEAD or the staged inventory changes before the
|
|
348
|
-
scan finishes, it exits 2 and asks for a rerun. The report's `source` is `index`;
|
|
349
|
-
`headSha` is an `INDEX:` snapshot digest, not a commit SHA, and an unborn base is `EMPTY`.
|
|
350
|
-
The JSON schema version for context reviews is now `1.1.0`.
|
|
43
|
+
For Claude Code there is also a plugin: `/plugin install agent-roast --marketplace Nari-Ab/agent-roast`.
|
|
351
44
|
|
|
352
|
-
|
|
353
|
-
|
|
45
|
+
When the agent is about to finish, agent-roast reviews everything it changed. If a check got weaker, the agent is **sent back
|
|
46
|
+
once**, with the file, the line and the before and after, and told to fix the code instead. If it tries again, you get a
|
|
47
|
+
warning rather than an endless loop. Anything agent-roast cannot check lets the agent finish: it never breaks a session. An
|
|
48
|
+
intended change is accepted by committing it. Setup for each agent, what it does not do, and how to pause it:
|
|
49
|
+
[docs/integrations.md](docs/integrations.md).
|
|
354
50
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
a Git repository, initialization uses the supplied directory. Its output shows the
|
|
358
|
-
actual destination and existing policy/hooks are preserved.
|
|
51
|
+
> The agent hooks follow each agent's documented hook protocol and are tested with simulated hook input, not yet in long live
|
|
52
|
+
> sessions with every agent. Reports of what you see are welcome.
|
|
359
53
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
Create `.agentroastrc.json` (or run `npx agent-roast init`):
|
|
363
|
-
|
|
364
|
-
```json
|
|
365
|
-
{
|
|
366
|
-
"rules": {
|
|
367
|
-
"test-skip": "error",
|
|
368
|
-
"test-focus": "error",
|
|
369
|
-
"trivial-assert": "error",
|
|
370
|
-
"swallowed-error": "warn",
|
|
371
|
-
"type-escape": "off"
|
|
372
|
-
},
|
|
373
|
-
"ignorePaths": ["**/generated/**", "**/vendor/**"],
|
|
374
|
-
"panicLoopWindowMinutes": 10,
|
|
375
|
-
"scoreThreshold": 70
|
|
376
|
-
}
|
|
377
|
-
```
|
|
378
|
-
|
|
379
|
-
`off` removes findings and score penalties; `warn` reports without blocking a diff;
|
|
380
|
-
`error` blocks PR/staged checks, including `test-focus` by default in 0.7.0. An explicit `failOn` array overrides which enabled
|
|
381
|
-
rules block (`[]` makes the audit advisory). CLI `--fail-on` takes precedence over
|
|
382
|
-
that array. History and badge audits honor disabled rules and the panic-loop window.
|
|
383
|
-
History exit status is controlled by `scoreThreshold` or `--fail-under`.
|
|
384
|
-
Invalid JSON, unknown rule names and invalid settings stop the audit with exit code 2.
|
|
385
|
-
Configurations generated by older versions may contain unsupported rules such as
|
|
386
|
-
`hallucinated-package`, `empty-catch` or `mock-leak`; remove these entries and use
|
|
387
|
-
`swallowed-error` for empty catches.
|
|
388
|
-
|
|
389
|
-
Exit codes: `0` passed, `1` blocking findings/score threshold, `2` invalid configuration,
|
|
390
|
-
Git refs or an incomplete scan. Since 0.8.0, legacy/history CLI audits also return 2
|
|
391
|
-
when lines were skipped or supported source was marked binary by Git attributes,
|
|
392
|
-
instead of treating missing coverage as a clean result. `--format json` also works for history audits. A history
|
|
393
|
-
sample below 200 added lines has no score, but its findings are still shown.
|
|
394
|
-
|
|
395
|
-
### GitHub Actions Integration
|
|
396
|
-
|
|
397
|
-
Add `agent-roast` as a gate in your pull request workflow (`.github/workflows/agent-roast.yml`):
|
|
54
|
+
## Check every pull request
|
|
398
55
|
|
|
399
56
|
```yaml
|
|
57
|
+
# .github/workflows/agent-roast.yml
|
|
400
58
|
name: Agent Roast
|
|
401
|
-
on:
|
|
402
|
-
|
|
403
|
-
branches: [main]
|
|
404
|
-
|
|
405
|
-
permissions:
|
|
406
|
-
contents: read
|
|
407
|
-
|
|
59
|
+
on: pull_request
|
|
60
|
+
permissions: { contents: read, pull-requests: write }
|
|
408
61
|
jobs:
|
|
409
62
|
audit:
|
|
410
63
|
runs-on: ubuntu-latest
|
|
411
64
|
steps:
|
|
412
65
|
- uses: actions/checkout@v4
|
|
413
|
-
with:
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
- name: Run agent-roast audit
|
|
417
|
-
uses: Nari-Ab/agent-roast@v1
|
|
418
|
-
with:
|
|
419
|
-
format: github
|
|
66
|
+
with: { fetch-depth: 0 }
|
|
67
|
+
- uses: Nari-Ab/agent-roast@v1
|
|
68
|
+
with: { comment: true } # one comment, updated on every push; add `advisory: true` to try it without failing PRs
|
|
420
69
|
```
|
|
421
70
|
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
> **Security Note:** `agent-roast` runs in an isolated runner directory (`$RUNNER_TEMP`) with `--ignore-scripts` to neutralize malicious `.npmrc` files in untrusted pull requests. `pull_request_target` is not supported.
|
|
427
|
-
|
|
428
|
-
---
|
|
71
|
+
Also: `npx agent-roast review --base origin/main` in any CI, `npx agent-roast init --hook` or the
|
|
72
|
+
[pre-commit framework](docs/integrations.md#the-pre-commit-framework) for the next commit, and SARIF output for code scanning.
|
|
73
|
+
Policy is read from the **base** branch, so a pull request cannot switch off the rules that review it. Before you decide,
|
|
74
|
+
`npx agent-roast replay` shows what it would have said about your last 50 commits.
|
|
429
75
|
|
|
430
|
-
|
|
76
|
+
## What it catches
|
|
431
77
|
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
-
|
|
440
|
-
- **Stub abandonment (`stub-abandonment`):** Dummy stubs left unimplemented in committed code (`throw new Error("Not implemented")`, `raise NotImplementedError`, Rust `todo!()` / `unimplemented!()`).
|
|
441
|
-
- **Type escapes (`type-escape`):** `as any`, `as unknown as`, `as never`, `// @ts-ignore`, `// @ts-nocheck`, `// @ts-expect-error`, `# type: ignore`, `# noqa`, `eslint-disable`.
|
|
442
|
-
- **Swallowed errors (`swallowed-error`):** Empty `catch {}` or `except: pass` blocks hiding runtime failures.
|
|
443
|
-
- **Panic fix loops (`panic-loop`):** Heuristic chain analysis of rapid-fire fix/revert commits by the same author within 15 minutes touching overlapping files. *(Observational metric for repository audits; not a PR blocker)*.
|
|
444
|
-
|
|
445
|
-
---
|
|
446
|
-
|
|
447
|
-
### Scoring Methodology
|
|
78
|
+
| Rule | Fires when | By default |
|
|
79
|
+
| --- | --- | :-: |
|
|
80
|
+
| `assertion-weakened` | an exact check is replaced by a weaker one: `toBe(42)` → `toBeDefined()`, `assert x == 1` → `assert x` | blocks |
|
|
81
|
+
| `guard-weakened` | a coverage threshold is lowered, `strict` is switched off, a lint rule is downgraded, a CI step may fail, a workflow stops running tests | blocks |
|
|
82
|
+
| `test-skip` | a test is switched off: `it.skip`, `@pytest.mark.skip`, `t.Skip`, `#[ignore]`, `@Disabled`, `[Ignore]`, `xit`, ... | blocks |
|
|
83
|
+
| `test-focus`, `trivial-assert` | `.only` / `fit`; `expect(true).toBe(true)` and its relatives in ten languages | blocks |
|
|
84
|
+
| `assertion-removed`, `test-removed`, `expectation-rewritten` | a test loses assertions, disappears, or its expected value is edited next to production code | warns |
|
|
85
|
+
| `swallowed-error`, `type-escape`, `stub-abandonment` | `catch {}` / `except: pass`, `as any` / `# type: ignore`, `throw new Error("Not implemented")` | warns |
|
|
448
86
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
87
|
+
Renames, moved tests, parametrization, moved assertions and reformatting are recognized and not reported, and neither is a skip
|
|
88
|
+
that depends on the environment (`if testing.Short() { t.Skip() }`, `test.skip(isMobile, ...)`). JavaScript/TypeScript, Python
|
|
89
|
+
and Go get the full before/after comparison; skips and placeholder assertions also cover Rust, Java, Kotlin, C#, Ruby, PHP and
|
|
90
|
+
Swift; CI and config files are checked whatever the language. Each rule with examples and limits: [docs/rules.md](docs/rules.md).
|
|
453
91
|
|
|
454
|
-
|
|
92
|
+
## Configure
|
|
455
93
|
|
|
456
|
-
|
|
94
|
+
Rules, severities and paths live in `.agentroastrc.json` at the repository root (`npx agent-roast init` writes a starting file):
|
|
457
95
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
-
|
|
461
|
-
|
|
96
|
+
```json
|
|
97
|
+
{
|
|
98
|
+
"failOn": ["assertion-weakened", "guard-weakened", "test-skip", "test-focus", "trivial-assert"],
|
|
99
|
+
"rules": { "type-escape": "off" },
|
|
100
|
+
"ignorePaths": ["**/generated/**"]
|
|
101
|
+
}
|
|
102
|
+
```
|
|
462
103
|
|
|
463
|
-
|
|
104
|
+
A change cannot edit this file to relax its own review, because it is read from `HEAD` or the base branch. To accept one
|
|
105
|
+
intentional finding, add an expiring exception instead of turning a rule off, and adopt an existing project without blocking on
|
|
106
|
+
old debt with a baseline: [docs/reference.md](docs/reference.md#configuration).
|
|
464
107
|
|
|
465
|
-
|
|
108
|
+
## Does it work?
|
|
466
109
|
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
patterns, not proof of AI authorship or developer intent. Deliberate skips and abstract
|
|
470
|
-
methods can be legitimate. Since 0.8.0, the analyzer improves language-specific checks, multiline skips/assertions,
|
|
471
|
-
Rust raw strings/lifetimes and Java/Kotlin text blocks. Contiguous comments, Python
|
|
472
|
-
docstrings and multiline empty handlers are recognized. Template interpolation, complex language syntax and context outside
|
|
473
|
-
the added diff in legacy audit modes are not fully parsed. Custom test API aliases,
|
|
474
|
-
computed property calls and type/import resolution are not handled. Panic loops are an observational history heuristic.
|
|
475
|
-
Test registration options such as Node's `test('name', { skip: true }, fn)` and
|
|
476
|
-
`{ only: true }` are currently not inspected; use explicit `.skip`/`.only` APIs and
|
|
477
|
-
the runner's CI safeguards. Regexp masking is contextual, not a full JavaScript
|
|
478
|
-
parser. Formatting across contiguous lines is supported for casts, empty catches
|
|
479
|
-
and placeholder errors, but legacy added-line audits cannot recover missing hunks.
|
|
480
|
-
The discipline score summarizes added history; it does not certify current code quality.
|
|
481
|
-
`check` reports actionable findings without assigning a personality or quality score.
|
|
482
|
-
History attribution is based on explicit text/identity heuristics; it does not prove
|
|
483
|
-
AI authorship. Since 0.8.0, the analyzer avoids classifying ordinary people by name fragments
|
|
484
|
-
or treating every automation bot as an AI author. Use `--all` for all commits.
|
|
110
|
+
Measured, with the denominators and the caveats in [docs/benchmarks.md](docs/benchmarks.md). **Weakened checks are rare, mostly
|
|
111
|
+
deliberate, and not specific to AI. agent-roast is a tripwire that stays silent until a check gets weaker.**
|
|
485
112
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
113
|
+
- **64 of 64** hand-labeled cheating edits are caught and **44 of 44** harmless look-alikes (reformats, moves, raised
|
|
114
|
+
thresholds, environment-gated skips) stay silent. The cases were written with the detector, so they guard against regressions;
|
|
115
|
+
they do not prove accuracy. Three gaps are documented and still open.
|
|
116
|
+
- **12,645 commits** that touch tests or CI/config in 166 public repositories: blocking rules fired on 0.3% of AI-signed commits
|
|
117
|
+
(Claude, Copilot, Cursor, Codex, Devin, aider) and on 0.3% of the others. Inside the same repositories the odds for an
|
|
118
|
+
AI-signed commit were 0.81 times those of another commit (95% CI 0.40–1.67). There is no sign that AI-signed commits weaken
|
|
119
|
+
checks more often.
|
|
120
|
+
- **About one finding in five was a false alarm**, and most of the rest were deliberate, explained changes a reviewer should
|
|
121
|
+
see rather than mistakes. The labels come from one reader (an AI assistant), so treat them as a first estimate.
|
|
122
|
+
- `replay` ran on 179 public repositories that use coding agents: no commit would have been blocked in 149 of them.
|
|
491
123
|
|
|
492
|
-
|
|
124
|
+
## How it compares
|
|
493
125
|
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
126
|
+
TDD Guard and Probity enforce a *process* (tests first) through agent hooks; aislop scans for broad "AI slop" across 11
|
|
127
|
+
languages; hallucinot, fakegreen and SlopGate look at diffs for the same shortcuts; linters and coverage gates see the current
|
|
128
|
+
code but not that a check got weaker. agent-roast narrows to one question, reads the full before and after, and says how it was
|
|
129
|
+
measured. Most of these tools are complementary. [docs/comparison.md](docs/comparison.md) has the details.
|
|
498
130
|
|
|
499
|
-
|
|
500
|
-
npm ci
|
|
501
|
-
npm run typecheck
|
|
502
|
-
npm test
|
|
131
|
+
## Safe to run on code you do not trust
|
|
503
132
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
133
|
+
- **Offline.** No network request, no model call, no telemetry; a test inspects the bundle for network modules.
|
|
134
|
+
- **Reads, never runs.** It reads Git objects (or regular files inside the repository for `--worktree`) and never executes
|
|
135
|
+
project code, hooks, diff programs or package scripts. Reports escape control characters.
|
|
136
|
+
- **Policy from the trusted side.** The rules come from `HEAD` or the base branch, not from the change under review.
|
|
137
|
+
- **Honest about gaps.** An incomplete scan exits 2, never "clean". [SECURITY.md](SECURITY.md) says how to report a problem.
|
|
507
138
|
|
|
508
|
-
|
|
509
|
-
against current code. Regression tests use disposable Git repositories. The programmatic
|
|
510
|
-
`auditPullRequest({ staged: true })` API retains the legacy added-lines contract;
|
|
511
|
-
use `reviewStagedChanges()` for the new context comparison and `ReviewResult`.
|
|
512
|
-
The composite Action installs exactly 0.10.1. For local development, use
|
|
513
|
-
`node dist/cli.js --staged` after building.
|
|
139
|
+
It is a review aid. It cannot prove who wrote a change or that code is correct, and it reads text, not program meaning.
|
|
514
140
|
|
|
515
|
-
|
|
141
|
+
## Documentation
|
|
516
142
|
|
|
517
|
-
|
|
143
|
+
[Rules](docs/rules.md) · [Integrations](docs/integrations.md) · [Reference](docs/reference.md) (commands, exit codes,
|
|
144
|
+
configuration, exceptions, baselines, limits) · [Comparison](docs/comparison.md) · [Measurements](docs/benchmarks.md) ·
|
|
145
|
+
[Try it on your repository](docs/pilot.md) · [Contributing](CONTRIBUTING.md) · [Changelog](CHANGELOG.md)
|
|
518
146
|
|
|
519
|
-
|
|
147
|
+
Found a finding that was wrong, or a shortcut it missed? That is the most useful report there is:
|
|
148
|
+
[open an issue](https://github.com/Nari-Ab/agent-roast/issues/new/choose).
|
|
520
149
|
|
|
521
|
-
|
|
150
|
+
## License
|
|
522
151
|
|
|
152
|
+
[MIT](LICENSE). Created by Nariman Abdukarimov.
|