jevcrates.git / README.md
README.mdpreviewREADME.mdsource142 lines · 6.5 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
103Who uses what: postjevsql uses `jev-protocol`, `jev-client` and `jev-mock`,
104with its own Postgres transport. jevsnes and jevhooks use `jev-http`. lmjtfy's
105Worker uses `jev-worker`, and its `tools/eval` uses `jev-http`.
106
107> **Aside.** The crates moved here on 2026-10-01 from postjevsql
108> (`jev-protocol`, `jev-client`, `jev-mock`) and jevsnes (`jev`, `jev-http`),
109> with their git history, and the two protocol layers (`jev` and
110> `jev-protocol`) were merged into one.
111
112## Try it
113
114```
115cargo test --workspace
116```
117
118Every test runs offline. The ones that need a server start `jev-mock` on
119loopback; the retry tests run on a virtual clock and finish instantly.
120
121The chapters follow the stack from the bottom up: start with
122[jev-protocol](jev-protocol/), the vocabulary every other crate speaks.
123
124## For the people who maintain it
125
126### In this folder
127
128| Path | What |
129| --- | --- |
130| [jev-protocol/](jev-protocol/) | Chapter 17: the wire protocol, no I/O. |
131| [jev-client/](jev-client/) | Chapter 18: the retry policy, behind two ports. |
132| [jev-worker/](jev-worker/) | Chapter 19: the ports on a Cloudflare Worker. |
133| [jev-http/](jev-http/) | Chapter 20: the ports on tokio, and the spend ledger. |
134| [jev-mock/](jev-mock/) | Chapter 21: the fake endpoint for tests. |
135| [Cargo.toml](Cargo.toml) | The workspace: its members, and every dependency's version, declared once and inherited by the crates. |
136| [CLAUDE.md](CLAUDE.md) | What an agent working here must not break. |
137| [.gitignore](.gitignore) | Ignores `target/`, Cargo's build output. |
138
139All five crates are version `0.0.1`, edition 2024, `publish = false`, and
140licensed MIT OR Apache-2.0.
141
142← Previous: lmjtfy's third-party/ chapter · Next: [Chapter 17: jev-protocol](jev-protocol/) →