How we reviewed this: we installed the published package in Docker, ran the repository’s tests offline, and did dry runs over a directory we built to see what it selects. We made no Jev calls.
What it does
JevLint, by iamtoomas (huntedman when we tested it), turns a written convention into a file-level check. Each rule is a Noul:
Does this file contain at least one application-defined symbolic string literal that should be replaced with a named member of a descriptive constant object?
One request per file carries every rule that applies to it; code applies the threshold (0.8 by default) and the exit codes — 1 for findings, 2 for failures — which is what makes it usable in CI.
The basics all worked: init doesn’t overwrite an existing config, --dry-run prints the request without a key, and with no key a real run fails with a clear message. Its 65 tests pass offline.
The exclusion list was half the size of the file list
It scans {js,jsx,mjs,cjs,ts,tsx,mts,cts} — eight extensions. The default credential exclusion is:
**/{secrets,credentials}.{js,mjs,cjs,ts}
four. So secrets.tsx, credentials.mts, secrets.jsx and credentials.cts are selected like any other source file, and the whole file content goes into the request. We confirmed it with a dry run: three such files appeared in the payload with their contents intact, while secrets.ts was correctly excluded. The CLI’s own help text says credentials are excluded.
Directory names (secrets/, credentials/) are excluded properly; it’s the filename rule that has the hole.
And --dry-run isn’t a safe preview. Plugins declared in the config are dynamically imported before the dry-run branch, and modern Node executes TypeScript directly — so running npx jevlint --dry-run inside an untrusted repository executes that repository’s plugin code. We reproduced it: exit code 0, no network request, and a file written by the “plugin”. This is the same shape as a linter config, but the README describes the flag as printing the request without calling the API, which reads as safe.
We reported both, and both were addressed within a day.
The exclusion now builds from the same extension list the scanner uses, so all eight are covered — one list, not two, which is the fix that can’t drift again. The dry-run behaviour was kept and documented instead: --help now says plainly that it “still imports and executes configured JavaScript/TypeScript plugins” and that “plugin code is not sandboxed”. That’s a reasonable call — a plugin is code you configured, like a linter’s — and the flag now reads the way it behaves.
What it sends
The entire file, as {filePath, source}, with no redaction and no truncation — only a size cap that skips files over 128 KB. Files are processed serially, one request each, so a large repository is a lot of sequential calls.
The key is read from the environment or a local .env and only ever sent as a header.
Verdict
The idea works and the ergonomics are right: a plain-English rule, a probability, a threshold, and an exit code. For a ten-star project it is unusually finished — typed, validated, tested, published to npm.
Take a version newer than 96b9d69 if you point it at a repository with credentials in a .tsx or .mts file, and treat --dry-run as “runs this repo’s plugins but makes no request” — which is now what its help says.
For rules taken from your own instruction files instead, see Abide.
See how it compares with other tools in Best Jev tools, tested hands-on.
Review updated Sep 20, 2026. Numbers quoted from the project are its author's own; we don't publish our own measurements of Jev.