1@README.md 2 3- **Only the Worker talks to Jev**, through `jev-client` on `jev-worker`'s 4 ports. Do not add a second Jev client or a retry loop here. Anything 5 missing belongs in `~/jevcrates`, and this repo moves its submodule pin 6 (the user, 2026-10-02: move shared functionality to jevcrates and depend on it). 7- **The engine is not this repository's.** `rete` and `rete-draw` are in 8 `third-party/rustcrates` (a submodule); `packages/rules` is the LMJTFY 9 domain over them and `apps/lmjtfy/src/diagram.rs` only says what the 10 drawing is to say. Change the engine in `~/rustcrates`, then move the pin. 11- **The rules decide what happens to a query** (`packages/rules`, `RULES`), 12 and `decide` in `apps/lmjtfy/src/lib.rs` only carries out what 13 `Network::next` says. A new step is a new fact and a rule, not an `if` in 14 the Worker. The diagram is drawn from the same network, so it cannot show 15 rules other than the ones that run. 16- **Jev facts are asked for together.** `Network::next` returns every Jev 17 fact a live rule is waiting on, and they go out as one request (the user, 18 2026-10-02: "firing a single request with N questions to backfill"). Do 19 not ask for one in a request of its own. 20- **The LLM is given only the tools the rules asked for** (`llm::request` 21 with `wants`), and a question of any other kind it writes is not sent 22 (`llm::takes`). Jev has already answered the other readings itself; a 23 second answer to one of them from the LLM's wording disagrees with the 24 first, as it did on 2026-10-02. 25- **Jev answers; the LLM only writes the question.** Never show the LLM's own 26 text as an answer, and never have it answer when it makes no tool call. 27- **The tool call panels show the bodies that crossed the wire**, indented and 28 coloured for reading (the user, 2026-10-02). Printing may add whitespace and 29 nothing else: no reordered keys, no dropped or summarised fields. `view`'s 30 test parses the printed JSON back and compares it to the raw body, and 31 `ask`'s tests hold the body shown equal to the body sent. 32- **`/ask` sends the whole transcript in every event.** Keep it that way: the 33 browser has no state to get out of step with. 34- **The same request is never sent to the same model twice** (the user, 35 2026-10-02: "never send the same exact shape to the same 36 model, ever"), **unless a visitor presses ↻ on it** (the owner, later the 37 same day: "a button to bypass cache for a request"). Every Jev and LLM call 38 goes through `archive::call` (`apps/lmjtfy/src/archive.rs`), which returns 39 the kept response or makes the call once. `Pick::Fresh` is the only way to 40 send a kept request again, and only `$pins` from the page sets it: never 41 add another path that does. Every response is kept, as a numbered version, 42 and does not expire; stepping through versions (`Pick::Version`) sends 43 nothing, and neither does any call after the one stepped (`KeptOnly`). A new call site that reaches 44 Jev or Workers AI any other way breaks the rule, and is also unmetered 45 public spend: the archive is where the budget is held. 46- **The site shows questions and answers and nothing about who asked.** No 47 page, feed, toast or preview may show a visitor's address, browser id, 48 network or exact place (the online list's city and country is the one 49 thing shown, the owner's ruling of 2026-10-02). 50- **The archive keeps everything, for the owner alone** (the owner, 51 2026-10-03: "anywhere in the app where we are dropping data we should 52 plug", and of visitors, "Everything, linked"). Every request worth keeping 53 is a row of `events` (`packages/archive/src/event.rs`): the question, how 54 it ended, the address, the browser's id, the user agent, and Cloudflare's 55 network and place. This reverses the rulings of 2026-10-02 (no address, 56 nothing linking one browser's questions). Do not write that the site keeps 57 nothing about visitors; chapter 2, "What is kept about visitors", is the 58 true account, and a new thing that is known and thrown away is a bug. 59- **`events` is read only through the admin door** (`archive::ADMIN`, the 60 archive object's `/admin` path), which only the owner's separate admin 61 Worker reaches, by binding the object. This Worker must never send a 62 request there or pass a visitor's request to the object, a socket upgrade 63 on `/live` aside: the object would read it as a message. 64- **A question counts each browser once** (`askers`, the owner, 65 2026-10-02): the archive gets `asker(id, question)`, a hash per browser 66 per question, which is what counts it once. The hash is the key and says 67 nothing to a reader; the browser's id is kept beside it (`browser`), as 68 it is in `events`, for the owner's backend. 69- **What is listed is the rules' call** (`Note::List`, which needs Jev's `fit` 70 fact), **unless the owner overrules it** (`asked.moderated`, set through 71 the admin door; the owner, 2026-10-03: "approve or unapprove, basic 72 moderation"). Jev's verdict stays in `listed` beside it. Do not list a 73 question by any other path, and read the feed with 74 `COALESCE(moderated, listed)`. 75- **A suggestion as the visitor types is a question the feed may show** 76 (`Ask::Suggest`, from the same `COALESCE(moderated, listed)`), and 77 nothing else: it is shown to strangers. It reads the archive object's 78 memory and asks nobody anything. Do not suggest from `events` or from 79 questions the feed hides, and do not have a model write one without the 80 owner's say (2026-10-03: the feed first, an LLM only if that falls short). 81- **A link preview reads the archive and asks nothing.** Bots fetch every 82 pasted link; a preview that made a call would spend the shared budget on 83 them. 84- **The `wasm-bindgen` crate is pinned to the CLI's exact version** in the 85 root `Cargo.toml`, and the CLI is `cargo:wasm-bindgen-cli` in `mise.toml`. Move both 86 together and `cargo update -p wasm-bindgen`; `mise run check-versions` fails if they differ. 87- **The dev server is pitchfork's, and starting it is the agent's job.** 88 `nix develop .#owner -c op-env-run -- mise run dev`, then read `mise daemons logs worker`. 89 Do not start `wrangler dev` by hand beside it, and do not hand the user a 90 command to run (the user, 2026-10-02). If the supervisor was already running 91 from another shell, `mise daemons stop worker` and start it again from the owner's: 92 a daemon gets the environment its supervisor had. 93- **Stop or restart it with mise** (`mise daemons stop worker`, `mise daemons 94 restart worker`), never with `pkill -f wrangler`: `-f` matches the shell 95 running the command and kills it (twice, 2026-10-02). 96- **The toolchain is `mise.toml`'s, and nothing in the repository may require 97 nix** (the user, 2026-10-05). A reader runs only `mise` commands. mise.toml 98 is the one place for versions; the few files that must repeat one (Cargo.toml's 99 wasm-bindgen pin, hk.pkl's hk release) are held equal by 100 `tools/check-versions.sh`, part of `mise run check`. Scripts under `tools/` 101 must not assume nix or mise: they read the environment and say what is missing. 102- **Two nix shells, both only wrapping mise: `nix develop` for anyone, `nix develop 103 .#owner` for the owner's tools** (lmjtfy-wrangler, lmjtfy-secret, lmjtfy-eval). 104 Only the owner shell may use `nix-pkgs` or `nix-facts`: Nix fetches a 105 locked input only when an output uses it, so one reference from the 106 default shell breaks `nix develop` for everyone who clones (they cannot 107 read those repositories). Never put a tool version in flake.nix. 108- **Do not export an `op://` value from the devshell.** `op-env-run` resolves 109 every such value in the environment it is started from, with an account 110 that cannot read the Cloudflare item, and refuses to start. That is why the 111 eval's reference lives inside `lmjtfy-eval`. 112- **Never pipe a value into `lmjtfy-wrangler`.** It runs op.exe before 113 wrangler, and op.exe eats the stdin (an empty secret went live that way, 114 2026-10-02). Use `lmjtfy-secret jev | account | analytics`. 115- **The neuron count is the account's, read from Cloudflare.** Do not go back 116 to counting only this Worker's calls: on 2026-10-02 the eval and local dev 117 had spent 950 neurons the site's counter knew nothing about. 118- **Do not load-test the live site.** Every answered ask is counted on the 119 public feed and in "So far" (2026-10-02: the agent's own rate-limit test put 120 "asked 67 times" on the home page). Load-test the dev server. On the live 121 site, ask once; to test the visitor limit there, post an empty `q`, which 122 counts towards the limit and touches nothing else. 123- **After a deploy, check Jev with `/gate` on text never sent before** 124 (`{"q":"deploy check <time>"}`): a missing or empty key still deploys 125 cleanly and serves the page, and only a request that is really sent shows 126 it. Never check with `/ask`: a question already kept sends nothing, so it 127 tests nothing, and it adds an ask to the public count (2026-10-02: four 128 such checks took one question from ×3 to ×7; MIGRATIONS step 4 undid it). 129 To check the clone proxy, `git ls-remote <site>/lmjtfy.git`, which is not 130 counted; a clone is. 131- **The clone proxy serves `Repo::ALL` and only `git-upload-pack`.** Its 132 token must stay read-only (Contents: read on those repositories), so a push 133 is impossible at GitHub and not only at the routes. A new repository is a 134 new `Repo` variant; never take the upstream from the request path. 135 `.gitmodules` URLs stay relative, or a clone from the site points its 136 submodule at private GitHub and fails. 137- **The folders are a guide, chapter by chapter** (the owner, 2026-10-02: 138 "read like the documentation subsite and like a tutorial flow", in the 139 spirit of why's (poignant) guide). Every folder's README is a chapter: 140 `# Chapter N: <name>, <subtitle>`, an opening that teaches the idea, `> 141 **Aside.**` detours, a `Try it` against the live site or `cargo test`, the 142 maintainers' reference, and a last line `← Previous · Up · Next →` in 143 reading order (the prologue's table). A new folder gets its chapter and a 144 CLAUDE.md, and the chapters after it are renumbered; `view::code::guide` 145 fails the build on a folder without both, or a link that goes nowhere. 146 The code pages' ◀ ▶ tabs follow those last lines, so the Next chain must 147 be a depth-first walk (each folder before its subfolders, a subtree 148 finished before its next sibling, every folder once, the last chapter with 149 no Next); `the_chapters_lead_on_depth_first_through_every_folder` holds it. 150 Playful, never at the expense of a true fact. 151- **A deploy that people on the site should hear about carries a 152 `Release-Note:` trailer** in its HEAD commit: one line, plain text, shown 153 as a toast to every page from an earlier build when it reconnects 154 (`build.rs`, `LMJTFY_NOTE`). Most deploys have none. 155- **The site is `https://lmjtfy.fun`, bare, and the code is 156 `https://code.lmjtfy.fun`** (the owner, 2026-10-05). `lmjtfy.deizel.workers.dev` 157 (where it began) and `www.lmjtfy.fun` answer only to redirect to the site 158 for good, and every served repository's path, on any of the three, to the 159 code host with a `308` (`host::gate`), **once `GIT_REDIRECT` is `"on"`**. 160 It is `"off"` in `wrangler.toml` until `code.lmjtfy.fun` is deployed and 161 checked, and the home page's clone links follow it 162 (`Host::code_origin`): do not hard-code the code host into a page the 163 apex serves. Write the code host in clone lines 164 and Cargo lines, and the bare address for the site. Do not redirect a 165 request that is not a navigation: a page still open on the old address 166 would lose its socket and its posts. 167- **Release files of the served repositories** (`/<name>/latest/<kind>`, 168 `/<name>/releases/<tag>/<asset>`, `src/release.rs`) are served by the code 169 host only; with `GIT_REDIRECT` on the apex and old addresses `308` them 170 there like a clone, with it off the apex `404`s them. 171- **Each host has its own routes** (`fetch`, `site_routes` and 172 `code_routes`), and `host::gate` decides before any route. The code host 173 has no `/ask`, archive, `/live`, `/feed` or `/seen`: do not add a route 174 there without saying why it is safe on a host that has no budget behind it. 175 A repository is served by being in the `repositories!` list in 176 `clone.rs`, which is also the list on the code host's front page and the 177 list `gate` redirects: do not write a second. 178- **Deploy to staging first, then the site** (the owner, 2026-10-04: "a 179 preview environment so we aren't pushing straight to prod"). 180 `lmjtfy-wrangler apps/lmjtfy deploy --env staging`, check 181 `https://staging.lmjtfy.fun` (through Access, with the service token's 182 two headers), and only then `lmjtfy-wrangler apps/lmjtfy deploy`. A 183 migration step has run on staging's archive before it runs on the 184 site's. Both without asking (the user, 2026-10-02: "please deploy 185 without asking"): the site is public and spends real money for every 186 visitor, so deploy only verified, committed work, and check the live 187 site after. 188- **Deploying the code host is two deploys** (the owner, 2026-10-05: do not 189 break the live site). First with `GIT_REDIRECT` off (the toml's value): 190 the code host and its domain go live, clones at the apex are unchanged. 191 Check `https://code.lmjtfy.fun` and a real `git clone 192 --recurse-submodules` from it. Then `lmjtfy-wrangler apps/lmjtfy deploy 193 --var GIT_REDIRECT:on` (or edit the toml), check the `308` and a clone 194 through the old address. Rollback: `lmjtfy-wrangler apps/lmjtfy rollback`. 195 The var is parsed strictly; a typo runs as off and logs an error. Run 196 `tools/check-hosts` in each mode (its header has the dev servers) after 197 touching `host.rs`. 198- **Staging has no workers.dev address and no preview addresses**, and 199 must not get one: Access at `staging.lmjtfy.fun` is all that stands in 200 front of it, and the Worker itself lets anyone in. Its archive is its 201 own; nothing done there reaches the site's. 202- Open work lives in the brain page `technology/artificial-intelligence/jev/lmjtfy.md`.