Releases: SemplificaAI/MikeRust
v0.5.6 — Chat composer UX fixes
MikeRust v0.5.6 — Chat composer UX fixes
Two bug fixes in the chat composer that surfaced during hands-on
testing of the v0.5.5 cycle, plus an opt-in experimental local-only
LLM mode for Ollama users (off by default).
Bug fixes
Doc picker — project scope
The "Sfoglia tutti" picker inside a project-scoped chat used to show
every document the user had ever uploaded anywhere — including
documents from other projects and standalone-chat attachments. It
now restricts to the current project's documents via the existing
?project_id=… filter in documents.rs::list_documents.
Standalone chats (Assistant tool, no project attached) keep the
global picker unchanged — that's the path the user takes to add a
library-wide doc to a fresh conversation.
New-chat-in-project confirm modal
Clicking + (new chat) in the sidebar while a project-scoped chat
was active used to silently inherit the project on the new chat —
the user had no way to know the chip had carried over until they
glanced at the composer. Reported as confusing.
The new flow:
- If the active chat is in a project, clicking
+now opens a
confirm modal: "Stai lavorando dentro un progetto. Vuoi
mantenere il progetto associato alla nuova chat?" with two
action buttons — Chat indipendente / Sì, mantieni il
progetto — and implicit cancel via the X / Esc / backdrop
click. - If the active chat is not in a project, the flow is unchanged
(no modal, instant new chat).
Internally this also fixes the long-standing "chip persists
silently" bug where the composer's $effect early-returned on a
null activeProjectId instead of clearing the chip. A new monotonic
chatStore.clearProjectTick lets the modal's "Chat indipendente"
branch reset the chip without race conditions.
New (opt-in, experimental)
Local-only LLM mode for Ollama users
New toggle in Settings → Modelli LLM → "Modalità sicura locale".
Off by default, retro-compatible with existing local-provider
configurations.
When on:
- The local provider's base URL is locked to
http://localhost:11434
(loopback only — refuses LAN endpoints or public IPs). - The chat composer's model picker collapses to two curated entries
(Qwen 3.5 4Bq4_K_Mand Gemma 4 E2B IT GGUFQ4_K_M), both
derived through Ollama Modelfiles MikeRust creates on demand with
thinking suppression baked in. - Install / cancel / parallel-download UX directly from Settings,
with real-time progress streaming.
Backed by:
- New module
src/llm/ollama_manager.rs
wrappingollama-rs0.3. - Schema migration 0032 — adds
user_settings.local_secure_mode INTEGER DEFAULT 0. - 13 new unit tests across
llm::localandllm::ollama_manager
(15/15 + 6/6 green).
Treat this as an experimental preview for the v0.6.x line. The
mechanism is feature-complete and tested, but the UX around model
discovery / context-window tuning / cross-platform Ollama detection
is still being refined. Power users who want to try it can flip the
toggle; everyone else can ignore it — the rest of the local
provider works exactly as before.
Downloads
Pre-built MSIs for Windows:
MikeRust_0.5.6_x64.msi— Windows x86_64MikeRust_0.5.6_arm64.msi— Windows ARM64, Snapdragon X Elite
native
Drop-in replacement for v0.5.5.
Migration notes
- New schema migration 0032 is applied automatically on first
launch. The only column added defaults to 0 — existing installs
preserve their custom Ollama URL and free-form model id. - New direct dependencies:
ollama-rs = 0.3(withstream) and
async-stream = 0.3. Both pure Rust, no native libs added.
License
MikeRust is distributed under AGPL-3.0-only. The Semplifica
wordmark and logo are trademarks; see NOTICE.md. The full
licence text is available in-app under Settings → Licenza.
v0.5.5 — stable consolidation of the v0.5.4 amendment cycle
MikeRust v0.5.5
Stable consolidation of the v0.5.4 amendment cycle. The v0.5.4 tag
was force-rewritten several times as fixes were appended
(back-stack regressions, untrack boundaries, export-shape gaps,
tabular review rename); v0.5.5 marks the end of that iteration with
a clean, non-rewritten tag.
What's in v0.5.5
Everything from the v0.5.4 cycle — see the v0.5.4 release notes for
the full per-feature breakdown — plus the final polish landed
during the same testing session:
Closed .mikeprj export-shape gaps
The v0.5.4 audit ("Known gaps" section in the v0.5.4 release notes)
called out fields the exporter wasn't reading or was
reading-and-discarding. All fixed:
ProjectRecordgainsdomainandisolation_mode— the
recipient lands on the same domain filter and retrieval-scope
mode the source project had.DocumentRecordgainsdomain,project_folder_id(path
hint), and the accept/reject decision tuple from migration 0029
(decision,decision_reason,decision_summary).
content_hashis rehydrated on import from the manifest's
sha256so tabular dedup-by-hash works immediately.TabularReviewRecordgainsdomain(review-level — can diverge
from the project's).WorkflowRecordgainsdomain. The exporter also stops
hard-codingtype = "assistant"and discardingcolumns_config
— a custom tabular workflow finally travels intact.
All new fields are Option<…> with #[serde(default)] so older
archives still deserialise cleanly. Two new back-compat tests pin
the behaviour; 21/21 mikeprj tests green.
Tabular reviews — per-row Pencil rename
The Revisioni tabellari list view gains a Pencil icon between the
domain Badge and the Trash on every row — parity with the
Projects-list rename affordance. Opens a small inline modal with
the current title pre-filled, Enter submits, Escape cancels, Save
is disabled when the input is empty or unchanged. New i18n keys
TabularReviews.renameReview and TabularReviews.renamedToast
localised in all six locales.
What v0.5.5 inherits from v0.5.4
The full v0.5.4 work ships in v0.5.5 — to recap the highlights:
- Tabular extraction now works for ANY upload path — the new
"Upload" button in the doc picker lets the user upload directly
from the filesystem; the previously silentload_document_text
failures (relative storage key + missing extension defeating
pdfium) are fixed with absolute-path resolution and
file_type-driven extension synthesis. - Schema hotfix — migration 0031 drops the residual FK on
tabular_reviews.workflow_id → workflows(id)that blocked
every preset-based "Nuova revisione" with SQLite error 787. - Per-row tabular dedup on re-upload — adding a document that
is byte-identical to one already extracted in the same review
(filename + SHA-256 content_hash) inherits the earlier row's
cells instead of re-running the LLM. - Project-flow polish — "Nuova revisione" inside a project,
scope-correct doc picker (domain + project_id + global rules),
per-row Export icon on the Projects list, "Importa progetto"
button on the Projects header. - Generic router back-stack — drill-downs always return to the
originating screen. First consumer wired is Chat-from-Project →
"Torna a {nome progetto}". ThenavTicksignal handles
re-navigation to the same route (sidebar accordion clicks);
every mutating router method runs insideuntrack(…)so callers
inside$effectbodies don't accidentally loop on the
read-modify-writes. - Sidebar "Progetti recenti" accordion — top 5 projects by
updated_atDESC between the tool nav and the existing Chat
recenti accordion. - PickerModal select-all / deselect-all — multi-select pickers
gain a toggle bar between the search input and the list. Scope
is the visible (search + filter applied) set.
Downloads
Pre-built MSIs for Windows:
MikeRust_0.5.5_x64.msi— Windows x86_64MikeRust_0.5.5_arm64.msi— Windows ARM64, Snapdragon X Elite native
Drop-in replacement for v0.5.4 (and any of its force-retag drops):
same database schema (migration 0031 still the latest), same
on-disk paths, same config.
Migration notes
- No new database migration. Schema unchanged from v0.5.4.
- v0.5.4 users: install
MikeRust_0.5.5_*.msion top. - v0.5.3 and earlier: same — the auto-migration runs on first
launch.
License
MikeRust is distributed under AGPL-3.0-only. The Semplifica
wordmark and logo are trademarks; see NOTICE.md. The full licence
text is available in-app under Settings → Licenza.
v0.5.4 — tabular-review FK hotfix + four UX up# MikeRust v0.5.4
MikeRust v0.5.4
Bundle release on top of v0.5.3. What started as a single SQLite
schema hotfix grew into a full tabular-review pass after the same
testing session surfaced the biggest practical bug: tabular
reviews could only analyse documents that had previously been
attached to a chat or uploaded into a project — files dragged in
directly from the filesystem went through a different storage path
and silently failed extraction, leaving every cell as "Document
text unavailable". v0.5.4 fixes that, adds in-place upload from the
review's own picker so the user no longer has to bounce through a
chat, and dedups re-uploads so identical content doesn't get
re-extracted by the LLM. Layout and a couple of UX upgrades came
along for the ride.
Highlight — tabular extraction now works for ANY upload path
The previously hidden contract was: only documents that went through
the chat/project flow (cache-based storage layout with text
extracted at upload time and a sidecar .txt persisted alongside)
worked in tabular reviews. Files uploaded by other means used the
legacy cache=false storage layout — documents/<uid>/<doc_id>
with no extension and no extracted-text sidecar. When the
extraction job tried to read those it hit two cascading bugs in
load_document_text:
- The storage key was being passed as-is to
extract_text_dispatch. That key is a relative path (e.g.
documents/<uid>/<doc>); pdfium needs an absolute on-disk
path to open a PDF, so every PDF failed silently and the row
surfaced as "Document text unavailable". - The dispatcher dispatches on the path's file extension. The
legacy key has none, so even after fixing the absolute-path
problem the dispatcher fell into the catch-all branch and
returned "format not supported".
Both legs fixed:
- The storage key is now resolved to an absolute path under
STORAGE_PATH/default_storage_path()before dispatch. - The query also reads
file_typefrom thedocumentsrow. When
the on-disk path has no extension, a sibling with the right
suffix (.pdf/.docx/ …) is materialised so pdfium can open
it directly and the dispatcher's extension match hits the right
branch.
Exhaustive [tabular][doc-text] tracing was added at every branch
(sidecar hit, sidecar miss, storage.get failure, extension
synthesis, dispatch result, skip reason) so the next regression
surfaces in mike-tauri.log directly.
This unblocks the new "Upload" button in the tabular-review doc
picker (see "Upload affordance inside the doc picker" below): files
the user drags in from the filesystem now get extracted just like
chat-attached or project-attached docs.
Schema hotfix — preset workflows blocked tabular-review creation
Tabular-review creation against preset workflows
Picking any of the 49 built-in workflow presets (legal, insurance,
medical-legal, finance) in the "Nuova revisione" modal returned
error returned from database: (code: 787) FOREIGN KEY constraint failed
directly in the modal and refused to create the review.
The root cause was a residual foreign key from the v0.1.0 schema:
CREATE TABLE tabular_reviews (
...
workflow_id TEXT REFERENCES workflows(id) ON DELETE SET NULL,
...
);Built-in workflows live as JSON manifests under
config/workflow-presets/ and are merged into the registry
in-memory at startup — they intentionally never own a row in the
workflows table. We hit and fixed the same pattern on
workflow_hidden in migration 0022; tabular_reviews carried the
same FK and the bug had been latent since the JSON-preset registry
shipped.
New migration 0031 rebuilds tabular_reviews dropping the
workflow_id FK while keeping the user_id / project_id
references intact and preserving all existing data plus the
domain index. After the migration runs once on first launch of
v0.5.4, workflow_id is a free text id that resolves either against
the DB workflows table (user-created workflows) or the in-memory
preset registry (built-in workflows).
No frontend / backend code change — the route handler was already
binding workflow_id as a free string. No behaviour change for any
existing review.
UX upgrades from the same testing session
Four quality-of-life improvements landed alongside the schema fix
because they touch the same screens:
Workflow picker now labels Tabellare vs Assistente
The chat composer's "Allega un workflow" modal renders a coloured
pill on the right of each row — Tabellare in purple, Assistente in
blue, using the brand-audit Badge tones that already existed but
hadn't been surfaced. Identifies workflow kind at a glance without
opening the workflow.
Upload affordance inside the doc picker
The "Aggiungi documenti" modal on the tabular-review detail page
gains an "Upload" button bottom-left. Selected files upload
sequentially via documentsApi.upload, refresh the picker list, and
are automatically linked to the review — the user does not re-tick
files they just uploaded. The "Conferma" button now stays enabled
even with zero items ticked once an upload has succeeded during the
session, so the user has a clean way out (Cancel implied undo of an
action that had already committed).
Import Project button on the Projects list
A secondary "Importa progetto" button next to "Nuovo progetto"
triggers a .mikeprj file picker, reusing the email-prompt modal
that was previously reachable only by drag-and-dropping a .mikeprj
file onto the page. The POST /project/import endpoint and the
ProjectImport.* i18n catalogue were already complete since
v0.4.x — this just makes the affordance discoverable.
Tabular layout + dedup polish
Tabular detail — full-width layout
The grid no longer constrains itself to max-w-6xl (~1152 px).
Header and table fill the available container width — wide monitors
stop wasting 60%+ of the horizontal real estate. The side
document-viewer panel resizes/collapses independently and the grid
shrinks back when it is open, expands edge-to-edge when it isn't.
Tabular row dedup on re-upload
Adding a document that is byte-identical to one already extracted in
the same review (match key: filename + SHA-256 content_hash) now
inherits the earlier row's cells + status instead of asking the LLM
to re-extract them. Rows still in pending are ignored — there is
nothing to copy yet. Hits log as
[tabular][dedup] review=… new_doc=… inherits cells ….
Prereq for this feature: the legacy upload path now also computes
the SHA-256 content_hash. Without it the dedup join couldn't match
any document coming through the new picker Upload affordance.
Project-flow polish
"Nuova revisione" inside a project
The project's Revisioni tabellari tab gains a "Nuova revisione"
button — parity with the existing "Nuova chat" affordance on the
Conversazioni tab. The inline modal lists tabular workflows scoped
to the project's own domain, inherits project_id + the project's
domain on submit, and drills straight into the new review's
extraction grid without leaving the project shell. Existing review
rows on that tab are now click-targets and open the same inline
detail.
Scope-correct doc picker in tabular reviews
The "Aggiungi documenti" modal of a tabular review previously
surfaced every document the user had ever uploaded anywhere —
including cross-domain chat attachments and other projects' files.
It now applies, in order:
domain == review.domain(always);- if the review is project-scoped, the project's
Ambito di recupero mode drives the rest:- rigoroso → only docs with
project_id == review.project_id; - condiviso → also include global docs
(project_id IS NULL);
- rigoroso → only docs with
- if the review is not project-scoped → only global docs.
Backend GET /document now returns each doc's project_id so the
filter can run client-side. The picker's Upload button inherits the
review's project_id on uploads so a doc added through a
strict-scope picker stays visible there afterwards instead of
vanishing into the global pool.
Generic router back-stack — every drill-down returns to where you came from
The 2026-06-06 nav-consistency directive: a back button from a
drilled-in view must always return to the originating screen, not
to the destination's natural sidebar parent. The
TabularDetail-inside-ProjectDetail fix earlier the same day was
inline; this generalises the mechanism.
The router store gains a small back stack
(goWithReturn(target, ctx, entry) / popBack() /
consumePending(): NavContext). Drill-down callers push a back
entry so the destination renders a context-aware back arrow
("Torna a {name}") that pops the stack and restores the
originating screen's nested state. Standard router.go() clears
the stack (sidebar nav is "switch context", not "drill").
First consumer wired: a chat opened from inside a project pushes
a back entry pointing at that exact project. Assistant.svelte
shows the back arrow whenever the stack is non-empty; clicking it
returns to Projects and re-opens the originating project's detail.
New i18n key Nav.backToProject localised in all six locales.
Extending the mechanism to any future drill-down (Workflow editor,
DOCX template editor, …) is two lines per call-site.
Two follow-up fixes needed to make the back-stack robust:
- navTick — clicking a different project in the new sidebar
accordion while already on the Projects screen did nothing,
becauserouter.go('projects', { projectId: X })short-circuited
oncurrent === 'projects'and the destination$effectnever
re-fired. The router now exposes a monotonicnavTick(bumped
by every mutating method). Projects.svelte dereferences it
(`void route...
v0.5.3 — hotfix: accumulate Gemini parallel tool calls across SSE chunks
MikeRust v0.5.3
Single-fix hotfix on top of v0.5.2. The chat loop dropped parallel
tool calls from gemini-3.5-flash mid-stream, surfacing as a
hard 400 from the Gemini API on the next iteration.
The fix
Gemini 3.5 parallel-tool-call accumulator
gemini-3.5-flash streams parallel function calls across separate
SSE chunks (one functionCall per data: line). The chat dispatch
loop in src/routes/chat.rs was replacing its iter_tool_calls
vec on every StreamEvent::ToolCalls event:
Ok(StreamEvent::ToolCalls(calls)) => {
iter_tool_calls = calls; // ← drops everything from earlier chunks
}So when Gemini emitted three parallel calls in iteration 1, only the
last chunk's calls survived — the rest of the parallel batch vanished
before they were ever dispatched. Iteration 2's request to Gemini
then carried a truncated assistant turn that no longer matched the
model's internal record of which calls it had emitted, surfacing as:
Gemini API error 400 Bad Request:
"Function call is missing a thought_signature in functionCall parts.
Additional data, function call `default_api:read_document`, position 2."
The fix is one line — extend instead of =:
Ok(StreamEvent::ToolCalls(calls)) => {
iter_tool_calls.extend(calls);
}extend is safe for the other providers too. Claude tool use never
emits StreamEvent::ToolCalls in the SSE path (Anthropic streams
deltas through a different channel); the OpenAI-compatible local
adapter emits a single batched event per turn, so extend of one vec
of N is identical to assignment of the same N.
Per the official Gemini docs
(https://ai.google.dev/gemini-api/docs/thought-signatures), only the
first function call in a parallel batch carries a thoughtSignature
and the others must not — so this accumulator fix is sufficient on
its own; the original to_wire_contents echo-back logic in
src/llm/gemini.rs was already correct.
Downloads
Pre-built MSIs for Windows:
MikeRust_0.5.3_x64.msi— Windows x86_64MikeRust_0.5.3_arm64.msi— Windows ARM64, Snapdragon X Elite native
Drop-in replacement for v0.5.2: same database schema (migration 0030
still the latest), same on-disk paths, same config.
Migration notes
- No new database migration. Schema unchanged from v0.5.1/v0.5.2.
- v0.5.2 users: install
MikeRust_0.5.3_*.msion top — the only
difference is the one-line fix in the chat dispatch loop. - v0.5.1/v0.5.1b users: the v0.5.2 security hardening
(drop S3 fallback + Parquet size cap + platform-support
clarification) still applies on top of this hotfix.
License
MikeRust is distributed under AGPL-3.0-only. The Semplifica
wordmark and logo are trademarks; see NOTICE.md. The full licence
text is available in-app under Settings → Licenza.
v0.5.2 — security hardening: drop S3 fallback, parquet size cap, platform-support clarification
MikeRust v0.5.2
Security-driven patch release on top of v0.5.1b. Three changes land
together — all resolve outstanding Dependabot findings without
touching application behaviour.
Known issue: Gemini 3.5 Flash is still not working.
Highlights
Drop the s3-storage feature and the AWS SDK chain
aws-sdk-s3 + aws-config are gone from Cargo.toml. Removing them
drops 70+ transitive crates from the lockfile, including:
rustls 0.21.12+rustls-webpki 0.101.7— the Dependabot
advisory that prompted this release. The AWS SDK chain was the
only path that pulled in the vulnerable 0.21 line of rustls; the
rest of the codebase (fastembed, sqlx, hf-hub) already uses
rustls 0.23+rustls-webpki 0.103.13.aws-smithy-*,aws-sigv4,rustls-native-certs,sct, … the
full SDK transitive graph.
The S3/R2 path was always feature-gated OFF by default and the
s3-storage feature was never actually wired into
src/storage/mod.rs::make_storage — that function has only ever
returned LocalStorage. The trait stays for the ergonomic win of a
single Box<dyn Storage> handle and to keep the door open for a
sovereign-cloud backend on rustls 0.23 later. End-user behaviour
is unchanged.
local-storage is kept as a no-op feature so anyone who pinned it
in their own manifest still resolves cleanly.
Parquet shard size cap — mitigation for the Thrift advisory
The parquet crate (used by the Italian Legal Cassazione bulk
importer) transitively depends on thrift 0.17.0, which carries an
unfixed-upstream "Memory Allocation with Excessive Size Value"
advisory: a crafted Parquet footer can declare an allocation that
the decoder honours before validating against the actual stream
length, causing a DoS-style OOM. The Apache Thrift Rust bindings
have not shipped a fix; even the latest parquet 58 still depends
on thrift ^0.17, so a version bump alone would not help.
Mitigation lands as a hard byte cap applied before the bytes ever
reach the Parquet decoder:
- New file
config/corpora.jsonholds the knob
max_parquet_file_size_mb(default 500 MB — comfortably above
any legitimate shard from the corpora we ingest, well below the
threshold at which a malicious footer would matter on a 16 GB
workstation). - New module
src/corpora/limits.rsis the loader. Same
env-override + ancestor-walk pattern assrc/presets/model.rs
(MRUST_CORPORA_LIMITSenv var). Falls back to defaults with a
warning if the JSON is missing or malformed. src/corpora/italian_legal.rsrefuses to decode a shard above the
cap with a clear bail message.docs/CORPUS_PLUGINS.mdgains a Security section explaining
the Thrift advisory, thedila-bulk-xmlanalogous concern
(oversized XML / tar-walker hardening), and concrete guidance for
plugin authors — pin URLs to official publishers, never accept
user-supplied URLs verbatim, leave the cap at default unless you
have a specific reason to raise it.
Platform-support clarification (resolves the glib 0.18.5 finding)
README gains a "Supported platforms" section right at the top of
Quick start:
- Windows is the only currently shipping target (x86_64 + ARM64).
- macOS is on the roadmap but work hasn't started — codebase
compiles toaarch64-apple-darwinalready; gating items are
signing / notarisation and a Touch-ID equivalent of the
Windows-Hello unlock flow. - Linux is not supported and there are no plans to add it.
The practical consequence for security scanners: the gtk / glib /
atk / webkit2gtk / tao-linux chain that Tauri pulls in for the
Linux WebView backend is not present in any shipped MSI —
webview2-com + windows-rs are what compile in on Windows.
Advisories on that chain (e.g. glib 0.18.5 flagged 2026-05-26) are
therefore inert for end users and tracked as "not affected — Linux
support is not in scope".
Downloads
Pre-built MSIs for Windows:
MikeRust_0.5.2_x64.msi— Windows x86_64MikeRust_0.5.2_arm64.msi— Windows ARM64, Snapdragon X Elite native
Each bundles onnxruntime.dll 1.20.0 + pdfium.dll. Double-click to
install; runtime logs land in %USERPROFILE%\mikerust-data\mike-tauri.log.
Migration notes
- No new database migration. Schema unchanged from v0.5.1 (still
at migration 0030). - v0.5.1 / v0.5.1b users: install the new MSI on top — no data
changes, no config changes required. - Custom corpus plugin authors: read the new
Securitysection
indocs/CORPUS_PLUGINS.mdbefore pointing ahf-dataset-bulk
strategy at a third-party dataset. Themax_parquet_file_size_mb
cap inconfig/corpora.jsonwill refuse oversized shards by design. - Anyone consuming the
s3-storagecargo feature in a fork:
drop the feature flag from your build invocation. The feature is
gone;local-storage(a no-op) is still accepted for back-compat.
License
MikeRust is distributed under AGPL-3.0-only. The Semplifica
wordmark and logo are trademarks; see NOTICE.md. The full licence
text is available in-app under Settings → Licenza.
v0.5.1b — bugfix: Gemini sampler restored to default for versatile heterogeneous-document analysis
MikeRust v0.5.1b
Hotfix release on top of v0.5.1. Single fix: rolls back the
Gemini temperature override so the model stays versatile when
analysing heterogeneous documents (mixed-content medical records,
multi-format legal bundles, etc.) — the v0.5.1 tightening from 1.0
to 0.5 was making gemini-2.5-flash lose expressiveness on long,
varied inputs.
Everything else from v0.5.1 ships unchanged: hybrid bracket splitter,
cross-message citation lookup, tightened citation rules, orphan KB
cleanup endpoint, A4-fit DOCX viewer, diagnostic logging, and the
E2E test scaffold.
The fix
Gemini white-out on long heterogeneous contexts
Symptom. On gemini-2.5-flash, with a long context made of
varied document types (the "Timeline cronologica clinica" workflow
on three medical PDFs reproduced it cleanly), the model would emit
the first ~30 characters of real content (e.g. a Markdown table
header) and then get stuck in a low-entropy whitespace loop —
generating 155,010 characters of pure spaces in one observed run,
~1.96 million in another — before closing the stream. The user saw
a frozen response with no error.
Root cause. v0.5.1 set temperature = 0.5 on every provider
for citation determinism. On Claude / OpenAI / local that lower
temperature is fine. On Gemini 2.5 Flash specifically, with a
system prompt above ~45 kB plus heterogeneous tool-result content,
the low temperature collapsed the sampler into a repeating-token
regime that the model couldn't escape.
Fix. src/llm/gemini.rs no longer sets temperature on any
Gemini family. generationConfig is now only attached when
thinkingConfig is needed (2.5 family), and legacy 1.5 / 2.0
families get no generationConfig at all. The result: Gemini falls
back to its API default (~1.0), recovering the versatility that
heterogeneous-document analysis depends on, while Claude / OpenAI /
local keep their tighter 0.5 for deterministic citation output.
23 llm::gemini unit tests pass; the regression test
build_body_omits_generation_config_on_legacy_families now pins
the new behaviour.
Downloads
Pre-built MSIs for Windows:
MikeRust_0.5.1b_x64.msi— Windows x86_64MikeRust_0.5.1b_arm64.msi— Windows ARM64, Snapdragon X Elite native
Drop-in replacement for v0.5.1: same database schema (migration
0030 still the latest), same on-disk paths, same config. Install
on top of v0.5.1; no migration step.
Migration notes
- No new database migration. Schema unchanged from v0.5.1.
- v0.5.1 users: install
MikeRust_0.5.1b_*.msion top — the
citation pipeline, doc viewer, and KB cleanup endpoint are
byte-identical to v0.5.1, only the Gemini sampler config differs. - v0.5.0 and earlier: the v0.5.1 release notes still apply on
top of this one for the citation overhaul + A4 viewer + orphan
cleanup changes.
License
MikeRust is distributed under AGPL-3.0-only. The Semplifica
wordmark and logo are trademarks; see NOTICE.md. The
full licence text is available in-app under Settings → Licenza.
v0.5.1 — citation pipeline overhaul + orphan KB cleanup + A4 doc viewer
MikeRust v0.5.1
Stable consolidation of four work-in-progress drops (formerly tagged
v0.5.1 → v0.5.4) into a single shippable release. v0.5.0 exposed a
clutch of citation-pipeline failures with mid-tier LLMs (Gemini 2.5
Flash, smaller local models): mixed-content brackets, dropped
cross-message references, orphan KB chunks surviving file deletions,
and run-to-run citation inconsistency. This release fixes all of them
— and, while we were in the doc viewer, adds an A4-fit DOCX preview
that auto-zooms when the side panel is resized.
Highlights
Citation pipeline — model-independent post-processors
- Hybrid bracket splitter (
split_hybrid_citation_brackets).
Decomposes mixed-content brackets the model occasionally emits
([c1, c2, FILE.pdf, p.4, doc-7, doc-8]) into clean ones the
frontendMARKER_GROUPregex can pill-ify
([c1] [c2] [doc-id: FILE.pdf, page 4] [doc-id: doc-7] [doc-id: doc-8]).
Idempotent; stops at<CITATIONS>so it can't corrupt the
trailing JSON block (regression test pins this). - Cross-message citation lookup (
renderMessageHtml). When a
[cN]in the current turn has no matching annotation but an
earlier assistant turn in the same chat did, the pill resolves to
the older annotation. Catches the common case of models reusing
cNlabels across turns. - Tightened CITATION QUALITY RULES in
MRUST_SYSTEM_PROMPT:
omit empty / short quotes; page ranges only for[[PAGE_BREAK]]
spans (else integer pages); prefer per-passage over per-document
citations; prefer attacheddoc-Nover KBgN/pN; re-emit
cross-turn[cN]annotations in the current turn's
<CITATIONS>block.
Cross-provider determinism + headroom
temperature = 0.5on every LLM provider
(Anthropic / Gemini / OpenAI / local-OpenAI-compatible).
Defaults were 1.0 across the board — too random for structured
output. Lowering it makes citation extraction reproducible run to
run across all four providers.max_tokens4096 → 8192 on Claude + local. Doubles the
headroom for trailing<CITATIONS>JSON on long answers; Gemini
was already on its default (≥8192 on the 2.x family).
Orphan KB chunks — chat-time filter + cleanup endpoint
User-reported failure mode: removing a synced doc from the UI left
its embeddings behind, and every chat turn the cosine retrieval kept
surfacing those stale chunks — one chat ended up emitting 12
citations all pointing to the same dead PDF page.
retrieve_kb_chunksnow probes each chunk'ssource_pathon
disk and drops missing ones with an
[rag] orphan KB chunk dropped …warning + per-turn summary.- New endpoint
POST /sync/cleanup-orphans— per-user cascade
delete ofdocuments+doc_chunks+synced_filesrows whose
backing file is gone. Returns
{ scanned, orphans, deleted_docs, deleted_chunks, deleted_synced }. - Frontend modal: when a citation source 404s, the doc viewer
surfaces a warning panel with aPulisci sorgenti rimossebutton
that calls the cleanup endpoint and toasts the row count.
DocxView — A4 fit (default) + reflow toggle
Preserves the document's native A4 page geometry (width + height +
margins, breakPages: true) and applies CSS
zoom = containerWidth / pageWidth (clamped to [0.4, 1.5]) via a
ResizeObserver so the page auto-scales when the user drags the
side-panel divider. A top-right toggle flips to a reflow mode (drops
the page geometry, prose flows the full panel width) for narrow
side-panel reading. ResizeObserver detached in reflow mode so the
responsive cost is zero off-path.
Diagnostic logging
[rag][cite-diag] retrieve_kb_chunks …spells out HyDE on/off +
locale + domain + top-K and clarifies that base cosine retrieval
always runs regardless of HyDE (removes the recurring "I turned
HyDE off, why is it still searching?" confusion).[chat][cite-diag] …events trace each step of the citation
pipeline: final response shape, tail dump, per-step outcome, FINAL
SSE payload size.[chat] <CITATIONS> block found but is not valid JSONwarning
dumps head / mid / tail (300 chars each) of the offending payload
for offline diagnosis.
E2E test scaffold
New tests/medical_citations_e2e.rs bypasses the frontend entirely:
places 10 PDFs from tests/medical/ straight into cache + documents
rows, exercises the real POST /chat handler via
tower::ServiceExt::oneshot, parses the SSE stream, and prints a
structured JSON report of citation quality. Gated by #[ignore] +
GEMINI_API_KEY; A/B switches via E2E_HYDE / E2E_MODEL.
$env:GEMINI_API_KEY = "..."
cargo test --test medical_citations_e2e --features rag,pdf `
-- --ignored --nocapturev0.4.7 — version badge fix + chat-files popover + License panel
MikeRust v0.4.7
Rollup release that closes a string of UX and persistence gaps reported during the v0.4.x review cycle, plus a hotfix for the visible-version regression introduced in v0.4.6.
Highlights
Generated-docx Accept / Reject flow — full lifecycle
When the model emits a docx the user can now Accept it (keep in chat context) or Reject it (replace with an LLM-generated summary anchored on a mandatory user motive). Re-Accept restores the original; Re-Reject overwrites the archive with a fresh summary. A new "Vedi riassunto" read-only modal surfaces the archived reason + summary after the reject modal closes, so the user can re-read what the model now sees in place of the document.
Backend: documents.decision / decision_reason / decision_summary columns (migration 0029); POST /document/:id/decision runs the summariser and persists; chat::load_attached_docs substitutes the body with a reason + summary stub on every subsequent turn.
Chat-files popover — five categories, one shortcut
New Files button in the composer footer opens a popover listing every document the chat has ever interacted with, across the five categories the chat archive is expected to retain:
| Origin | Where it comes from |
|---|---|
Caricato |
composer paperclip → documents.chat_id |
Generato |
generate_docx tool → documents.chat_id |
Rifiutato (variant) |
any of the above with decision='rejected' — strikethrough + red badge |
Progetto |
chats.project_id → documents.project_id |
Citato |
KB / corpora docs cited via messages.annotations |
Per-format icon colours (Excel green / Word blue / PDF red / PowerPoint orange / Markdown text-primary). Click a row to open it in the existing doc-viewer side panel, where Accept / Reject / Vedi riassunto / Apri in Word all already work. Backed by a new GET /chat/:id/documents endpoint that survives chat reload, chat switching and message compaction.
Version badge + License panel
Small v{version} badge next to "MikeRust" in the sidebar so the user always knows which build is running. New Settings → Licenza panel shows MikeRust + version, the SPDX identifier (AGPL-3.0-only), a plain-language summary of the AGPL terms and the full bundled LICENSE text in a scrollable monospace block.
Multi-doc anamnesis docx (v0.3.6)
Fixed a Gemini tool-code crash on multi-document anamnesis flows and a doc-label off-by-one (1-indexed labels now match [doc-N] references).
Full changelog by patch
- v0.4.7 — version badge actually renders (replaced runtime
getVersion()+$statewith build-timepackage.jsonimport) - v0.4.6 — version label + License settings panel (broken; superseded by 0.4.7)
- v0.4.5 — chat-files popover surfaces all 5 doc categories (project + KB-referenced)
- v0.4.4 — chat-files popover backend-sourced, survives reload (new
GET /chat/:id/documents) - v0.4.3 — chat-files popover MVP
- v0.4.2 — fix reject modal step-2 transition (
untrack(initialReason)in$effect) - v0.4.1 — persistent "Vedi riassunto" for rejected docs
- v0.4.0 — domain-aware system-prompt prologue (66 .md files × 6 locales × 11 domains)
See HISTORY.md for the per-patch details and rationale.
Downloads
Pre-built MSIs for Windows:
MikeRust_0.4.7_x64.msi— Windows x86_64MikeRust_0.4.7_arm64.msi— Windows ARM64 (Snapdragon X Elite native)
Each bundles onnxruntime.dll 1.20.0 and pdfium.dll. Double-click to install; runtime logs land in %USERPROFILE%\mikerust-data\mike-tauri.log.
License
MikeRust is distributed under AGPL-3.0-only. The Semplifica wordmark and logo are trademarks; see NOTICE.md. The full licence text is now also available in-app under Settings → Licenza.
v0.3.2 — tool iter cap, Ollama probe proxy, biometric icon
Three independent fixes in one release.
Fixed — chat stops with "too many tool iterations" on multi-doc workflows
Reported on Gemini 2.5 Flash with a medical-anamnesis workflow attached to ten clinical-record PDFs: the model called read_document on a couple of files, then aborted with "stopped: too many tool iterations". MAX_TOOL_ITERATIONS = 5 in src/routes/chat.rs was a holdover from single-doc debug runs; legitimate due-diligence / medical-anamnesis flows need 5–15 source-doc reads before composing the answer. Bumped to 20 — bounds a runaway loop at ~20× the per-turn latency while comfortably covering ten-doc anamnesis flows. Fix applies to every LLM that does tool-use (Gemini, Claude, OpenAI, local Ollama / vLLM, …).
Fixed — Settings → "Modelli LLM" probe CORS-blocked
The Settings page used to issue fetch(${base}/models) directly from the WebView origin http://tauri.localhost. External Ollama / llama-server / vLLM instances rarely whitelist that origin, so the browser blocked every probe with the "No 'Access-Control-Allow-Origin' header is present" message and the model dropdown stayed empty.
- New backend endpoint
GET /models/local/probe?base=…&api_key=…does the server-to-server fetch (no Origin involved → no CORS) and returns the upstream payload verbatim, plus typed error fields (upstream_status,error). ModelsSection.sveltenow goes through the proxy instead of fetching the runtime directly.- The chat path was never affected — chat-time LLM calls already go through the Rust
reqwestclient.
Fixed — biometric unlock dialog used a hand-drawn fingerprint
BiometricPrompt.svelte rendered its fingerprint via seven inline SVG paths. The result looked off-centre and hairline-thin against the brand-500 background and didn't match the lucide-svelte icon family the rest of the app uses. Swapped for <Fingerprint size={40} class="text-(--color-brand-500)" /> from lucide-svelte. The currentColor inheritance preserves the brand-tint behaviour, so no styling change at the call site.
Installer artefacts
MikeRust_0.3.2_x64.msi— Windows x86_64MikeRust_0.3.2_arm64.msi— Windows ARM64
See HISTORY.md for the cumulative v0.2.x → v0.3.x timeline.
release: v0.3.1 — bundle JSON config registries in the MSI
Configs, workflows, templates were missing.