Docs
OfficialJev Cookbooks
Cookbook: Structure Recovery
Reconstruct Markdown from unformatted text in two requests: 16 Noul line-pair questions stitch split sentences, then 62 questions classify each block's type and companions.
- Format
- Docs
- Reading time
- 3 min
- Published by
- TypeSafe AI
- Last verified
- Sep 2026
Works forJev for Classification
Used inJev for Robotics & Hardware
Highlights
- Two round trips on a 28-line memo: 16 stitch questions then 62 classification questions, 10,211 tokens in 0.8 seconds.
- Join cutoffs of 0.2 after dangling lines and 0.5 after terminal punctuation healed 11 line breaks.
- Asking whether a line picks up mid-sentence instead of whether it is the same paragraph kept blocks at 17 rather than collapsing to 12.
- Type dictionaries act as the whole classifier spec, and companion questions ride the same request.
Quickstart
python
JOIN_AFTER_DANGLING, JOIN_AFTER_TERMINAL = 0.2, 0.5
joins = client.system_one( # pass 1: 16 Nouls, one per adjacent line pair
state=tag(LINES, "L"),
questions={line_id(i): join_question(i) for i in range(1, len(LINES)) if not LINES[i]["gap"]},
model=TYPESAFE_MODEL,
).answers
blocks = merge([joins[line_id(i)].noul if line_id(i) in joins else 0.0
for i in range(len(LINES))])
classified = client.system_one( # pass 2: 62 questions about 17 blocks, one request
state=tag(blocks, "B"), questions=classify_questions([b["text"] for b in blocks]),
model=TYPESAFE_MODEL,
)Watch out
Stitching and typing are two separate judgment layers, so a bad stitch can produce a clean-looking document with the wrong structure.
Questions about this entry
Short answers drawn from the linked project or page.
The first sends 16 Noul line-pair questions to stitch split sentences; the second classifies the resulting blocks' types and companions. On a 28-line memo that was 10,211 tokens in 0.8 seconds.
Because that wording kept blocks at 17 rather than collapsing to 12 in the cookbook, and join cutoffs of 0.2 after dangling lines and 0.5 after terminal punctuation healed 11 line breaks.
For the 28-line memo it is two round trips, 10,211 tokens, 0.8 seconds and $0.0015, using the published rate of $0.042 per million input tokens with output free for jev-1.12 as of 2026-09. The document is fetched from a pinned gist so the numbers stay reproducible.
Because a rewrite can change the words. Here the model never generates text: it answers narrow questions about the document and code does the rendering, so every character of the output comes from the input and every judgment arrives with a probability.
Direct evidence stays in code. Line splitting, blank-line tracking and id tagging happen without a model, each line gets a short id like L014 that questions and answers refer to, and blank lines plus explicit markers such as -, 1. and # are read in code rather than sent back to the model to reconsider. This particular memo kept its blank lines but lost every marker.
Heading level, step order and callout kind ride in the same request as the block type, and their answers are read only when the block's type makes them relevant. The whole behavior is specified in the pass-2 criteria, three dicts of one-line descriptions plus the step question's true/false criteria, so the rest of the code is plumbing.
pip install ipython 'cooksafe>=0.2.0,<0.3.0' and set TYPESAFE_API_KEY. Every call is cached to json_cache.json, which ships with the cookbook, so re-rendering replays the published numbers without calling the API. Delete that file to run everything live, and note the notebook targets jev-1.12 with a 120-second client timeout.
Reactions & coverage
Posts, threads, and videos about this entry from around the web.
X: 200 rows, 32 template families, and traps, judged in one call
From the Jev guides
Original write-ups on what this entry is for.
From the Jev AI model community
Posts from builders shipping with Jev right now.