jevgrep (dzhng)
★ 3.1k▲ 239dzhng/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. Unrelated to the JevGrep above, which has the same name.
Turns a sentence into a call of a small program you installed from Git, run only when the confidence gate allows. A CLI, a package manager for those recipes, and a TypeScript SDK over the same core; your overlay may tighten a reflex's effect but never loosen it.
View on GitHub →Hands-on review
A sentence becomes a call of a small program you installed, gated on confidence. Every 'this may only tighten' rule we could reach, we tried to loosen.
Good for
Watch out for
Tested Sep 22, 2026 at 6d74482cf561 · debian:13 in Docker with its own pinned mise toolchain; its full lint and test tasks, then the built CLI driven with no key at all
How we reviewed this: we ran its own mise run lint and mise run test on its own pinned toolchain, then built the CLI and spent an afternoon trying to break the guarantees its security page makes — loosening what may only tighten, minting values outside a closed set, and running a destructive reflex without a terminal. We used no API key, and made no Jev calls.
A sentence becomes a call of a small program:
$ evoke "kill the lights in the den"
lights room="den" state="off" 0.85
den lights off
Jev picks which program and which arguments; a confidence gate decides whether the call runs, asks, or confirms. What runs is always a reflex — a recipe someone wrote and you installed from git. One binary is three things: a CLI you talk to, a package manager for reflexes, and a TypeScript SDK over the same core compiled to WebAssembly.
The design goes out of its way not to marry the engine: evoke-core is “the rules with no engine and no I/O”, and Jev is described as “the first adapter”.
docs/manual/security.md is the most precise document of its kind we have read in this directory, and unusually it is written as a list of things that cannot happen. So we tried to make them happen. Every row below is the real CLI, offline, no key:
| what we tried | what happened |
|---|---|
a gate with read above write |
adapters.jev.gate: read 0.9 is above write 0.8 |
an overlay loosening write to read |
effect "read" loosens "write"; an overlay may only tighten |
an overlay tightening write to destructive |
accepted; the reflex is now destructive |
an overlay setting run, a contract key |
run is contract, not wording; an overlay cannot change it |
| a bidi override (U+202E) in a manifest string | not_for contains a bidi control (U+202E) |
| a value outside an argument’s option set | "purple" is not an option of state: on, off, dim |
| a destructive reflex with no terminal | a confirm needs a terminal; nothing ran |
| an argument the reflex does not have | lights has no argument nonsuch |
| changing an overlay behind a trusted project’s back | ~/lab changed since you trusted it |
Nine for nine. Every refusal ends in an arrow and the command that fixes it, and the three that came from a file named the file, the line and the column.
Two of those deserve emphasis. Effect only tightens is the property we have now seen four ways this month — dsh-jev refuses to build the object, Canny makes the gate a pure function, JevLoop controls the option set — and evoke puts it in the merge rule between two files on your disk, where a git pull is the attacker. There is no --yes. We looked; the help has no such flag, and a destructive reflex without a terminal declines rather than proceeding.
There is no sandbox yet. Containment, with Landlock on Linux and Seatbelt on macOS, comes together with a permissions field in the manifest, in one change. So a claim and its enforcement arrive together.
That last sentence is the whole argument for trusting the rest of the document. It would have been easy to ship a permissions key now and the enforcement later; the manifest schema does not have one.
The same page is equally plain about the residual risk, and it is the right one:
Injected text can choose a call. It can never mint a value. … Whatever it does with a span it is handed, like a URL or a quoted text, an injected sentence can make it do. So its effect is the author’s promise about exactly that.
We confirmed the first half — a value must be an author’s option key, one of your vocabulary words, or a span checked against its range, and purple was refused. The second half is an honest statement of what a closed-set guarantee does not buy you.
And A body runs with your user, under a scrubbed environment … The scrubbing prevents leaks. It does not contain malice. **Read what you install.**
This is the part that makes it reviewable at all. evoke run <call> calls no classifier:
$ evoke run lights state=off
lights state="off"
lights off
The tool’s own line — the call, the effect, the weakest judgment — prints before the reflex’s own output, which is the stated defence against a reflex repainting the prompt. evoke show, evoke teach, evoke vocab and the whole overlay system are keyless too; the manual says so: “No command here needs the classifier’s key.”
mise run test is 452 tests with no key configured — 192 across the Rust workspace, 254 in the SDK against the same core compiled to WebAssembly, and 6 in the first-party reflex collection. mise run lint is shellcheck, taplo, the spec’s shapes, the manual’s links, a full site build, cargo fmt, clippy with warnings denied, a wasm32 build, cargo deny, and two TypeScript type-checks. Both finished clean.
A note on our own method, since it cost us two hours: our first three runs “failed”. Every one was us. The project pins node 24.20.0 and rust 1.98.1 in mise.toml and documents Node 24 in four places; we gave it Node 20, then no Node, then a checkout owned by another user so git refused it. Run mise install first, as the README says, and it is green. In its favour: each failure named its own fix, including git config --global --add safe.directory.
spec/ holds JSON schemas, golden vectors and transcripts, and both hosts are tested against them — the Rust core and the WebAssembly one run the same vectors. tests/transcripts.rs compares whole terminal sessions against expected text including exit codes, which is why our broken container produced a diff rather than a vague failure.
evoke.lock pins every remote reflex by tag, commit and an h1 content hash, with the recipe for computing it printed in the manual so you can check it yourself. Local reflexes are deliberately not locked, and trust covers the project’s four owned paths rather than a local reflex’s body — we confirmed both behaviours, and both are what the documentation says.
The repository was created the day before we tested it. What is there is unusually complete for that — a manual, a published site, a trademark file, a release pipeline with build provenance and a Homebrew tap — but there is no track record, ten stars, and no reason yet to expect API stability.
How little: we reviewed 0.1.0, and by the time we came to publish, 0.2.0 had landed with fifty-three files changed, including how the CLI parses its own flags. We re-ran everything above against it — all nine guarantees held unchanged, and the suite had grown to 452 tests. That is a good sign about the project and a warning about the version number.
The Jev endpoint is a compiled-in const, not a setting. That is defensible for a tool whose threat model includes a cloned repository pointing your decisions somewhere else — the manual makes exactly that argument about adapter names — but it does mean you cannot put it behind a proxy, and it is why parts of the decision path can only be exercised by paying for real calls.
The most carefully built thing we have reviewed this month, and the security page is the reason: it is a list of claims specific enough to be tested by a stranger in an afternoon, and every one we could reach held.
Read docs/manual/security.md even if you never install it. Then look at what it declines to claim — no sandbox, an injected sentence can still choose a call — and compare that with the confidence of the average README in this directory.
Treat the version number as real, though. This is a two-day-old project on its second minor release, with a very good foundation and nothing settled yet.
For the same “may never loosen” property proved three other ways, see dsh-jev, Canny and JevLoop; for an orchestrator built on the same instinct, Helm.
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.
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. Unrelated to the JevGrep above, which has the same name.
dorkitude/webctl
Search CLI for agents: results from up to three backends are scored by Jev against your query and an explicit --goal, and only the relevant ones reach the agent's context. Its benchmark excludes an arm it could not observe.
uehaj/sys1grep
Greps by meaning rather than pattern, scoring every line against a description and combining meanings with AND, OR and NOT; a single dependency-free Node file. Japanese and English. Formerly jev-semgrep.
New Jev releases, pricing changes, and the best new projects, once a week. No spam; unsubscribe anytime.
Powered by Buttondown. See our privacy policy.