Skip to main content
CHANGELOG

What shipped

Released versions only, generated at build time from the product Keep a Changelog file. Unreleased work is not listed here: if it is not in a version heading, it has not shipped.

Latest released v3.23.4 · · 61 releases

Currently downloadable v3.25.2-preview.1 · preview channel

Those are two different questions. This page lists versions that have been released, from the product changelog. The download page serves whatever the live preview channel points at, which moves ahead of the last released version with every build. Download the current build from /download. Channel and exact version always come from the live release manifest.

Releases 1–5 of 61

Page 1 of 13

v3.23.4

Added

Fixed

  • Packaged updater self-version. The bundled runtime manifest now consumes the same build-time version injection as nala version. Installed copies no longer fall back to 3.20.0 and repeatedly offer their own release; missing build metadata is reported explicitly as 0.0.0 instead of silently impersonating an old version.

v3.23.3

Added

Fixed

  • Update-origin continuity before the custom domain launches. Website installers now persist the exact credential-free HTTPS origin that served the verified release. Nala Desktop and nala update honor that marker after an explicit environment override, so installations from the temporary Railway hostname continue receiving preview notices without weakening origin validation.
  • Shipped dependency advisories. Electron, the Model Context Protocol SDK and its HTTP stack, Vite, and PostCSS were advanced to patched versions. The installable production dependency tree now reports zero known vulnerabilities through npm audit --omit=dev.

v3.23.2

Added

  • Website-backed native updates on Windows, macOS, and Linux. Desktop and nala update now consume the same strict preview/stable release manifest as the download site, pin the selected version, enforce bounded downloads plus exact byte length and SHA-256, verify Authenticode or macOS trust when the release claims a signature, and launch only the validated native artifact. Update checks stay non-blocking and installation remains an explicit two-step user action.
  • Release-channel continuity. Site installers persist whether an installation came from preview or stable, and both Desktop and the packaged CLI honor that preference without silently crossing channels. NALA_UPDATE_ORIGIN remains available for HTTPS staging and loopback tests.

Fixed

  • Packaged Desktop/Agent launch handoff. The installed CLI now carries the desktop executable path, supplies complete workspace activation parameters, strips Electron CLI-only environment flags before launching the GUI, and supports nala desktop --agent as the combined Desktop-with-active-agent choice advertised by the installer.
  • Updater restart races. Renderer controls no longer relaunch the application independently while the main process is launching a native installer or atomically replacing an AppImage.

v3.23.1

Added

Fixed

  • task_id path-traversal guard (ORCH-008a). taskDirLayout/taskPromptRelPath (A2A reliability file-backed task store) joined task_id into a filesystem path with no validation. The only current caller always mints a safe UUID-based id, so this was latent rather than exploitable today, but any future caller passing a raw id could have escaped .nala/tasks/ via ../path separators. Both now reject empty ids, .., path separators, and null bytes.
  • install.ps1 printed a blank/garbled Authenticode failure reason (CLI-013). The abort path referenced $_.Status/$_.StatusMessage (unbound outside a catch block) instead of $sig.Status/$sig.StatusMessage, the actual signature-check result two lines above.
  • Packaged CLI version 0.0.0, take two (CLI-008 hotfix). The v3.23.0 fix for this was itself broken: it swapped a runtime readFileSync for a runtime require('../../../../package.json'), but esbuild bundles every CLI module into one file, and after bundling __dirname resolves to the bundle's own directory (dist/cli-bundle/ / resources/cli-bundle/) for every merged module, not each module's original source path — so the relative require still found nothing in a packaged install. Fixed properly by injecting the version at CLI-bundle build time via scripts/build-cli.js (new — mirrors the already-correct scripts/build-mcp.js esbuild define pattern) as process.env.NALA_VERSION; nala version / nala doctor read that first, falling back to the require only for the dev/vitest path where it's genuinely reachable. Verified against the actual bundled output copied to an unrelated directory (not just the dev tree).
  • nala version's daemon column always showed "(unreachable)" even when the daemon answered. It read ping.version, but daemon.ping has never returned a version field — only spawnedByVersion (see src/daemon/index.ts). Now reads the field that actually exists.

v3.23.0

Added

  • NALA Crew Mode (optional orchestration). Progressive workflow for the existing NALA agent: /crew, /scout, /ship, /review, /operate, /brief, /afk, /stow, /recover; daemon MissionSupervisor + crew.* RPC; progressive skills; status-bar Crew shortcut (hide ≠ disable). Does not alter YOLO. Not always multi-agent — one worker when enough.
  • Free product + managed credits foundation. Explicit funding modes (existing_agent_subscription / byok_api / local_model / nala_managed / hybrid_with_approval), machine-enforced free-product boundary (free routes cannot open credit reservations), integer microdollar credit ledger with reserve/settle/idempotent payment grants, managed inference estimate + receipt types, offline-safe cloud control-plane stub. Core local/BYOK use stays free; NALA charges only for optional NALA-hosted services. See docs/product/NALA_FREE_PRODUCT_CONTRACT.md and src/shared/nala/managed/.

Changed

  • Product positioning: free & local-first. README, marketing context, and recovery UI now state clearly that NALA itself is free (MIT), requires no NALA subscription or cloud account for core use, and that only third-party agent providers bill under their own accounts. Reset/export copy no longer implies a NALA billing subscription.

Added

  • Terminal / agent voice foundation (daemon-owned). Desktop-closed TTS via system speech (nala speak, TUI /speak, bark play fallback); STT via daemon portable faster-whisper host (nala dictate --wav); cross-client speech claims; speech sanitization policy; nala voice status|test; doctor voice section; Pi nala_speak tool. Live mic capture helper and daemon Kokoro deferred (Desktop PTT/Kokoro remain for highest quality).
  • Job / career application workflow for the NALA agent. Progressive skills (career-profile, direct-job-search, tailored-cover-letter, application-prep) plus a Pi coordinator (/apply, /jobs, /career-profile, /application-review) and shared deterministic library under src/shared/nala/jobs. Supports resume ingest (including minimal DOCX OOXML), hard criteria vs preferences, direct-employer / ATS discovery filters (Indeed/LinkedIn excluded as final destinations when requested), cover-letter factuality gates, form field plans with voluntary demographics left blank, and a review queue that never auto-submits. Synthetic portal fixtures cover Greenhouse/Lever/Ashby/Workday-style forms, CAPTCHA blockers, and expired postings.
  • Kimi Code (Moonshot) first-class provider. Status-bar launch button with the official Kimi brand mark from kimi.com, Settings visibility toggle like other agents, discovery of the kimi / kimi-code binary, YOLO via --yolo when NALA policy allows, optional -m model selection (including Kimi K3 when the runtime exposes it), plan mode via --plan, and Windows KIMI_SHELL_PATH injection when Git Bash is present. No second YOLO switch.
  • Cross-platform unsigned release readiness. Architecture maps (runtime, packaged resources, native deps), process-tree termination helper, multi-platform managed Node targets (win/mac/linux archives), Windows portable ZIP maker, multi-OS GitHub Actions package matrix with draft-only assemble, install guides + inspectable install scripts, SECURITY/PRIVACY/KNOWN_ISSUES, unsigned preview policy and signing/update roadmaps. Production signing remains deferred; preview labeled unsigned.
  • Packaged dogfood / managed Node / capability enforcement mission. Mission ledger docs/missions/NALA_PACKAGED_DOGFOOD_AND_RUNTIME_MISSION.md, packaged dependency map, managed Node 24.18.0 policy, Windows dogfood protocol, and Windows/macOS signing decision docs. Canonical NodeRuntimeResolver + integrity-gated managed installer (no PATH mutation). missionCapability context builder, MCP tool map, permission preview, and spawn-path enforcement via the evaluator (YOLO preserved). MCP registration writes absolute Node when resolved. nala doctor reports node source/version, capability health, and signing mode. scripts/verify-packaged-resources.mjs + packaged self-test helper. Signing modes: dogfood unsigned vs release fail-closed (NALA_SIGNING_MODE).
  • Sequential mission program (Missions 1–8 pack). Baseline ledger, capability matrix, YOLO map, contracts inventory, and scripts/mission-baseline-harness.mjs under docs/missions/. Runtime Mission 2: hidden-pane retention default on, leading-edge PTY/daemon batching, 15s liveness, snapshot force backstop, lazy Playwright connect, packaged hook bridge paths, detector/OSC hardening, windowed notifications. Mission 3: shared rpcHelpers, src/shared/atomicWrite, unified logSinkCore, renderer nalaRpc helper, nala method-set contract test. Mission 5.2 pure capability intersection evaluator. Mission 7.1 FanOut per-task prompts[]. SystemProfile gains agent concurrency tip, scrollback lines, watchdog RSS soft ceiling. Gate: passed with limitations; release decision: blocked pending packaging dogfood/signing (see docs/missions/08-release-decision.md).
  • Hardware-adaptive sizing (SystemProfile, F2.1/F2.2). src/shared/systemProfile.ts profiles host CPU count + total RAM once per process and derives a low/medium/high tier. PTY pool cap (PTYManager.MAX_PTY_INSTANCES), spawn-scheduler concurrency (SchedulerService.DEFAULT_LIMITS.maxConcurrent), and the default scrollback ring-buffer size (daemon/config.ts bufferSizeMb/bufferMaxMb) now scale with the tier instead of a fixed constant. Medium tier matches the prior fixed values exactly, so typical hardware sees no behavior change; a low-end device (≤2 cores or ≤4GB RAM) gets a smaller pool/buffer instead of thrashing under workstation-sized ceilings, and a high-end machine (≥8 cores and ≥16GB RAM) gets headroom to use more of it.
  • nala on PATH after every install. The Squirrel install/update hook now writes a nala.cmd shim next to the existing wmux.cmd (<root>\bin, already PATH-registered), so nala works from any terminal and directory — bare nala opens the agent, nala desktop / nala sit open or focus the full app, exactly as the site's install one-liners advertise. Launching from the home directory, its parent, or a drive root prints a peer-CLI-style warning ("⚠︎ NALA works best when run in a project directory…") and continues.
  • Oscilloscope playback visual for Read Aloud. A second animated visual — an "electric" two-post oscilloscope trace — is now selectable alongside the existing speech bubble via Settings → Read Aloud → Playback animation (Bubble / Oscilloscope / None), remembered across restarts. Both visuals resolve their colors from the live theme tokens, so either works correctly in every NALA theme. The oscilloscope's "life" (energy/glitch bursts) is entirely audio-driven — level's rate of change and onset spikes — not mouse-driven like its source component.

Added

  • Durable process diagnostics for postmortem crashes (F2.7 follow-up). Main process now writes structured JSONL snapshots under the Electron logs directory (…/logs/diagnostics/diag-YYYY-MM-DD.jsonl) for boot, memory pressure, renderer-gone, child-process-gone (GPU/utility), unresponsive, and uncaughtException/unhandledRejection — with RSS/heap/free system memory, never PTY text or tokens. Complements the daily main-*.log tee so a hard kill still leaves something greppable. Heartbeat interval only logs when under memory pressure (healthy runs stay quiet).
  • Bounded TTS model cache under ~/.wmux/tts-cache (F9.3). Kokoro / transformers.js downloads are pinned to a NALA-owned directory (instead of scattering across package-relative + HF hub caches with no ceiling). After each successful model load, stale Kokoro dtype siblings (other model_q* / model_fp* weights) are pruned when the tree exceeds ~1.5 GiB, while the active dtype is protected so the next speak does not re-download it.
  • Shared proto-pollution-safe JSON helpers (F6.9). src/shared/safeJson.ts is the single reviver used by company templates, configIO, PipeServer, DaemonPipeServer, and DaemonClient — the CHANGELOG promise to "manage in one place" is now actually landed for the hot parse paths.

Fixed

  • Promote-session cleanup removes the consumed .buf dump when the DATA-007 canonical-path fallback was used. Previously only the persisted meta.bufferDumpPath was unlinked, so fallback-restored sessions left their scrollback dump behind on disk.
  • Packaged CLI no longer reports version 0.0.0 (CLI-008). nala version and nala doctor resolved the version by reading package.json from disk relative to the bundle, which fails in packaged installs; the version is now inlined into the CLI bundle at build time.
  • AUMID icon registration fallback matches the prestart script (audit F5). main/index.ts now also accepts nala-icon.ico when icon.ico is missing, so the taskbar icon registrars can no longer disagree.
  • NALA Agent status-bar logo now matches the real product mark. The nala-agent provider button (and every other ProviderLogo render site: Settings, launch cards, approval dialog) previously drew a made-up italic "n"; it now renders the actual >n mark from the desktop/app icon (assets/icon.svg) as currentColor strokes, so it inherits the button accent in every theme.
  • Company template RPC handlers blocked the main event loop (F8.2 / F8.7). CompanyTemplateManager used readFileSync / readdirSync / writeFileSync from async pipe RPC handlers (company.save / company.restore / company.templates), so listing N templates cost N sync reads on the main process (IPC dispatch + PTY forwarding stalled for the duration). Fully async via fs/promises, with parallel load on list. Corrupt JSON is now logged instead of vanishing silently; oversized import files throw (the size guard used to collapse into a null that looked like "not found", defeating the security check).
  • Resource cleanup gaps on quit (F7.1–F7.5). Daemon shutdown now closes the shared channels/A2A AppendOnlyLog fd; main before-quit explicitly stops DaemonNotificationRouter / RemoteInboxBridge / WorkspaceContextRouter / bark bridge (previously only cleaned via onUninstall, which DaemonRespawnController.dispose() skipped) and disposes the metrics aggregator; TUI adapter closes its poll timer after app.run().
  • Removed dead duplicate company main/MCP trees (F6.10). src/company/main/ and src/company/mcp/ had no live importers — the production paths are src/main/company/* + src/main/pipe/handlers/company.rpc.ts and src/mcp/index.ts. Deleting the forks ends the second CompanyTemplateManager / WorktreeManager / PID-walk that had already drifted from the real implementations.
  • Delegation idle timeout stopped firing after the first heartbeat (F5.10). TimeLimitEnforcer.recordActivity re-armed the idle timer without the onIdleExceeded callback, so a long-running delegation could run forever once any activity was recorded. The callback is now stored on the timer and re-bound on every reset.
  • Recursion breaker half-open race (F5.11). canDelegate() now atomically claims the single half-open probe slot (previously multiple concurrent callers could all pass before startHalfOpenTest()).
  • Deferred PTY unmute could target a replacement session (F5.6). Unmute timer pins the original bridge instance, not just the session id.
  • Scheduler redeem hang could stall a wave forever (F1.10). Each redeem() is now raced with a 120s timeout so inFlight always clears.
  • ErrorBoundary infinite retry (F1.9). Manual retry is cooldown-gated and capped at 3 consecutive attempts; optional resetKeys remounts cleanly; budget resets after 5s of healthy render.
  • Daemon could crash on a write to a dead/failed PTY (F1.5). ptyProcess.write() in the SessionPipe input path was unguarded — an EPIPE from a dead PTY threw synchronously and could kill the daemon (taking every other session down with it). Now logs a warning and continues.
  • Daemon reconnect could hard-fail every pending renderer RPC call (F1.5 follow-up). registerHandlers's teardown was calling removeHandler(IPC.RPC_INVOKE), opening a gap during daemon reconnect/respawn where renderer invokes failed with "No handler registered for 'rpc:invoke'" (16 occurrences in one production log) instead of the graceful {ok:false} response the handler itself returns while the bridge is down. The register site already removeHandler-then-handle's, so re-registration never double-registers — the teardown-side removal was unnecessary and harmful.
  • Renderer autosave blocked the main-process event loop every 5s (F2.3). scrollback:dump wrote every open terminal's buffer synchronously (atomicWriteTextSync) on the renderer's 5-second crash-safety tick. Now writes asynchronously, with in-flight coalescing per surface so a slow disk can't stack up overlapping writes to the same file — a dump that arrives mid-write replaces the queued payload instead of racing a second concurrent write.
  • Stale Start Menu/Desktop shortcuts pointed at a deleted version directory ("white page" instead of the NALA icon). Squirrel installs/updates now run a best-effort shortcut repair (squirrelShortcuts.ts) that retargets any NALA.lnk with a dead target, a target inside a versioned app-*\ directory, or a missing icon back to the version-independent stub launcher.
  • Production daemon crashed at boot with EPERM writing state (F9.2). registerSessionLifecycleRpc.ts's state-dir resolver and the credential vault's storage dir fell back to process.cwd() when NALA_STATE_DIR was unset; the packaged daemon can spawn with cwd=C:\WINDOWS\System32, which is not writable. Both now fall back to getWmuxHomeDir() instead.
  • Spawn-scheduler fan-out launches ran sequentially instead of in parallel (F5.1). SchedulerService.tick() awaited each redeem() call inside its dequeue loop, so maxConcurrent never had any effect — the next launch couldn't start until the previous one finished. Now builds and starts every eligible proposal in a wave before awaiting any of them, so redemptions genuinely run in parallel up to the configured limit.
  • Two installer-hook helpers (CLI shim + shortcut repair) and the Pi runtime env-var injection silently never ran in the packaged app. All three were loaded via a dynamic require('./relative-module'), which is invisible to the Rollup bundler that packs the main process into a single-file bundle — the call resolved relative to the bundle's own directory in production, where the target file doesn't exist, threw MODULE_NOT_FOUND, and was swallowed by a best-effort catch. Converted to static imports (all three modules are side-effect-free at load time, so there's no added per-launch cost).
  • The bundled CLI crashed at startup on every command. Two import-time landmines in dist/cli-bundle/index.js: (1) the nala banner read its wordmark .txt assets from __dirname at module load, but they were never copied next to the bundle — ENOENT killed every nala-routed command; the build now ships them and a missing asset degrades the banner instead of aborting. (2) update-signed was statically imported and its module graph requires electron, which throws under plain Node/ELECTRON_RUN_AS_NODE — now lazily imported only when update --signed actually runs.
  • Expired spawn proposals stayed listed as pending forever (F1.4). Nothing ever transitioned a past-expiresAt draft/pending proposal to expired; list()/listPendingApprovals() now reap them lazily on every read.
  • A crashed agent's worktree lease or delegation could stay stuck forever, permanently blocking that worktree or occupying a concurrency slot (F1.6/F1.7). Orphan-lease and stale-delegation recovery only ran lazily (on the next attempt to touch the same resource) or at daemon boot/sleep-resume. Added a periodic (10-minute) sweep for both — deliberately using pure wall-clock checks (heartbeat timeout, taskRuntimeSec age) rather than the full boot-time recovery path, since the latter also resets every still-alive agent's session status and would wrongly clobber a live agent if run on a plain timer with no actual restart/suspend.