{"slug": "show-hn-ephemeral-runner-for-jev-style-models", "title": "Show HN: Ephemeral runner for JEV-style models", "summary": "Developer zatsepin released jigor, a Rust-based zero-shot classifier runner that executes JEV-style decision models locally via ONNX or remotely through OpenRouter's Decisions API. The tool installs via npm (@zatsepin/jigor), pip (jigor), or cargo (jigor-cli) and supports ephemeral execution through npx or uvx, with local backends von (sevenreasons/von-onnx-fp16, 759M model.onnx) and laya (Mattepiu/laya-onnx, fp32 and int8 variants) plus remote models typesafe/jev-1.13 and jaredpalmer/kev-4b. A sample remote call to typesafe/jev-1.13 returned a noul probability of 0.92 at a billed cost of $0.000012306 for 293 input tokens and 24 output tokens.", "body_md": "This is a zero-shot classifier models gateway or runner.\n\nOr, if you prefer marketing terms, \"System one decision\" models.\n\nThis is written in Rust (blazing fast as it should be), one wire protocol across\nbackends: `von` and `laya` run locally as ONNX (via `ort`); `jev` runs remotely on\nOpenRouter's Decisions API.\n\n- HF `sevenreasons/von-onnx-fp16` (`model.onnx` 759M,`tokenizer/tokenizer.json` 3.5M)\n- HF `Mattepiu/laya-onnx` (`laya.onnx` fp32 — matches the python reference\nbit-for-bit;`int8/laya_int8.onnx` via`LAYA_ONNX_FILE` )\n- OpenRouter Decisions (`typesafe/jev-1.13` ,`jaredpalmer/kev-4b` )\n\nYou can install it via npm, pip, or cargo. Is it enough? If not -> [subscribe](https://zatsepin.dev/subscribe)\n\n```\nnpm install --global @zatsepin/jigor\n# `pnpm approve-builds` may be needed\npip install jigor\ncargo install jigor-cli --locked\ncargo bininstall jigor-cli\n```\n\nYou can use ephemeral execution with npx or uvx.\n\n```\nnpx @zatsepin/jigor ask --model von <<'JSON'\n{\n  \"state\": { \"error\": \"Disk volume /var/log at 98% capacity.\" },\n  \"questions\": {\n    \"requires_intervention\": {\n      \"type\": \"noul\",\n      \"instructions\": \"Does this disk space condition require operational intervention?\"\n    }\n  }\n}\nJSON\n{\"answers\":{\"requires_intervention\":{\"noul\":0.7822,\"type\":\"noul\"}},\"backend\":\"local\",\"model\":\"von-1.0.0\"}\n```\n\nIf you have OPENROUTER_API_KEY in your env, you can easily run this from your terminal and get a quick response.\n\n```\nnpx @zatsepin/jigor ask --model jev <<'JSON'\n{\n  \"state\": { \"error\": \"Disk volume /var/log at 98% capacity.\" },\n  \"questions\": {\n    \"requires_intervention\": {\n      \"type\": \"noul\",\n      \"instructions\": \"Does this disk space condition require operational intervention?\"\n    }\n  }\n}\nJSON\n{\"answers\":{\"requires_intervention\":{\"noul\":0.92,\"type\":\"noul\"}},\"backend\":\"openrouter\",\"model\":\"typesafe/jev-1.13\",\"usage\":{\"cost\":0.000012306,\"input_tokens\":293,\"output_tokens\":24}}\n```\n\nFeel free to use it with your agents. This README.md is enough to teach them how to use it.\n\nOne dependency, one entry per backend — `noul`/` choice`/` score` questions\nin, typed answers out. Identical on von, laya and any OpenRouter model.\n\n```\n[dependencies]\njigor = { path = \"../jigor\" }                             # local checkout\n# jigor = { git = \"https://github.com/Partysun/jigor\" }   # from GitHub\n# jigor = \"0.1.5\"                                         # once published\nserde_json = { version = \"1.0\" }                          # Value, json!\nuse jigor::{Answer, Question, Backend, Result, VonBackend, choice, noul, score};\nuse serde_json::json;\n\nfn main() -> Result<()> {\n    let mut von = VonBackend::new()?;   // VonBackend::new, LayaBackend::new,\n                                        // OpenRouterBackend::for_model(...):\n                                        // the same answers() call on all three\n    let questions = vec![\n        noul(\"churn\", \"Is the customer likely to churn?\"),\n        choice(\n            \"want\",\n            \"What does the customer want?\",\n            &[\"refund\", \"order status\", \"technical help\"],\n        ),\n        score(\"urgency\", \"How urgent is this?\", &[\"calm\", \"annoyed\", \"angry\"]),\n    ];\n    let asks = von.answers(\n        &json!(\"Customer: I was charged twice for order #4471.\"),\n        &questions,\n        None,\n    )?;\n\n    match asks.get(\"churn\").unwrap() {\n        Answer::Noul { probability } => println!(\"churn: {:.4}\", *probability),\n        _ => {},\n    }\n    Ok(())\n}\n```\n\nOnly have a model id? `jigor::ask` resolves aliases and the provider for you:\n\n``` js\nlet asks = jigor::ask(\"jev\", &state, &questions, None)?;  // OpenRouter jev\nlet asks = jigor::ask(\"laya\", &state, &questions, None)?; // local laya\n// Asks { model, backend, answers, usage }\n// usage: tokens + billed cost (USD) on remote asks, None for local backends\n```\n\nErrors are one type — `jigor::Error` (carried by\n`jigor::Result<T>`): `UnknownModel`/` MissingApiKey`/` Remote` for\nrouting and OpenRouter responses, `Wire`/` MissingAnswer`/` MissingAnswers`\nfor malformed question/answer payloads, `Serialization` for JSON text,\n`External`/` Internal` for everything else. No foreign error type ever\nleaks out of the library.\n\n```\nuse jigor::{Error, Result};\n\nmatch von.answers(&state, &questions, None) {\n    Ok(asks) => { /* typed answers */ }\n    Err(Error::Remote { status, message }) => { /* upstream 4xx/5xx */ }\n    Err(e) => println!(\"{e}\"),\n}\n```\n\nThe local ONNX models (`von`, `laya`) download to `~/.cache/huggingface` on\nfirst use.\n\nSet `OPENROUTER_API_KEY` for the remote `jev` backend.\n\n```\ncargo run -p jigor --example decide\ncargo run -p jigor --release --example bench\ncargo run -p jigor --example decide --offline\n```\n\nExpected `decide`:\n\n```\ninfrastructure\n0.428\n{'infrastructure': 0.6203, 'billing': 0.1873, 'feature_request': 0.1924}\njudge: 0.3586\nrate score: 1.02 conf: 0.707 probs: {\"1\": 0.8109, \"2\": 0.1036, \"0\": 0.0855}\nfan-out intent: payment_failure 0.539\n```\n\nSet `JIGOR_DEVICE=cuda` to try CUDA EP\n(`ort` `cuda` feature, falls back to CPU if unavailable).\n\n```\njigor serve --host 0.0.0.0 --port 8000   # HTTP gateway\n```\n\nThe gateway mirrors the library: noul/choice/score questions in, typed\nanswers out — `von`/` laya` locally, anything else routed to the OpenRouter\nbackend selected by the `model` field:\n\n```\ncurl -X POST http://localhost:8000/v1/systemone \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"model\": \"von-1.0.0\",\n    \"state\": { \"error\": \"Disk volume /var/log at 98% capacity.\" },\n    \"questions\": {\n      \"requires_intervention\": {\n        \"type\": \"noul\",\n        \"instructions\": \"Does this disk space condition require operational intervention?\"\n      }\n    }\n  }'\n# {\"model\":\"von-1.0.0\",\"backend\":\"local\",\"answers\":{\"requires_intervention\":{\"type\":\"noul\",\"noul\":0.2739}}}\n```\n\nRoute by provider + model pair — `typesafe/jev-1.13` (alias `jev`) and\n`jaredpalmer/kev-4b` (alias `kev`) go to OpenRouter, `von-1.0.0` (alias `von`)\nstays local; unknown pairs are rejected.\nResponses from the OpenRouter backend add `usage` (tokens + cost in USD) next\nto `answers`, so each `/v1/systemone` call reports what it cost.\n\nAlso: `GET /healthz` returns `{\"status\":\"ok\"}`.\n\n`examples/tweet.rs` is a complete Tweet Tester written *only* against the lib\nAPI — it demonstrates how to build a Jev-style tool on top of\n`noul`/` choice`/` score` questions through one `answers` interface. All\ntweet-specific code lives in the example:\n\n- the 61-question viral-score bank (question set `v1.1` , 8 families\nEMO/CNV/SHR/TIM/CRF/IDN/FMT/ANTI);\n- a transparent 0-100 aggregation (`0.65 * content mean + 0.35 * clean anti-signal` ) — scoring semantics: 50 = your account's normal post, above\n50 beats it, below 50 does worse;\n- per-family \"fired % of N questions\" radar stats, top helped/hurt, and\nengagement `counters` (a wire JSON shape mirroring the viral-score API).\n\n```\ncargo run -p jigor --example tweet -- \"We just crossed 10,000 paying customers. Thank you.\"\ncargo run -p jigor --example tweet -- --json \"We just crossed 10,000 paying customers.\"\n# {\"score\":53,\"beats_own_normal\":0.53,\n#  \"families\":{\"EMOTION\":{\"label\":\"Emotion\",\"fired\":0.11,\"total\":9},...},\n#  \"counters\":{\"likes\":{\"multiple\":1.1,\"p75\":2.1,\"p90\":4.6,\"breakout_share\":0.1,\"probability\":0.5,\"confidence\":\"normal\",\"own_median\":null,\"expected\":null},...},\n#  \"helped\":[{\"id\":\"k_concrete_numbers\",\"family\":\"CRAFT\",\"label\":\"Numbers that carry weight\",\"answer\":\"Yes\",\"detail\":\"Stronger than your usual post\",\"effect\":0.95}],\n#  \"hurt\":[...],\"answers\":[...61 items...],\"engine\":{\"model\":\"von-1.0.0\",\"question_set\":\"v1.1\",...}}\n```\n\nThe example resolves the backend by model, exactly like `jigor ask`: `--model von` (default, local ONNX), `--model jev` (OpenRouter) or any other alias.\nThe 61-question bank, score, radar and counters are identical across\nbackends, so you can compare the same tweet side by side:\n\n```\ncargo run -p jigor --example tweet -- --model von \"We just crossed 10,000 paying customers. Thank you.\"\ncargo run -p jigor --example tweet -- --model jev \"We just crossed 10,000 paying customers. Thank you.\"\ncargo run -p jigor --example tweet -- --model jev --json \"Hot take.\" > jev.json\n```\n\nFor the milestone tweet the outputs line up: von gives 53/100 (conservative, CRAFT 35%), jev gives 63/100 (CRAFT 73%). Scores across backends are not calibrated to each other, but the shape is directly comparable.\n\nFamily `fired` is the \"X% of its questions fired\" radar value. The engagement\n`counters` (multiples, p75/p90, probabilities) and the `effect` coefficients\nare transparent placeholders for a fitted engagement model — tune the\nweights in the example's `counter_json`/` counter_multiple` once you have\npaired data. Von is a general decision model, so scores are a signal, not a\nforecast; fitting an engagement model on the same answers is the calibration\nstep.\n\nQuestion builders: `choice` takes plain option strings (each is both key and\ndescription), `choice_pairs` takes `(key, description)` pairs, `score` takes\nordered level texts, `noul` a plain instruction — and all three kinds mix\nfreely in one `answers` call.\n\n`examples/tagger.rs` shows a `choice` workflow: given a note and a list of\nexisting tags, one question — \"Which tag best matches the content of this\nnote?\" — picks the best tag (or the `None of these fit well` fallback) with a\nprobability distribution. Also runs on either backend via `--model`/`--provider`.\n\n```\ncargo run -p jigor --example tagger -- --title \"Hiring notes\" --tags \"work, ideas, personal\" \"Budget approved for two engineers.\"\n# Best tag: work  (confidence 0.440)\n#   work 60%  ·  ideas 16%  ·  personal 13%  ·  None of these fit well 10%\ncargo run -p jigor --example tagger -- --model jev --tags \"bugs, docs, ship\" \"Fixed the retry loop that dropped webhook events.\"\ncargo run -p jigor --example tagger -- --json --tags \"a, b\" \"note text\"   # wire JSON out\n```\n\nRequires [hurl](https://hurl.dev) and the local ONNX model (downloaded on\nfirst run). Wire fixtures live in `tests/fixtures/` (the OpenRouter Decisions\nrequest/response payloads are the reference for the wire format).\n\n```\nmake test        # unit tests + hurl suite + CLI tests\nbash tests/hurl/run.sh   # jigor serve: /v1/systemone (health, noul, choice,\n                         # score, fan-out, error paths, backend routing)\nbash tests/cli/ask.sh    # jigor ask / jigor models over stdin fixtures\n# or against a running server:\nhurl --test --variable BASE_URL=http://localhost:8000 tests/hurl/*.hurl\n```\n\nYou can [subscribe](https://zatsepin.dev/subscribe).\nI will not spam you, but 100% will share my work with you sometimes. I am lazy, don't worry too much.\n\nOr try one of my apps:", "url": "https://wpnews.pro/news/show-hn-ephemeral-runner-for-jev-style-models", "canonical_source": "https://github.com/Partysun/jigor", "published_at": "2026-09-26 15:07:49+00:00", "updated_at": "2026-09-26 15:31:55.701677+00:00", "lang": "en", "topics": ["ai-tools", "developer-tools", "machine-learning", "artificial-intelligence"], "entities": ["jigor", "zatsepin", "OpenRouter", "von", "laya", "typesafe/jev-1.13", "jaredpalmer/kev-4b", "Rust"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/show-hn-ephemeral-runner-for-jev-style-models", "markdown": "https://wpnews.pro/news/show-hn-ephemeral-runner-for-jev-style-models.md", "text": "https://wpnews.pro/news/show-hn-ephemeral-runner-for-jev-style-models.txt", "jsonld": "https://wpnews.pro/news/show-hn-ephemeral-runner-for-jev-style-models.jsonld"}}