Releases: sergezuber/FABULA-LLM-5
Release list
FABULA v0.219.0 — a user-added provider is editable
Connecting any model without a predefined provider already worked; now editing one works too, and the write follows where the provider lives.
0.219.0 — 2026-08-12
-
A provider added via «Custom provider» can now also be EDITED. Connecting a new model without a predefined provider already worked (the form writes the global config), but changing it did not: the Edit button showed, yet saving failed with «provider not in launch config». The cause is the familiar one — create wrote one file (the global ~/.config/fabula) while every edit path looked only at the project config. One provider, three places, disagreeing.
-
A custom provider is a property of the user, not of a folder, so it lives in the GLOBAL config and is available in every project; edits now write where it was created. The edit path became location-aware: a project-config provider (e.g. the local LM Studio) is patched in place as before; a global one is patched in the global file with precise replacement (a removed model is really removed — the old merge kept it) and JSONC-comment-safe, schema-validated BEFORE it touches disk.
Also shipped 0.218.0 in this push: the example config the project ships now loads through the strict loader, and a config already copied from the broken example no longer dies at startup on pseudo-comment keys.
FABULA v0.218.0 — the example config loads
A fresh install could not start on the config this project ships as its own example. Both halves are repaired — for new installs and for every config already copied.
0.218.0 — 2026-08-12
-
A fresh install no longer dies on a config this project itself handed out. The shipped example carried four keys the strict loader refuses: three pseudo-comments (
_comment_*— prose written as KEYS in a file that is actually parsed as JSONC, where real//comments are legal) andenhance— a genuine setting of the Enhance-prompt button, which its route reads from the same file directly, bypassing the schema. One reader required the key, the other forbade it — and setup copied that example to every new user. Machines with an older config never crashed, so the defect lived unseen until a second machine. -
Fixed for everyone, not only for new installs:
enhanceis declared in the schema (the feature is real — deleting it would treat the symptom), the example carries real comments, and the loader TOLERATES top-level pseudo-comment keys with a log warning — because setup never overwrites an existing config, so anyone who copied the example in a bad week would carry those keys forever. Below top level an underscore is data (enhance._defaultis a live contract) and is not stripped. The example now passes the REAL schema in tests — not an allowlist of keys, which would have to be kept in step by hand, the very failure that produced this defect.
Also in this push: two hand-made rotation-log copies are removed from the tree, the ignore rule now covers rotated logs (*.log.*), and the public-hygiene gate refuses any tracked file containing the home directory of the machine it runs on.
v0.217.0 — Windows and Linux, measured
Windows and Linux are first-class: the whole matrix is green on all three platforms, the
application starts on a clean Windows machine, and the model list now reflects what is
actually running rather than what the config declares.
0.217.0 — 2026-08-09
- Two log entries carried ONE number. The change of 7 August was labelled 0.209.0 while it actually shipped as 0.210.0 — the version was bumped that time and the entry kept the previous number, colliding with the genuine 0.209.0 of the 6th. The log is what release notes are assembled from: two different changes under one number means one of them is either lost from the notes or attributed to the wrong release. The number is corrected against what the version REALLY was at that commit, not against what the entry claimed.
0.216.0 — 2026-08-09
- The model list is shown by SIX different places, and all six now re-ask it. The change had been written three times before, each time in the wrong file: what was on screen was the home page menu while the session composer's picker was being edited. No test failed, because the route and the filter both answered correctly; the untrue thing was the surface nobody was measuring. It was found by a counter placed in the code, not by reasoning about it.
- The rule is pinned by an enumeration rather than by memory: a check reads the sources and requires that EVERY interface file reading the model list also re-asks it. The first version of the check tried to separate showing from counting and found three of the six surfaces — half of them wrap the call across a line break. A rule with exceptions rots; the first-run screen shows how many models there are, and that number has to be true when it is shown too.
0.213.0 — 2026-08-09
- The model list stops offering what is not running on this machine, and "nobody is there" is now asked of the KERNEL rather than read out of an error message. The rule "offer only what a provider really serves" used to rest on the provider ANSWERING, and a closed port did not count as an answer — so every model of such a provider stayed in the menu. Now a failed request to a local address opens a plain connection to the port: a refusal from the kernel, and only that, means nobody is listening. Open, timed out, any other error, any remote address — nothing is hidden.
- The first version read the error text, and that was a costly mistake: with HTTP_PROXY set in the environment, even a loopback request travels through the proxy, and an unreachable proxy answers with a message byte-identical to a closed port. A live runtime answering 200 was hidden entirely — precisely what this mechanism exists to prevent. The hostname cannot settle it: whether to use a proxy is decided by the transport, not by the address. A direct socket to the port is something a proxy cannot spoof: either something accepts, or nothing does.
- A hiding that was true for one instant is no longer a verdict for the whole session. The map was asked once per launch, so an owner who starts the application before the runtime — the ordinary order — would see no models until the window was reloaded. Now exactly one answer is re-asked, the single one that is not fail-open, and only while it stands: when nothing is hidden there is no polling at all.
- A hidden model no longer breaks model selection. A candidate's fitness was checked against the configuration while the model was then looked up in the FILTERED list — so a declared-but-unserved candidate was accepted and then lost, and selection returned nothing instead of trying the next one. "Can this be used?" is now asked of the same list the menu shows, and the default scan walks all of a provider's models rather than only its first. Onboarding's model count moved to the same source: two different answers to "how many models do you have" were contradicting each other.
- An empty model list now says WHY it is empty and names the runtime that is not running — that state simply did not exist before, and "No model results" tells nothing to someone whose runtime is off.
0.212.0 — 2026-08-09
- Template parsing understands the
generationextension. It is a real chat-template extension, not a typo: it marks which span of the text belongs to the assistant. A plain environment does not know the tag and REFUSES to compile the template — so the audit called a perfectly ordinary model a layout violation, a statement about our parser dressed as a statement about the model. Once the template could be read, the honest answer was different: that model is not tools-first. Three of the four on this disk are; one is not. - The sweep over installed models REPORTS their layout and asserts only what is ours: the template was readable and the probe answered. What the layout is, for a model this project neither writes nor ships, is that author's decision and not a defect here; the invariant FABULA depends on is asserted separately, against the model in the socket.
- The production model is DERIVED from the same file the engine reads instead of being written down as a path. The path was written down, the model it named had long been replaced — and the invariant this very file calls design-critical was skipped in silence on the owner's machine for as long as it had been gone. A fact about a moving thing, recorded once, stops being a fact and nothing says when. And a sweep that examined nothing now says so: absence and success look identical in a count.
0.211.0 — 2026-08-09
- The rule "a name that resolves to an internal address is refused" is finally TESTED. The resolver is injectable, so the verdict comes from this code and from nothing else. The real network cannot produce that case at all — no public name resolves to a loopback address — and it is precisely why the async check exists beside the synchronous one; until now nothing tested the anti-rebinding floor. It also removes a verdict that depended on whether DNS answered: on another machine two checks failed on resolution timeouts while the code was fine. One live check remains, asking a different question — that the default path is wired to a resolver at all — and on a silent network it reports a SKIP that names itself.
FABULA v0.210.0 — the list offers what a provider serves
FABULA v0.210.0
- 0.209.0 — The model list now shows what the model runtime itself shows: a clean name, the format with its quantization, and the context window as one number. The previous labels carried working notes — "(A/B)", "(stable tools)", one model called the best by a judgement our own measurement later disproved — and one was not written in the interface language. Format and window are omitted rather than guessed when a provider does not report them.
FABULA v0.209.0 — the picker states format and window
FABULA v0.209.0
- The model list now shows what the model runtime itself shows: a clean name, the format with its quantization, and the context window as one number. The previous labels carried working notes — "(A/B)", "(stable tools)", one model called the best by a judgement our own measurement later disproved — and one was not written in the interface language. Format and window are omitted rather than guessed when a provider does not report them.
FABULA v0.198.0 — the front page shows the product at work
FABULA v0.198.0
- 0.198.0 — The showcase frame on the front page shows the product at work rather than an empty launch. The frame carries the essence itself: the hard gate that refused to count green tests without a proven reproduction of the bug, the verdict with the real test score, and the minted receipt with its re-verification command. Every fact in the frame comes from a real run on a local model; captured from the live interface.
- 0.197.0 — The resume check names the STEP, not just the clock. It performs two full runs and a resume where its neighbours perform one, and on expiry it reported only that time had run out — which cannot tell a stalled first run from a stalled resume, and invites raising the number instead of learning which. Its outer budget now sits BEHIND the sum of its own bounds rather than in front of them.
- 0.196.0 — When the suite reported no numbers at all, the RUN itself now speaks — its exit code and last lines. "Zero passed" looks identical for three different findings: the suite shrank, the suite never started, the run was cut off part-way. Its budget is raised to twenty-five minutes; the same suite takes about twelve on a quiet runner, and this criterion runs beside the whole rest of the matrix.
- 0.195.0 — The final sweep is bounded by TIME, not by a number of attempts. A count is a bound on the wrong quantity: each attempt costs a forced garbage collection and a pause, so raising it to outlast a stubborn handle pushed the sweep past the suite's own budget — and a sweep that times out fails the run as loudly as one that throws, with nothing to read. Both targets now fit inside the budget with room to spare.
FABULA v0.194.0 — the storefront reads the way the best ones do
FABULA v0.194.0
- The project storefront was aligned with the best open repositories. The first image is now the app itself — a real capture with clean data, not a diagram; installation moved into the first half of the page and every platform states its launch command; a community section was added. The plugin table stopped being an essay in a grid: the longest cell shrank from two thousand characters to an ordinary paragraph, with the two main gates' details moved to their own linked sections. The architecture overview gained a clickable table of contents.
Also in this release: the v0.104–v0.193 platform wave — the engine and every plugin now run on
Linux (verified by execution), Windows artifacts build and verify, and the desktop shell compiles for
all three platforms. The full per-version log ships in the app: Settings → Changes.
FABULA v0.103.0 — every artifact proves its version
FABULA v0.103.0
- The deploy guard now checks the version number itself, not only timestamps and contents. It used to look at the engine alone: nobody checked the built web interface or the app bundle's manifest, and a binary built five minutes ago from a different copy of the repository passed as fresh — newer than every source file and carrying every required mechanism. Now the number declared in the source must sit inside each of the three artifacts — the built interface, the bytes of the engine itself, and the app bundle's manifest; each artifact answers with its own report line, and on a mismatch the guard names the number the artifact actually carries. The checks are pinned by a test that runs the script itself over synthetic trees where each artifact in turn carries a foreign number: remove any one of the three checks and exactly its test falls.
FABULA v0.102.0 — a missing directory says so
small but annoying one.
a connected mcp server showed a red dot and the log said ENOENT: no such file or directory pointing at the server's own binary. the binary was fine — it answered a full handshake in half a second. what was actually missing was the working directory the server was being started from: leftovers of finished runs, and a folder deleted during cleanup.
the OS reports both cases identically. running /bin/echo — which definitely exists — inside a deleted directory gives the same error, naming the command and not the missing path. so anyone debugging it goes and checks a file that was never the problem.
now the directory is checked before anything is spawned, and a session pointing at a folder that no longer exists says exactly that. a cleaned-up run or a removed branch worktree is an ordinary thing, and it should not look like a broken tool.
also cleaned a stale project entry out of serena's own config that made it warn on every start.
FABULA v0.101.1 — the count that sees every tool
FABULA v0.101.1
- The public tool count was corrected from 85 to 89. The command that derived the number missed tools with a digit in their name — four fell out of the count, and the storefront undersold its own product. The command itself was corrected at the source so the defect cannot return.