lmjtfy.git / CLAUDE.md
CLAUDE.mdpreviewCLAUDE.mdsource145 lines · 9.8 KB · raw
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 rules decide what happens to a query** (`packages/rules`, `RULES`),
8  and `decide` in `apps/lmjtfy/src/lib.rs` only carries out what
9  `Network::next` says. A new step is a new fact and a rule, not an `if` in
10  the Worker. The diagram is drawn from the same network, so it cannot show
11  rules other than the ones that run.
12- **Jev facts are asked for together.** `Network::next` returns every Jev
13  fact a live rule is waiting on, and they go out as one request (the user,
14  2026-10-02: "firing a single request with N questions to backfill"). Do
15  not ask for one in a request of its own.
16- **The LLM is given only the tools the rules asked for** (`llm::request`
17  with `wants`), and a question of any other kind it writes is not sent
18  (`llm::takes`). Jev has already answered the other readings itself; a
19  second answer to one of them from the LLM's wording disagrees with the
20  first, as it did on 2026-10-02.
21- **Jev answers; the LLM only writes the question.** Never show the LLM's own
22  text as an answer, and never have it answer when it makes no tool call.
23- **The tool call panels show the bodies that crossed the wire**, indented and
24  coloured for reading (the user, 2026-10-02). Printing may add whitespace and
25  nothing else: no reordered keys, no dropped or summarised fields. `view`'s
26  test parses the printed JSON back and compares it to the raw body, and
27  `ask`'s tests hold the body shown equal to the body sent.
28- **`/ask` sends the whole transcript in every event.** Keep it that way: the
29  browser has no state to get out of step with.
30- **The same request is never sent to the same model twice** (the user,
31  2026-10-02: "never send the same exact shape to the same
32  model, ever"), **unless a visitor presses ↻ on it** (the owner, later the
33  same day: "a button to bypass cache for a request"). Every Jev and LLM call
34  goes through `archive::call` (`apps/lmjtfy/src/archive.rs`), which returns
35  the kept response or makes the call once. `Pick::Fresh` is the only way to
36  send a kept request again, and only `$pins` from the page sets it: never
37  add another path that does. Every response is kept, as a numbered version,
38  and does not expire; stepping through versions (`Pick::Version`) sends
39  nothing, and neither does any call after the one stepped (`KeptOnly`). A new call site that reaches
40  Jev or Workers AI any other way breaks the rule, and is also unmetered
41  public spend: the archive is where the budget is held.
42- **The site shows questions and answers and nothing about who asked.** No
43  page, feed, toast or preview may show a visitor's address, browser id,
44  network or exact place (the online list's city and country is the one
45  thing shown, the owner's ruling of 2026-10-02).
46- **The archive keeps everything, for the owner alone** (the owner,
47  2026-10-03: "anywhere in the app where we are dropping data we should
48  plug", and of visitors, "Everything, linked"). Every request worth keeping
49  is a row of `events` (`packages/archive/src/event.rs`): the question, how
50  it ended, the address, the browser's id, the user agent, and Cloudflare's
51  network and place. This reverses the rulings of 2026-10-02 (no address,
52  nothing linking one browser's questions). Do not write that the site keeps
53  nothing about visitors; chapter 2, "What is kept about visitors", is the
54  true account, and a new thing that is known and thrown away is a bug.
55- **`events` is read only through the admin door** (`archive::ADMIN`, the
56  archive object's `/admin` path), which only the owner's separate admin
57  Worker reaches, by binding the object. This Worker must never send a
58  request there or pass a visitor's request to the object, a socket upgrade
59  on `/live` aside: the object would read it as a message.
60- **A question counts each browser once** (`askers`, the owner,
61  2026-10-02): the archive gets `asker(id, question)`, a hash per browser
62  per question, which is what counts it once. The hash is the key and says
63  nothing to a reader; the browser's id is kept beside it (`browser`), as
64  it is in `events`, for the owner's backend.
65- **What is listed is the rules' call** (`Note::List`, which needs Jev's `fit`
66  fact), **unless the owner overrules it** (`asked.moderated`, set through
67  the admin door; the owner, 2026-10-03: "approve or unapprove, basic
68  moderation"). Jev's verdict stays in `listed` beside it. Do not list a
69  question by any other path, and read the feed with
70  `COALESCE(moderated, listed)`.
71- **A link preview reads the archive and asks nothing.** Bots fetch every
72  pasted link; a preview that made a call would spend the shared budget on
73  them.
74- **The `wasm-bindgen` crate is pinned to the nix CLI's exact version** in the
75  root `Cargo.toml`. After `nix flake update`, move the pin and `cargo update
76  -p wasm-bindgen` together.
77- **The dev server is pitchfork's, and starting it is the agent's job.**
78  `nix develop .#owner -c pitchfork start --local`, then read `pitchfork logs worker`.
79  Do not start `wrangler dev` by hand beside it, and do not hand the user a
80  command to run (the user, 2026-10-02).
81- **Stop or restart it with pitchfork** (`pitchfork stop --local`, `pitchfork
82  restart worker`), never with `pkill -f wrangler`: `-f` matches the shell
83  running the command and kills it (twice, 2026-10-02).
84- **Two shells: `nix develop` for anyone, `nix develop .#owner` for the
85  owner's tools** (lmjtfy-wrangler, lmjtfy-secret, lmjtfy-eval, pitchfork).
86  Only the owner shell may use `nix-pkgs` or `nix-facts`: Nix fetches a
87  locked input only when an output uses it, so one reference from the
88  default shell breaks `nix develop` for everyone who clones (they cannot
89  read those repositories).
90- **Do not export an `op://` value from the devshell.** `op-env-run` resolves
91  every such value in the environment it is started from, with an account
92  that cannot read the Cloudflare item, and refuses to start. That is why the
93  eval's reference lives inside `lmjtfy-eval`.
94- **Never pipe a value into `lmjtfy-wrangler`.** It runs op.exe before
95  wrangler, and op.exe eats the stdin (an empty secret went live that way,
96  2026-10-02). Use `lmjtfy-secret jev | account | analytics`.
97- **The neuron count is the account's, read from Cloudflare.** Do not go back
98  to counting only this Worker's calls: on 2026-10-02 the eval and local dev
99  had spent 950 neurons the site's counter knew nothing about.
100- **Do not load-test the live site.** Every answered ask is counted on the
101  public feed and in "So far" (2026-10-02: the agent's own rate-limit test put
102  "asked 67 times" on the home page). Load-test the dev server. On the live
103  site, ask once; to test the visitor limit there, post an empty `q`, which
104  counts towards the limit and touches nothing else.
105- **After a deploy, check Jev with `/gate` on text never sent before**
106  (`{"q":"deploy check <time>"}`): a missing or empty key still deploys
107  cleanly and serves the page, and only a request that is really sent shows
108  it. Never check with `/ask`: a question already kept sends nothing, so it
109  tests nothing, and it adds an ask to the public count (2026-10-02: four
110  such checks took one question from ×3 to ×7; MIGRATIONS step 4 undid it).
111  To check the clone proxy, `git ls-remote <site>/lmjtfy.git`, which is not
112  counted; a clone is.
113- **The clone proxy serves `Repo::ALL` and only `git-upload-pack`.** Its
114  token must stay read-only (Contents: read on those repositories), so a push
115  is impossible at GitHub and not only at the routes. A new repository is a
116  new `Repo` variant; never take the upstream from the request path.
117  `.gitmodules` URLs stay relative, or a clone from the site points its
118  submodule at private GitHub and fails.
119- **The folders are a guide, chapter by chapter** (the owner, 2026-10-02:
120  "read like the documentation subsite and like a tutorial flow", in the
121  spirit of why's (poignant) guide). Every folder's README is a chapter:
122  `# Chapter N: <name>, <subtitle>`, an opening that teaches the idea, `>
123  **Aside.**` detours, a `Try it` against the live site or `cargo test`, the
124  maintainers' reference, and a last line `← Previous · Up · Next →` in
125  reading order (the prologue's table). A new folder gets its chapter and a
126  CLAUDE.md, and the chapters after it are renumbered; `view::code::guide`
127  fails the build on a folder without both, or a link that goes nowhere.
128  The code pages' ◀ ▶ tabs follow those last lines, so the Next chain must
129  be a depth-first walk (each folder before its subfolders, a subtree
130  finished before its next sibling, every folder once, the last chapter with
131  no Next); `the_chapters_lead_on_depth_first_through_every_folder` holds it.
132  Playful, never at the expense of a true fact.
133- **A deploy that people on the site should hear about carries a
134  `Release-Note:` trailer** in its HEAD commit: one line, plain text, shown
135  as a toast to every page from an earlier build when it reconnects
136  (`build.rs`, `LMJTFY_NOTE`). Most deploys have none.
137- **The site is `https://lmjtfy.fun`, bare.** `lmjtfy.deizel.workers.dev`
138  (where it began) and `www.lmjtfy.fun` answer only to redirect there for
139  good (`moved`, `ELSEWHERE`). Write the bare address in docs, clone lines
140  and Cargo lines. Do not redirect a request that is not a navigation: a
141  page still open on the old address would lose its socket and its posts.
142- **Deploy without asking** (the user, 2026-10-02: "please deploy without
143  asking"). It is public and spends real money for every visitor, so deploy
144  only verified, committed work, and check the live site after.
145  Open work lives in the brain page `technology/artificial-intelligence/jev/lmjtfy.md`.