mindfork 0.11.1

A terminal AI chat written in Rust: local models via llama.cpp or OpenAI, Anthropic, Gemini and Grok in the cloud, with persistent memory, notes, RAG and tools.
# Generated screenshots

Every image here is rendered **from code**, never captured from a live
session — so no private data can leak into them, and they cannot silently rot
as the app evolves. The pipeline is described in
[docs/history/demo-screenshots.md](../../docs/history/demo-screenshots.md):

1. `src/features/demo.rs` — a fixed showcase conversation, chat list, config
   and self-model (fixed ids and timestamps: captures are byte-stable);
2. `cargo test dump_demo_frames -- --ignored` — renders the screens headlessly
   and (re)writes the JSON frame dumps under `dumps/`;
3. `python tools/screenshots.py` — renders the dumps into the images here:
   **PNG** for the README (GitHub cannot load fonts into an embedded SVG) and
   **SVG** for mindfork.io, which inlines them and serves the webfont the
   `@font-face` reference names (JetBrains Mono with symbol-font fallbacks;
   `pip install pillow fonttools`).

A drift gate (`app::demo_shots::tests::committed_dumps_match_the_code`) fails
the ordinary test suite when the committed dumps stop matching what the
current code renders. When it goes red, run the two commands above and commit
the regenerated dumps **and** images together with the change that moved
them.

The set (per the design plan's confirmed forks): the chat hero shot, the chat
list, settings twice — Model/server and Tools — and the self-model screen,
each in Dark and Light themes, English UI.

**Which variant goes where.** The project README (and therefore the crate's
page on crates.io) embeds the **Dark** PNGs unconditionally — a picture of a
terminal should look like a terminal whatever theme the page is read in, and
most consoles are dark. mindfork.io inlines the **light and dark SVGs** and
switches them with its own theme toggle. The Light PNGs are generated and
committed all the same: the drift gate sweeps the whole matrix, so a Light
capture that stopped matching the code is still caught.