#jev#harness-engineering#claude-code#ai-agents#tutorial

Jev Engineering: LLM Writes, Jev Decides, Code Acts [2026]

Jev engineering from a real production harness: a Claude Code guard hook, a model router, a 10-minute log cron with cost receipts, and when not to use Jev.

25 min read

Jev engineering is a way of building AI agents where the roles are split by the kind of model that is good at them: a large language model writes (plans, code, prose), Jev decides (a typed Choice, Score or Noul answer with a probability on every option), and plain code acts on those numbers. The point is to stop paying LLM prices and LLM latency for every small fork in a loop, and to put each fork behind a number your code can threshold. In a replay of 600 real daemon log entries on 2026-09-22, Jev handled every entry for $0.00029 and a median of 302 ms per call, and the one case it would not own went to Claude Code for $0.083.


Where did "Jev engineering" come from?

The term is a week old. TypeSafe AI shipped Jev on 2026-09-15 and dropped the waitlist on 2026-09-20. On 2026-09-18 0xCodila published a 10-step roadmap on X with the line that stuck: LLM writes, agents act, Jev chooses the next move. A day later 0xRicker framed it as a control system: state, decision, action, verification, next state, with the expensive model moved out of every decision loop.

Both are right about the shape. What neither post has is a production harness you can read, with the bills. That is what this page is: the definition once, then three working patterns from my own loops, with every number produced by scripts you can download from this page.

This is the same move as harness engineering and loop engineering, one layer down. Harness engineering is about the system around the model. Jev engineering is one layer of that: the small decisions inside the system get their own model.


What is Jev, in one screen?

Jev is TypeSafe AI's first System One model. You send a state (any text or JSON, up to 32k tokens with the longest question) and a map of typed questions. It evaluates every question against the state in parallel and returns typed answers with a probability distribution, in one pass, without generating tokens. It cannot write a sentence, cannot write code, cannot explain itself, and cannot pick an option you did not list.

Question typeAskReturns
ChoiceWhich one of these options?choice, probabilities over every option, confidence
ScoreWhere on this ordered scale?score (a weighted mean), probabilities per level, confidence
NoulIs this true?noul, the probability of yes, from 0 to 1 (no separate confidence field)

The numbers that matter for a harness, checked against docs.typesafe.ai on 2026-09-22:

Modeljev-1.13.0, aliased as jev-latest
Price$0.042 per million input tokens, output free
Context64k tokens per request; 32k for the state plus the longest question
Rate limits250,000 tokens per second, 1,200 requests per minute (TypeSafe says these move while demand settles)
Latency I measured302 ms median (the script's upper-middle of 8), 525 ms slowest, from a script; hook calls end to end (Node startup, proxy hop, model call): 749 to 1,563 ms for the five that answered in the run shown plus one 4,375 ms timeout, 591 to 949 ms on the earlier run
TrainingRLCD, calibrated probabilities. TypeSafe says it is not trained on customer requests or responses. English first; other languages work with lower accuracy
EndpointPOST https://api.typesafe.ai/v1/systemone

TypeSafe's own coding-agents page says it plainly: there is no model: "jev-latest" setting that turns Claude Code into a Jev agent. Jev is a component inside the agent you are building, not the agent's brain. So don't go looking for that setting. Jev lives inside the harness, not in the model config.


Why split the loop into three roles?

Kahneman's System 1 is fast, cheap and intuitive, and right often enough to run on by default; it is also where the biases live, which is why the thresholds section further down exists. System 2 is slow, expensive and the only one that can reason about something new. The metaphor is loose, and TypeSafe chose it, not me. Chat LLMs are System 2 machines that we have been forcing to make System 1 calls: is this log line an incident, which team owns this ticket, is this command safe, should the agent stop. Every one of those calls costs seconds and, at frontier prices, cents, and comes back as text you then have to parse and trust.

My estimate from running loops for the last four months, stated as an estimate: about 90% of the steps in an unattended agent loop never needed a big model. They needed a fork to be taken and a number to justify it. When I said that in the 09/20 club workshop, the pushback was "but the LLM can do that too." It can. It also tells you "you're absolutely right" when you're wrong, and it can't tell you how sure it actually was.

Jev engineering three-role loop: the LLM writes plans and code as System 2, Jev decides with Choice, Score and Noul answers as System 1, and deterministic code acts on the thresholds; new state feeds the next step and most steps never reach the LLM

So the split is:

RoleWhoRuns onProduces
WritesClaude Code, Codex, any LLMThe exception pathPlans, code, prose, a patch to a rubric
DecidesJevEvery stepA probability on every option you listed, plus confidence on Choice and Score
ActsYour codeEvery stepThe threshold check, the action, the new state

The rule that makes it work: the LLM never sits in the hot loop of a classification job. In the cron it is called when Jev will not own a template, and when it is called, it edits data the fast model reads (a rubric, a config, a taxonomy), not the loop's code. In the router the LLM does the task either way; Jev only picks which one.


The harness pattern with real code

Three places Jev sits in front of the model in my Claude Code setup. All three ran on 2026-09-22; the outputs are pasted, not typed. Every script reads TYPESAFE_API_KEY if you have one in the environment. I ran them with treg's proxy in front, which supplies the credential from the run's environment, so no TypeSafe key sits on disk. With neither, the API answers 401.

1. A PreToolUse hook that gates dangerous commands with a Noul question

Claude Code hooks are the one place in a session where a decision can block an action. The hooks guide on this site says to keep hooks dumb: a regex, a path check, an exit code. That advice is still right for the cases a regex can name. The gap is everything else: the psql -c "DROP TABLE" that your force-push regex never sees.

.claude/settings.json:

json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [{ "type": "command", "command": "node \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/jev-guard.mjs" }]
      }
    ]
  }
}

.claude/hooks/jev-guard.mjs:

js
// PreToolUse hook: Jev decides whether a Bash command is safe to run. Code enforces the policy.
import fs from 'node:fs';
const input = JSON.parse(fs.readFileSync(0, 'utf8'));
const command = input.tool_input?.command;
if (!command) process.exit(0);

const headers = { 'content-type': 'application/json' };
if (process.env.TYPESAFE_API_KEY) headers.authorization = `Bearer ${process.env.TYPESAFE_API_KEY}`;

let answers;
try {
  const r = await fetch('https://api.typesafe.ai/v1/systemone', {
    method: 'POST', headers, signal: AbortSignal.timeout(4000),
    body: JSON.stringify({
      model: 'jev-latest',
      state: { command, cwd: input.cwd },
      questions: {
        destructive: {
          type: 'noul',
          instructions: 'Would running `command` delete data, rewrite shared history, or change production state in a way that is hard to undo?',
          criteria: {
            true: { what: 'Irreversible or shared-state changes', examples: ['rm -rf on a real path', 'git push --force to a shared branch', 'DROP TABLE', 'a curl that POSTs to a production API'] },
            false: { what: 'Read-only, local, or trivially reversible', examples: ['ls', 'git status', 'npm test', 'cat a file', 'creating a new branch'] },
          },
        },
        kind: {
          type: 'choice',
          instructions: 'What kind of command is this?',
          criteria: { read_only: 'Inspects files or state', build_or_test: 'Compiles, lints, or runs tests', local_write: 'Writes files inside the working tree', git_history: 'Rewrites or force-pushes git history', deletion: 'Deletes files or data', remote_mutation: 'Changes state on a remote service or database' },
        },
      },
    }),
  });
  if (!r.ok) throw new Error(`jev ${r.status}`);
  ({ answers } = await r.json());
  const noul = answers?.destructive?.noul;
  if (!(Number.isFinite(noul) && noul >= 0 && noul <= 1)) throw new Error('bad answer shape');
  if (typeof answers?.kind?.choice !== 'string') throw new Error('bad answer shape');
} catch (err) {
  // Fail closed: no decision from Jev means the user decides, never silent allow.
  out('ask', `jev-guard: Jev unavailable (${err.message}); confirm manually`);
}

const p = answers.destructive.noul;
const reason = `jev-guard: p_destructive=${p.toFixed(2)}, kind=${answers.kind.choice}`;
if (p >= 0.7) out('deny', `${reason}. Ask the user first.`);
else if (p >= 0.35) out('ask', reason);
process.exit(0);

function out(permissionDecision, permissionDecisionReason) {
  console.log(JSON.stringify({ hookSpecificOutput: { hookEventName: 'PreToolUse', permissionDecision, permissionDecisionReason } }));
  process.exit(0);
}

I ran the same six commands twice. The first run was on the version of the hook before the fail-closed fix; it scored rm -rf ./dist at 0.60 and DROP TABLE at 0.96. The second run, shown here, is the hook printed above, except that two checks were tightened afterwards (a review found that an out-of-range probability, and a missing kind answer, slipped past the old validation); none of the six results depend on them. The first call timed out at 4 s and the fail-closed path fired; my guess is a cold proxy, I did not trace it:

code
ls -la src/                     ask    Jev unavailable (The operation was aborted due to timeout); confirm manually   4375 ms
npm test                        allow (silent)                                          1563 ms
git push --force origin main    deny   p_destructive=0.95  kind=git_history              814 ms
rm -rf ./dist                   ask    p_destructive=0.63  kind=deletion                 953 ms
psql -c "DROP TABLE users;"     deny   p_destructive=0.95  kind=remote_mutation          749 ms
git checkout -b feat/jev-guard  allow (silent)                                           852 ms

rm -rf ./dist landed at 0.63 (0.60 on the first run), inside the ask band, which is where a build folder belongs: usually fine to delete, sometimes not, so the hook asks instead of deciding. "allow (silent)" means the hook printed nothing and Claude Code's normal permission rules apply; the hook has no opinion there, it does not grant anything. And the policy is two numbers, 0.7 and 0.35, on the Noul probability itself: Noul returns P(yes) and no separate confidence, so a low value is a confident no, not an uncertain answer. When I decide the team can live with more risk, I change two numbers; nothing is re-prompted.

The cost: 749 to 1,563 ms per answered Bash call in the run shown, and one 4 s timeout, measured end to end (Node startup, the proxy hop and the model call together; I did not split them), against the hooks guide's 200 ms target. I pay it on Bash only, not on every tool. If that is too slow for you, run the hook as a long-lived process or filter commands inside the hook before calling Jev. Two more honest limits: the hook sees the command string and the working directory, nothing else, so it cannot know what npm test runs; it is one more signal on top of Claude Code's permissions and your sandbox, not the authorization boundary. And 0.35 and 0.7 are illustrative; six commands are a demo, not an evaluation. Before trusting a guard like this, run a labelled set that includes destructive commands and report the false-allow rate. And when Jev cannot answer, or answers in a shape the hook does not expect, the hook asks; it never allows by default.

2. Model and effort routing with a Choice question

Before the expensive model sees a task, Jev decides which tier it deserves and whether it should plan first. The bit that matters is the fallback: a low-confidence answer never picks the cheaper model.

js
const models = { small: 'claude-haiku-4-5', mid: 'claude-sonnet-5', frontier: 'claude-opus-5' };

const headers = { 'content-type': 'application/json' };
if (process.env.TYPESAFE_API_KEY) headers.authorization = `Bearer ${process.env.TYPESAFE_API_KEY}`;

export async function route(task) {
  const r = await fetch('https://api.typesafe.ai/v1/systemone', {
    method: 'POST',
    headers,
    body: JSON.stringify({
      model: 'jev-latest',
      state: { task },
      questions: {
        tier: {
          type: 'choice',
          instructions: { question: 'Which model tier should handle `task`?', focus: 'Judge the reasoning depth the task needs, not its length.' },
          criteria: {
            small: { what: 'Mechanical edits, renames, formatting, one-file changes with a clear spec', not_for: 'Anything that needs a design decision' },
            mid: { what: 'Multi-file changes with a known pattern, tests, refactors inside one module', not_for: 'Architecture or ambiguous requirements' },
            frontier: { what: 'Architecture, debugging across systems, ambiguous specs, security-sensitive changes', not_for: 'Work a junior engineer could do from the ticket alone' },
          },
        },
        needs_plan_first: { type: 'noul', instructions: 'Should the agent write a plan and get it approved before editing files for `task`?' },
      },
    }),
  });
  const { answers } = await r.json();
  const tier = answers.tier;
  // Low confidence falls one tier UP, never down.
  const pick = tier.confidence >= 0.75 ? tier.choice : (tier.choice === 'small' ? 'mid' : 'frontier');
  return { model: models[pick], tier: tier.choice, confidence: tier.confidence, plan_first: answers.needs_plan_first.noul >= 0.6 };
}

Four tasks:

TaskJev saidConfidenceModel selectedPlan first
Rename userId to accountId across the billing modulemid0.85claude-sonnet-5no
Add a unit test for parseEntries covering multi-line entriessmall0.62claude-sonnet-5 (bumped)no
Design retry and idempotency for our Stripe webhook; duplicate charges in prodfrontier1.00claude-opus-5yes
Fix the typo in README.mdsmall1.00claude-haiku-4-5no

Task text is shortened for the table. Each call cost about 500 input tokens, so about $0.00002, and took 280 to 610 ms, from the usage and timing fields the script logs; the block above keeps only the routing logic. The second row is the pattern in one line: Jev leaned small at 0.62, the code refused to trust a cheap pick at that confidence, and the task was routed to Sonnet. The router returns a model name; running the task on it is your loop's job. Wrong-and-cheap doesn't show up in the logs. Wrong-and-expensive shows up on the bill.

3. The 10-minute log cron: Jev classifies, Claude Code rewrites the rubric

This is the pattern from the 09/20 workshop, built and run. Every 10 minutes the cron tails a log, dedupes the entries into templates (same level and message, same field values once IDs, paths and wait times are dropped), and asks Jev two questions per template: which class in rubric.json does this belong to, and how urgently should a human look. If the class is known and confidence clears 0.8, code records the class's action: ignore, count, alert or page. Severity is a separate Score on a 0 to 2 scale (Ignore, Watch, Page) and its weighted mean never exceeds 2, so the page bar is 1.5, not 2 (the run used 2, which nothing could clear; the highest severity in the run was 1.4, so lowering it changes no result). A known class whose severity read is uncertain keeps the class action and does not page. Wiring alert and page to your pager is the one line this script leaves to you. If not, the unknown templates and the current rubric go to Claude Code, which returns a JSON patch adding a class. The patch is validated in code, written to rubric.json, and Jev re-runs on the unknowns. Anything still unknown after that is appended to an unresolved queue file for a human before the cursor moves on. Claude Code is only asked for the patch, and the validator is the boundary: the run used the CLI's default tool set, so if you want the boundary enforced rather than relied on, disallow the file-editing tools on that call.

The 10-minute log cron: log entries are deduped into templates, Jev classifies each against rubric.json and scores severity, code selects the action when confidence clears 0.8, and unknown templates go to Claude Code which writes a validated rubric patch that Jev reads on the next cycle

The rubric is data, and it is the whole prompt:

json
{
  "version": 1,
  "thresholds": { "auto": 0.8, "page_on_severity": 1.5 },
  "classes": {
    "server_unreachable": {
      "what": "The daemon could not reach the loopany server: fetch failed, connection refused, or a 5xx gateway error on poll",
      "not_for": "Failures inside a Claude session or failures syncing a loop folder",
      "examples": ["poll failed err: fetch failed", "poll non-ok status: 502 Bad Gateway"],
      "action": "count"
    },
    "claude_transient": {
      "what": "A Claude Code session exited abnormally and the daemon is retrying it after a backoff",
      "not_for": "Network errors between the daemon and the server",
      "examples": ["transient claude failure - resuming the session after backoff, attempt: 1, error: claude exited with code 1"],
      "action": "alert"
    },
    "normal_delivery": {
      "what": "Routine lifecycle: a run was claimed, finished, a folder is being watched, or the daemon is polling",
      "not_for": "Anything with an error, a non-ok status, or a retry",
      "examples": ["delivery claimed - running", "delivery finished", "watching loop folder", "polling for deliveries"],
      "action": "ignore"
    }
  }
}

The core of the cron, as an excerpt: the parser, askJev, timing, the cursor and the unresolved queue are in the full script, which you can download with the raw outputs at /code/jev-engineering/ (execFileSync comes from node:child_process):

js
function questionsFor(rubric) {
  const criteria = {};
  for (const [name, c] of Object.entries(rubric.classes)) criteria[name] = { what: c.what, not_for: c.not_for, examples: c.examples };
  criteria.unknown = { what: 'A log entry that does not fit any class above', not_for: 'Entries that clearly match one of the classes, even if the wording differs' };
  return {
    issue: { type: 'choice', instructions: { question: 'Which known class does `entry` belong to?', focus: 'Match on what happened, not on exact wording.' }, criteria },
    severity: { type: 'score', instructions: 'How urgently should a human look at `entry`?', criteria: [
      { summary: 'Ignore', signals: ['Routine lifecycle', 'No failure'] },
      { summary: 'Watch', signals: ['A failure that the system retries by itself', 'Transient upstream trouble'] },
      { summary: 'Page', signals: ['Work was lost or delivered late', 'Auth or data-integrity errors', 'Repeated failure with no recovery'] },
    ] },
  };
}

async function triage(templates, rubric) {
  const q = questionsFor(rubric);
  const handled = [], unknowns = [];
  for (const t of templates) {
    const { answers } = await askJev({ entry: t.sample, seen_in_window: t.count }, q);
    const ok = answers.issue.choice !== 'unknown' && answers.issue.confidence >= rubric.thresholds.auto;
    if (!ok) { unknowns.push(t); continue; }
    let action = rubric.classes[answers.issue.choice].action;
    if (answers.severity.score >= rubric.thresholds.page_on_severity && answers.severity.confidence >= rubric.thresholds.auto) action = 'page';
    handled.push({ ...t, class: answers.issue.choice, action });
  }
  return { handled, unknowns };
}

function escalateToClaude(unknowns, rubric) {
  const prompt = `You maintain rubric.json for a log-triage cron. Jev (a decision model) could not classify these log templates with confidence:

${JSON.stringify(unknowns, null, 2)}

Current rubric classes:
${JSON.stringify(rubric.classes, null, 2)}

Return ONLY a JSON object of NEW classes to add, same shape as the existing ones: {"<snake_case_name>": {"what": "...", "not_for": "...", "examples": ["..."], "action": "count|alert|ignore"}}. Prefer one class per distinct failure mode. No prose, no code fences.`;
  // claude -p refuses to start nested inside a Claude Code session unless CLAUDECODE is stripped from the env.
  const env = Object.fromEntries(Object.entries(process.env).filter(([k]) => k !== 'CLAUDECODE'));
  const out = JSON.parse(execFileSync('claude', ['-p', prompt, '--output-format', 'json', '--model', 'sonnet'], { encoding: 'utf8', maxBuffer: 1 << 24, env }));
  const patch = JSON.parse(out.result.replace(/```(?:json)?/g, '').trim());
  for (const [name, c] of Object.entries(patch)) {
    if (typeof c.what !== 'string' || typeof c.not_for !== 'string' || !Array.isArray(c.examples) || !['count', 'alert', 'ignore'].includes(c.action)) throw new Error(`rejected ${name}`);
    if (rubric.classes[name]) throw new Error(`rejected ${name}: already exists, patches are additive only`);
  }
  return { patch, cost: out.total_cost_usd };
}

I pointed it at the last 600 entries of the loop daemon log on this machine, the one that runs my scheduled agents. This is a replay: the script reads the file and keeps a cursor; the scheduler, a single-run lock and log-rotation handling are the loop's job, not this script's. Three classes in the rubric on purpose; I knew the log had a fourth failure mode.

Terminal output of the real log-cron run on 2026-09-22: seven templates from 600 entries, six classified by Jev at confidence 0.99 to 1.00, one unknown at 0.50 escalated to Claude Code, which added sync_request_timeout to rubric.json for $0.0834 in 10.4 seconds, after which Jev classified it at 1.00; summary line shows 8 calls, 7,014 input tokens, $0.00029, 302 ms median

What happened, in numbers:

Entries in the window600
Templates after dedupe7
Jev calls8 (7 plus one re-check)
Jev input tokens7,014
Jev cost$0.00029
Jev latency302 ms median, 525 ms slowest of 8
Handled by Jev without escalation6 of 7 templates, 597 of 600 entries, confidence 0.99 to 1.00
Escalated1 template, sync request failed, 3 entries, confidence 0.50
Claude Code escalationadded sync_request_timeout to the rubric, $0.0834, 10.4 s
After the patchJev classified the same template at 1.00
Wall time13.2 s for the whole cycle

The escalation was about 283 times the Jev spend (0.0834 over 0.000295, list price times tokens, not a billing receipt), for one template. Read that as the price of an escalation, not the per-decision saving: the fair per-decision comparison is a small chat model classifying the same seven templates, and I did not run that, so there is no number for it here. Send every template to Sonnet with a rubric-writing prompt like this one and the cron would cost tens of dollars a day; that is an estimate, I did not run that version. With Jev in front, the Jev side of a cycle costs a fraction of a cent (this cycle was 8.4 cents in total, almost all of it the one escalation), and Claude gets called only when the rubric has a hole, to write the entry that fills it.

The 0.50 is worth a look. Jev picked unknown for "sync request failed", at confidence 0.50, and the code escalates on the choice itself: anything that lands on unknown, or under 0.8, goes to Claude regardless of the number. I did not log the full distribution, so I cannot show which class it was torn between; my guess is server_unreachable, whose not_for line excludes folder-sync failures, and a guess is all that is. What matters for the design is that the rubric gave the model an honest place to put a leftover, and the code treated that as a hole to fill rather than an answer to act on.

Want the full loop, with the scheduler and the verifier around it? The Loop Engineering course builds exactly this shape: a loop that wakes on schedule, hands the small decisions to a cheap model, and only wakes the big one when a rubric has a hole.


Rubrics, not prompts

Everything you would put in a prompt goes into the question, and every field that takes a string also takes JSON: the instructions, each option, each score level, the true and false sides of a Noul. TypeSafe's structure page documents the shape; the shape that has held up for me across fraud scans, buying-signal triage and this cron is three keys per option:

json
"billing": {
  "what": "Charges, invoices, refunds, or subscriptions",
  "not_for": "Order tracking or account access",
  "examples": ["I was charged twice", "Where is my refund?"]
}

what is the definition. examples work like few-shot prompting. not_for is the lever: it is the line that separates two options that sound alike in plain English, and it is where product knowledge goes. "We do not have a Framer export" in a not_for is the difference between a bug report and a feature request. In the cron above, not_for is my reading of why Jev did not file the sync failure under server_unreachable; I did not run the ablation.

Three rules I follow when writing one:

  1. One question, one judgment. "Rate this ticket" is a bad question. "Which team owns this" plus "how urgent is this" plus "is the customer threatening to churn" are three good ones, sent in one call, combined in code. TypeSafe's own docs say the same: atomic questions, composed in code.
  2. Options are a closed set you can defend. If you cannot list the acceptable answers, the fork is not ready for Jev. Add an unknown option with its own not_for so the model has somewhere to put the leftovers.
  3. The rubric is versioned data. It lives in a file, it has a version number, and the LLM edits it through a validated patch. That is what makes the loop self-improving without becoming self-modifying.

Route on confidence

Jev hands back probabilities. Your code owns the decision, which is what lets the cases that clear your bar run unattended, and why the threshold is on you.

How I set them, every time:

  • Label a small set. Twenty to fifty real cases through the question, marked right or wrong by a human. For the fraud scan on treg that is a morning's worth of signups; for the cron it was one window of the log.
  • Pick the floor per action, not per question. The docs' confidence-routing pattern shows the shape: a floor under which nothing acts, then a higher bar for the irreversible action. In the guard hook that is 0.35 to ask and 0.7 to deny, on the Noul probability rather than a confidence. In the cron it is 0.8 to auto-apply and a separate 0.8 on severity before anything pages.
  • Low confidence escalates, never auto-applies. Below the floor, the case goes to the LLM or to a person. The router above encodes the same idea as "fall one tier up, never down."
  • Two numbers own the policy. When the business changes its mind, you edit two numbers and the same answers route differently. Nothing is re-run.
  • Pin the model version when the thresholds matter. Every response carries the versioned id in its model field (jev-1.13.0 today); log it, my scripts above do not yet. Aliases move. If you tuned thresholds against a version, log it and re-run the labelled set before you follow the alias.

The launch posts don't cover this part. TypeSafe says the model is trained to return calibrated probabilities, and its own docs tell you to start conservative and test on your data. Anthus ran 8,801 labeled examples and found Jev overconfident: in the top confidence bucket (5,559 Choice answers, 63% of the set) average stated confidence was 99.4% against 90.2% accuracy, and over all Choice answers it was 91.4% against 76.1%. Higher confidence still meant more likely right, so the ordering holds even where the calibration does not. Two caveats before you carry those numbers over: Anthus thresholds the probability on the predicted answer, not the API's confidence field this article thresholds (for a two-way Choice the two are tied, confidence is about 2p minus 1), and the set is binary sentiment with 2,000 deliberately arbitrary neutral labels. Read it as the shape of the problem, not a test of the cron's 0.8. I have not reproduced those numbers and I have not seen the failure on my own distributions, which are close to the examples in my rubrics. Read that as: calibration inside your examples' distribution is what you can measure, calibration outside it is what you should assume degrades. Both are arguments for the labelled set and the floor, not against the model.


When not to use Jev

The launch posts skip this section, so here it is from someone who runs it in production.

Do not use Jev whenWhyUse instead
You need text, code, or an explanationIt returns probabilities over options you wrote. It cannot say why.The LLM, with Jev in front of it to decide whether the call is needed
The answer is arithmetic, a date, a regex matchA calibrated guess at 3 times 17 is still a guessCode
The input is adversarial and nothing checks the output"Ignore your instructions" in a signup form is a real thing in our logs. One classifier, however calibrated, is one point of failureJev plus a second signal (email verification, rate limits, a second question phrased differently)
The state is over 32k tokensHard limit for state plus the longest question. Above it you chunk or summarise, and now a summariser is in the loopMap-reduce with Jev per chunk, or an LLM summary first
Nobody has written the acceptable options downA Choice with vague options returns a confident answer to a question you did not askWrite the rubric first. If you cannot, it is an LLM job
Non-English state where accuracy mattersEnglish is the primary training language; TypeSafe says other languages, including CJK, currently score lowerTest on your own content and watch confidence, or translate first
The fork happens onceA 300 ms decision model in front of a one-off human decision is engineering for its own sakeAsk the human

One more that is not a limit of the model: do not use Jev to replace the model in your coding agent. TypeSafe's docs say it, and the repos that got this right in the first week show the pattern. browser-use/jev-ultrafast uses Jev to pick the DOM target before any text is generated. tamaratran/fast-jev-compaction is a Claude Code plugin where Jev decides what to keep at compaction time. Both keep the LLM for writing and put Jev on the fork.


Where this is already running

The three patterns on this page are harness patterns. The same model also runs the GTM side of my two products, and that lives on its own page: how we use Jev with treg for signup fraud scans, buying-signal triage and launch radar, with the cost per run. The short version from those runs: a day of 236 signups costs about $1.20 on treg and $0.01 on Jev, and a single guardrail call is about $0.00002 (the signup demo on that page is a synthetic sample built to show the segments; the pipeline and the prices are the production ones). That's roughly what pushed me to stop putting the LLM in the loop.


Key takeaways

  • Jev engineering is a role split: the LLM writes, Jev decides, code acts. In the cron pattern the LLM only gets called when Jev won't own the fork; in the router it picks which LLM does the work.
  • Jev returns a probability on every option you listed, in one pass, for $0.042 per million input tokens, at roughly 300 ms from a script.
  • The three harness placements that work today: a PreToolUse hook that gates commands, a router that picks the model tier, a cron that triages logs.
  • Write rubrics, not prompts: what, not_for, examples per option, in a versioned JSON file the LLM patches through validation.
  • Thresholds are yours. Label a small set, pick a floor per action, escalate below it, never auto-apply a low-confidence answer, pin the model version.
  • The cron's receipt: 600 entries, $0.00029 on Jev, one $0.083 escalation that added the missing class, which Jev then classified at 1.00.
  • Do not use it for text, arithmetic, adversarial input without a second check, states over 32k tokens, or forks nobody has written options for.

Frequently Asked Questions

What is Jev engineering? A way of building AI agents where the roles are split by model type: an LLM writes (plans, code, prose), Jev decides (typed Choice, Score and Noul answers with a probability on every option), and plain code acts on those numbers. The LLM becomes the exception path instead of the loop.

What is a System One model? TypeSafe AI's category name for Jev. It takes a state (text or JSON) plus typed questions and returns probabilities over the options you listed, in one pass, without generating tokens. It cannot write text or code. The name comes from Kahneman's fast, intuitive System 1 versus the slow, deliberate System 2.

Does Jev replace the LLM in Claude Code or Codex? No. TypeSafe's docs say there is no model setting that turns a coding agent into a Jev-powered agent. Jev sits inside the harness around the agent: in a hook that gates a command, in a router that picks the model, in a cron that triages logs. The LLM still writes the code.

How do you choose a Jev confidence threshold? Label a small set of real cases, run them through your question, and pick the lowest confidence at which the answers were still right for that action. Use a higher bar for irreversible actions than for read-only ones, and treat anything below the floor as escalate, never as auto-apply. Re-check when you change the rubric or the model version.

Is Jev's confidence calibrated? TypeSafe says the model is trained for calibrated probabilities and tells you to test thresholds on your own data. One independent test (Anthus, 8,801 labeled examples) found Jev overconfident: in the top confidence bucket of 5,559 Choice answers, average stated confidence was 99.4% against 90.2% accuracy, and over all Choice answers 91.4% against 76.1%, though higher confidence still meant more likely right (their metric is the probability on the predicted answer, on a sentiment benchmark). Measure calibration on your labelled set, assume it degrades on inputs unlike your examples, and keep a human path for low confidence.

What does Jev cost in a real agent loop? $0.042 per million input tokens, output free. The 600-entry log replay on this page took 8 calls, 7,014 input tokens and $0.00029. The one Claude Code escalation in the same run cost $0.083, about 283 times the Jev spend.

When should you not use Jev? When you need text, code or an explanation; when the answer is arithmetic or a date; when the input is adversarial and nothing checks the output; when the state is over 32k tokens; and when nobody has written the acceptable options down. Jev picks from a list you wrote.

What is the difference between Jev engineering and harness engineering? Harness engineering is the whole runtime control system around a model. Jev engineering is one design choice inside it: giving the harness its own decision model so the LLM is not called for every fork. Every Jev pattern here is a harness layer.



Start Here

Watch the 09/20 workshop where I walked through the System 1 / System 2 cron live, with the fraud scan and the buying-signal filter that run on the same model: it is on the live AI workshops hub.

Then build the loop around it. The Loop Engineering course takes you from "you are the for loop" to a scheduled loop that decides cheaply, escalates rarely, ships behind quality gates, and reports back. Jev is the cheapest model-backed verifier I have put in one; a deterministic check is cheaper still whenever one exists.

Frequently Asked Questions

What is Jev engineering?

Jev engineering is a way of building AI agents where the roles are split by model type: a large language model writes (plans, code, prose), Jev decides (typed Choice, Score and Noul answers with a probability on every option), and plain code acts on those numbers. The LLM becomes the exception path instead of the loop.

What is a System One model?

System One model is TypeSafe AI's category name for Jev. It takes a state (text or JSON) plus typed questions and returns probabilities over the options you listed, in one pass, without generating tokens. It cannot write text or code. The name comes from Kahneman's fast, intuitive System 1 versus the slow, deliberate System 2.

Does Jev replace the LLM in Claude Code or Codex?

No. TypeSafe's own docs say there is no model setting that turns a coding agent into a Jev-powered agent. Jev sits inside the harness around the agent: in a hook that gates a command, in a router that picks the model, in a cron that triages logs. The LLM still writes the code.

How do you choose a Jev confidence threshold?

Label a small set of real cases, run them through your question, and pick the lowest confidence at which the answers were still right for that action. Use a higher bar for irreversible actions than for read-only ones, and treat anything below the floor as escalate, never as auto-apply. Re-check the numbers when you change the rubric or the model version.

Is Jev's confidence calibrated?

TypeSafe says the model is trained to return calibrated probabilities, and its docs tell you to test thresholds on your own data. One independent test (Anthus, 8,801 labeled examples) found Jev overconfident: in the top confidence bucket of 5,559 Choice answers, average stated confidence was 99.4% against 90.2% accuracy, and over all Choice answers 91.4% against 76.1%, though higher confidence still meant more likely right (their metric is the probability on the predicted answer, on a sentiment benchmark). In practice: measure calibration on your labelled set, assume it degrades on inputs unlike your examples, and keep a human path for low confidence.

What does Jev cost in a real agent loop?

Jev bills $0.042 per million input tokens and output is free. A replay of 600 daemon log entries in this article took 8 Jev calls, 7,014 input tokens and $0.00029. The one Claude Code escalation in the same run cost $0.083, about 283 times the Jev spend.

When should you not use Jev?

When you need text, code or an explanation, when the answer is arithmetic or a date, when the input is adversarial and you have no second check, when the state is bigger than 32k tokens, or when nobody has written down the acceptable options. Jev picks from a list you wrote; it cannot invent an option.

What is the difference between Jev engineering and harness engineering?

Harness engineering is the whole runtime control system around a model. Jev engineering is one design choice inside it: giving the harness its own decision model so the expensive LLM is not called for every fork. Every Jev pattern here (hook, router, cron) is a harness layer.

Sources & Verification

The log-cron, guard-hook and router numbers were produced on 2026-09-22 by running the code shown on the author's machine (the cron against a real loop-daemon log), through the treg proxy from Sydney, and are reported as measured end to end. Jev pricing and limits were read from docs.typesafe.ai the same day. The calibration figures are Anthus's and were not reproduced here.

Join AI Builder Club

65+ lessons, 22+ workshops
350+ plug-and-play prompts & skills
Weekly live builder workshop
Premium tools (e.g. 10xCoder, AI tutor)
AI Builder Pack ($5,000+ in exclusive AI credits & perks)
1k+
Join 1,000+ builders already inside
Start shipping →30-day money-back · Cancel anytime

$37/mo

Get the free newsletter

Weekly deep-dives on AI tools, automation workflows, and builder strategies. Join 5,000+ readers.

No spam. Unsubscribe anytime.

Continue Learning