README.mdpreviewREADME.mdsource142 lines · 6.5 KB · raw

Chapter 16: jevcrates — one post office for four towns

Four projects ask Jev questions: postjevsql (a Postgres extension), jevsnes (Jev plays a SNES game), jevhooks (Jev judges Claude Code hooks) and lmjtfy (the site you may be reading this on). Jev is TypeSafe AI's "System One" model. It does not write text. It answers typed questions (Noul, Choice, Score) with calibrated probabilities. This repository is the one copy of the code that asks it, and every one of those projects uses it.

Think of it as a post office shared by four towns. Each town used to run its own: its own idea of how to address an envelope, how long to wait for a reply, and when to give up and send it again. Now there is one post office, and the towns differ only in the road the mail van takes (a raw HTTP/2 connection, a Postgres backend, or a Cloudflare Worker's fetch).

Aside. If you come from JavaScript: a crate is a package (one Cargo.toml, the way an npm package has one package.json), and this repository is a Cargo workspace, which is what pnpm or npm workspaces are to a monorepo. A trait is close to a TypeScript interface. The crates here are libraries only; nothing in this repository is a program you run.

Use it in your own project

You do not need a GitHub account, or to clone anything by hand. Cargo fetches the crates straight from the lmjtfy site, which serves this repository:

[dependencies]
jev-protocol = { git = "https://lmjtfy.fun/jevcrates.git", rev = "46514413a1e73ad848fc2b1f106cca83eaf081f1" }
jev-http = { git = "https://lmjtfy.fun/jevcrates.git", rev = "46514413a1e73ad848fc2b1f106cca83eaf081f1" }
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }

Pick the crates by where your code runs (the table below has the detail):

  • A native program (a CLI, a server, a bot): jev-protocol and jev-http.
  • A Cloudflare Worker: jev-protocol and jev-worker.
  • Anywhere else, with your own way of sending a request (a database's HTTP, a sandbox): jev-protocol and jev-client, and implement its two ports.

rev pins the commit, so a new commit here never changes your build until you move it. The front page at https://lmjtfy.fun/jevcrates.git shows these lines with the latest commit filled in.

Then, with TYPESAFE_API_KEY set:

use jev_http::Jev;
use jev_protocol::{Json, ModelId, Noul, Questions};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // TYPESAFE_API_KEY from the environment; None when it is not set.
    let Some(jev) = Jev::from_env("usejev", ModelId::pinned("jev-1.13.0")?) else {
        return Err("set TYPESAFE_API_KEY".into());
    };
    let jev = jev?;
    let mut questions = Questions::new();
    let good = questions.noul("good", Noul::new(Json::text("Is this a good retirement plan?")))?;
    let state = Json::text("Put it all on red at the casino.");
    let answered = jev.ask(&state, &questions, "trying it out").await?;
    println!("p(yes) = {:.2}", answered.response.get(good).noul);
    Ok(())
}

jev-http keeps a spend ledger under $XDG_STATE_HOME/jev that every program on the machine shares, and refuses a request before sending it when the shared limits say so (chapter 20). The third argument to ask is why the money was spent, and it is written into that ledger.

How the crates fit

The crates are split along one line: whether they do I/O. The two at the bottom never touch a network, a file or a clock, so they compile anywhere, WebAssembly included. The ones above them supply the network for one kind of host.

flowchart BT
  protocol["jev-protocol<br/>what to ask, what came back"]
  client["jev-client<br/>retries, timeouts, redials"]
  worker["jev-worker<br/>a Cloudflare Worker's fetch"]
  http["jev-http<br/>HTTP/2 on tokio + spend ledger"]
  mock["jev-mock<br/>a fake Jev for tests"]
  client --> protocol
  worker --> client
  http --> client
  http -. "tests only" .-> mock
CrateWhat it doesI/O
jev-protocol/The questions and answers, the exact request bytes, response verification, error classification, the retry policy and the price.none; builds for wasm
jev-client/Runs the retry policy: budgets, per-attempt timeouts, never-sent redials, request ids. Reaches the world through two ports, Transport and Runtime.none
jev-worker/The two ports for a Cloudflare Worker (wasm32, workers-rs). No ledger.network
jev-http/The two ports for a native process (HTTP/2 over pure-Rust TLS on tokio), and Jev, which has an on-disk spend ledger admit every request.network, files
jev-mock/A local HTTP/2 TLS stand-in for the endpoint, with fixture replay and recording.loopback

Who uses what: postjevsql uses jev-protocol, jev-client and jev-mock, with its own Postgres transport. jevsnes and jevhooks use jev-http. lmjtfy's Worker uses jev-worker, and its tools/eval uses jev-http.

Aside. The crates moved here on 2026-10-01 from postjevsql (jev-protocol, jev-client, jev-mock) and jevsnes (jev, jev-http), with their git history, and the two protocol layers (jev and jev-protocol) were merged into one.

Try it

cargo test --workspace

Every test runs offline. The ones that need a server start jev-mock on loopback; the retry tests run on a virtual clock and finish instantly.

The chapters follow the stack from the bottom up: start with jev-protocol, the vocabulary every other crate speaks.

For the people who maintain it

In this folder

PathWhat
jev-protocol/Chapter 17: the wire protocol, no I/O.
jev-client/Chapter 18: the retry policy, behind two ports.
jev-worker/Chapter 19: the ports on a Cloudflare Worker.
jev-http/Chapter 20: the ports on tokio, and the spend ledger.
jev-mock/Chapter 21: the fake endpoint for tests.
Cargo.tomlThe workspace: its members, and every dependency's version, declared once and inherited by the crates.
CLAUDE.mdWhat an agent working here must not break.
.gitignoreIgnores target/, Cargo's build output.

All five crates are version 0.0.1, edition 2024, publish = false, and licensed MIT OR Apache-2.0.

← Previous: lmjtfy's third-party/ chapter · Next: Chapter 17: jev-protocol →