Last updated: September 2026
Jev Choice vs Score vs Noul
Every question you can ask Jev is one of three types. Choice picks one option out of up to 255. Score places the state on an ordered scale of 2 to 10 levels and returns a probability-weighted float. Noul answers a yes or no statement with a single float from 0 to 1.
Below: the exact request and response JSON for each, when to reach for which, and the gotchas. The examples are social media judgments, because that is the domain these pages cover. Every shape here matches TypeSafe's primitives docs.
The three at a glance
All three go to the same endpoint, POST https://api.typesafe.ai/v1/systemone, in one request body of { state, model, questions }. You can mix types freely inside questions.
Choice
What it is. One option out of a fixed set. You declare the set as criteria, a map of option key to description, and the answer comes back as one of your keys plus a probability for every option.
When to use it. Unordered categories. Routing a reply to a queue, tagging a post by topic, picking which of your accounts should answer. Reach for it whenever the answer is a name your code will switch on.
{
"state": "Been using this for three weeks and the scheduler silently dropped two posts. Anyone else seeing that?",
"model": "jev-1.13.0",
"questions": {
"reply_intent": {
"type": "choice",
"instructions": "What does this reply want from the account owner",
"criteria": {
"bug_report": "Describes something that is broken or behaved unexpectedly",
"question": "Asks for information or help",
"praise": "Positive feedback with nothing requested",
"promotion": "Promotes the replier's own product, link or account",
"troll": "Insult or provocation with no substance"
}
}
}
}{
"model": "jev-1.13.0",
"answers": {
"reply_intent": {
"type": "choice",
"choice": "bug_report",
"probabilities": {
"bug_report": 0.871,
"question": 0.104,
"troll": 0.020,
"praise": 0.003,
"promotion": 0.002
},
"confidence": 0.744
}
},
"usage": { "input_tokens": 96, "output_tokens": 12 }
}Gotchas.
- criteria is a map, not an array. There is no
optionsfield. If you copied anoptions: [...]example from a launch write-up, it will not validate. - Descriptions can be null.
{"calm": null, "frustrated": null, "angry": null}is valid when the key says everything. Write a description the moment two options could overlap. - 255 options is the ceiling. Past that, do two stages: a Choice over groups, then a Choice inside the winning group.
- probabilities covers every option and sums to 1.0. Read it. A top answer at 0.44 with the runner-up at 0.42 is a coin flip with a label on it.
- The key is the contract.
choicereturns your key verbatim, so name keys the way your switch statement wants them. - confidence is derived. It is a statistic computed from the distribution you already have, not an independent second opinion.
Score
What it is. A position on an ordered scale. You declare the levels as criteria, an ordered array of 2 to 10 descriptions, and the answer is a float: the probability-weighted mean of the level indices.
When to use it. Anything with a rubric. Hook strength, clarity, how far a post is likely to travel, how angry a reply is. Also use it any time you want to rank a batch, because a float sorts and a category does not.
{
"state": { "draft_post": "I deleted 90% of our code and revenue went up.", "platform": "X (Twitter)" },
"model": "jev-1.13.0",
"questions": {
"hook": {
"type": "score",
"instructions": "How well does the opening line stop someone mid scroll?",
"criteria": [
"No hook. Opens with context, throat clearing, or a greeting.",
"Functional. States the subject plainly without creating a reason to continue.",
"Strong. Creates tension, a gap, or a surprise in the first line."
]
}
}
}{
"model": "jev-1.13.0",
"answers": {
"hook": {
"type": "score",
"score": 1.87,
"legend": {
"0": "No hook. Opens with context, throat clearing, or a greeting.",
"1": "Functional. States the subject plainly without creating a reason to continue.",
"2": "Strong. Creates tension, a gap, or a surprise in the first line."
},
"probabilities": { "0": 0.01, "1": 0.11, "2": 0.88 },
"confidence": 0.86
}
},
"usage": { "input_tokens": 84, "output_tokens": 6 }
}The float is not a rounding of the top level. It is the weighted mean of the indices: 0 x 0.01 + 1 x 0.11 + 2 x 0.88 = 1.87. TypeSafe's own docs work the same sum on a different example.
Gotchas.
- criteria is an ordered array, and there is no min or max. The scale runs from index 0 to index length minus 1. Write the levels in ascending order and phrase them so a higher index means more of the thing.
- 2 levels minimum, 10 maximum. Three to five is the useful range. Ten levels that a human cannot tell apart produce a float that looks precise and is not.
- A score is for ranking and thresholding, not measuring. 1.5 does not mean halfway between level 1 and level 2 in meaning. It means the distribution straddled them.
- legend keys are strings. To get the level text a draft landed on, index with
String(Math.round(score)). - A level can be an object, not just a string. TypeSafe's advanced primitives docs allow structure, so a level can carry examples alongside its description. The legend then returns that same object, so read whichever shape you sent.
- Every Score returns confidence. That includes a two-level Score, which is how you get a confidence number on a yes or no question that a Noul will not give you.
Noul
What it is. A yes or no statement, answered with one float from 0 to 1. You write instructions as a statement rather than a question, and the float is the probability that the statement is true of the state.
When to use it. Flags. Is this engagement bait, does this contain a slur, does this read as AI written, is this off topic for the account. Nouls are cheap to add, so a feed filter usually runs several at once.
{
"state": { "draft_post": "Drop a 🔥 if you agree and I'll DM you the template. Follow for part 2.", "platform": "X (Twitter)" },
"model": "jev-1.13.0",
"questions": {
"slop": {
"type": "noul",
"instructions": "This reads like it was generated by an AI rather than written by a person.",
"criteria": {
"true": "Uniformly long sentences, triadic lists, words like delve or landscape.",
"false": "Uneven rhythm, specific detail, an identifiable voice."
}
},
"bait": {
"type": "noul",
"instructions": "This post explicitly asks the reader for likes, reposts, replies, follows, or bookmarks."
}
}
}{
"model": "jev-1.13.0",
"answers": {
"slop": { "type": "noul", "noul": 0.21 },
"bait": { "type": "noul", "noul": 0.97 }
},
"usage": { "input_tokens": 118, "output_tokens": 4 }
}A Noul answer has no confidence field
This is the single most common error in third-party writing about Jev. A Noul returnsnoul and nothing else. There is no confidence, no probabilities map, no legend. Reading answers.bait.confidence gets you undefined. The probability itself is the confidence signal: 0.97 and 0.03 are both confident, and 0.5 is the model saying it cannot tell. Source: docs.typesafe.ai/primitives/noul.Gotchas.
- Write a statement, not a question. "This post asks for engagement" beats "Does this post ask for engagement?" A statement makes it obvious which direction high means.
- criteria is optional and takes true and false keys. Use it when the statement is fuzzy, which is most of the time. Put the boundary cases in it.
- You set the threshold, and it is not 0.5. Pick it from your own labelled examples, and keep a dead band in the middle where nothing acts automatically.
- Threshold per consequence. Blurring a post and deleting a post should not share a cutoff.
- Avoid negations. "This is not off topic" is two negations deep by the time your code reads it, and TypeSafe documents that indirection degrades accuracy.
Which primitive to reach for
All three in one request
TypeSafe documents that all declared questions are evaluated in the same parallel pass, so mixing types adds no extra round trip. They also share one copy of the state, which is why TypeSafe's fan-out pattern exists: a cookbook that batched 13 questions over one document measured 12.2x cheaper and 10.0x faster than asking them one at a time, with no change in the answers.
This is the shape the free post scorer uses. Seven questions, one request: one Score for reach strength on a five-level rubric, three Scores for hook, clarity and specificity on three levels each, and three Nouls for AI-slop, engagement bait and toxicity. All seven questions are answered in the same parallel pass.
import { TypeSafeClient, noul, score } from '@typesafe-ai/sdk';
const client = new TypeSafeClient({ timeout: 4000 });
const { answers, usage } = await client.systemOne({
state: { draft_post: text, platform: 'X (Twitter)' },
questions: {
strength: score('How far will this post travel compared to a typical post from the same author?', STRENGTH_LEVELS),
hook: score('How well does the opening line stop someone mid scroll?', HOOK_LEVELS),
clarity: score('How easily does a reader with no context understand this?', CLARITY_LEVELS),
specificity: score('How concrete is this?', SPECIFICITY_LEVELS),
slop: noul('This reads like it was generated by an AI rather than written by a person.'),
bait: noul('This post explicitly asks the reader for likes, reposts, replies, follows, or bookmarks.'),
toxicity: noul('This text contains slurs, harassment, sexual content, or abuse targeted at a person or group.'),
},
});
answers.strength.score; // 2.41
answers.strength.confidence; // 0.63
answers.strength.probabilities; // { "0": 0.03, "1": 0.14, ... }
answers.hook.legend['2']; // the rubric text the draft landed on
answers.bait.noul; // 0.04
answers.bait.confidence; // undefined. Nouls do not have one.Two practical notes from running this. Pin the model string: log jev-1.13.0 rather than jev-latest, or the thresholds you tuned drift the day the alias moves. And keep the state small. TypeSafe documents that irrelevant context degrades accuracy, so send the draft and the platform, not the whole account history.
Seven mistakes worth knowing before you write the schema
The wider version of the last point is on TypeSafe's model jaggedness page, and the practical consequences are in can Jev hallucinate. For the request ceilings that decide how you batch, see Jev rate limits and context window.
Keep exploring
The rest of the Jev reference, and what we built on it.
Jev rate limits and context window
64k tokens per request, 1,200 requests per minute, and where the two caps cross.
How to get Jev API access
The waitlist, plus Vercel AI Gateway, OpenRouter and Cloudflare.
Can Jev hallucinate?
Schema conformance is guaranteed. The value inside the schema is not.
Is Jev an LLM?
No. One parallel pass, typed decisions, no text generation.
Jev vs GPT
Cost, latency and accuracy on TypeSafe's four-workflow eval.
Will it go viral?
Seven Jev questions over one X draft. Free, no signup.
See seven questions answered at once
Will it go viral? runs four Scores and three Nouls over any X draft and shows the confidence band that the Scores return. Free, no signup. When the judgment is made, the OpenTweet API publishes to X, Bluesky and LinkedIn in one call.