Elyra · · 7 min read

Elyra 0.9.39: A Second Opinion for Two Cents a Thousand

Jev is a decision model: typed yes/no, choice and score questions that come back as probabilities for about two cents per thousand calls. Plus an opt-in bash gate, and the registry bug that quietly ate four models.

Elyra 0.9.39: A Second Opinion for Two Cents a Thousand

Most of what a coding agent does is not writing code. It is deciding. Is this log line worth reading? Is this command about to delete something I care about? Which of these forty files actually matter for the bug I am chasing? Today those decisions all go through the same expensive model that writes your code, one paragraph of reasoning at a time.

Elyra 0.9.39 adds a different kind of model for a different kind of question. It also fixes a bug that quietly ate four models from the registry, and closes a small but annoying gap in the release process. Let us start with the interesting part.

Meet Jev

TypeSafe Jev is a decision model. It does not write prose. You hand it a piece of content and a typed question, and it hands back a probability. A yes/no question comes back as 0.97. A multiple-choice question comes back as a distribution over the options. A “rate this on a scale” question comes back as an expected value plus the full spread.

It is fast (about a second) and cheap (around $0.00002 per call, which is roughly two cents per thousand). Input is billed at $0.042 per million tokens and output is free, because there is no output to speak of.

Our first instinct was to add it to the model list like any other provider. That turned out to be the wrong shape. Jev does not speak the chat-completions protocol. It has no messages, no tool calls, no streaming text. OpenRouter exposes it through a separate decisions endpoint with a request that looks like this:

{
  "model": "~typesafe/jev-latest",
  "state": "rm -rf node_modules dist",
  "questions": {
    "destructive": {
      "type": "noul",
      "instructions": "Would running this shell command destroy data or make a change that is hard to reverse?"
    }
  }
}

So instead of a model you can switch to, Jev arrives in Elyra as a tool the main model can call. The package is @elyracode/jev-tools.

elyra install npm:@elyracode/jev-tools

It reuses whatever OpenRouter key you already have. If you have run /login and picked OpenRouter, you are done.

The decide tool

The tool takes a state and a list of questions. Three question types are supported.

noul is yes/no with a probability. The name is odd but it is what the API calls it.

{
  "name": "refund",
  "type": "noul",
  "instructions": "Is the customer asking for their money back?",
  "criteria": {
    "true": "explicitly requests a refund, chargeback, or return of payment",
    "false": "complains, asks for help, or anything else"
  }
}

choice picks one option and returns the full distribution, so you can see how confident it was.

{
  "name": "route",
  "type": "choice",
  "instructions": "Which kind of work does this request need?",
  "criteria": {
    "code": "write or change code in the repository",
    "research": "look something up on the web",
    "question": "answer from existing knowledge",
    "other": "none of the above"
  }
}

score rates on an ordinal scale of two to ten labels, low to high.

{
  "name": "severity",
  "type": "score",
  "instructions": "How serious is this log line?",
  "criteria": ["debug", "info", "warning", "error", "critical"]
}

You can ask several questions about the same state in a single call, and it costs the same as asking one. The result comes back readable:

refund: yes (p=0.97)
route: code (p=0.81, conf=0.70)
  code=0.81, research=0.15, question=0.03, other=0.01
severity: 2.60/4 -> error (conf=0.40)
  debug=0.05, info=0.10, warning=0.25, error=0.50, critical=0.10

[typesafe/jev-1.13 · 120 tok · $0.000005]

What it is good for

The pattern is: many small judgements, where spending a paragraph of frontier-model reasoning on each one would be wasteful.

Triage. You have a hundred failing test names and want the ones that look like real regressions rather than flakes. Ask the agent to run them through decide with a noul question and only read the ones above 0.7.

Filtering. tail -f app.log is too noisy. Ask the agent to score each line for “user-visible failure” and surface the top of the scale.

Routing. Before deciding whether to search the web, read the codebase, or just answer, the agent can ask Jev which kind of request this is. The answer arrives before the main model has finished thinking about it.

Classification at scale. Labelling issues, sorting feedback, tagging commits by Conventional Commit type. Jev handles a thousand of these for two cents.

What it is not good for

Anything that needs generated text. Jev filters and ranks; it does not summarize or explain. Its context window is about 32K tokens, so hand it the paragraph, not the whole file. And it reads your criteria literally. If you ask “does this contain actionable information” it will say yes to a spam message offering a free course, because a free course is, technically, actionable. Spell out both sides.

The bash gate

The example we kept coming back to during development was destructive shell commands. The agent runs git reset --hard or rm -rf and you find out afterwards. Existing guards are regex lists, which catch rm -rf and miss find . -delete, truncate, DROP TABLE, and git push --force to a shared branch.

So jev-tools ships an opt-in gate. When enabled, every bash call is first sent to Jev with the question above. The command and the working directory are the state; the criteria list what counts as destructive (deletes, drops, force-pushes, discarding uncommitted work, broad permission changes, running as root) and what does not (reads, builds, tests, installs, anything git or a package manager can undo).

If the probability clears the threshold, Elyra asks:

Jev: 92% likely destructive

git push --force origin main

Run this command?

In print or RPC mode, where there is nobody to ask, the command is blocked instead.

Turn it on with elyra --jev-gate, JEV_BASH_GATE=1, or /jev gate on mid-session. The threshold defaults to 0.7 and is tunable with JEV_BASH_GATE_THRESHOLD. It is off by default because it adds about a second to every shell command, and on a build-and-test loop that adds up.

Two design choices are worth spelling out. First, the gate fails open. If the API is down or the key is missing, it logs a warning and lets the command through. Blocking all shell access because a classifier is unreachable would be worse than the problem it solves. Second, and for the same reason, this is a second opinion, not a security boundary. Treat it like a colleague glancing over your shoulder, not like a sandbox.

The four models that went missing

The other change in this release is a fix. Elyra generates its model registry from three upstream sources, one of which is models.dev. This week models.dev renamed the Kimi For Coding provider from kimi-for-coding to kimi-code-plan-cn and kimi-code-plan-global. Our generator looked up the old key, found nothing, and silently produced a registry with zero kimi-coding models.

The interesting part is how it surfaced. The KnownProvider type still listed "kimi-coding", but the generated MODELS object no longer had that key, so (typeof MODELS)[TProvider] stopped type-checking. Fifteen errors, none of them in the file anyone had touched. The generator now reads the new key with the old one as fallback, and k3, k3-256k, kimi-for-coding, and kimi-for-coding-highspeed are back.

We also caught a related nuisance while releasing: the image-model generator wrote JSON.stringify output that biome then reformatted, so every npm publish left a whitespace-only diff in the working tree. It now emits formatted output directly. Small thing, but it was going to bite on every release forever.

Everything else

The model registry got its usual refresh. OpenRouter dropped mistralai/mistral-large-2512 and stealth/union-alpha, and added zai/glm-5.3-flashx, deepseek/deepseek-v4-flash-0731:free, alibaba/qwen3.8-omni-flash, and unbiased/pareto, alongside pricing and context updates.

All packages are on 0.9.39. Upgrade with:

npm install -g @elyracode/coding-agent@latest
elyra install npm:@elyracode/jev-tools
or elyra update

Then try it:

> Before we start, use decide to rate each of these five TODO comments
> for how likely they are to be a real bug rather than a nice-to-have.

A caveat to close on. OpenRouter’s decisions endpoint is marked alpha, and there is no official specification for it yet; the request shape here comes from reading community clients. If the endpoint moves, JEV_BASE_URL lets you point the extension somewhere else without waiting for a release. We will keep an eye on it.