fast-jev-compaction
★ 7.8k▲ 59tamaratran/fast-jev-compaction
Claude Code plugin that replaces the compaction summary with Jev decisions. Every tool call and result is scored; stale ones are dropped or truncated, and everything kept stays verbatim.
Lints a tree against fuzzy rules kept in one markdown file, behind a provider-neutral interface so the judge can be swapped. Its LICENSE is not a recognised open-source license.
View on GitHub →Hands-on review
Write a coding rule in Markdown and have a model check every file against it. The install and the credential skip list were both fixed in a day.
Good for
Watch out for
Tested Sep 22, 2026 at 31810ef (v0. · node:22 and node:24 in Docker against a local stand-in that logs every request; published package installed from npm
How we reviewed this: we installed the published package from npm in node:22 and node:24 and ran it against a scratch tree with a local stand-in judge that logs every request body, planting a distinct canary string in each credential file. We re-ran all of it against patdown@0.11.0 on 22 September. We made no Jev calls.
You write a rule as a Markdown heading plus prose — “no hardcoded secrets”, “every exported function has a doc comment” — and patdown sends each matching file, whole, with that rule as a yes/no question. Over the cutoff (0.85 by default, overridable per rule) is a violation and the process exits 1.
The framing is good. A rule you can read is easier to argue with than a regex, and the per-rule cutoff acknowledges that some rules are fuzzier than others. The judge sits behind an Effect layer and is genuinely swappable, and TYPESAFE_BASE_URL is honoured — we didn’t have to patch anything to point it at our stand-in, which is rarer than it should be.
This was the finding that mattered, because everything below it was about code you could not execute.
README.md said npx patdown --help. Help worked. A real run did not:
$ npx --yes patdown@0.7.0 --rules rules.md --no-github
[16:26:19.381] ERROR (#2): Error: Service not found: effect/platform/FileSystem
exit=1
Same on patdown@0.6.0, and on Node 22 and Node 24. patdown@0.7.0 pinned effect: 4.0.0-rc.112; @effect/platform-node-shared imports effect/ByteSize, which does not exist until a later release candidate. npm’s exact pin gave you an effect too old for the platform package, and any tree that hoisted a newer one — which is what npx does — gave you one too new for patdown’s own compiled service tags. Both ends failed; only --help survived.
Fixed in v0.10.0, the same day we reported it. The published packages now declare @effect/platform-node-shared at the same exact rc as a direct dependency — the workspace override never shipped inside the tarball, which is the part that made it invisible in CI — and CI now packs the tarball and installs it with npm after every check, which is the change that stops it happening again.
At patdown@0.11.0, on a three-file tree with our stand-in as the judge:
$ npx --yes patdown@0.11.0 --rules rules.md --no-github
patdown: linting against 1 rule
FAIL prod.tfvars: no-todo-comments
FAIL rules.md: no-todo-comments
FAIL src/a.ts: no-todo-comments
patdownGlobExcludes was five build directories — .git, .turbo, coverage, dist, node_modules. No .env, no *.pem, no id_rsa, no extension allow-list, no size cap and no binary check, while patdown-lint.ts read whatever it was given with readFileString and sent it whole. A linter whose job is to read every file in your tree and post it to a third party is the worst place for that particular gap.
v0.10.0 added the credential names. We put a distinct canary string in each planted file and logged every request the judge received:
| planted file | canary bytes on the wire |
|---|---|
.env |
0 |
id_rsa |
0 |
secrets.yaml |
0 |
credentials.json |
0 |
server.pem |
0 |
prod.tfvars |
2 occurrences |
Five of six closed. The sixth is the shape of the approach rather than a mistake: the list is a list, and a Terraform variables file holding DB_PASSWORD= is not on it. Neither are .npmrc, .pgpass, *.p12 or .git-credentials. We’ve suggested the rest of the set, and asked whether an extension allow-list would end the category instead — a linter for prose rules about code needs a fairly short list of things it has to read, and a deny list has to keep growing.
Credit where it is due, and this is the part most tools in this directory get wrong: naming a path with --files does not bypass the check. patdown-file-judgment.ts runs patdownPathIsExcluded(relativePath) on explicit paths too. The author thought about the bypass and closed it before we arrived.
An empty globs: means the whole tree, and that became ['**/*']. Node’s glob returns directory entries as well as files, and '**/dist/**' does not match the bare entry dist, so src and dist went to readFileString as if they were files — while the README promised at line 140 that dist was always skipped. The author had not hit it because every rule in the repository’s own packs/ sets globs: explicitly and CI runs with --files-from; the documented default path had never been exercised.
Fixed in the same release: bare directory entries are in the exclude list now, and directory matches are dropped before reading. In our run above, an empty-globs rule over a tree containing dist/bundle.js read three files and no directories, and printed no error.
Both loops run at { concurrency: 1 } — serial, no cache, no budget, no token cap. We measured it at v0.11.0 on three files and three rules, counting requests and bytes at the stand-in:
total requests: 18 total state bytes sent: 3993
path: rules.md 6 requests
path: src/a.ts 6 requests
path: src/b.ts 6 requests
Nine judgments plus nine evidence lookups, from 65 bytes of source. Three multipliers are easy to miss: a file matched by M rules is sent M times; each FAIL costs a second call whose payload carries the file contents twice over, once whole and once as per-line candidate descriptions; and the rules file is itself linted.
The author’s reply to our report said the same thing — “multi-rule matches are still judged once per rule with no cache/budget yet” — and invited a patch. Ours adds --max-judgments N, which resolves every rule’s file list before the first judge call and refuses a run whose plan exceeds the cap without sending anything, and makes each file a single read per run so every rule judges the same snapshot.
0BSD, one contributor, four days old, and — unlike most of this batch — real CI on a Node 22/24 matrix. That CI runs the monorepo, which is why it stayed green while the published artifact could not start; it now installs the packed tarball too, which is the specific lesson of that week.
The idea is sound, the --files handling shows care, and the three things that made it unusable were all closed within a day of being reported. What is left is the arithmetic: this is a tool that reads your files and pays per file per rule, so decide what it is allowed to read and what it is allowed to spend before you point it at a large tree.
Four releases landed on 21 September alone, v0.10.0 through v0.11.0. Pin the version your CI installs.
For the same idea in a smaller package, see JevLint and jev-lint.
See how it compares with other tools in Best Jev tools, tested hands-on.
Review updated Sep 22, 2026. Numbers quoted from the project are its author's own; we don't publish our own measurements of Jev.
tamaratran/fast-jev-compaction
Claude Code plugin that replaces the compaction summary with Jev decisions. Every tool call and result is scored; stale ones are dropped or truncated, and everything kept stays verbatim.
thruwire/foreman
Puts Jev as a fast supervisor above slower coding agents such as Codex, starting from a ticket, spec, or bug report.
devagrawal09/jev-review
Staged code-review workflow for JavaScript and TypeScript with a local dashboard. Jev screens correctness, security, reliability, compatibility, and test risk, then scores severity and suggests a reviewer, with no generative model involved.
New Jev releases, pricing changes, and the best new projects, once a week. No spam; unsubscribe anytime.
Powered by Buttondown. See our privacy policy.