Playful hand-drawn adventure-game illustration of a late-night sports den. A goofy brass sorting machine with a gauge reading 0.58 sorts a stack of bet slips into a crate with a green check, a crate with a red X, and a small crate with a question mark. A pinned chart on the wall shows dots climbing along a dashed line, a baseball game plays on an old TV, and a man in a hoodie leans back with a coffee mug, amused.

Learning Jev with Personal Data

13 min read

I’ve been wanting to learn Jev, but there’s not much in my day-to-day work that I can use it for yet. So I thought I’d take some bet data I’ve been collecting and learn it while making a post. Every section has a point where you make a quick decision based on limited information, and your progress saves in the browser.

The subject is Jev, the first “System One” model from TypeSafe, and decision models in general. I didn’t want to use made-up examples, so everything here runs on my own data.

Since April, I’ve logged Rithmm’s sports bet picks so far, with 252 at by the time I was writing this. My original experiment with this was to see if I could use the Martingale betting theory in limited sets and profit more than I would have with money in a high-yield savings account. The answer is no. However, after reviewing the data, I found that Rithmm hit at a profitable rate on NBA picks with 60% or higher confidence. WNBA was in range as it went on, but MLB was not as successful. Jev leads me to some new experiments.

I sent the ones that settled as wins or losses through Jev and saved every answer. The question running through the whole course is pretty simple: can a decision model help me choose which picks to bet?

Syllabus
0 of 7 checkpoints passed
  1. Start with a guess not started
  2. What a decision model is not started
  3. A pick becomes state not started
  4. Reading the three answers not started
  5. Thresholds are break-even not started
  6. Did the numbers mean anything? not started
  7. Where it breaks not started

Start with a guess

Before any model gets involved, you try it. Here’s what I see before a game, minus the result.

Warm-up · You be the model
Five real picks. Which ones hit?
This is what I see before a game: the pick, the odds, recent form, and Rithmm's projection. Call each one, then check it against how the game actually went.

    What you just did is what Daniel Kahneman calls System 1 thinking in Thinking, Fast and Slow: a fast gut call without much deliberating. Rithmm’s confidence number is supposed to make that call easier. Across the 248 picks where it gave one, Rithmm averaged 63.8%, and the picks hit 58.1%. It also never went below 56% on anything, so as a filter it says yes to every pick it hands me.

    Checkpoint · L1
    Rithmm averaged 63.8% confidence across 248 picks. How often did they actually hit?

    What a decision model is

    System 2 is the slow, effortful reasoning, and it’s what most of the LLM conversation for the last few years has been about: models that write, plan, and reason out loud. Jev goes the other way. You hand it some text or JSON, ask it questions, and get back typed answers with probabilities your code can branch on. It can’t write a sentence, summarize, or chat.

    Every question is one of three types, and each maps to something you already write in code:

    • A Noul (as in Bernoulli) is a yes/no question. It returns one number between 0 and 1, the probability the answer is yes. It’s an if.
    • A Choice picks one option from a set you define. It returns the winner, a probability for every option, and a confidence. It’s a switch.
    • A Score places something on ordered levels you describe. It returns a position, a probability per level, and a confidence. It’s what you sort by.

    It’s also cheap enough that cost barely comes up. My whole run was 504 requests (every pick twice, more on that in a minute) and 330,106 input tokens. At $0.042 per million input tokens, with output tokens free, that’s about a penny and a half, and it finished in 8 seconds.

    Exercise · Sort the tasks
    Which betting questions are Jev questions?
    Does this pick's recent form back it up?
    What kind of bet is this: moneyline, spread, game total, player over, or player under?
    How strong is the case at these odds: pass, lean, or play?
    Write a recap of last night's bets for the group chat
    Work out the break-even hit rate for -150 odds
    0 of 5 sorted
    Checkpoint · L2
    Jev answers "Will this bet win?" with 0.62. What is that?

    A pick becomes state

    A request has two parts. The state is the thing being judged: a string, a JSON object, or an array of strings (text only for now). The questions are what you want to know about it. Every question sees the same state, each one is answered on its own, and they all come back in one response, so asking four questions doesn’t cost four round trips.

    The state docs suggest keeping the state to facts and putting your framing in the questions. For a pick, the facts are easy: the date, sport, matchup, the pick, the odds, and recent form. Nothing about the result or what I bet. Then I asked every pick the same four questions: will it win, does recent form back it, what kind of bet is it, and how strong is the case at these odds.

    Here’s the twist. I sent every pick twice, once with Rithmm’s projection in the state (“Tigers 5.9, Angels 3.2”) and once without it.

    Lab · One request, real answers
    What Jev did with a pick
    Each of these is a real request to jev-1.14.0. Flip Rithmm's projection in and out of the state and watch what moves. The questions never change.
    state
     
    answers
    will_hit
    form_backs_pick
    bet_type
    lean
    See the four questions sent with every pick
    {
      "will_hit": {
        "type": "noul",
        "instructions": "Will this bet win?",
        "criteria": {
          "true": "The pick as written wins when the game is settled",
          "false": "The pick as written loses"
        }
      },
      "form_backs_pick": {
        "type": "noul",
        "instructions": "Does the player's or team's recent form support this pick?",
        "criteria": {
          "true": "The recent form record points the same direction as the pick",
          "false": "Recent form is mixed, thin, or points the other way"
        }
      },
      "bet_type": {
        "type": "choice",
        "instructions": "What kind of bet is this?",
        "criteria": {
          "moneyline": "A team to win the game outright",
          "spread": "A team to cover a point spread or run line",
          "game_total": "The combined score of both teams over or under a number",
          "player_over": "A player stat over a number (hits, points, rebounds, receptions, and so on)",
          "player_under": "A player stat under a number"
        }
      },
      "lean": {
        "type": "score",
        "instructions": "How strong is the case for placing this bet at these odds?",
        "criteria": [
          "Pass; the case doesn't justify the price",
          "Lean; some support, but a small stake at most",
          "Play; the case clearly beats the price"
        ]
      }
    }

    Rithmm’s projection is an opinion about the game, but sitting in the state it reads like a fact. With it, Jev’s pass/lean/play Score landed on “play” for 69 picks. Without it, Jev never said “play” once. Look at the Tigers moneyline: recent form 2/10, a lean of 0.07 on the facts alone, and 1.21 once Rithmm’s projected runs show up. It lost. Adding the projection also made Jev worse at telling winners from losers overall, which we’ll get to in a couple of sections.

    If you want to compare Jev against another model, the lesson is to keep the other model out of the request and compare the two numbers in your own code.

    Checkpoint · L3
    You want Jev's read and Rithmm's read on the same pick. Where does Rithmm's projection go?

    Reading the three answers

    The Noul is the simplest. “Does recent form support this pick?” came back 0.84 for a receptions over with 9/10 recent form, and 0.10 for a Sky moneyline with 1/10. That one number turns out to be one of the most useful things in the whole run, so keep it in mind.

    The Choice is where Jev caught some data issues. I asked what kind of bet each pick was and compared the answer to the labels in my own data. The first time I checked, Jev “missed” 40 of them. It hadn’t. My bots had filed 39 run lines, game totals, and a moneyline as “combo” player props. Jev was right, my labels were wrong, and I fixed them. A few of them:

    PickMy old labelJev
    Blue Jays +1.5combo overspread
    Athletics @ Mariners Over 7.5 Total Runscombo overgame total
    Tigers @ Reds Under 9.5combo undergame total
    Blue Jays Moneylinecombo overmoneyline

    It also caught one more: I typed a total bases pick as an Under when I actually bet the Over. After fixing both, Jev matches my labels on all 252.

    The Score is the probability-weighted average of the level positions, so with pass at 0, lean at 1, and play at 2, a 0.9 means “mostly lean.” The Score docs say to describe situations instead of degrees, which is why my levels read like “Lean; some support, but a small stake at most” instead of just “1.” The catch is that the average hides how the probability is spread.

    Exercise · Same score, different answer
    Both of these scored about 0.9. Which one was Jev sure about?
    Reds +1.5
    -152 · recent form 7/10
    score 0.90
    Kaleb Johnson Under 38.5 Rushing Yards
    -111 · recent form 10/10
    score 0.89

    That’s what confidence is for. The confidence docs put it at 1 when all the probability sits on one level and 0 when it’s spread about evenly. Check it before your code acts on the score.

    Checkpoint · L4
    A Score comes back 0.9 with confidence 0. What should your code do?

    Thresholds are break-even

    A Noul gives you a probability and leaves the decision to you. The Noul docs suggest starting with 0.7 for yes and 0.3 for no, sending the middle to a person, and raising the bar when a false yes is expensive.

    Betting hands you the line for free, because the odds already tell you what being wrong costs. At -150 you risk 150 to win 100, so you need to win 150 out of 250, or 60%, just to break even. At +120 it’s 100 out of 220, about 45%. Every pick has its own threshold, and your code can work it out:

    const breakEven = odds < 0 ? -odds / (-odds + 100) : 100 / (odds + 100);
    
    if (answers.will_hit.noul > breakEven + margin) placeBet(pick);
    Lab · Thresholds are break-even
    Bet only when the model beats the price
    Every pick's odds set a break-even hit rate. The rule: bet when the probability clears break-even by at least the margin. Betting all 248 picks went 144–104 for +6.54 units.
    bets
    record
    units
    per bet
    Units at every margin from -10 to +15 points. The dot is where you are.

    At zero margin, Jev on the facts alone picks 86 of the 248 picks and goes 57–29 for +19.42 units, compared with +6.43 for betting all of them. With Rithmm’s projection in the state, it bets 135 and finishes +16.57. Rithmm’s own number cleared break-even on every single pick, so its version of the rule is “bet everything.”

    One thing I was careful about: zero margin is just break-even, so I didn’t tune it. Dragging the slider until the units peak is exactly the kind of fitting the docs warn about (“avoid fitting thresholds closely to a handful of test cases”). It’s fun to look at, but the best margin on these 248 picks won’t translate to the next 248.

    Checkpoint · L5
    A pick is at -150 and Jev says 0.58. Do you bet it?

    Did the numbers mean anything?

    There are two different questions you can ask about any set of probabilities, and a model can pass one and fail the other:

    • Calibration: when it says 60%, do those picks hit about 60% of the time?
    • Ranking: do the winners get higher numbers than the losers?

    An independent evaluation of Jev found that its yes/no split probabilities ranked well but were poorly placed against a fixed 0.5 cutoff. Here’s how it looks on my picks.

    Chart · Did the numbers mean anything?
    What each source said vs. how often the picks hit
    The 248 picks are split into five groups of about 50, sorted by the probability each source gave them. On the dashed diagonal, a group the model called 60% hits 60% of the time. The bars show how far each group could swing by chance alone.
    Rithmm's confidence: said 60%, hit 60%; said 61%, hit 58%; said 63%, hit 60%; said 65%, hit 50%; said 70%, hit 63% 30% 30% 40% 40% 50% 50% 60% 60% 70% 70% 80% 80% avg break-even 57% what it said how often they hit
    Average it said: 64% Actually hit: 58% Ranking skill: 0.49

    Rithmm’s points sit on a flat line around 60% no matter what it said. Its most confident group (67% to 74%) hit 62.5%, about the same as its least confident group. That’s a ranking skill of 0.49, a coin flip, and its probabilities were slightly less accurate than using the break-even rates from the odds.

    Jev on the facts alone climbs. Its least confident group hit 56%, and its most confident group hit 69%. It was too cautious overall (averaging 54% on picks that hit 58%), but it put them in roughly the right order. If you’re wondering what “ranking skill” means in practice, this is the easiest way to see it.

    Game · Can it tell a winner from a loser?
    Draw one pick that hit and one that missed
    A model that can rank should give the winner the higher number. Draw pairs and keep score. A coin flip gets about half right.
    pairs0
    Rithmm got right–
    Jev, facts only–
    Checkpoint · L6
    Rithmm's ranking skill is 0.49. What does that mean?

    Where it breaks

    I like what I saw. I also think the quickest way to get burned by a new model is to believe the first good chart, so here’s what I don’t trust yet.

    Jev might have seen the results

    Every one of these games happened between April and October, and Jev 1.14 became available on October 14. If any of these results ended up in its training data, the “will it win” numbers would look smart for the wrong reason. The gap is small, though. Jev averaged 54.5% on picks that hit and 52.8% on picks that missed, which doesn’t look like a model peeking. And a lot of the signal is sitting right there in the input: the raw recent form number (7/10 as 0.7) ranks winners at 0.56 all by itself, and Jev’s “does form back this pick?” Noul ranks at 0.59. I still can’t rule it out.

    The sample is small

    57–29 sounds great. Fewer than 1 in 200 random 86-bet slices of these picks do that well, so it probably isn’t pure luck. But Jev’s ranking skill ranges from 0.51 to 0.65, and the bottom of that range is barely better than a coin flip.

    Typed doesn’t mean right

    The launch post says Jev “can’t hallucinate” and “never makes type errors,” and both held up here: every answer came back well-formed. But “0.62 that this bet wins” is a valid answer whether or not Jev knows anything about baseball.

    The benchmarks are the vendor’s

    TypeSafe’s own launch post notes its workflow evals were made by its own team, “so some bias could exist.” Independent work is mixed so far. One evaluation ran 346,009 requests across 37 datasets for under $10 and found Choice probabilities well calibrated, while another paper found neither model it tested beat chance at zero-shot model routing.

    Pin the version

    I used jev-1.14.0, not jev-latest. The alias will move, and every number in this post could move with it.

    So, can it help me choose?

    On these 248 picks, a plain break-even rule on Jev’s facts-only read beat betting everything, and Rithmm’s own number couldn’t. I’m not betting on that until it holds up on games Jev couldn’t have seen.

    What’s next

    The only clean test is going forward: score each pick before the game, log the answer with the model version, and check back after a few hundred more. That’s what I’m building next.

    Checkpoint · L7
    What's the only clean way to know if Jev's edge on these picks is real?
    Course complete?
    0 of 7 checkpoints passed
    Pass every checkpoint above to finish the course. Progress is saved in this browser only.

    Cheat sheet

    • A Noul is an if: one condition, one probability, and the threshold lives in your code.
    • A Choice is a switch. Describe every option and check confidence before you act.
    • A Score is a sort. Describe each level as a situation and read the probabilities along with the number.
    • The state holds facts. Another model’s projection is an opinion, so compare it in your code.
    • In betting, the threshold is break-even, and the odds hand it to you.
    • Check calibration and ranking separately, on your own data, with enough of it to mean something.
    • Pin the model version and log it with every answer.

    Baseline by sport

    Before Jev becomes part of my daily tracking, here’s where things stand without it. This covers all 253 settled Rithmm picks from April 18 through October 18. “All picks” counts everything Rithmm sent me, including picks I only watched or skipped. “Bet” counts only the picks I put money on.

    SportAll picks (W–L–P)Win %Bet (W–L)Bet win %StakedNetROI
    NFL15–671.4%15–575.0%$1,110+$453.39+40.8%
    NBA41–22–165.1%7–277.8%$540+$228.48+42.3%
    MLB85–7054.8%5–1426.3%$1,140−$602.07−52.8%
    WNBA6–554.5%6–554.5%$660−$9.10−1.4%
    NCAAF1–150.0%1–150.0%$120−$4.45−3.7%
    Total148–104–158.7%34–2755.7%$3,570+$66.25+1.9%

    Football and basketball carried it. MLB gave nearly all of it back: Rithmm was barely better than a coin flip on baseball overall, and the baseball picks I actually bet went 5–14. WNBA and college football are too small to say anything about yet. This is the number Jev has to beat going forward, sport by sport.

    Sources