diff --git a/CLAUDE.md b/CLAUDE.md index cd2651d..38b62f4 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -19,7 +19,7 @@ lembas info # paths + counts, useful when confused lembas secret-key # generate LEMBAS_SECRET_KEY lembas create-admin # create or promote an admin -pytest # 212 tests, ~8s +pytest # 230 tests, ~9s ruff check . # lint (line length 100) python scripts/build_artwork.py # regenerate all SVG artwork python scripts/fetch_vendor.py # verify vendored JS against the lockfile @@ -191,6 +191,34 @@ null in the composer; `files.claim()` binds them, and only unclaimed rows owned by that user, so a forged id cannot pull in someone else's file. Abandoned ones are swept at startup. +**Markdown renders progressively, server-side.** The stream sends `render` +events carrying the whole answer re-rendered from Markdown, at most every +`RENDER_INTERVAL`, swapped with `innerHTML`. Appending raw tokens instead would +mean formatting only appearing at the end -- a list or code fence is only +correct once its context exists, so partial output must be re-rendered whole +rather than appended to. + +**Stopping a stream is an in-process set.** `api/chats.py:_CANCELLED` holds +message ids the reader asked to stop; the generator checks it between chunks. +Correct for the single-worker deployment this ships with; multiple workers +would need it in the database or a broker. + +**Editing rewinds, it does not branch.** `POST .../messages/{id}/edit` rewrites +a user turn and **deletes everything after it**. Branching would need a UI for +choosing between versions; "go back and try again from here" is what was asked +for and what other clients do. `Message.parent_id` still exists unused. + +**Dialogs and toasts are ours, not the browser's.** `static/js/ui.js` provides +`lembas.notify/confirm/prompt`, and intercepts htmx's `htmx:confirm` so every +existing `hx-confirm` gets the themed dialog with no change at the call site. +Plain forms opt in with `data-confirm`, lone submit buttons with +`data-confirm-button`. Never add a `window.confirm` back. + +**The model picker is hand-built.** A ` renders only text in an