Skip to content
JJev AtlasField notes
Start hereBuild ideasFit checkClaimsFor agents
More
Ask wellCostProjectsPatternsIdeasEvidenceLibrary
Search⌘K

J Jev Atlas / Independent research

431 posts · 9 claims · 31 hypotheses

Back to top ↑

Practice

Ask Jev well.

A typed answer arrives in the right shape whether or not the question deserved it. These seven techniques are about the part the type system cannot check: what you put in the question, what you leave in your own code, and what you check afterwards.

Written here in our own words, with the source for each one listed underneath. TypeSafe’s documentation is the authority on the current API; this page is about how to use it well.

01

Rebuild the option list from the current state at every step.

An option list is a snapshot. Build it once at the start of a multi-step run and it starts drifting away from reality immediately — the row got archived, the button moved, the ticket was closed by someone else. The answer will still be well-typed, and it will still name something that is no longer there.

Browser Use’s jev-ultrafast regenerates the list of page controls before every decision, so the model only ever picks among things that exist right now. Regenerating costs you one cheap step and removes a whole class of failure that is otherwise very hard to see in a log.

Built oncestaleRebuilt eachstepstep 1step 2step 3
Illustrative. The list on top was built before the first step and reused; the list below is regenerated from the current state each time, so it can never name something that has gone.
  • Browser Use · jev-ultrafast
  • Case study in this atlas

02

Send independent questions together; fetch first, then ask.

Questions asked in one batch cannot read each other’s answers. That is the whole rule, and most of the mistakes come from forgetting it: a second question written as though the first one already answered it simply gets no answer to work from.

So split the work in two. Anything one question needs from another is a lookup, and lookups belong in your code, before the batch. What is left is genuinely independent, and all of it goes in a single round trip instead of a chain of them.

Chainedquestion 1question 2question 33 tripsFetch, then ask togetherlookupquestion 1question 2question 31 trip
Illustrative. Chaining three questions because the second needs the first costs three round trips. Fetching what they share in your own code first lets all three go in one.
  • TypeSafe docs · Parallel questions
  • Parallel decision matrix

03

Put the real requirement in the question, and describe every option.

The model reads what you wrote. It does not read the variable holding the option, the enum it came from, or the comment above the function. An option called tier_2 carries no meaning at all; “needs a specialist, not the general queue” carries the meaning you actually had in mind.

The same is true of the question itself. Whatever rule a trained person would apply — the deadline, the exception, the thing that makes this a borderline case — belongs in the sentence. If you find yourself explaining the answer afterwards, that explanation was the question.

Weaker

question: "classify" options: ["tier_1", "tier_2", "tier_3"]

Three identifiers and a verb. Nothing here says what separates one tier from the next, so the answer is a guess dressed as a category.

Better

question: "Who should handle this? Anything about billing goes to accounts even if it also mentions a bug." options: [ "front line — answerable from the help centre", "specialist — needs someone who knows the product", "accounts — anything touching money or invoices", ]

The requirement and the tie-break are in the text, and each option says what it means. The same words are what you would give a new colleague.

  • TypeSafe docs · Choice

04

Give evidence, not summaries.

When you compress the state into one tidy paragraph before asking, you have already made the judgment — in code that nobody reviews and no test covers. Whatever your summariser dropped is now invisible to the decision that depends on it.

Pass the pieces instead, as separate fields: what you found, where each piece came from, and what you looked for and did not find. The gaps matter as much as the findings, and they are the first thing a summary throws away. It also makes a wrong answer readable afterwards, because you can see exactly what the question was holding.

Weaker

state: { summary: "Customer seems frustrated about a late delivery and wants a refund.", }

One sentence, already interpreted. Whether the order was actually late, and whether anyone checked, has been quietly decided upstream.

Better

state: { message: "<the text, as received>", orderStatus: "shipped 9 days ago, not delivered", refundPolicy: "30 days, unused items", priorContacts: 2, notFound: ["delivery scan after leaving depot"], }

Findings, their sources, and the gap all travel separately. The question can weigh them; nothing has been decided on the way in.

  • Decision sidecar pattern
  • Probabilistic predicate + deterministic action

05

Confidence is not accuracy; set the threshold from your own examples.

A confidence of 0.9 is the model’s own report about its answer. It is not a measured hit rate, and it does not mean nine out of ten answers at that level were right on your data. Picking 0.9 as a review threshold because it looks high is guessing with a decimal point in it.

Label a few hundred of your own examples, bucket the answers by reported confidence, and look at how often each bucket was actually right. That table tells you where to draw the line for the cost you are willing to carry. Redraw it when the traffic changes, because the curve moves with your inputs, not with the model.

Accuracy you measuredthreshold0%100%0.01.0confidence the model reported
Illustrative. The dashed line is what it would mean for confidence to equal accuracy. The solid line is the sort of thing you find when you actually measure — which is why the threshold is read off your own curve, not chosen because it looks high.
  • TypeSafe docs · Confidence
  • Confidence gate pattern

06

For big candidate lists: filter in code, Score the rest, Choice over a shortlist.

A Choice holds up to 255 options. That is generous, and still far smaller than most real catalogues, inventories, or user lists. The answer is not a bigger question — it is three smaller stages.

Cut the list with the constraints you can state exactly: availability, region, permissions, anything a WHERE clause already knows. Rank what survives with a Score. Then put the handful at the top into a Choice for the judgment that genuinely needs one. Each stage is cheaper than one enormous question and, more usefully, each can be tested on its own.

candidates4,000filter in codesurvivors180Scoreshortlist12Choice · up to 255 options
Illustrative counts. Each stage is cheaper than the one above it and can be tested on its own: the filter against your rules, the ranking against a held-out set, the final judgment against labelled examples.
  • TypeSafe docs · Choice
  • Cascade router pattern

07

A confident answer never proves the action happened.

Deciding to click the button and the button having been clicked are two different facts, and only one of them is in the answer. Confidence describes the judgment, never the side effect that followed it.

jev-ultrafast checks its outcome separately, after the run reports that it is done. Do the same with anything that can spend money, send something, or delete something: verify the result against the world, not against the decision. And keep the guardrails where they can be read and tested — how many attempts are allowed, how much may be spent, and where the run got to — in your code, not in the question.

Not a check

if (decision.confidence > 0.95) { await refund(order) markComplete(order) }

The confidence is about the judgment. Nothing here observes whether the refund actually went through, and the run is marked complete either way.

A check

if (decision.confidence > threshold && spend.remaining() >= order.total && attempts.allow(order.id)) { await refund(order) } const seen = await readRefundStatus(order.id) if (seen !== "settled") escalate(order, seen)

The limits are ordinary code, and the outcome is read back from the system that owns it. The decision opens the door; it does not report what came through it.

  • Browser Use · jev-ultrafast
  • Probabilistic predicate + deterministic action

Where each decision lives

Every technique above is really one question asked again: which of these three columns does this belong in? Getting the split right is most of the work, and it is the part you can check without running anything.

Stays in code

Anything that has to be exact, repeatable, and reviewable.

  • Filters, joins, permissions, and arithmetic
  • Retries, timeouts, and rate limits
  • Spend caps and action budgets
  • Saved progress, so a restart resumes
  • Verifying that an action actually happened

Stays with an LLM

Anything whose output is language a person will read.

  • Writing the reply, the summary, the diff
  • Open-ended planning over many steps
  • Filling in free text an interface needs
  • Explaining a decision after it was made

Goes to Jev

The narrow judgments in between, one question at a time.

  • Which of these options applies
  • How far along a scale this sits
  • How likely a yes-or-no statement is
  • The same question asked over every item
  • A gate your code thresholds and logs

The boundary is the pointEach column is testable on its own

Fit checkPaste your workflow and get the split above drawn for it, decision by decision.Opportunity mapThe design space, grouped by the property that makes a typed judgment worth calling.

Sources

  • https://github.com/browser-use/jev-ultrafast
  • https://docs.typesafe.ai/cookbooks/parallel_questions
  • https://docs.typesafe.ai/primitives/choice
  • https://docs.typesafe.ai/confidence

This atlas is independent and not affiliated with TypeSafe. Where a technique comes from someone’s published work, that work is linked above rather than restated here.

What a stream of these decisions would cost