From f68caec849fa06bf098c7a7167595dc9120b77bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20Bene=C5=A1?= Date: Thu, 6 Aug 2026 21:36:44 +0200 Subject: [PATCH] A changelog, kept from now rather than assembled at the end Every version bump gets an entry in the same commit. Not afterwards: the reason a change was made is known while it is being made and gone a week later, and a changelog assembled from commit subjects at release time is a list of things nobody can act on. Backfilled 0.8.2 through 0.9.8, because those shipped as a running deployment rather than as releases and 1.0.0's notes have to be assembled from something. The rule that earns the file its place is the last one in CLAUDE.md: a fix to something that *looked* like it worked gets a line, always. Those are the entries somebody stops working around a bug because of, and they are invisible from outside -- nobody reports a control that silently does nothing, they just quietly stop using it. Half of what is in here is that shape: a group delete that left its grants, a share panel that only saved if you also saved the resource, an update script that stopped after "== fetching ==". A release is a signed annotated tag whose message is that version's entry, and that is not decoration -- /admin/updates reads release notes out of the tag object, so the tag message is literally what an administrator sees on the update page. Co-Authored-By: Claude Opus 5 (1M context) --- CHANGELOG.md | 169 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..7c1559e --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,169 @@ +# Changelog + +What changed, per version, for somebody using or running LLeMbas — not a +restatement of the commit log. If a change fixed something that *looked* like it +worked, that is worth a line: those are the ones nobody would otherwise know to +stop working around. + +Newest first. Versions are `__version__` in `src/lembas/__init__.py`, which is +the only place a version is written. + +The first tagged release is **1.0.0**. Everything below it shipped as a running +deployment rather than as a release, and is recorded here so the release notes +for 1.0.0 have something to be assembled from. + +--- + +## Unreleased + +Nothing since 0.9.8. + +## 0.9.8 + +**Updates follow a channel, not a commit.** `stable` tracks the newest `vX.Y.Z` +tag; `edge` tracks the branch tip. A branch tip is not a release — following one +means deploying whatever was pushed five minutes ago — so stable is the default +for anybody who is not the person writing it. + +- The Updates page shows a **version** rather than a commit sha: `1.0.0` at a + tag, `1.0.0-7-gd4f56d` seven commits past one, and a bare sha only before the + first release exists. +- Release notes come out of the **annotated tag itself**, so no forge API is + involved anywhere. That matters: the Gitea API this was checked against + returns a 500 from a server-side panic on exactly the releases endpoint. +- A tag with a suffix (`v1.1.0-rc1`) is deliberately not a release — git's + version sort ranks it *above* `v1.1.0`, so accepting one would step a stable + host onto a candidate. +- Fixed: `deploy/update.sh` stopped silently after `== fetching ==` on any host + with no release tags — which was every host. Fetched, not reset, not + restarted, and no error printed. +- Fixed: `install.sh` now refuses an `ssh://` repository URL up front instead of + letting the clone fail as a service user with no key. + +## 0.9.7 + +**Packaging, and updating without a shell.** + +- `/admin/updates`: what is running, what is available, and what changed between. + A button applies it — answered by an **opt-in** systemd helper, because the + service runs unprivileged and a web application that can restart its own + service is one whose worst day is much worse. Without the helper the page says + so and prints the command. +- `Dockerfile` and `docker-compose.yml`. No secret key, no data and no `.git` + baked in; loopback only; a TLS proxy expected in front, because a service + worker and a microphone both require HTTPS or localhost. +- `deploy/lxc-install.sh` creates an unprivileged Proxmox container and runs the + existing installer inside it. +- `/healthz`, which opens the database rather than only proving the socket is + listening. + +## 0.9.6 + +**Permissions, quotas and sharing.** + +- **"What can this account actually do?"** answered on screen, naming *where* + each permission came from — admin, the baseline, or a group. +- Users and groups are list-plus-detail, and membership is edited from **one** + side. It was on both, and a save from either overwrote what the other showed. +- Reading and writing split for notes, memory and skills. +- **Quotas on a group** — monthly tokens, concurrent replies, agent wall clock, + images a day, helpers a reply. Resolved by maximum across a person's groups, + with zero meaning *no limit* and winning outright. +- Fixed: **deleting a group or an account left every share naming it behind.** + `forget_principal` had existed since shares did and was called by nobody. +- Fixed: `library.share` defaulted to off, so sharing shipped documented as done + and unreachable — the panel only renders for somebody who holds it. +- The share panel is its own action with a search box. It used to be checkboxes + inside the resource's save form, listing every account on the instance, and a + tick only took effect if you also saved the resource. +- Reports are shareable, and every listing has a **Shared with me** filter. + +## 0.9.5 + +**Extraction settings, embeddings, and hybrid search.** + +- `/admin/extraction`: upload size, image edge, JPEG quality, PDF pages, + extracted characters, orphan age, extra text extensions. +- An **embedding model** can be chosen from models flagged for it. Library search + then fuses keyword and semantic ranking, so *"how do I get paid"* finds a + document that says *"invoicing"*. +- **Choosing none is not a degraded mode**: no rows written, no requests made, + and byte-for-byte the keyword search that was always there. +- Vectors carry their model and width, and a mismatch is skipped rather than + scored — comparing two embedding spaces produces a confident wrong answer. +- Indexing happens in the background as records are written, with a rebuild + button for everything that already existed. + +## 0.9.4 + +**An instance can be somebody else's.** + +- Name, tagline, logo, favicon and launcher icons derived from the logo. +- The Middle-earth wording is editable data. Leaving a box alone does not freeze + it, so a later release can still improve the default. +- **Custom themes** as a set of colours rather than a stylesheet, inheriting + whichever built-in they start from. +- Global CSS overrides, served as `/branding.css`. + +## 0.9.3 + +**Subagents.** A reply can hand a self-contained piece of work to a helper that +runs on its own and reports back — several at once, so research fans out instead +of queueing. + +- A helper cannot ask questions, cannot send helpers of its own, writes nothing + unless the call asked and the chat's mode allowed it, and on a machine runs + only a fixed list of read-only commands — in **every** mode, including Auto. +- Fixed, and it was live in scheduled runs too: an unattended chat that hit an + approval built a card nobody could see and sat on it for fifteen minutes. + +## 0.9.2 + +**Image generation defaults an administrator can actually set** — steps, cfg, +size, sampler, scheduler, denoise, negative prompt, checkpoint, batch. There were +none: one hard-coded set from the SD1.5 era, and prose in a box as the only way +to change it. + +- The samplers and schedulers ComfyUI had been reporting all along are now the + pickers; nothing had ever read them. +- The tool's own schema restates the instance's defaults, instead of telling the + model "Default 512" beside an instance that draws at 1024. + +## 0.9.1 + +**Everything that arrives is announced, not only chat replies.** A scheduled run +that filed a report used to light a dot in a corner and say nothing. + +- A count in the tab title while you are looking elsewhere. +- **Web push**, so a schedule firing at seven in the morning reaches a browser + that is shut. Opt-in per device. It is the one thing here that contacts an + outside service, and `services/push.py` says so plainly. + +## 0.9.0 + +**A model can schedule things.** There was no tool for it — asked to "remind me +every Monday", a model wrote a note and reported that it had scheduled +something, and every screen agreed with it. + +- `schedule_create`, `schedule_list`, `schedule_update`, `schedule_cancel`, over + the same rule normaliser the manual form uses. +- The reply says the resulting timing back in words, which is the only moment + anybody can check that Monday was understood as Monday. + +## 0.8.3 + +**An SSH connection may not point at this machine unless an administrator says +so.** A profile aimed at `127.0.0.1` walked straight past "nothing runs on the +LLeMbas host" — through a real login, onto the machine holding the database and +the encryption key. Three positions: off, one named port, or anywhere. + +## 0.8.2 + +- Fixed: **opening the canvas before a chat existed swapped the whole site into + the panel.** `hx-get=""` is not "fetch nothing" — htmx looks for the attribute, + not the value, so the empty one was a real request for the current document. +- Fixed: the Canvas and Terminal buttons appeared where they could not work. +- The bottom edge of the shell is no longer drawn, so the sidebar footer and the + composer stop meeting a line at two different heights. +- Admin pages scroll in one container; `/admin/prompts` no longer drops you at + the bottom of a shorter panel.