README.mdpreviewREADME.mdsource145 lines · 6.8 KB · raw
1# Chapter 16: jevcrates — one post office for four towns
2
3Four projects ask [Jev](https://docs.typesafe.ai) questions: postjevsql (a
4Postgres extension), jevsnes (Jev plays a SNES game), jevhooks (Jev judges
5Claude Code hooks) and lmjtfy (the site you may be reading this on). Jev is
6TypeSafe AI's "System One" model. It does not write text. It answers typed
7questions (`Noul`, `Choice`, `Score`) with calibrated probabilities. This
8repository is the one copy of the code that asks it, and every one of those
9projects uses it.
10
11Think of it as a post office shared by four towns. Each town used to run its
12own: its own idea of how to address an envelope, how long to wait for a
13reply, and when to give up and send it again. Now there is one post office,
14and the towns differ only in the road the mail van takes (a raw HTTP/2
15connection, a Postgres backend, or a Cloudflare Worker's `fetch`).
16
17> **Aside.** If you come from JavaScript: a *crate* is a package (one
18> `Cargo.toml`, the way an npm package has one `package.json`), and this
19> repository is a *Cargo workspace*, which is what pnpm or npm workspaces
20> are to a monorepo. A *trait* is close to a TypeScript `interface`. The
21> crates here are libraries only; nothing in this repository is a program you
22> run.
23
24## Use it in your own project
25
26You do not need a GitHub account, or to clone anything by hand. Cargo fetches
27the crates straight from the lmjtfy site, which serves this repository:
28
29```toml
30[dependencies]
31jev-protocol = { git = "https://lmjtfy.fun/jevcrates.git", rev = "46514413a1e73ad848fc2b1f106cca83eaf081f1" }
32jev-http = { git = "https://lmjtfy.fun/jevcrates.git", rev = "46514413a1e73ad848fc2b1f106cca83eaf081f1" }
33tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
34```
35
36Pick the crates by where your code runs (the table below has the detail):
37
38- **A native program** (a CLI, a server, a bot): `jev-protocol` and `jev-http`.
39- **A Cloudflare Worker**: `jev-protocol` and `jev-worker`.
40- **Anywhere else**, with your own way of sending a request (a database's
41  HTTP, a sandbox): `jev-protocol` and `jev-client`, and implement its two
42  ports.
43
44`rev` pins the commit, so a new commit here never changes your build until
45you move it. The front page at <https://lmjtfy.fun/jevcrates.git>
46shows these lines with the latest commit filled in.
47
48Then, with `TYPESAFE_API_KEY` set:
49
50```rust
51use jev_http::Jev;
52use jev_protocol::{Json, ModelId, Noul, Questions};
53
54#[tokio::main]
55async fn main() -> Result<(), Box<dyn std::error::Error>> {
56    // TYPESAFE_API_KEY from the environment; None when it is not set.
57    let Some(jev) = Jev::from_env("usejev", ModelId::pinned("jev-1.13.0")?) else {
58        return Err("set TYPESAFE_API_KEY".into());
59    };
60    let jev = jev?;
61    let mut questions = Questions::new();
62    let good = questions.noul("good", Noul::new(Json::text("Is this a good retirement plan?")))?;
63    let state = Json::text("Put it all on red at the casino.");
64    let answered = jev.ask(&state, &questions, "trying it out").await?;
65    println!("p(yes) = {:.2}", answered.response.get(good).noul);
66    Ok(())
67}
68```
69
70`jev-http` keeps a spend ledger under `$XDG_STATE_HOME/jev` that every
71program on the machine shares, and refuses a request before sending it when
72the shared limits say so (chapter 20). The third argument to `ask` is why the
73money was spent, and it is written into that ledger.
74
75## How the crates fit
76
77The crates are split along one line: whether they do I/O. The two at the
78bottom never touch a network, a file or a clock, so they compile anywhere,
79WebAssembly included. The ones above them supply the network for one kind of
80host.
81
82```mermaid
83flowchart BT
84  protocol["jev-protocol<br/>what to ask, what came back"]
85  client["jev-client<br/>retries, timeouts, redials"]
86  worker["jev-worker<br/>a Cloudflare Worker's fetch"]
87  http["jev-http<br/>HTTP/2 on tokio + spend ledger"]
88  mock["jev-mock<br/>a fake Jev for tests"]
89  client --> protocol
90  worker --> client
91  http --> client
92  http -. "tests only" .-> mock
93```
94
95| Crate | What it does | I/O |
96| --- | --- | --- |
97| [jev-protocol/](jev-protocol/) | The questions and answers, the exact request bytes, response verification, error classification, the retry policy and the price. | none; builds for wasm |
98| [jev-client/](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 |
99| [jev-worker/](jev-worker/) | The two ports for a Cloudflare Worker (wasm32, workers-rs). No ledger. | network |
100| [jev-http/](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 |
101| [jev-mock/](jev-mock/) | A local HTTP/2 TLS stand-in for the endpoint, with fixture replay and recording. | loopback |
102| [jev-ui/](jev-ui/) | The look and page shell the Jev sites share: stylesheet, head and body, components, link-preview tags and card, Datastar, fonts. Not about Jev's protocol at all. | none; builds for wasm |
103
104Who uses what: postjevsql uses `jev-protocol`, `jev-client` and `jev-mock`,
105with its own Postgres transport. jevsnes and jevhooks use `jev-http`. lmjtfy's
106Worker uses `jev-worker`, and its `tools/eval` uses `jev-http`. whiskers' site
107uses `jev-ui` (and lmjtfy is to).
108
109> **Aside.** The crates moved here on 2026-10-01 from postjevsql
110> (`jev-protocol`, `jev-client`, `jev-mock`) and jevsnes (`jev`, `jev-http`),
111> with their git history, and the two protocol layers (`jev` and
112> `jev-protocol`) were merged into one.
113
114## Try it
115
116```
117cargo test --workspace
118```
119
120Every test runs offline. The ones that need a server start `jev-mock` on
121loopback; the retry tests run on a virtual clock and finish instantly.
122
123The chapters follow the stack from the bottom up: start with
124[jev-protocol](jev-protocol/), the vocabulary every other crate speaks.
125
126## For the people who maintain it
127
128### In this folder
129
130| Path | What |
131| --- | --- |
132| [jev-protocol/](jev-protocol/) | Chapter 17: the wire protocol, no I/O. |
133| [jev-client/](jev-client/) | Chapter 18: the retry policy, behind two ports. |
134| [jev-worker/](jev-worker/) | Chapter 19: the ports on a Cloudflare Worker. |
135| [jev-http/](jev-http/) | Chapter 20: the ports on tokio, and the spend ledger. |
136| [jev-mock/](jev-mock/) | Chapter 21: the fake endpoint for tests. |
137| [jev-ui/](jev-ui/) | Chapter 22: what the Jev sites' pages share. |
138| [Cargo.toml](Cargo.toml) | The workspace: its members, and every dependency's version, declared once and inherited by the crates. |
139| [CLAUDE.md](CLAUDE.md) | What an agent working here must not break. |
140| [.gitignore](.gitignore) | Ignores `target/`, Cargo's build output. |
141
142All six crates are version `0.0.1`, edition 2024, `publish = false`, and
143licensed MIT OR Apache-2.0.
144
145← Previous: lmjtfy's third-party/ chapter · Next: [Chapter 17: jev-protocol](jev-protocol/) →