You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The plugin asks for its settings when it is enabled: the TypeSafe key (kept in the
Keychain), the claims_done threshold, the decision log, shadow mode, and a regex for
your own check command. Each arrives as CLAUDE_PLUGIN_OPTION_<NAME> and wins over the
plain environment variable.
Subagent work counts. The hook reads the subagents/ files next to the session
transcript, keeps the ones carrying this turn's prompt id, and merges them into the turn
by timestamp, so a turn that delegated its edits no longer looks like one that changed
nothing.
Shadow mode: the whole pipeline runs, the turn still ends, and a stop it would have
blocked prints jev-belay would have blocked this turn: and the reason through systemMessage, which Claude Code shows to you and not to the model.
The closing message is read from the Stop payload's last_assistant_message when the
host sends it, so the 300 ms re-read is paid only on older hosts.
belay.mjs stats (verdict counts, calls, cost, latency p50 and p90, the last 14 days), belay.mjs last (the last decision, rendered), and belay.mjs doctor (key, host
version, hook registration, transcripts readable, a round trip through a fake; --live
makes one real call).
Two skills: /jev-belay:why explains the last decision, /jev-belay:doctor reads the
doctor's output back and names the fix for anything that failed.
Belt 2 reads nextest, deno, ruff, mypy, mocha, rspec, minitest, phpunit, playwright,
swift, ctest and biome summaries, plus two compiler shapes, rustc's error[E0119]: and
go's file.go:12:3:, which decide fail when no runner summary follows them. A compile
error used to read as a passing check in a cargo check or a go build.
test/runners/ holds a captured or documented output per runner belt 2 claims to know,
passing and failing, so a belt change has something to fail against.
A check command of your own: set the check option (or JEV_BELAY_CHECK) to a regex
and belt 1 tests it next to the built-in runners. An invalid regex is ignored.
Changed
tui.mjs holds the live view, the replay, stats, last and doctor. belay.mjs is
the hook and imports it lazily, so the hook path never parses the TUI.
.env.example is gone. Nothing ever read it, and the README told people to copy it.
The claims_done threshold is 0.70, up from 0.65: on the re-extracted corpus, with
subagent turns folded in, 0.70 is the lowest cutoff holding wrong blocks under 2%, and
it catches the same 7 of 12 false dones.
A check regex that matches the empty string is ignored like a broken one, since .*
would make every Bash call a passing check. An RSpec error outside the examples is a
failure whatever the failure count says. The rustc rule needs the numbered diagnostic or
cargo's closing line, so git push is no longer quoted as a failed check.
Fixed
A threshold that is not a number no longer disables blocking silently; it falls back to
the default.
The plugin install never delivered a key. The README pointed at a .env file that
neither the hook nor Claude Code reads, so a plugin user got "no key", exit 0, forever,
with nothing saying so.
A compile error in a cargo check or a go build read as a passing check, which sent
Jev a state saying a check passed and put the same claim in the nudge.
Measured
The ablation on the re-extracted corpus (2,694 stops, 477 reaching the gate, 17.7%),
same 100-stop audit slice with 12 false dones, direct API, jev-1.13.0, 2026-09-20:
AUROC 0.777 for the wording alone, 0.886 with the evidence gate, 0.976 for the full
hook, interval 0.915 to 1.000. On the 76 gated stops: 0.967 against 0.844. At 0.70:
8 blocks in 100, 7 right. Median call 1,222 input tokens, $0.00005, 346 ms.