Skip to content
learnjev
Tutorial 03/13FoundationsBeginner9 min

Designing state Jev can actually use

There is no system prompt in Jev. Everything the model knows about your problem arrives in one field called state, and the single most reliable way to lose accuracy is to put too much in it.

By the end you'll be able to

  • Choose between string, object and array state
  • Point a question at one field with a dot path
  • Filter irrelevant context out before it costs you accuracy
  • Work within the two simultaneous token budgets
On this page

Three shapes#

state takes a string, a JSON object, or an array of text values. TypeSafe's advice is to reach for an object in most cases, so each part of the input has a descriptive name and its relationship to the others stays visible.

Python
# A message, article or passage.
state = "My card was charged twice."

# Named fields — the default choice.
state = {"message": "My card was charged twice.", "order_id": "A-104"}

# A sequence of messages or records.
state = ["Hi", "My customer number is TS1337.", "My card was charged twice."]

The useful mental model from TypeSafe's docs: state is "the material you would present to a panel of experts before asking them to make a judgment." Not the briefing, not the instructions — the evidence.

One state, many parts#

When a judgment requires comparing several things — a conversation against a policy against a set of charges — they belong in one state object, not three requests.

state.json
{
  "ticket": {
    "subject": "Duplicate charge",
    "messages": [
      {"from": "customer", "text": "I was charged twice for order A-104. Please refund the duplicate."},
      {"from": "support", "text": "We are checking the charges."}
    ]
  },
  "order": {
    "id": "A-104",
    "charges": [
      {"amount_usd": 49, "status": "captured"},
      {"amount_usd": 49, "status": "captured"}
    ]
  },
  "refund_policy": "Duplicate charges are eligible for a refund."
}

Point questions at fields by name#

When a question is about one part of a structured state, name that part in the instructions using a backticked dot-and-index path. This is a documented feature, not a prompt trick — it tells the model which slice of the record to judge.

questions.py
questions = {
    "refund_requested": {
        "type": "noul",
        "instructions": "Does `ticket.messages[0].text` request a refund?",
    },
    "policy_supports_refund": {
        "type": "noul",
        "instructions": (
            "Does `refund_policy` support the refund requested "
            "in `ticket.messages[0].text`, given `order.charges`?"
        ),
    },
}

This pays off twice. It raises accuracy by removing a hop of inference, and it makes a wrong answer debuggable — you can see exactly which field the question claimed to be about.

Context rot is real and it is documented#

TypeSafe lists "large state full of irrelevant detail" as one of nine named failure modes for jev-1.13. Accuracy falls as the state grows with content unrelated to the decision, and a large state makes it harder to work out which part produced a wrong answer. Their own summary is unambiguous: "Jev suffers from context rot, so unrelated material in the state costs you accuracy."

When you cannot filter deterministically, you can filter with Jev itself — a cheap Noul per candidate passage, then assemble the survivors into the real request. TypeSafe's classifying RAG passages cookbook is the worked version, and it doubles as an injection screen.

prefilter.py
from typesafe_sdk import Noul, TypeSafeClient

client = TypeSafeClient()

# One request, one Noul per retrieved passage. Output tokens are free,
# so the marginal cost of screening a candidate is the candidate itself.
screen = client.system_one(
    state={"query": query, "passages": passages},
    questions={
        f"relevant_{i}": Noul(
            instructions=f"Does `passages[{i}]` help answer `query`?",
        )
        for i in range(len(passages))
    },
)

kept = [
    p for i, p in enumerate(passages)
    if screen.nouls[f"relevant_{i}"].noul > 0.6
]

The two token budgets#

Jev does not have one context limit, it has two that apply at the same time:

BudgetCovers
64k tokensthe whole request — state plus every question combined
32k tokensstate plus the single longest question
From TypeSafe's Models page. The state is ingested once and every question is evaluated against it in parallel.

There is no documented cap on the number of questions. The only ceiling is tokens, and TypeSafe's own cookbooks routinely run in the low hundreds — 182 skills ranked in one request, 218 line IDs scored in another.

State is data, and Jev does not treat it as hostile#

This deserves its own heading because it is a security property, not a quality note. TypeSafe states it plainly: "State is data, and jev-1.13 does not treat it as hostile by default. Content written to adversarially steer the model — an injected instruction, a deliberately misleading framing, or text that argues for its own classification — can move the answer."

If you are putting Jev in a control path — deciding whether a tool call is safe, whether a transaction clears, whether content is allowed — and the state contains anything a user wrote, then prompt injection is inside your threat model. Be explicit in the criteria, test adversarial inputs before you ship, and do not let a single Jev answer be the only thing standing between untrusted input and an irreversible action.

A working checklist#

  1. 1

    Filter before you send

    Retrieve, slice and drop in code. Everything that cannot change the answer is costing you accuracy.
  2. 2

    Name the parts

    Use an object with descriptive keys, then reference those keys from the instructions with backticked paths.
  3. 3

    Keep computation out of state

    Dates, totals, counts and comparisons should arrive pre-computed. Jev reads dates as text and is not a calculator — see the failure modes.
  4. 4

    Separate evidence from judgment

    The refund policy belongs in state. "Does the policy cover this?" belongs in a question.
  5. 5

    Assume the state can be adversarial

    If any part of it came from a user, treat the answer as advisory until your own code has checked the consequences.

Next#

Now that one request can carry a well-shaped state, the next move is to stop making more than one. Continue to Ask every question at once.

Sources for this page

Last reviewed 2026-09-18. Jev is days old and moving — where a claim is TypeSafe's own rather than independently verified, this page says so in the sentence that carries it.