{"slug": "jev-cli-text-classification-in-your-terminal-with-probabilities-instead-of-prose", "title": "jev CLI: Text Classification in Your Terminal, With Probabilities Instead of Prose", "summary": "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.", "body_md": "[← All posts](https://shaharia.com/blog)\n\n# jev CLI: Text Classification in Your Terminal, With Probabilities Instead of Prose\n\njev 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.\n\n## On this page ▾\n\nYou 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.\n\nToday 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.\n\nI 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.\n\n**GitHub:** [https://github.com/shaharia-lab/jev-cli](https://github.com/shaharia-lab/jev-cli) (open source, MIT or Apache-2.0)\n**Install:** `curl -fsSL https://raw.githubusercontent.com/shaharia-lab/jev-cli/main/install.sh | sh`\n**Docs:** [quick start and the full guide](https://github.com/shaharia-lab/jev-cli/blob/main/docs/README.md)\n\n## One command, one number\n\n```\njev noul \"Is this customer angry?\" --state \"You charged me twice. Fix it now.\"\nanswer  noul  yes  0.96  ████████████████████░\nmodel jev-1.13.0 · 280 input tokens · est. cost $0.000012 · 783 ms\n```\n\nThat 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.\n\n|  | LLM prompt | `jev` | \n|---|---|---|\n| You get back | A sentence to parse | A number in a shape you defined | \n| Same input next month | May be worded differently | Same contract | \n| Cost per short ticket | Cents | A fraction of a cent | \n| Use in a shell script | Parse and hope | Exit code 0 or 10 | \n\n## Install it and ask something\n\n```\ncurl -fsSL https://raw.githubusercontent.com/shaharia-lab/jev-cli/main/install.sh | sh\n# or: brew install shaharia-lab/tap/jev\n```\n\nThe 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.\n\nThen give it a key from the [TypeSafe console](https://console.typesafe.ai/keys) and ask your first question:\n\n```\nexport TYPESAFE_API_KEY=...\njev noul \"Is this message asking for a refund?\" --state \"Please close my account and refund me.\"\n```\n\nAbout a minute, and a fraction of a cent.\n\n## A semantic `if` statement\n\nThis 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:\n\n```\nif jev noul \"Is this ticket about billing?\" --state-file ticket.txt --fail-under 0.7 --quiet; then\n  echo \"route to billing\"\nfi\n```\n\nExit 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.\n\nThree questions I actually run this way:\n\n- Does this commit message describe a user-facing change, so the pull request needs a changelog entry?\n- Is the text a user pasted into this form on topic, before it reaches anything expensive?\n- Did the model’s answer in this pipeline actually answer the question it was asked?\n\n## Three kinds of question\n\n| Type | Ask it when | You get back | \n|---|---|---|\n| `noul` | A property holds or it does not | The probability of yes, 0 to 1 | \n| `choice` | Exactly one of up to 255 options must win | The winner, its confidence, and a probability per option | \n| `score` | A described scale of 2 to 10 levels | A position on your scale | \n\nYou 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.\n\nA 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.\n\n## Built for AI agents, not just for people\n\nAgents were a first-class user from the first commit, not an afterthought:\n\n- `jev spec` prints every command, flag, default, exit code and example as one JSON document.\n- Every `--help` says*when to use this command rather than its siblings* .\n- `jev schema` prints JSON Schemas for everything jev reads and writes.\n- `jev validate` and`--dry-run` check a request offline, for free, so an agent can fix its own mistake before spending anything.\n\nAnd it speaks MCP, so an agent can call it without shell quoting at all:\n\n```\nclaude mcp add jev -- jev mcp serve\n```\n\nThe server takes a per-call spend cap, and it touches no file unless you start it with `--allow-dir`.\n\n## Thousands of rows, resumable\n\n```\njev batch run -f triage.yaml --input tickets.jsonl --state-field body \\\n  --id-field ticket_id --out results.jsonl --resume\n```\n\nRows 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.\n\n## What it will not do\n\nBeing 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.\n\nAnd 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.\n\n## Try it\n\n```\ncurl -fsSL https://raw.githubusercontent.com/shaharia-lab/jev-cli/main/install.sh | sh\njev noul \"Is this a good idea?\" --state \"Classify text from the command line with probabilities.\"\n```\n\nThe [documentation](https://github.com/shaharia-lab/jev-cli/blob/main/docs/README.md) covers the question types, writing questions that work, scripting and CI, batch runs, and the MCP setup for Claude Code, Cursor and VS Code.\n\nIf the idea is useful to you, **[star the repository](https://github.com/shaharia-lab/jev-cli)**. It takes two seconds, and it is how the next person finds it. Bug reports and feature requests are welcome in the [issue tracker](https://github.com/shaharia-lab/jev-cli/issues).", "url": "https://wpnews.pro/news/jev-cli-text-classification-in-your-terminal-with-probabilities-instead-of-prose", "canonical_source": "https://shaharia.com/blog/jev-cli-text-classification-terminal-ai-agents/", "published_at": "2026-09-20 00:00:00+00:00", "updated_at": "2026-09-28 19:20:34.221661+00:00", "lang": "en", "topics": ["ai-tools", "developer-tools", "artificial-intelligence", "natural-language-processing"], "entities": ["TypeSafe AI", "jev", "Jev model", "jev-cli", "shaharia-lab", "GitHub", "Homebrew", "Rust"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/jev-cli-text-classification-in-your-terminal-with-probabilities-instead-of-prose", "markdown": "https://wpnews.pro/news/jev-cli-text-classification-in-your-terminal-with-probabilities-instead-of-prose.md", "text": "https://wpnews.pro/news/jev-cli-text-classification-in-your-terminal-with-probabilities-instead-of-prose.txt", "jsonld": "https://wpnews.pro/news/jev-cli-text-classification-in-your-terminal-with-probabilities-instead-of-prose.jsonld"}}