one flow.
one request.
one verdict.

An intrusion detection system that asks TypeSafe's Jev two typed questions about one network flow and gets a verdict back, with no text to parse.

Put to the test on NSL-KDD, the classic intrusion detection benchmark, against an LLM (GPT-5.6 Luna) and a Random Forest.

input
flow        one connection record from NSL-KDD, plus k labeled examples

request: two typed questions to jev
is_attack   noul     Is the connection an intrusion attempt?
category    choice   Which category does it belong to?

output
is_attack   → 0.82
category    → dos, confidence 0.84
verdict     → attack   p_attack ≥ 0.5, the same cut for every detector

the request

Jev IDS runs on a new kind of AI, the System One Model (SOM). Instead of generating text, a SOM takes a state and standardized questions about it and answers each one with a probability. Jev IDS hands it one monitored network flow and gets back one verdict, attack or normal, with the probability behind it.

  1. input

    one flow

    The monitoring record of a single connection: duration, protocol, service, bytes in and out.

  2. jev

    one request

    State: the instructions, a few labeled examples and the flow. Questions: is_attack and category.

  3. output

    one verdict

    attack · p_attack 0.82
    dos · confidence 0.84

Everything Jev is told lives in one versioned file, prompts/nsl-kdd/jev.json. Python adds only the flow and the examples, and the file's sha256 rides with every prediction, so any verdict traces back to the exact prompt. Examples are labeled by category only; attack names never reach a model. Both questions are answered in parallel over the same state, in one round trip.

Two baselines follow the same protocol: an LLM agent with a JSON output schema and a scikit-learn Random Forest. Same frozen split, same examples, same seeds.

evidence

Pilot split of NSL-KDD: 300 flows, 160 of them attacks and 39 of those of a kind absent from KDDTrain+. Three seeds of examples, so 900 predictions per detector and k. Means over the three seeds, from the runs of 2026-09-21.

pilot split of NSL-KDD · mean of three seeds
detector k f1 precision recall novel recall latency cost / 1M flows
jev (typesafe-ai/jev) 1 0.859 0.941 0.790 0.838 504 ms $74
gpt-5.6 (gpt-5.6-luna) 1 0.776 0.914 0.675 0.547 2,410 ms $283
random forest (100 trees) 1 0.728 0.574 1.000 1.000 3 ms local
jev 2 0.839 0.929 0.765 0.761 494 ms $106
gpt-5.6 2 0.807 0.930 0.715 0.573 2,476 ms $399
random forest 2 0.766 0.629 0.990 0.991 2 ms local

Jev against the Random Forest at k = 1: of 900 paired verdicts, 439 differ. Jev is right in 338 of them and the forest in 101 (McNemar p ≈ 6 × 10⁻³¹). A forest trained on five rows calls almost everything an attack, which is why its recall is perfect and its precision is not: on the 420 benign flows it raised 362 false alarms, Jev 24.

limits worth knowing

try it

git clone https://github.com/jev-ids/jev-ids.git
cd jev-ids
uv sync
.env: AI_GATEWAY_API_KEY for Jev through the Vercel AI Gateway;
      DEEPSEEK_API_KEY and CHATGPT_CLIENT_ID only for the LLM baselines.

Download NSL-KDD into data/raw/nsl-kdd/ and prepare it once.

uv run python -m scripts.prepare_nsl_kdd
uv run jev-ids run --dataset data/nsl-kdd/dataset.json --detector jev --split smoke --k 0,1

The smoke split is five flows. The run writes results/<timestamp>-nsl-kdd-jev-smoke/ with config.json, one JSON row per flow in predictions.jsonl and the raw answers in responses.jsonl.

bring your own flows

Jev IDS is an independent research prototype, not a product. Its numbers come from one pilot on NSL-KDD. It can still sit inside a commercial solution, and this is how.

where jev fits

A commercial IDS already has sensors, a flow exporter and a signature engine feeding a SIEM. Jev IDS replaces none of them. It sits beside the pipeline, off the packet path, and judges one flow record at a time.

Sensor, exporter, signatures, alerts and SIEM in one line; a side channel leaves the exporter, goes through a queue to jev_ids and returns into the SIEM. sensor exporter signatures alerts SIEM queue jev_ids side channel

Half a second per verdict and a rate-limited gateway make this an asynchronous side channel, fed from the exporter (NetFlow, IPFIX, Zeek conn.log) through a queue, never an inline filter.

six steps

  1. Get a key. Jev is served through the Vercel AI Gateway; set AI_GATEWAY_API_KEY in .env. Pricing and terms are TypeSafe's and Vercel's.
  2. Describe your flows. Write a dataset card like data/nsl-kdd/dataset.json: the columns your flow exporter emits, in order, which of them are symbolic, your categories and which one is benign.
  3. Write the request. Copy prompts/nsl-kdd/jev.json, replace columns and the category descriptions with yours, and keep the two questions.
  4. Pick examples. One labeled flow per category from your own network is enough to start; k = 1 is what the pilot used.
  5. Call the detector. JevDetector(load_prompt(path)).predict(flow, examples) returns p_attack, category_pred and confidence for one flow in about half a second. Route p_attack to your alerting with the cut your alarm budget allows; 0.5 was the benchmark's choice, not a rule.
  6. Measure before you trust. Run jev-ids run and jev-ids metrics on a labeled split of your own flows. The numbers above are NSL-KDD's, not yours.

Only flow features leave your network, never payloads, but they do leave it: every request goes to the gateway.

the team