The problem
A control loop has a budget. A game at 60 frames per second has 16 milliseconds. An interface that responds to what the user is doing has maybe 200 before the response stops feeling connected to the action. An LLM that thinks for four seconds and writes a paragraph cannot participate in either.
What those loops need is a small decision, repeatedly, on the current situation. Which of these four moves, and is it safe to make right now. TypeSafe’s use-case map puts it as decisions made faster than human perception, fast enough to play games or to sit inside a UI, and quotes 150ms for that. TypeSafe’s launch post gives a range of 70ms to 500ms end to end. Both figures are the vendor’s own measurements, and neither appears on the models page alongside the published price and rate limits, so budget against your own numbers from your own region.
The awkward part is that Jev takes text only: a string, a JSON object, or an array of text. There is no vision input. Your code has to turn the frame, the scene or the screen into a description before asking anything, and the quality of that description sets the ceiling on everything after it. typesafe-mario and jev-drone both work this way, serialising a live situation into text and reading back a typed action.
What the state looks like
Your serialiser runs every tick. Send the entities that matter to the decision, already resolved into positions and relations code computed, and nothing else.
{
"player": { "x": 412, "y": 96, "on_ground": true, "facing": "right" },
"ahead": [
{ "kind": "gap", "distance_px": 64, "width_px": 96 },
{ "kind": "goomba", "distance_px": 210, "moving": "toward" }
],
"overhead": "clear",
"recent_action": "run_right"
}
Note what is already numeric. The distances were computed in code, not estimated by the model. Jev judges what the situation means, and everything measurable arrives pre-measured.
The questions you ask
One request per tick, carrying every question the loop might need.
import { choice, noul, TypeSafeClient } from "@typesafe-ai/sdk";
const client = new TypeSafeClient();
const response = await client.systemOne({
state: frame,
questions: {
action: choice("What should the player do right now?", {
run_right: "Keep moving right along the ground",
jump_right: "Jump forward to clear something ahead",
stop: "Stop and wait for the hazard to pass",
back_off: "Move left away from the hazard",
}),
risky: noul("Would acting now most likely cost the player a life?"),
},
});
const { choice: action, confidence } = response.answers.action;
const risk = response.answers.risky.noul;
The choice carries the decision, returning the winning option, a probability for every option, and a confidence value from 0 to 1. The noul, a yes/no question whose answer is one probability, acts as a brake that is independent of which action won. Read both from response.answers, which is where the JavaScript SDK puts every answer.
Send the speculative questions too. TypeSafe’s fan-out pattern states there is no speed cost for additional questions, so a loop can ask about situations that have not arisen yet and discard the answers it does not need. That is what keeps the request count at one per tick instead of one per question.
Decision policy
The loop runs whether or not an answer has arrived, so the policy has to include what happens when it has not.
const FLOOR = 0.55;
const BRAKE = 0.7;
function apply(action: string, confidence: number, risk: number) {
if (risk > BRAKE) return safeDefault(); // the brake overrides the pick
if (confidence < FLOOR) return lastGoodAction();
return action;
}
Your code owns the fallback, so a slow or failed request degrades into a scripted default rather than a freeze. It also owns the rate: asking on a state change or every nth tick beats asking every frame. The brake is a separate question from the action on purpose: a confident wrong move still gets stopped.
Treat the model’s answer as advice to a controller you already trust. TypeSafe documents a three-band policy, acting automatically on high confidence, confirming or gathering more in the middle, and refusing to act at the bottom, with worked thresholds from a 0.5 floor up to 0.9 for anything destructive. In a physical system the bottom band means the safe default, not a prompt to a human, and the thresholds are yours to set for your domain. The confidence-gated action recipe has the pattern, and Jev speed and pricing covers what the latency budget actually buys you.
When not to use this
Anything you can compute. Distance to the gap, time to collision, whether a trajectory clears an obstacle: that is physics, and it belongs in the same code that built the state. Jev is weak at arithmetic and does not count reliably, so “how many enemies are on screen” should come from your entity list.
Numeric representations read worse than semantic ones. A colour as a hex value performs worse than the same colour named in English, which matters when you are deciding what a serialiser should emit. Name things.
Hard real-time control is out of scope entirely. A loop that must hold a deadline every cycle cannot depend on a network request, whatever the median latency is. Keep Jev on the advisory layer above a deterministic controller that can run alone.
Watch the state size. Serialising the whole scene rather than the part the decision needs costs accuracy, and long states cost latency too. And if any of that text comes from a player, treat it as hostile: state is data, and Jev has no default defence against instructions written into it.
FAQ
How fast is it really?
TypeSafe reports 70ms to 500ms end to end and quotes 150ms in its own real-time examples. Those are the vendor’s measurements, and they do not include your network path, your serialiser, or queueing under load. Measure the full round trip from your own infrastructure before designing a loop around a number, and build the fallback path first.
Can it see the screen?
No. Jev takes text only, as a string, a JSON object, or an array of text. Anything visual has to be described by your code first, which in a game means reading the entity list you already have. That constraint often helps, because it forces the measurable parts into code where they are exact.
What happens when a request is slow or fails?
Your loop keeps running on the last good decision or a scripted default, and the late answer gets discarded rather than applied to a state that has moved on. Stamp each request with the tick it describes and drop anything that arrives stale. The SDK exposes error types and a retry policy, but in a loop, failing fast beats retrying.
Does asking more questions slow the tick down?
Not meaningfully. TypeSafe’s fan-out pattern states there is no speed cost for additional questions, which is why a real-time loop should batch everything it might need into the single request it was going to make anyway. Cost scales with the state you send rather than the questions you ask, and that state is small here.
Examples in the wild
Jev Ultrafast (Browser Use)
Browser Use's fast browser agent where Jev picks the operation and the DOM element in a single request; a small LLM is only invoked to write text when typing is required. Demoed on a Google Flights search.
typesafe-mario
Agent that plays Super Mario Bros. by feeding structured emulator state to Jev and acting on the returned controller action.
typesafe-computer-use
macOS computer-use loop that OCRs the screen, classifies the next action with Jev, then clicks. Author reports roughly $0.0002 per step.
hr98w/jev-visual
Educational Jev-like visual inference on Apple Silicon: Qwen3.5-0.8B under MLX answers several questions about one image by reusing shared multimodal context and scoring candidates from logits. Ships a browser UI, CLI, HTTP API and sorting-factory, Breakout and camera-gesture demos.
jev-drone
Camera-only autonomous drone simulated in MuJoCo with Jev in the control loop at 2.5 Hz.
mobile-jev
Standalone Android agent for Mobilerun where Jev makes every action decision, with a React studio UI and an Uber booking demo.
Jev Browser (vlad-terin)
Agent skill and runtime that uses Jev to select page elements through an agent's existing computer-use browser tools. The agent plans once, then Jev picks elements inside a continuous observe-act-verify loop without an agent turn between steps.
jkudish/jev-browser
Browser-use tool driving a real headless browser through an MCP server, CLI or library, with Jev choosing the actions. Returns text, markdown, HTML or accessibility-tree output plus traces and screenshots.
typesafe-snake
Snake auto-played by Jev: one Choice per game tick, with legal moves and board facts computed in code before the call.
tsai-sc (Jev plays StarCraft)
Harness that lets Jev control the original StarCraft shareware through synthetic keyboard and mouse input, recording action probabilities for each decision.
TypeSafe AI Playground (jev.works)
Community playground for Jev with around 110 use cases, games, dilemmas and model challenges. Supports editable prompts, A/B comparisons, conversation routing, document field extraction and code-policy inspection in a Next.js interface. Hosted at jev.works.
Ying-Kai-Liao/jev-browser
Browser automation where an LLM plans and Jev decides each tactical action, executed through Playwright without feeding page snapshots to the LLM. README reports 40/42 tasks passing and roughly 5x less token context.