Chapter 3: the source, read in the order it runs

A dozen or so files. They are easiest read in the order a question meets them: in through the router, out to the archive, back as HTML. You do not need to read Rust fluently to follow along. Every file opens with a comment (//!) that says what it is for, and those are worth reading first.

flowchart TD
  L["lib.rs: routes, and the loop that answers"] --> AR["archive.rs: the archive object"]
  L --> M["meter.rs: the budget object"]
  AR --> AI["ai.rs: Workers AI"]
  AR --> O["object.rs: talking to an object"]
  M --> O
  L --> V["view.rs: the page as HTML"]
  V --> D["diagram.rs: the rules as SVG"]
  V --> VC["view/: code pages, toasts"]
  L --> P["playground.rs: /rules"]
  L --> C["clone.rs: git, and the code page"]
  C --> B["browse.rs: folders and files"]

1. lib.rs: the front door

The routes are at the top (fetch): one line per address, each sent to a function. The interesting one is ask, which starts the loop that answers a question. It does not decide anything itself. It asks the rules engine (Network::next, chapter 6) what to do, does that, records what it learned, and asks again, until the rules say it is done. Each turn, the whole transcript so far is sent to the browser as one Datastar event.

Aside. Why re-send the whole transcript every time instead of just the new bit? Because then the browser has no state to get wrong. It throws away what it had and shows what it was sent. A reconnect, a missed event, a second tab: none of them can leave the page in a state the server does not know about.

The calls themselves are made by learn (the facts request), drafted (the LLM) and judge (Jev judging what the LLM wrote), and every one of them goes through the archive. glance is the as-you-type request behind /gate. answer records what was asked so it can join the feed.

2. archive.rs: the memory, and the only door out

The archive is a Durable Object, and it is the only code that sends a request to Jev or the LLM. Ask it for a call and it either hands back the response it kept from last time, or makes the call once, keeps it, and hands that back. Two visitors asking the same new thing at once share one call (once). Chapter 9 is about why.

It also keeps the feed of questions (asked), the tallies (counts), and the /live sockets of every open page, and it pushes the toasts.

3. meter.rs: the budget object

The other Durable Object. Before a call goes out, the archive asks it to hold the call's worst-case cost; after, to settle it at the real cost. It also reads the whole Cloudflare account's AI usage, so a dev server or the eval spending the same free allocation is counted too, and it keeps each visitor's per-minute count, in memory only. Chapter 10 has the arithmetic.

4. object.rs and ai.rs: the plumbing

object.rs posts a JSON message to a Durable Object and reads one back. ai.rs calls Workers AI through the AI binding, with JSON text in and JSON text out, so the reply can be shown exactly as it came.

5. view.rs and view/: everything you see

view.rs turns a View (what has happened so far) into HTML with maud. It is pure: no network, no clock, so its tests run on your laptop. The answer stamps, the bars, the panels that show every request and response pretty-printed, the home page's feeds: all here. Chapter 4 covers view/.

diagram.rs draws the rules engine as an SVG, marked with what is known about the current question: what held, what failed, which rules fired and in what order.

When the ending is one Jev cannot take (the gate said it is not a question, or the LLM wrote nothing Jev can answer), the explanation gets a block: "You would have Please choose an LLM instead:", three large coloured pixel logos (shuqikhor's, MIT; see chapter 15⅞), Claude, ChatGPT and Gemini, each a link to "Let Me MeatProxy That For You" (https://lmmptfy.com/) carrying the visitor's own words in the link's fragment, which no server sees; and under "Provided by:" a preview card of that site, as Discord would draw it. The Worker builds the card itself: it fetches https://lmmptfy.com/ (the only address it ever fetches, with a 2.5 second limit and 64 KB read), reads the <head>'s og: tags and keeps them for an hour per isolate. The card image is served from our own /meatproxy/card, not linked, so the visitor's browser never asks the other site for anything; the route takes nothing from the request and re-derives the address from the kept head. If the site cannot be read, the icons show without the card. meatproxy.rs holds the format, the reading and the route. An outage (Failed) does not get any of it, and a question too long for the site's limit gets none rather than a cut one. The link preview and the feed read the archive, not this block, so they are unchanged.

6. playground.rs: /rules

The rules with facts you set by clicking: every test in the diagram is a link that sets its fact. It runs the same engine and asks nobody anything.

7. clone.rs and browse.rs: the code, shared

clone.rs is a tiny git server, or rather a forwarder: it passes a clone's two requests to GitHub with a read-only token and refuses everything else. The same address in a browser is the code's front page. browse.rs reads folders and files from GitHub's API so they can be shown as pages, like this one.

release.rs is the same forwarding for a repository's GitHub release files: code.lmjtfy.fun/whiskers/latest/arm64.apk streams the latest release's arm64 build, from a private repository, to anyone. The route parsing, the file kinds and the headers are pure and tested; the chapter on the Worker has the rules.

8. page.css and page.js

The look, copied on purpose from typesafe.ai: near-black on white, one pink band, dithered dot fields, old-computer windows. And the only JavaScript the site has: typing a ?q= question in, the copy buttons, the /live socket (online count, toasts, live feeds, the reload offer), and enlarging a diagram on a click, and telling /seen how long a page was in view and how far down it was read as it is put away. live.js is the SharedWorker that holds that socket once for all of a browser's tabs.

9. events.rs: what happened, kept

As the Worker serves a request it makes an event of it: what it was, what came of it, and everything the request and Cloudflare said about where it came from. The archive keeps each one as a row. Nothing on the site shows them; the owner reads them from a separate admin Worker. Chapter 2 says what is in a row, and chapter 9 has the event itself.

Aside. Keeping the row must not slow the page. So the Worker answers first and writes after: wait_until lets a Worker finish a job once the response has left.

For the people who maintain it

FileWhat
lib.rsThe routes, and the loop that does what the rules say next, streamed as the transcript.
archive.rsThe Archive Durable Object: every answered request keyed by the exact body, the calls themselves, the feed, the tallies, the /live sockets.
meter.rsThe Budget Durable Object: hold and settle, the account's usage, per-visitor counts.
object.rsPosting a JSON message to a Durable Object.
ai.rsThe Workers AI binding, JSON text in and out.
past.rsWhat an object's storage can do that workers-rs has no binding for: name a moment in its last thirty days, go back to it, and run a migration step as all or nothing.
view.rsThe page and the transcript as HTML. A View in, markup out.
view/The code pages, the toasts, and view.rs's tests.
diagram.rsThe rules as an SVG of the Rete network, and /rules.svg.
playground.rs/rules: facts set by the link.
meatproxy.rsThe links to lmmptfy.com for a question Jev cannot take: the base address, the providers and the exact encoding, plus the preview card read from its <head> and the /meatproxy/card route. The parsing and markup are pure; only the two fetches use worker.
host.rsWhich address a request came to (lmjtfy.fun, code.lmjtfy.fun, the old ones) and what each does: the redirects, and which routes each has, under the GIT_REDIRECT switch (GitRedirect, on or off). Pure.
clone.rsgit clone: smart HTTP forwarded read-only; the code page; the latest commit; clone and pull counting.
release.rs/<name>/latest/<kind> and /<name>/releases/<tag>/<asset>: a repository's GitHub release files, looked up and streamed with the read-only token (never sent to the signed address), plus the two listing pages' data. Routes, kinds, content types and ranges are pure.
browse.rs/lmjtfy.git/<path>: folders and files from GitHub's contents API, kept a minute per isolate; jevcrates at its pin.
page.css, page.jsThe look, and the browser code.
events.rsA request as an archive::Event, with Cloudflare's account of where it came from, and the sending of it to the archive.
live.js/live.js: the SharedWorker that holds one /live socket for every tab of a browser.

The invariants for all of these (what must never await, what must stay pure, where calls may be made) are in the Worker's CLAUDE.md, one folder up.

← Previous: Chapter 2, the Worker · Up: apps/lmjtfy · Next: Chapter 4, view/ →