What's New in v0.4.10
🇧🇷 Versão em português · 📋 Full CHANGELOG · 📦 Download
A stable release of October 25, 2026 — replaces v0.4.9 as the latest
release. Validated as rc1 (10/23) and rc2 (10/24); the fixes found during the
rc1 validation are all in here.
This version has three fronts. The first is the Garra Desktop coming out of its shell: the app gains a First-Run Assistant — a five-screen wizard in pt-BR that installs, pairs WhatsApp by scanning a QR code and gets the user talking without ever opening a terminal — and the installers now ship a private Node runtime (downloaded with GPG + SHA-256 verification), with installer smoke tests on all three platforms running in CI.
The second is the product learning to explain itself: the binary now
ships a versioned feature catalog (the garra_capabilities tool), the gateway
gains a native read-only diagnostic (garra_diagnostics), and the project
publishes a Docusaurus documentation site on GitHub Pages, generated from
the markdown that already lives in the repository.
The third points toward the Garra Cloud: the foundation of the billing
schema lands (plans, subscriptions and invoices per tenant, ADR 0026 — no
pricing is defined in this MIT repository) and the D1/D3a/D9 dogfood gate
becomes a CI job (dogfood-linux.yml).
Rounding it off: a wide band of fixes — installers no longer fall onto a
prerelease, voice with the official Chatterbox, a desktop that leaves no
orphan processes, Docker builds with the third_party/ forks, honest
diagnostics on a fresh install — and the security batch: revocation of the
privileges migration 007 leaked, wasmtime 49.0.4 (a critical RUSTSEC), and
jsonwebtoken switching its crypto backend to aws_lc_rs, which drops twenty
crates from the RustCrypto chain in the lockfile.
The desktop installs, pairs and chats without a terminal
- First-Run Assistant (#1636, slice 3). On first launch, the Garra
Desktop opens a five-screen wizard in pt-BR — Welcome → Mode → QR →
Personality → Done. The QR is rasterized on a canvas from the NDJSON matrix
emitted by the
garraia whatsapp link --machinesidecar (slice 1) — the raw payload (the credential) never reaches the webview. The "own number" vs "dedicated number" choice persists inonboarding.jsonand stays configurable later under Settings → WhatsApp. - Mode and personality mapping into the config (#1636). "My own number"
applies
whatsapp access open --yes, only with the user's explicit confirmation; "Dedicated number" applieswhatsapp access restrictedandwhatsapp allow <personal number>(the personal number must be authorized, otherwise the gate would hold zero allowees and silently drop the owner). No security default is loosened silently; the persona becomesagent.system_prompt, and the wizard only writesconcluido— and restarts the gateway — after every step exits 0. - Hardened webview (#1636). A restrictive CSP in
tauri.conf.jsonand all desktop JS moved to external files, no inline scripts; the wizard gets its own minimal capability, outside the broaddefault. - An honest "Done" screen (#1700). With no LLM provider in the config,
the assistant warns before the first unanswered "hi", with the path to
garraia init(and the Windows path) — the key never crosses the webview. Choosing the provider inside the assistant is deferred to 0.5.0. - Private Node runtime bundled in the installers (#1636, slice C). The
Windows MSI/NSIS, Linux
.deb/AppImage and macOS DMG/.appnow carry Node v24.22.1 LTS and the pre-built WhatsApp bridge — no Node/npm to install and no dependencies to download on first run.docs/desktop.mddocuments the per-format layout, uninstall and what remains (~/.garraia/whatsapp/is preserved). - Clean-environment installer smoke in CI (#1636). Per-platform jobs
extract the tree into a path with a space, hide every global Node from the
PATHand requirenode_origin == private+self_test == okfrom the installed sidecar; sibling jobs cover app launch (/api/healthwithin 15s), upgrade (v0.4.9 → new, session survives) and uninstall (user data preserved).
The bridge's private Node, verified end to end
- Verified build (#1636, slice B).
build-node-runtime.shdownloads the OFFICIAL Node artifact, proves provenance via GPG against the release team's keys vendored in the repo (fingerprint allowlist, isolated GNUPGHOME) and integrity via SHA-256, builds the bridge with the tarball's own npm, and generatesTHIRD_PARTY_NOTICES.txt+manifest.json. Thenode-runtime.ymlworkflow also proves the rejection of tampered artifacts or SHASUMS. - Node by explicit path (#1636). The order is
GARRAIA_NODE_BIN→ the private Node next to the running executable →PATH, always by absolute path, without touching the processPATHor replacing existing installations; CLI and gateway share the resolver and record the origin (env/private/path). garra whatsapp self-test [--json](#1636). Imports Baileys/pino/sharp with no socket and no pairing, and reports the Node origin, path and versions — the smoke the installers run without a global Node.- NDJSON pairing:
garra whatsapp link --machine(#1636). One line per event (status,qr,error,log), the QR as a0/1matrix from the same engine as the terminal, the raw payload never printed, errors and exit codes identical to the interactivelink. Built for the desktop app to consume as a sidecar (seedocs/whatsapp.md, "Machine mode"). - Robustness details.
npmis only required when there are dependencies to install; the pre-built bridge tree is seeded when it matches thepackage-lock.jsonembedded in the binary; and the onboarding state machine lives ingarraia-desktop-core— pure logic, CI-tested, no Tauri.
The product explains itself
- Versioned feature catalog embedded in the binary (#1670). The Garra
answers what it can do from the
crates/garraia-gateway/assets/catalogo-funcionalidades.jsonmanifest, embedded viainclude_str!— it works even on a clean install, without a repo clone. Each feature carries a short description, prerequisites, limitations and state (available/configurable/optional), with a feature/config marker for what depends on compilation or a switch. The newgarra_capabilitiestool (filters byname/category; without filters it returns counts only) and acatalogsection ingarra_status. Under a restricted turn it returns only what the permission allows. - Native, safe diagnostics (
garra_diagnostics, #1669). A structured, read-only report of the installation itself — version, gateway, channels, MCP servers, tools, validated effective config, credential presence and ORIGIN (vault / config / env, never values), a redacted sample of the log — with a closed state vocabulary (ok/error/not_configured/blocked/degraded/unsupported), a file jail for log reads, and access gated by operator session + turn, fail-closed. - Docusaurus documentation site on GitHub Pages (#1639). The content is
the markdown that already exists in the repository (
README,docs/**,wiki/**,CHANGELOG, ...), synced by a pure-Node script — a single source of truth, nothing rewritten by hand. Portuguese as the default language, partial English, offline search, light/dark theme, and a publish on every push tomain(https://michelbr84.github.io/GarraRUST/). It does not touchci.ymlnor the garraia.org site.
Toward the Garra Cloud
- Billing schema foundation: plan/subscription/invoice (#1652, ADR 0026).
plansis a global catalog seeded only with thefreeplan at no price (pricing is not set in this MIT repository);subscriptionsandinvoicesare per-tenant under FORCE RLS (fail-closed), money as integer cents + ISO 4217, the invoice as an immutable ledger, provider payment IDs optional and UNIQUE, never card PII. Every group without a live subscription resolves to Free, so a new tenant is born Free without touching anyone. Schema only: the Stripe/Pix webhook, entitlements, metering and the signup page are the next issues. - The D1/D3a/D9 dogfood gate runs in CI.
dogfood-linux.yml(workflow_dispatch) installs the version-pinned, SHA-256-verified Ollama, starts the server, pulls the model and runsscripts/dogfood/linux-clean-install.sh --source localagainst the candidate; the job fails if the summary says FALHOU. The lines that need two real phones remain manual by design.
WhatsApp cadence and reliability
- Cross-turn cadence guard per chat (#1650 + #1658). Past 20 admitted
turns in 60s on the same chat (configurable ceiling,
channels.whatsapp_linked.max_turnos_per_minute), the turn is cut with thepossivel loop entre agenteslog; the cut turn does not count against the window, and the chat recovers on its own once the other side goes quiet. Growing backoff per burst (60s → 120s → 240s, 8min ceiling, resets after 2min of silence) andturnos_ultima_horaingarra_diagnostics.
Fixes worth the release
- Installers no longer fall onto a prerelease through the unpinned path.
The
install.sh/install.ps1fallback now skipsprerelease: true(in addition todraft: true) and picks the most recent stable, classifying each release bytag_name/draft/prerelease. To install an RC on purpose, pinGARRAIA_VERSION=vX.Y.Z-rcN. - Voice with the official Chatterbox works again. The client discovers
the signature of
generate_tts_audio(the official app binds 7 inputs, not the 4 the client used to send — Gradio 6.x rejected the short call) and builds the call from the server's defaults, caching the signature; an SSEevent: errorbecomes a real error with the server's message, and/api/ttsand the Telegram voice channel log the reason before falling back to text. - Docker builds again with the
third_party/forks (#1694). The post-v0.4.9[patch.crates-io](tauri-plugin-updater,utoipa-swagger-ui) brokecargo chef— the rc1 Deploy published no image. The Dockerfile now copiesthird_party/, a test pins the rule on every PR, anddocker-build.ymlbuilds the image and answers/pingwhenever Dockerfile/Cargo/third_party change. - Honest
/api/diagnosticson a fresh install (#1695, #1696, #1698). Missing configuration becomesnot_configured(neutral) instead ofwarning; with nonpxon thePATHthe boot no longer provisions an MCPfilesystemthat could never start (and says how to enable it); and on Windows both sides of the path comparison go through the same canonical form, so the workspace is no longer reported as "outside the data_dir". Configured-and-broken stays yellow. - No orphans when the parent dies abruptly (#1636). On Windows, the
bridge and sidecar join a
KILL_ON_JOB_CLOSEJob Object; on Unix, their own process group +kill(-pgid)andgarra start --exit-with-parentwatching the app's PID (PID-reuse proof viagetppid()); on all platforms, EOF on stdin shuts down. Orphan tests on ubuntu/windows/macos in CI, includingTerminateProcess. - A band of point fixes. The boot probes Whisper before declaring STT
ready (
STT readyonly when the server answers); the Web Console dashboard shows the real bind instead of a fixed "0.0.0.0"; the provider selector shows the real instances (llm.<key>), not just fixed types;garraia doctorwarns when an older binary masks the new one on thePATH; the WhatsApp reconnect log reportsreason/reason_code;find_executablerequires the executable bit on Unix; the non-streaming autonomous path no longer publishes[no textual response provided by the model]; and the autoprovisioned@modelcontextprotocol/server-filesystemis pinned to@2.0.0(upstream deprecated the date-based series).
Security
- Revoking the privileges migration 007 leaked (migration 036,
forward-only). Migration 007's ALTER DEFAULT PRIVILEGES granted full CRUD
to every table created after it; nine tables carried excess
UPDATE/DELETE on the
garraia_approle. The revocation is selective — SELECT/INSERT and each table's legitimate mutation privilege remain — and the LGPD cross-tenant deletion keeps running in dedicatedSECURITY DEFINERfunctions, never through the app pool. The heavyweight case isaccount_deletion_requests: without the revoke, a handler could mark a request as completed without the purge. jsonwebtokenswitches its crypto backend toaws_lc_rs(#1701). RUSTSEC-2026-0387 has no fix inrust_crypto(a monolithic feature) and the code only uses HS256/RS256 — the entire RustCrypto EC/RSA chain (20 crates, including the vulnerablecrypto-bigint, only fixed in 0.7.6) leaves the lockfile with no exception indeny.toml/audit.toml. The documented trade-off:aws-lc-syscompiles native C (cmake + perl).- The wasmtime family at 49.0.4 closes RUSTSEC-2026-0379 (critical) and
RUSTSEC-2026-0378 in the plugin sandbox;
rustls-webpki0.103.16 andwebpki-roots/webpki-root-certs1.0.10 close RUSTSEC-2026-0381/0382/0383;ctutils0.4.5 closes RUSTSEC-2026-0385 (non-constant-timeu128masking and comparisons) — it enters viadigest0.11, used byargon2/blake2/hmac. - Fail-closed jail for filesystem MCP tools (#1482) — a tool from the filesystem server that the confinement does not map (a new or renamed tool from a future package version) is refused instead of passed through unchecked.
- Per-orchestrator jail and workdir for the MCP HTTP
garra_agent(#1626). Each orchestrator now gets its own writable subtree under<data_dir>/workspace, derived from its identity by digest — the single effective root of the file tools and the sandbox workdir. The jail used to be global: what one orchestrator wrote, the others could read.