Skip to content
MrJev

Sniff Test

Prose linter for AI writing tells: countable regex rules run locally, and one judgment question covers the rest.

View on GitHub →

Hands-on review

A prose linter for AI writing tells, with the most careful consent gate we've seen. Name a file explicitly and the extension check is skipped.

Good for

  • A consent gate that defaults to sending nothing and names the destination, not a boolean
  • Regex rules locally and one judgment call for the rest, batched into a single request
  • The best CI in this batch, including gitleaks over the full history

Watch out for

  • A path you name is read whatever its extension; only the directory walk filters
  • `--yes` returns before the disclosure prints, so first-time users never see it
  • The endpoint is a hardcoded constant with no override

Tested Sep 20, 2026 at 240653e · Bun in Docker, offline against a local stand-in, with the endpoint constant patched to reach it

How we reviewed this: we ran it in Docker offline against a local stand-in, patching its one hardcoded endpoint constant to reach it, then reverted and diffed. We made no Jev calls.

What it does

It reads Markdown and plain text and flags the tells of machine-written prose. Countable rules — em dashes, tricolons, banned words, uniform sentence length — run locally and cost nothing. Whatever those can’t settle goes out as a single request carrying the paragraph and all the rules at once, so asking five questions costs about what asking one does.

This is the only project in the batch that treats sending your text as a decision rather than a default. Nothing is sent until you agree. There is no TTY, no send — it exits rather than guessing. The environment variable that grants consent is named after the destination rather than being a boolean, so agreeing to one provider doesn’t silently agree to another. A stored yes covers only the destination it was given for, and the record lives in your config directory rather than in the repository being checked.

Every part of that is a deliberate choice someone made, and most tools here make none of them.

One gap in it: --yes returns before the disclosure is printed, so somebody whose first run includes that flag never sees the description of what leaves their machine.

Naming a file skips the filter

The directory walk is careful — three extensions, dot-files skipped, symlinks refused:

/** Extensions a directory walk picks up. A file named outright is always read. */
const DRAFT_EXTENSIONS: ReadonlySet<string> = new Set([".md", ".markdown", ".txt"]);

The comment tells you the shape of the problem, and the code does what it says:

if (stats.isDirectory()) {
  for (const file of walk(path, skip)) found.add(file);
} else {
  found.add(path);
}

Anything you name is read, extension or not. That is defensible for a tool you point at a draft — you asked for this file — and it is the same pattern we found in jgrep and jegrep on the same day. The difference here is that the consent gate stands in front of it, so the mistake costs you a prompt rather than a request.

Verdict

The CI is the most thorough in this group by a wide margin: typecheck, tests, a package allow-list, gitleaks across the full history and the working tree, a dependency review that fails on low severity, an assertion that there are no runtime dependencies, a smoke test of the installed binary, a size ceiling, and it lints its own Markdown with itself. Publishing goes through an approval-gated environment with provenance.

Three open issues, one author, 97 commits. If you want to see what taking distribution seriously looks like in a one-person project, read this one.

For rules about code rather than prose, see jev-lint and perch.

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.

More in Command-Line Tools

jevgrep

★ 866

dzhng/jevgrep

Finds code by what it does rather than what it matches: a CLI for coding agents that asks which files and which regions are relevant to a description.

TypeScript

JevRev

★ 434

Alex314618-create/JevRev

Puts an LLM and Jev in one workflow, with sift, loop and long modes, a TUI, and a CLI that can be pointed at any /v1/systemone host. English and Chinese.

TypeScript

semgrep (uehaj)

★ 145▲ 26

uehaj/jev-semgrep

Grep by meaning: Jev scores each line against a description in any language, with AND, OR, and NOT. A single dependency-free Node file.

JavaScriptReviewed

Get new Jev projects every week

New Jev releases, pricing changes, and the best new projects, once a week. No spam; unsubscribe anytime.

Powered by Buttondown. See our privacy policy.