1# Chapter 3: the source, read in the order it runs 2 3A dozen or so files. They are easiest read in the order a question meets them: in 4through the router, out to the archive, back as HTML. You do not need to 5read Rust fluently to follow along. Every file opens with a comment (`//!`) 6that says what it is for, and those are worth reading first. 7 8```mermaid 9flowchart TD 10 L["lib.rs: routes, and the loop that answers"] --> AR["archive.rs: the archive object"] 11 L --> M["meter.rs: the budget object"] 12 AR --> AI["ai.rs: Workers AI"] 13 AR --> O["object.rs: talking to an object"] 14 M --> O 15 L --> V["view.rs: the page as HTML"] 16 V --> D["diagram.rs: the rules as SVG"] 17 V --> VC["view/: code pages, toasts"] 18 L --> P["playground.rs: /rules"] 19 L --> C["clone.rs: git, and the code page"] 20 C --> B["browse.rs: folders and files"] 21``` 22 23## 1. lib.rs: the front door 24 25The routes are at the top (`fetch`): one line per address, each sent to a 26function. The interesting one is `ask`, which starts the loop that answers a 27question. It does not decide anything itself. It asks the rules engine 28(`Network::next`, chapter 6) what to do, does that, records what it learned, 29and asks again, until the rules say it is done. Each turn, the whole 30transcript so far is sent to the browser as one Datastar event. 31 32> **Aside.** Why re-send the whole transcript every time instead of just the 33> new bit? Because then the browser has no state to get wrong. It throws 34> away what it had and shows what it was sent. A reconnect, a missed event, 35> a second tab: none of them can leave the page in a state the server does 36> not know about. 37 38The calls themselves are made by `learn` (the facts request), `drafted` 39(the LLM) and `judge` (Jev judging what the LLM wrote), and every one of them 40goes through the archive. `glance` is the as-you-type request behind 41`/gate`. `answer` records what was asked so it can join the feed. 42 43## 2. archive.rs: the memory, and the only door out 44 45The archive is a Durable Object, and it is the only code that sends a 46request to Jev or the LLM. Ask it for a call and it either hands back the 47response it kept from last time, or makes the call once, keeps it, and hands 48that back. Two visitors asking the same new thing at once share one call 49(`once`). Chapter 9 is about why. 50 51It also keeps the feed of questions (`asked`), the tallies (`counts`), and 52the `/live` sockets of every open page, and it pushes the toasts. 53 54## 3. meter.rs: the budget object 55 56The other Durable Object. Before a call goes out, the archive asks it to 57*hold* the call's worst-case cost; after, to *settle* it at the real cost. 58It also reads the whole Cloudflare account's AI usage, so a dev server or 59the eval spending the same free allocation is counted too, and it keeps 60each visitor's per-minute count, in memory only. Chapter 10 has the 61arithmetic. 62 63## 4. object.rs and ai.rs: the plumbing 64 65`object.rs` posts a JSON message to a Durable Object and reads one back. 66`ai.rs` calls Workers AI through the `AI` binding, with JSON text in and 67JSON text out, so the reply can be shown exactly as it came. 68 69## 5. view.rs and view/: everything you see 70 71`view.rs` turns a `View` (what has happened so far) into HTML with maud. It 72is pure: no network, no clock, so its tests run on your laptop. The answer 73stamps, the bars, the panels that show every request and response 74pretty-printed, the home page's feeds: all here. Chapter 4 covers `view/`. 75 76`diagram.rs` draws the rules engine as an SVG, marked with what is known 77about the current question: what held, what failed, which rules fired and in 78what order. 79 80## 6. playground.rs: `/rules` 81 82The rules with facts you set by clicking: every test in the diagram is a 83link that sets its fact. It runs the same engine and asks nobody anything. 84 85## 7. clone.rs and browse.rs: the code, shared 86 87`clone.rs` is a tiny git server, or rather a forwarder: it passes a clone's 88two requests to GitHub with a read-only token and refuses everything else. 89The same address in a browser is the code's front page. `browse.rs` reads 90folders and files from GitHub's API so they can be shown as pages, like this 91one. 92 93## 8. page.css and page.js 94 95The look, copied on purpose from typesafe.ai: near-black on white, one pink 96band, dithered dot fields, old-computer windows. And the only JavaScript the 97site has: typing a `?q=` question in, the copy buttons, the `/live` socket 98(online count, toasts, live feeds, the reload offer), and enlarging a 99diagram on a click, and telling `/seen` how long a page was in view and how 100far down it was read as it is put away. `live.js` is the SharedWorker that holds that socket 101once for all of a browser's tabs. 102 103## 9. events.rs: what happened, kept 104 105As the Worker serves a request it makes an event of it: what it was, what 106came of it, and everything the request and Cloudflare said about where it 107came from. The archive keeps each one as a row. Nothing on the site shows 108them; the owner reads them from a separate admin Worker. Chapter 2 says 109what is in a row, and chapter 9 has the event itself. 110 111> **Aside.** Keeping the row must not slow the page. So the Worker answers 112> first and writes after: `wait_until` lets a Worker finish a job once the 113> response has left. 114 115## For the people who maintain it 116 117| File | What | 118| --- | --- | 119| [lib.rs](lib.rs) | The routes, and the loop that does what the rules say next, streamed as the transcript. | 120| [archive.rs](archive.rs) | The `Archive` Durable Object: every answered request keyed by the exact body, the calls themselves, the feed, the tallies, the `/live` sockets. | 121| [meter.rs](meter.rs) | The `Budget` Durable Object: hold and settle, the account's usage, per-visitor counts. | 122| [object.rs](object.rs) | Posting a JSON message to a Durable Object. | 123| [ai.rs](ai.rs) | The Workers AI binding, JSON text in and out. | 124| [view.rs](view.rs) | The page and the transcript as HTML. A `View` in, markup out. | 125| [view/](view/) | The code pages, the toasts, and `view.rs`'s tests. | 126| [diagram.rs](diagram.rs) | The rules as an SVG of the Rete network, and `/rules.svg`. | 127| [playground.rs](playground.rs) | `/rules`: facts set by the link. | 128| [clone.rs](clone.rs) | `git clone`: smart HTTP forwarded read-only; the code page; the latest commit; clone and pull counting. | 129| [browse.rs](browse.rs) | `/lmjtfy.git/<path>`: folders and files from GitHub's contents API, kept a minute per isolate; jevcrates at its pin. | 130| [page.css](page.css), [page.js](page.js) | The look, and the browser code. | 131| [events.rs](events.rs) | A request as an `archive::Event`, with Cloudflare's account of where it came from, and the sending of it to the archive. | 132| [live.js](live.js) | `/live.js`: the SharedWorker that holds one `/live` socket for every tab of a browser. | 133 134The invariants for all of these (what must never await, what must stay 135pure, where calls may be made) are in the Worker's CLAUDE.md, one folder up. 136 137← Previous: [Chapter 2, the Worker](../) · Up: [apps/lmjtfy](../) · Next: [Chapter 4, view/](view/) →