Skip to content
MrJev

triagedy

Security alert triage as a Unix filter: JSONL alerts in, typed decisions out.

View on GitHub →

Hands-on review

JSONL alerts in, typed decisions out, with the routing done in Rust. The whole alert goes out unredacted, and one confidence is never checked.

Good for

  • Putting a cheap sieve in front of an expensive SOC queue
  • Shell-shaped: JSONL in, JSONL out, exit codes that mean something
  • Answer validation: an out-of-range answer becomes an error, not a default

Watch out for

  • The whole alert object goes out verbatim — no allowlist, no redaction, no cap
  • Low confidence on the attack-class question never sets `review_required`
  • One call per alert, no cache, no budget; the input file is read into memory whole

Tested Sep 20, 2026 at 5bef4e61518f · Rust in Docker, offline against its own bundled stand-in; 71 tests, fmt and clippy

How we reviewed this: we built and tested it in Docker offline, ran its own bundled stand-in server end to end with and without context, and fed it an alert carrying invented secrets to see what left the process. We made no Jev calls.

What it does

triagedy, by m0rphtail, is a Unix filter for security alerts. JSONL in, one request per alert, five typed questions out — disposition, severity, false-positive likelihood, escalation, attack class — and then src/policy.rs turns those answers into close, investigate, escalate or contain. The judgment is the model’s; the routing is plain Rust you can read.

The engineering is the most disciplined of this batch: 71 tests passing, cargo fmt --check clean, clippy -D warnings clean, CI green, dependabot, a SECURITY.md with a private reporting route, and a key stored 0600 in a 0700 directory with a test that fixes loose permissions. Answers outside the declared options or ranges become error records rather than silent defaults — we checked, and it holds.

The whole alert goes out

The state is built in src/backends/jev.rs:62:

match context {
    Some(c) if !c.is_empty() => json!({ "alert": alert.raw.clone(), "recent_activity": &c.items }),
    _ => alert.raw.clone(),
}

alert.raw is the raw JSON object, unchanged. No field allowlist, no redaction, no truncation. We fed it an alert containing an SSN, a clinical note and an AWS key; all three arrived in the request body intact, alongside the username, internal IPs and full command line.

There is a MAX_STATE_CHARS = 8_000 cap in src/questions.rs:108 — but it is only applied on the OpenAI fallback path, so the default backend is the one without a limit.

The --context window is the opposite: twenty recent decisions, seven named fields each. That’s the shape the alert itself should have.

One confidence isn’t checked

The README’s rule (line 259) is:

Any confidence below 0.6 sets review_required with a note explaining why.

policy.rs:82 checks disposition_confidence, and :88 checks severity_confidence. attack_class_confidence exists on the decision (decision.rs:20, populated at :91) and is never read. We drove it with an attack-class confidence of 0.05: review_required came back false, with no note. An alert the model can barely classify passes through unflagged. Reported.

Two smaller things: there’s no cache, no deduplication and no spend cap — one call per alert, retried up to three times on 429 or 529 — and engine.rs:79 reads the whole input file into a vector before it starts, which isn’t what a filter in front of a 1,185-event corpus implies.

Verdict

The shape is right, and the parts that are code rather than judgment are genuinely well made. Before you point it at real alerts, decide that every field of them may go to a third party, because right now every field does.

For the same question asked of logs instead, see Jev Logs.

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 (dzhng)

★ 3.1k▲ 239

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.

TypeScriptReviewed

webctl

★ 163▲ 1

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.

GoReviewed

sys1grep

★ 150

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.

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.