cd /news/ai-tools/jev-cli-text-classification-in-your-… · home › topics › ai-tools › article
[ARTICLE · art-141230] src=shaharia.com ↗ pub= topic=ai-tools verified=true sentiment=↑ positive

jev CLI: Text Classification in Your Terminal, With Probabilities Instead of Prose

TypeSafe AI released jev, an open-source CLI for its Jev model that returns calibrated probabilities instead of generated text, with the tool installed via a curl script or Homebrew and licensed under MIT or Apache-2.0. The CLI supports three question types — noul (yes/no probability from 0 to 1), choice (one winner among up to 255 options with per-option probabilities), and score (a position on a described scale of 2 to 10 levels) — and uses exit codes 0 and 10 so shell scripts can branch on a threshold such as --fail-under 0.7. The example run on model jev-1.13.0 returned yes at 0.96 probability for 280 input tokens at an estimated cost of $0.000012 in 783 ms.

by read6 min views21 publishedSep 20, 2026
jev CLI: Text Classification in Your Terminal, With Probabilities Instead of Prose
Image: Shaharia (auto-discovered)

← All posts

jev is an open-source CLI for TypeSafe AI's Jev model: ask any text a typed question, get a calibrated probability back, and branch on the exit code.

On this page ▾ #

You have a support ticket, a commit message, a product review, or something a user typed into a form. You need a decision about it: is this angry, which team owns it, should this pipeline continue.

Today you either write brittle keyword rules, or you ask a large language model and then parse the sentence it hands back. The rules break on the first message that says “not happy”. The model works, until the day it words the answer differently and your parser quietly starts returning the wrong thing.

I have been building a third option into my terminal, and I have just released it: jev, an open-source CLI for TypeSafe AI’s Jev model.

GitHub: https://github.com/shaharia-lab/jev-cli (open source, MIT or Apache-2.0) Install: curl -fsSL https://raw.githubusercontent.com/shaharia-lab/jev-cli/main/install.sh | sh Docs: quick start and the full guide

One command, one number #

jev noul "Is this customer angry?" --state "You charged me twice. Fix it now."
answer  noul  yes  0.96  ████████████████████░
model jev-1.13.0 · 280 input tokens · est. cost $0.000012 · 783 ms

That is the whole idea. Jev never writes text. You define the question and the possible answers, and the model returns a calibrated probability for each one. Your code decides what to do with it.

LLM prompt jev
You get back A sentence to parse A number in a shape you defined
Same input next month May be worded differently Same contract
Cost per short ticket Cents A fraction of a cent
Use in a shell script Parse and hope Exit code 0 or 10

Install it and ask something #

curl -fsSL https://raw.githubusercontent.com/shaharia-lab/jev-cli/main/install.sh | sh

The script never uses sudo, checks the download’s SHA-256 and its signature, and installs a single binary. Windows has a PowerShell one-liner, and cargo binstall jev-cli works anywhere Rust does.

Then give it a key from the TypeSafe console and ask your first question:

export TYPESAFE_API_KEY=...
jev noul "Is this message asking for a refund?" --state "Please close my account and refund me."

About a minute, and a fraction of a cent.

A semantic if statement #

This is where it stops being a demo and starts being useful. A gating flag turns the answer into an exit code, so your shell already knows how to use it:

if jev noul "Is this ticket about billing?" --state-file ticket.txt --fail-under 0.7 --quiet; then
  echo "route to billing"
fi

Exit 0 means yes above your threshold. Exit 10 means no, and it is not an error: the answer is printed as usual and stderr stays empty. Every other code is a genuine failure, so a missing key or an outage can never be mistaken for a “no”. That distinction is the part most hand-rolled wrappers get wrong.

Three questions I actually run this way:

  • Does this commit message describe a user-facing change, so the pull request needs a changelog entry?
  • Is the text a user pasted into this form on topic, before it reaches anything expensive?
  • Did the model’s answer in this pipeline actually answer the question it was asked?

Three kinds of question #

Type Ask it when You get back
noul A property holds or it does not The probability of yes, 0 to 1
choice Exactly one of up to 255 options must win The winner, its confidence, and a probability per option
score A described scale of 2 to 10 levels A position on your scale

You can ask all of them about the same text in one call, which is what a triage step usually needs: how urgent, which team, how upset, answered together and paid for once.

A probability near 0.5 means the model cannot tell, not “medium”. --abstain-band 0.4,0.6 turns that into its own exit code, so those cases go to a person instead of a coin flip.

Built for AI agents, not just for people #

Agents were a first-class user from the first commit, not an afterthought:

  • jev spec prints every command, flag, default, exit code and example as one JSON document.
  • Every --help sayswhen to use this command rather than its siblings .
  • jev schema prints JSON Schemas for everything jev reads and writes.
  • jev validate and--dry-run check a request offline, for free, so an agent can fix its own mistake before spending anything.

And it speaks MCP, so an agent can call it without shell quoting at all:

claude mcp add jev -- jev mcp serve

The server takes a per-call spend cap, and it touches no file unless you start it with --allow-dir.

Thousands of rows, resumable #

jev batch run -f triage.yaml --input tickets.jsonl --state-field body \
  --id-field ticket_id --out results.jsonl --resume

Rows are streamed, so memory does not grow with the file. Failed rows become records rather than stopping the run, the pool backs off when the API rate limits, and --resume picks up from the output file after a crash or a Ctrl-C. There is no state file to babysit.

What it will not do #

Being honest about this saves you a bad afternoon. Jev reads literally and quickly. It cannot count, do arithmetic, compare dates or look anything up, so keep that in your code and ask Jev only for the meaning. Answers are not bit-for-bit repeatable, so compare against thresholds rather than for equality, and pin a versioned model for anything that has to stay stable.

And the obvious one: jev is an independent community project. It is not affiliated with, endorsed by, or sponsored by TypeSafe AI, and you need a TypeSafe API key to use it.

Try it #

curl -fsSL https://raw.githubusercontent.com/shaharia-lab/jev-cli/main/install.sh | sh
jev noul "Is this a good idea?" --state "Classify text from the command line with probabilities."

The documentation covers the question types, writing questions that work, scripting and CI, batch runs, and the MCP setup for Claude Code, Cursor and VS Code.

If the idea is useful to you, star the repository. It takes two seconds, and it is how the next person finds it. Bug reports and feature requests are welcome in the issue tracker.

── more in #ai-tools 4 stories · sorted by recency
── more on @typesafe ai 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
→ Live at https://your-agent.zahid.host ✓
Get free account → Pricing
from €0/mo · no card required
LIVE [news/jev-cli-text-classif…] indexed:0 read:6min 2026-09-20 · —