Skip to main content

Jev (System One)

Jev is an optional classifier for decisions with a known set of answers: suggest a route, classify a failure, or recommend a task's model tier. Your main coding model still writes code and explanations. Deterministic code keeps authorization and policy.

See the practical EasyChamp example and inspect recorded calls. The published 26-input intent benchmark uses synthetic, author-labelled messages, not production traffic. It records 25/26 correct Jev labels versus 12/26 for the ported regex baseline, with 258 ms median API latency and $0.00073853 total API cost. These are measurements of that run, not a service guarantee or evidence of developer time saved.

Jev is TypeSafe's System One model. It selects among specified outcomes and returns confidence information. Validate responses and apply confidence thresholds; a score is not proof that a decision is correct or safe.

The one test​

Can every possible answer be written down before the call?

If yes, first check whether a rule, lookup, or existing parser already solves it. Use Jev for the remaining language ambiguity. If no, keep the task with a generative model or a human. Count total latency and cost, including fallbacks, before enabling it.

Three primitives, nothing else:

PrimitiveAnswer shapeUse for
choiceone of 2 to 255 named options, plus probabilities and a confidencewhich skill, which tier, which scope, which failure kind
noulprobability that a statement is true, from 0 to 1yes/no gates: needs an increment, AC satisfied, injected text
scoreposition on 2 to 10 ordered, described levelsgraded severity, risk, priority

Setup​

Jev is off by default. It is a paid external call, so nothing happens until you opt in.

specweave jev setup     # live ping, then writes jev.enabled into .specweave/config.json
specweave jev doctor # provider, model, key source, live latency

The key lives in the environment, never in a config file or a log:

ProviderEndpointModelVariable
openrouter (default)https://openrouter.ai/api/v1/systemonejev-1.13OPENROUTER_API_KEY
typesafehttps://api.typesafe.ai/v1/systemonejev-latestTYPESAFE_API_KEY
openaihttps://api.openai.com/v1/decisionsgpt-6-lunaOPENAI_API_KEY

JEV_API_KEY is honoured for all three providers. Every SpecWeave surface reports the variable name only and never its value. SPECWEAVE_JEV=0 disables Jev for one process; SPECWEAVE_JEV=1 enables it ad hoc.

Optional OpenAI Decisions provider​

# OPENAI_API_KEY must already be in the environment; do not put it in config.
specweave jev setup --provider openai
specweave jev doctor
specweave jev route "Explain the retry error" --json

Setup makes one small live ping and enables the provider only if it succeeds. Jev remains off by default; no global installation settings or other projects change. The adapter uses raw HTTP, so it does not require an OpenAI SDK upgrade.

The Decisions API is in public beta. Its predicate answer maps to Jev's noul; choices retain both their probability map and separate confidence. Score levels use zero-based indices and scores remain fractional probability-weighted averages. This adapter accepts text/JSON state only; it does not fetch images, listen to audio, invoke tools or generate explanations.

Evaluate labeled examples before routing real work. Thresholds configured for Jev have not been calibrated for OpenAI. Test abstention and false positives, preserve all deterministic permissions and require real tests for completion; a classifier cannot authorize a command or certify an acceptance criterion.

Each request is capped locally at 40 questions and 512 KiB, its streamed response at 1 MiB, with at most two retries inside the total configured deadline (1–60,000 ms). Refusal, unknown/duplicate answers, invalid probabilities, timeouts and exhausted retries are unavailable results (a refusal makes the entire batch unavailable): callers retain their normal fallback. These are application budgets, not provider limits. Redirects are rejected. Provider error bodies and source text are excluded from errors and the usage ledger. The ledger retains a request ID and a hash of the redacted, versioned request for comparisons without storing source text. Token usage is recorded; cost remains unknown unless the provider supplies it.

What leaves the machine​

Every specweave jev call sends the question state to the configured provider (OpenRouter, TypeSafe or OpenAI) under your own key: the prompt text, task titles and acceptance criteria, the shell command, test-output tails, screened text, and page text and element names while browsing. Secret-shaped values (tokens, --password and --token flags, KEY=value assignments, bearer headers and URL credentials) are masked heuristically before the request and the number of masked values is reported, but the masking is best-effort and never a guarantee. Treat Jev like any other third-party API: if you would not paste the state into one, do not send it.

Configuration​

{
"jev": {
"enabled": true,
"provider": "openrouter",
"model": "jev-1.13",
"apiKeyEnv": "OPENROUTER_API_KEY",
"timeoutMs": 4000,
"thresholds": { "route": 0.7, "guardDeny": 0.85, "guardWarn": 0.5 },
"guards": { "bash": false },
"browse": { "allowDomains": [], "maxSteps": 20 }
}
}

Every field, its default and the SPECWEAVE_JEV / SPECWEAVE_JEV_PROVIDER / SPECWEAVE_JEV_MODEL overrides are in the configuration reference. Thresholds are clamped to 0 to 1 on load, and guardDeny is never allowed below guardWarn.

With jev.enabled true, specweave update-instructions adds a Jev section to AGENTS.md and a one-line pointer to it in CLAUDE.md, so every agent in the project knows when to delegate.

Commands​

CommandPrintsExit codes
specweave jev doctorprovider, model, key source, live latency0 ok, 4 unavailable
specweave jev setuplive ping, then enables Jev in the project config0 ok, 4 unavailable
specweave jev askraw typed answers as JSON for your own state and questions0 ok, 1 bad input, 4 unavailable
specweave jev route "<prompt>"skill, request kind, complexity to model tier, needs-increment, each with confidence0 ok, 4 unavailable
specweave jev task T-01 [inc]complexity to model tier for one task in the ledger0 ok, 4 unavailable
specweave jev guard "<command>"scope and destructiveness verdict with probabilities0 allow, 2 warn, 3 deny, 4 unavailable
specweave jev screen [file]injection probability and whether the text is flagged0 ok, 4 unavailable
specweave jev failure [file]failure kind with probabilities0 ok, 4 unavailable
specweave jev browsesteps, final url and title, page text excerpt, screenshot paths0 ok, 4 unavailable
specweave jev usagecalls, tokens and cost from the usage ledger0

ask takes --state and --questions as inline JSON, plain text, @file or - for stdin. For a one-off question use the shorthand --choice "..." --option key=description (repeatable) or --noul "...". screen and failure read stdin when no file is given, and --json on any action prints the machine-readable form.

Exit 4 is not a failure. It means Jev is disabled, unconfigured or unreachable, and the agent should continue with its own judgement.

What SpecWeave uses it for​

  • Task tier suggestions. specweave jev task T-NN asks how much reasoning one task in the ledger needs (trivial to haiku, moderate to sonnet, complex to opus). It is a suggestion you act on: SpecWeave does not re-route model tiers behind your back.
  • Skill and request routing. specweave jev route "<prompt>" suggests the skill, the request kind, a model tier and whether the work needs an increment.
  • Bash guard, per project. See the guard below.
  • Headless browsing. specweave jev browse runs a Playwright loop where Jev picks the next click, scroll, back or done from the observed interactive elements, and no visible window is ever opened. See browser delegation.

The guard verdict​

specweave jev guard "the command" asks two questions, a choice over the command's scope and a noul for "would this destroy data that cannot be recovered from git or by re-running a build?", and turns the pair into one verdict.

It denies on any of four arms:

  1. scope destructive_remote with confidence at or above guardDeny (0.85);
  2. destructiveness at or above guardDeny with scope local_irreversible or destructive_remote;
  3. scope local_irreversible with confidence at or above guardDeny and destructiveness at or above guardWarn (0.5);
  4. the probabilities of local_irreversible and destructive_remote summed at or above guardDeny, with destructiveness at or above guardWarn. A deleteMany against a database Jev cannot place splits the scope 0.50 / 0.45 and would otherwise fall to a warn.

The third arm exists because a near-certain local wipe scores its scope high and its destructiveness only moderately: rm -rf ~/Projects comes back local_irreversible at 0.99 with destructive 0.81, which the first two arms alone let through as a warn.

It warns when destructiveness reaches guardWarn, or the scope is shared_or_remote, local_irreversible or destructive_remote. destructive_remote is in the warn set so a low-confidence remote-destruction reading degrades to warn instead of falling through to allow. Everything else is allowed.

The prefilter, and what it means​

A regex prefilter runs before any call. npm test, npm run build / test / lint, pnpm test, yarn test, cargo test, go test and plain read commands (ls, cat, grep, git status / log / diff / show, and friends) skip Jev entirely, so the common case costs nothing, and project-defined scripts are therefore trusted by the guard: whatever npm test runs in a repo is never scored.

Commands containing shell quotes or backslashes go through the guard. Helper-capable search tools such as rg, find, and file also go through it, even for ordinary reads; their optional execution and output modes are not a safe bypass.

The Bash guard is per project​

The default hooks are SessionStart and Stop. PreToolUse is not registered in plugins/specweave/hooks/hooks.json, so upgrading does not turn a guard on anywhere. You enable the Bash guard one project at a time:

specweave jev setup --guard-bash      # config flag + marker + project hook
specweave jev setup --no-guard-bash # removes all three

--guard-bash does three things: it sets jev.guards.bash in .specweave/config.json, writes the marker .specweave/state/jev-guard.enabled, and registers a project-level Claude Code hook in .claude/settings.json: hooks.PreToolUse, matcher Bash, command node "<installed specweave>/plugins/specweave/hooks/run.mjs" pre-tool-use. specweave jev doctor shows the marker and the project hook.

A deny verdict blocks the command with the probabilities in the reason; a warn verdict attaches them as context; any error, timeout, missing key or disabled config fails open. Without the marker the hook returns {} without loading anything.

This is a Claude Code surface. Other tools (Codex, Cursor, Gemini CLI) call specweave jev guard "the command" explicitly before running anything unattended.

The guard's escape hatch is an environment variable set in the shell that launches the agent, or --no-guard-bash. A bypass prefix typed in front of a command does nothing: a denied command is for the user to approve, not for the agent to route around.

Browser delegation across tools​

ToolUse
Claude Code, Cursor, Gemini CLIspecweave jev browse: one headless Playwright loop, the same JSON everywhere
Codex app, with Computer Use and a browser attachedthe community jev-browser-use skill
Codex app, without a browser attachedspecweave jev browse

The loop is headless by definition and never opens a visible window. Text is typed only from --input Label=value, never a string Jev chose. jev.browse.allowDomains and the repeatable --allow-domain flag are merged, and the --url a run starts from must already be inside that allow-list. A control counts as sensitive by its label or its link target (pay, delete, buy, sign out, and similar) and is skipped unless --allow-sensitive is passed.

Patterns for your own project​

  1. Find the closed sets. Walk your flows and mark every LLM call whose only job is to pick one of a handful of outcomes: intent routing, moderation triage, write-approval gates, dedupe, rerank, tagging.
  2. One constants file. Keep every question in a single module and import it. The wording is the contract; editing it at a call site silently changes behaviour.
  3. Fan out. Independent questions over the same state belong in one request. They run in parallel and cannot see each other's answers, so ask speculative branch questions up front and consume only the answers the chosen branch needs.
  4. Confidence gate. Every consumer needs a documented threshold and a fallback for below it. Without one the probability is decoration.
  5. Cascade. Jev first, frontier model only for the cases it is unsure about. Measure accuracy, latency and cost before and after.

Usage ledger​

Every call appends one line to .specweave/state/jev-usage.jsonl with the timestamp, kind, provider, model, token counts, cost and latency. specweave jev usage totals it.

Limits and anti-patterns​

  • Up to 32k tokens of state per question and 64k per request. Summarise in code first.
  • Between 2 and 255 options for a choice; between 2 and 10 levels for a score.
  • Weak at counting, arithmetic, dates and ordering by number. It reads literally.
  • Susceptible to injected instructions: screen untrusted text as data with a noul and never make the screened text the question.
  • Never ask it to write code, specs, commit messages or reviews, to compact or summarise, or to judge another model's free-text output.
  • Errors: 401 auth, 422 validation, 429 rate limit, 529 overloaded. SpecWeave retries 429 and 529 with backoff and fails open on everything else.
  • The sw:jev plugin skill and the portable sw-jev skill ship the same guidance to agents; install the portable one with npx vskill install anton-abyzov/specweave/sw-jev.
  • TypeSafe's own docs index: docs.typesafe.ai/llms.txt (append .md to any docs path for Markdown).