# Changelog

## [Unreleased]

## [0.2.201] - 2026-09-18

### Changed

- **Parallel work no longer runs in Git worktrees.** A session or worker that needs to write gets its own private workspace instead: real files, materialized by a native volume clone where the filesystem offers one and by an independent copy otherwise, tracked by Unary's own content store and catalog rather than by Git plumbing. Git keeps exactly the jobs it is good at — history, remotes, and the branches you create yourself — and it is no longer asked to isolate concurrent agents, which is where the old automatic worktrees kept getting stuck: a tree that could not be folded back left work stranded behind a merge conflict nobody asked for. Manual worktrees you create stay untouched and keep their own vocabulary.
- **Finishing work is now "Smart Merge to Parent".** A private workspace submits a candidate that is built against the parent's ACTUAL current state; if the parent moved in the meantime, the candidate is prepared again instead of applied blindly. A conflict hands over the complete package — base, your version, the target version and the affected paths — so the later contributor resolves it with full context, and there is no partial apply. Every integration leaves a receipt naming its base, contributors and what was deliberately excluded, and repeating it is idempotent rather than a second effect.
- **Interrupted work is recoverable instead of lost.** Crashes, takeovers and cancelled workers leave a visible waiting state with its own recovery step; a coordinator takeover fences the old owner and quarantines generations whose processes may still be alive rather than killing them, and unknown liveness always keeps the data.

### Fixed

- **A paused worker is no longer killed for its supervisor's scheduling latency.** When the watchdog suspected a worker had stalled it paused it and asked you to decide — and then gave that pause five minutes to live, measured from the moment it started. But only the session itself can answer such a question, and it can only answer between turns: a long model reply, a batch of tool calls, a compaction or its own wait on other workers eats those five minutes effortlessly. In one measured 19-hour session that single rule destroyed 13 workers whose context was completely intact, every one of them while the session was 5 to 18 minutes deep in other work, and the session had already started polling its workers every 10 to 240 seconds purely to beat the clock — roughly one in seven of everything it did was bookkeeping against this deadline. The clock now starts when the decision actually reaches the session's queue rather than when the pause begins, then runs for 30 minutes, with a one-hour backstop so a session that never wakes at all still cannot pin a worker forever. Nothing about a worker that really is stuck has been relaxed: the repeated-identical-step signal still pauses it immediately.
- **A finished session showing “busy” forever is fixed where it was caused.** That spinner was what the five-minute rule above had been introduced for, and it came from counting paused workers as unfinished execution. A worker waiting for your decision is now counted as exactly that — waiting for you — so the session settles on its own and no worker has to be terminated to stop an animation.
- **A worker in the middle of an expensive step is no longer mistaken for a dead one.** Pausing a worker is delivered as a live interrupt with a quarter-second window to acknowledge, and three unanswered attempts used to be treated as proof of death. A worker deep in a long reasoning call cannot answer in a quarter second no matter how healthy it is, so the most expensive steps were the likeliest to be aborted — 10 further workers in the same session. Termination now additionally requires that the attempts span at least a minute and that the worker is not observably alive.
- **A retry no longer starts with the budget that just proved too small.** A worker that ran out of its time or token ceiling was restarted with exactly that ceiling, so the second attempt spent a full budget arriving at the same wall. Retries after that class of failure now start with a larger allowance; a worker that failed on the quality of its work keeps its original budget, because the budget is not what it failed on.

## [0.2.200] - 2026-09-18

### Fixed

- **A project's sessions are visible again after a branch switch.** The Desktop sidebar routes a project's sessions through three renderers — worktree rows, branch groups, and the flat list — and two of them could hand a session to nobody. `groupSessionsByBranch` dropped every pair whose isolated workspace looked like a managed or foreign worktree, which is correct only while a worktree row actually renders it: once that tree was folded back and removed, no row claimed the session, and because it still matched its project by cwd it never reached the unassigned bucket either. On top of that the flat list and the branch grouping read different sets — the flat list took `activeSessions`, the grouping also took the worktree sessions no row had claimed — while `groupByBranch` requires MORE THAN ONE branch group. A checkout that moved to a new branch therefore marked every session recorded on the old branch as detached (`isDetachedFromMainCheckout` compares the recorded branch against the live one), collapsed them into a single group, and rendered neither that group nor those rows: the project kept its count badge and showed almost nothing. Sessions are now excluded from branch grouping only by the ids the caller says it already renders, and one `planSessionRendering` decision names the renderer AND hands it the exact set, so a pair cannot fall between the flat list and the branch groups.

## [0.2.199] - 2026-09-17

### Fixed

- **Worktree return now explains why it is blocked instead of silently giving up.** Recovery tools can reconnect a session to its own recoverable worktree while preserving files and commits. Ambiguous cases remain safely blocked rather than being reported as a successful return.
- **File claims now follow completed turns and workspace changes promptly.** Older operations no longer overwrite newer ownership or erase the next writer's claim. Uncommitted changes remain tracked separately from active editing.
- **Chat shows a compact return-status box instead of a perpetual “Folding back…” label.** It displays reported blocking files, owners, conflicts and next steps. Queued returns are not labelled as running, and failed refreshes leave the last report explicitly unconfirmed.

## [0.2.198] - 2026-09-16

### Fixed

- **A branch switch reaches the session list at once instead of up to a minute later.** The Desktop sidebar groups a project's sessions by the branch its checkout is on, but the workspace state relay had exactly one branch-shaped kind — `branch-deleted` — so the most common branch event there is, a plain switch, had no producer at all and the 60 s poll owned the branch subgroup alone. Every checkout path in `crates/unc_rust_workspace/src/git.rs` now reports `HeadChanged` with the new branch, and a switch made OUTSIDE Unary (a terminal `git checkout`) is picked up by a new host HEAD watcher: one non-recursive watch of each registered project's git directory — never the HEAD file itself, whose inode git replaces on every switch — reading the branch out of HEAD rather than spawning `git`, reporting only when the branch actually moved. The sidebar registers the projects it shows (bounded at 64, idempotent, advisory: an uninstallable watch leaves the poll as the backstop), and because the event carries its root, the refresh re-reads ONE project's branch instead of spawning `git branch` per project.
- **The first workspace-state event of a burst no longer waits out its own debounce.** `workspace-state:changed` was purely trailing at 250 ms, so a fold-back, a worktree removal or a branch switch spent a quarter second doing nothing before the sidebar even started a worktree measurement that costs seconds. The channel now has a leading edge with a 250 ms throttle, so the burst still collapses to one additional refresh and the first one is immediate.

## [0.2.197] - 2026-09-16

### Fixed

- **A session working in its own worktree no longer asks the user to fold back work the harness is already folding.** The only fold-back text a session ever saw is resolved from a path on every catalog rebuild and may not spawn `git`, so it was state-blind — and it named the user-facing fold-back control beside the automatic path. A session that had finished its work read that as the user's next step and reported the fold-back as homework, while the pending row for its tree was `waiting-owners`/`automatic-transient` with the watcher armed, retrying by itself, waiting only for a foreign live session to release the files it still held. Nothing was stranded and nothing was owed. The live row now rides in the per-request `[Session facts v1]` tail — state, classification, watcher, attempt count, blocking file count and owner — where `waiting-user` is the only state that names a person, `waiting-agent` points at the machine assignment, and an unreadable store reads as "nothing pending", never as "a person must act". The path-derived note no longer mentions the user-facing control at all, because a model that never hears about it cannot hand it over as a task. The pending-fold-back store is read only for a cwd that already has the managed worktree shape, so an ordinary session pays no per-request disk access.

## [0.2.196] - 2026-09-16

### Changed

- **Codex Voice is a voice device now, not a second agent.** It was ported from the Codex CLI with the CLI's own architecture: the realtime model was the conversational front, it owned a `background_agent` tool and a delegation channel, and it handed work to the coding session while it kept talking. That shape shipped a second prompt source — the composer already sends the finished transcript as a user message, so one utterance could reach the session twice — and it made the model's own reasoning and progress chatter audible. The realtime session now only transcribes and reads out. Speech in becomes an ordinary user message to the session model; the only thing ever spoken is that session's finished answer, markdown-stripped, at the real end of the turn — never reasoning, never tool output. No protocol version advertises a tool, a `tool_choice` or a `delegation` target any more, v2 sets `turn_detection.create_response: false`, and a speech gate drops every output audio frame and output transcript that no read-aloud request asked for — including on the WebRTC route, where the composer bar mutes the remote audio element unless that gate is open. The `delegationAckFiller` setting is gone; `speakReplies` now means "read the session's answer aloud", and dictation stays input-only.

### Fixed

- **A spoken reply no longer depends on a system notice arriving.** The desktop live feed's end-of-turn speech hook sat in the `system_notice` branch, so a voice plugin read an answer out only when a notice happened to land with that turn and most turns stayed silent. It runs on `agent_end` now, for both voice plugins.

## [0.2.195] - 2026-09-16

### Fixed

- **A worker that had already finished no longer buys a supervision decision turn.** The stall watchdog treated an unreadable sample as a stalled worker: a contended child-snapshot lock — or no active handle at all, which is exactly what a worker writing its handoff looks like — left every evidence field at its default, and the ladder read those unmeasured zeros as "nothing happened", parked the worker, interrupted its active step and woke the parent for a decision. The report then printed `childProcessRunning=false, newOutputBytes=0, filesChanged=false` for measurements it never made, which reads exactly like a real stall. An unobserved sample now yields a check-in and can never nudge, park or terminate; the report prints `snapshotAvailable` and `unknown` for every unmeasured field; a worker whose completion slot is already claimed is skipped entirely; and a park interrupts the child only on loop evidence, because aborting the active step of a merely slow worker destroys the step it was in the middle of.
- **A supervision decision the parent can no longer act on is withdrawn instead of delivered.** Staleness was checked only where the decision notice was enqueued, never between that enqueue and the queue drain — so a worker that terminalized seconds after its park still woke the parent, for work whose patch was already applied. The queued wake is now retired by its deterministic id prefix as soon as the record stops awaiting a decision, and the resolution is stamped rather than deleted: resume no longer erases the decision it answered, a cancelled record records `Closed`, any other terminal state records `WorkerTerminal`, and every resolution word now has exactly one production writer.
- **File and commit progress are no longer invisible for a whole window after each commit.** The comparison was gated on a non-empty previous fingerprint, so the clean tree that follows a commit — the strongest progress evidence a worker can produce — reported "nothing changed", and a worker without a worktree reported it forever. An unknown baseline is now `unknown` instead of `false`, and a growing message stream with fresh activity withholds the first decision rung's park for a worker that is reading and planning rather than looping.

## [0.2.194] - 2026-09-14

### Fixed

- **A provider pack's own base URL survives the settings pass.** The pass that applies `settings.json` calls `set_provider_base_url(provider, None)` once per provider entry (`None` for an entry that carries only `enabled`/`visibleModelIds`), and `None` means "clear the override". A provider that lives in a pack has nothing to fall back to — it has no entry in the static built-in default table — so the clear wiped the URL the pack declares, on the provider config and on every model row, and the session-level setter did the same to the active model. Every later request then failed with `UnsupportedApi`, "provider … with api … is not implemented in Unary yet", while the dialect, the credential and the pack were all fine and only the endpoint was gone. Both setters now reset to the URL the provider was registered with (the pack's URL first, then the static built-in default), and a provider whose URL exists nowhere else keeps what it carries.
- **DeepSeek requests now match the provider's current wire contract.** The official endpoint receives `max_tokens`, native `low` effort stays low, and Strict Function Calling is no longer advertised on the non-beta endpoint. Thinking requests with tools omit the `tool_choice` field that DeepSeek rejects even when it is `"auto"`; reasoning-content replay remains intact. HTTP 402/422 and `finish_reason: "aborted"` now take their deterministic billing, request-body and cancellation paths instead of generic retries or errors.
- **A silent or keepalive-only provider stream no longer looks productive for five minutes.** Unary tracks bytes, complete SSE frames, valid JSON and semantic events separately, applies a bounded first-semantic-event deadline, and reports only sanitized counters and elapsed times. This makes an upstream inference stall distinguishable from authentication, request validation and a disconnected socket.

## [0.2.193] - 2026-09-14

### Fixed

- **A model from a provider pack can now actually run.** Listing a pack's provider was only half the path: five production sites still resolved the *model* through the compiled-in catalog, which by construction cannot contain a model that only a pack contributes. Selecting such a model therefore failed at execution time instead of at selection, with a misleading "provider … with api … is not implemented" error. Model resolution now uses the runtime registry, like the provider list already does.

## [0.2.192] - 2026-09-14

### Fixed

- **A provider added by a provider pack now exists in the app at all.** The provider list was built from the built-in, compiled-in catalog, which by construction cannot contain a provider that only a pack registers. A pack under `~/.unary/extensions/<extension>/providers/*.pack.json` loaded cleanly, registered its provider in the runtime registry, and resolved its models there — but the one list the settings dialog renders and every model picker filters never saw it, so a self-added provider was invisible everywhere at once with no error anywhere. That list now comes from the runtime registry.

## [0.2.191] - 2026-09-14

### Fixed

- **A provider you added yourself now appears in the model pickers.** A provider contributed by a provider pack (`~/.unary/extensions/<extension>/providers/*.pack.json`) starts life without an entry in `settings.json` — it cannot have one before it is first visible enough to be edited. The provider list treated that missing entry as "not configured" and overwrote the verdict the credential store had just given it, so a provider with a working API key was listed in Settings but absent from every model picker, the agent-mode model list, research and plugin model selection. A missing entry now means "enabled with defaults", exactly as it already did for local providers; switching a provider off explicitly still switches it off.
- **The Open IDE button no longer opens a half-finished second app.** It is disabled with a "Unary IDE — coming soon" tooltip while the Desktop app is the only surface under development.
- **The pinned chat header keeps naming the newest request while you read back through a long session.** Reading older history prepends pages and evicts the tail, so the loaded window stops holding the newest real human request while it still holds older user rows — and the header answered with the newest row the window happened to contain. At the top of a long conversation that is the FIRST request, which is what the header then showed instead of your last one. The authoritative anchor now owns the identity whenever that request sits outside the loaded window on either side, and only hands it back to a loaded row while the anchor itself is inside the window.
- **Saving settings can no longer lose the settings file.** The writer rendered the new state to a `.tmp` sibling and then, on Windows, DELETED the live `settings.json` before renaming the temp onto it — and deleted the temp too when that rename failed. A process terminated inside that window, or a rename the OS refused, left no settings file at all: the app then started on defaults, silently, with every provider, model-visibility and MCP entry gone and nothing in the log. The rename replaces the target directly now, transient sharing violations are retried, and a refused replace keeps both the previous file and the pending copy, naming the latter in the error. The same delete-then-rename shape is gone from `editors.json` and the IPC registry.

## [0.2.190] - 2026-09-13

### Fixed

- **Worker admission and execution use the same resolved account.** Account-specific rate limits are checked before a worker starts, credential binding is acknowledged by its session actor, and resume prepares against the actual child model rather than a potentially stale role default. Bound workers reject unrelated key overrides while retaining refreshed tokens for their admitted account.

### Added

- **A session can move itself into an existing worktree.** When a worktree already exists — created from the Worktrees panel, by an earlier turn, or by another session — the agent can now relocate the session into it (`session` action `switch_workspace`) instead of writing into that tree from the main checkout, where the system prompt names the wrong directory, `search` treats the gitignored `.unary` tree as out of scope and `git` keeps reporting the other checkout. The target must be a worktree of the session's own repository: a bare repository, another repository and a plain directory are refused with the session left exactly where it is. The next tool call already runs in the new tree; the working directory and system prompt follow at the turn boundary (one prompt-cache invalidation). A move back to the main checkout is the same action. The Worktrees panel offers the same move for the focused session, and a session moved into a branch-named tree keeps its Goals board instead of re-keying to an empty one.

### Changed

- **The live canary no longer requires a USD ceiling.** Cost limits apply only when explicitly supplied; missing cost measurements remain visible. This does not claim a completed 24-hour endurance test.

- **The chat header's worktree button now opens a dialog with a generated branch name.** One click on the branch icon opens "Create session worktree" with the managed `unary/session-<word>-<word>` name prefilled — two words instead of the session-id hex — and the name stays an ordinary editable input. The managed destination folder is shown read-only, Create stays disabled on an empty name, a collision with an existing local branch gets a numeric suffix, and a failure appears inside the dialog instead of a chat entry. The branch pill's inline form keeps its own path; both run the same create flow.

## [0.2.189] - 2026-09-13

### Fixed

- **Starting one session no longer blanks the whole "Needs attention" group.** A project the worktree overview could not measure — cut off for budget, or because `git worktree list` raced the fold-back that a session start sets in motion — arrived as `truncated` with empty rows, and both the Desktop sidebar and the Sessions dock treated that emptiness as the truth: every row of the project vanished, including trees nobody had touched, and nothing pulled them back until an unrelated refresh. One shared rule now folds every overview answer in (a truncated project keeps the rows it had), the sidebar retries a raced measurement a bounded number of times, the backend keeps its fallback snapshot across the invalidation a fold-back performs, and a failing listing reports Git's own reason instead of an empty list. The dock's notice also stops calling every truncation a time budget.

- **Close and maximize can no longer be pushed out of any dialog header.** The window controls now live in their own fixed track next to — never inside — the shrinkable action row, so a dialog whose action row is too wide clips that row instead of spilling over its own controls.

- **The image viewer's close button can no longer be pushed out of its header.** The dialog title grew to absorb the header's leftover space while the action row — zoom group, Regenerate region, Show in File Manager — asked for the same leftover with a zero flex basis, so the two split it and the actions box landed short of its own rigid content. The row spilled past the panel's right edge and the header's clip ate the window-control group first: a detached image window had no visible X, even though the button was in the DOM and focusable (measured live — the close button laid out at x=1908..1951 on a 1904px-wide window). The title now takes its own width and the actions row owns the leftover — the same rule and the same reason the file preview has carried since 2026-09-08.

- **The pinned chat header now always names the newest user message instead of the one before it.** The header resolved its identity from the scroll position — "the newest user row that has left through the top edge" — so it kept naming the previous request for as long as the newest one was still on screen, which is exactly the state right after sending, and it named an older message again whenever you scrolled back through the transcript. The identity is now the newest real human request (the newest loaded one, or the authoritative anchor when that request is outside the loaded window), and the measurement decides one thing only: whether that request's own row is on screen, in which case the header stays hidden rather than duplicating a message you can already read.

## [0.2.188] - 2026-09-12

### Changed

- **Maintenance release — no user-visible behavior change.** The runtime is the same code 0.2.187 shipped; the only committed difference is the documentation for how a compacted session is handed back, re-measured and corrected.

## [0.2.187] - 2026-09-11

### Fixed

- **An image produced by a tool now reaches the model on every dialect that can carry one.** A `read` of a PNG, a snip capture or a screenshot arrives as a tool-result block, and the OpenAI Responses family, Amazon Bedrock and LM Studio each discarded it with no error and no note — while the same picture attached to a chat message went through. That asymmetry is why the complaint reproduced on one provider and was impossible to reproduce on another. Responses now lifts the image into the user message that follows `function_call_output`, which has no image slot of its own, exactly as the Chat Completions dialect already did; Bedrock emits Converse image blocks in user content and inside tool results, where it previously accepted only text; LM Studio carries tool-result images the same way it already carried attached ones. Where an encoder genuinely cannot carry an image, it now leaves a note saying so instead of leaving nothing.

- **One predicate decides whether a model accepts images.** The wire encoders tested for the exact capability token `image`, while the harness's own capability check also accepted `images`, any token containing `image`, and any token containing `vision`. A model the picker advertised as vision-capable could therefore have every image dropped by the encoder in silence, with the two layers disagreeing in a way neither of them could see.

## [0.2.186] - 2026-09-11

### Fixed

- **The fold-back button works again after a mid-run move into a worktree.** When a session was relocated into its managed worktree while running, the chat's fold-back button could answer with a context-free "This worktree was not folded back." because the live session handle still pointed at the parent checkout. The button now passes the worktree it already knows, and the harness accepts it as the fold target — but only when that tree demonstrably belongs to the session. A genuine refusal now names its reason instead of showing an empty dialog.

- **DeepSeek keeps its wire format behind a custom base URL.** A DeepSeek gateway reached through a reseller or a self-hosted endpoint was recognised by hostname alone, so it silently fell back to plain OpenAI semantics — `store`, the developer role and a forced `reasoning_effort: low`. The dialect is now decided by the provider id as well, so a custom DeepSeek base URL keeps its thinking format and its reasoning-effort map.

- **DeepSeek thinking turns always replay `reasoning_content`.** DeepSeek's thinking mode requires the assistant's `reasoning_content` on every replayed turn; a tool loop whose turns carried only tool calls, or whose thinking signatures had been restored or compacted away, sent none and the request failed with a 400. Such a turn now falls back to an empty `reasoning_content`, the same way Kimi's does, so the loop continues instead of erroring.

- **A tool call refused for a misplaced field now names where that field belongs.** `additionalProperties: false` is the right contract, but its own sentence said only that `maxSources` was unexpected in `config` — next to a list of valid actions, which reads as though the action were wrong. A refusal now resolves the offending value's path and names its accepted home, e.g. `config.advanced.maxSources` for a `maxSources` sent directly under `config`; a name with no home there gets the properties its node does accept instead of a guess.

## [0.2.185] - 2026-09-11

### Fixed

- **The context meter's breakdown popover opens through the shared portal anchor.** It no longer clips inside the composer on narrow panels, and the popover-position policy guard covers the component again instead of exempting it.

### Changed

- **One click from the chat header to a session worktree.** A branch icon left of the auto-commit-and-push button opens the worktree form with the managed `unary/session-…` branch name prefilled, so moving a session into its own worktree no longer needs the detour through the branch pill.

- **The IDE chat toolbar's model picker refreshes the model registry when it opens.** Newly enabled providers and models appear in the picker without restarting the app, and the same refresh backs the chat's open-picker catalog.

- **Inco Kimi K3 and GLM 5.3 expose their reasoning-effort gradient.** Both models now offer low/high/max effort in the model picker instead of hiding the control; the effort mapping follows the gateway's documented gradient and is recorded as unverified in the provider notes until a live check confirms it.

- **Qwen Cloud Token Plan is a separate provider.** It now has its own `qwencloud-token-plan` identity, Qwen Cloud credential name, catalog and provider pack instead of being represented internally as an Alibaba provider. Existing saved Token Plan configuration migrates to the new identity; Qwen Cloud Pay-per-token remains an independent provider with its own key and billing realm.

- **A successfully folded-back session carries a "Folded back" state in the session lists.** The fold stamps the session header with the moment its worktree landed in the parent checkout; the sidebar row and the sessions panel show the state word from the worktree vocabulary until you open the session, and re-isolating the session retires the state. No color coding: the state is the word, like "Not folded back".

### Fixed

- **Folding one worktree no longer blanks the whole needs-attention group.** The overview builds its rows from `git worktree list`, which answers nothing while the fold removes a tree; that empty answer was cached and served as authoritative and erased every row of the group until the next refresh. A degraded measurement now serves the previous rows (or reports itself truncated so the sidebar keeps its state), and the sidebar keeps its attention counts on transient fetch errors.

## [0.2.184] - 2026-09-10

### Fixed

- **The image viewer opens as its own window with working edit and fullscreen controls.** The Desktop chat's image dialog stayed an in-app overlay even where the app can give a dialog a real window, and the detached viewer mounted the bare shared dialog without the region editor, so "Regenerate region" handed the composer a raw image source where it expected an edit draft instead of opening the editor. The chat path now detaches first — same window, remembered size and bridged actions as every other dialog, with the web build keeping the overlay — the detached window mounts the same wrapped viewer as the overlay, and the header's zoom presets and meta row collapse via container queries at narrow widths so the edit, reveal and fullscreen controls are never pushed out of the header.

- **A session worktree fold-back completes in the installed app instead of failing forever.** The final removal step ran `git worktree remove` with the app's inherited working directory, which is outside any repository — Git answered "not a git repository" on every attempt, the fold rolled everything back, and the retry loop preserved the same tree five times per sweep, which is also why the needs-attention row kept disappearing and returning. Removal is now rooted at the parent checkout, and a regression guard refuses bare un-rooted removal calls. A successful explicit fold-back also emits `harness-sessions-changed`, so the folded session immediately appears under its project instead of vanishing from the session lists until an unrelated reload.

### Added

- **Tool failures have individual audit evidence.** Memory Errors separates recorded calls from older summaries, preserves available worker and turn identity, and shows missing evidence and export limits instead of treating recurring errors as confirmed defects.

### Changed

- **A worktree fold-back that hits a conflict is resolved by the session that owns it, not parked for you.** Closing a session, quitting, the crash-recovery sweep and the retry watcher all used to leave a conflicted session worktree under "needs attention". Every path now hands the conflict to the owning session's agent: the session is resumed if it was closed, it rebases inside its worktree, and the fold runs again in the same turn. You see a conflict only when the agent has tried and explicitly reported which file it could not decide. A worktree you chose yourself is no longer listed as needing attention while it simply waits; its `Fold back` action stays available.

## [0.2.183] - 2026-09-10

### Fixed

- **Decision cards accept JSON-wrapped question arrays.** `request_user_input` now applies the existing schema-guided argument repair before its early hook validation, instead of rejecting valid questions before the executor can repair them. Invalid JSON and invalid card content remain rejected.

## [0.2.182] - 2026-09-10

### Fixed

- **Long-running workers remain supervised and actionable.** Watchdog checks follow the next deadline, stalled workers send durable decisions to the parent without bypassing a manual Stop, and a running subprocess alone no longer counts as progress. Stale acknowledgements cannot reopen a completed worker, and temporary monitoring failures retain a bounded retry schedule.

### Added

- **The checkout remembers what happened the last time something was built.** When several sessions work in one repository, a session that hit a build error had no way to know whether the error was new, since when it existed, or that a sibling had already seen it. Every `cargo_check` and every build or test command run through the shell now records its outcome and the exact error identities into one facts-only ledger per repository (shared across linked worktrees, keyed by commit and worktree so a divergent worktree's red build is never mistaken for the parent's). The agent reads it with `diagnostics` `action=repo_ledger` — red builds, open errors with first-seen session and commit, recently fixed ones — and gets a one-line brief at the start of a turn only when the ledger changed since it last looked. Nothing in it blocks anything, and nothing is injected into another session: reaching the session that saw the error stays an explicit `session` `send_input` or `finding`.

### Changed

- **The compaction handover is a set of pointers again, not a digest.** It used to inline every assistant answer, every reasoning digest and the Goals rows three times over — while the Goals board is durable and handed over anew at the start of every turn anyway. It now inlines every failed tool use, only the newest twelve successes, the newest reasoning digest and a count for the rest, and tells the model exactly where to look for anything missing (the segment ledger, the tool result by id, the repository ledger, the other live sessions). The handover ceiling dropped from 32 KiB to 12 KiB.

## [0.2.181] - 2026-09-09

### Fixed

- **A provider you switched off no longer offers its models.** Turning a provider off in Settings left its selected models in the picker, because every path that builds that list read the visible-model selection and ignored the enabled flag. Choosing one sent the request to the provider you had just disabled — and where two providers ship models with identical names, that arrived as a bare `Invalid API-key provided.` from the wrong account.

- **A pinned model names its provider.** The pinned block is the one place a row carries no provider header, so two providers offering the same model name were indistinguishable there.

## [0.2.180] - 2026-09-09

### Added

- **GPT Image 2.5 is selectable for image generation through the ChatGPT (Codex) account.** The Codex image path sent no model at all, so it could only ever produce whatever the backend happened to default to. The image slot now offers GPT Image 2.5 Sunburst, GPT Image 2.5 Flare and GPT Image 2 under the OpenAI Codex provider, and the chosen line is sent with every generate, edit and inpaint request. Leaving the slot on the plain account entry keeps the previous behaviour.

## [0.2.179] - 2026-09-09

### Fixed

- **A tool call that dies mid-flight no longer bricks the session for good.** When a call ended without ever producing a result, the transcript's last message advertised a `tool_use` nothing would ever answer, and the provider refused every later request in that session — on every account, permanently, with `tool_use ids were found without tool_result blocks immediately after`. The encoder now completes the pairing at the end of the transcript too, so a dead call reads as a failed step instead of a wall.

- **A pending chip disappears once its message is on screen.** The chip was released only when it carried an in-memory mark that a reload — or any append path that did not go through the resolver — never set, so it sat in the composer next to the very message it was waiting for. A transcript row stamped with the chip's id now releases it, because that row exists precisely because the chip was delivered.

## [0.2.178] - 2026-09-09

### Fixed

- **Folding a session back is a decision, not a dead end.** When the parent checkout carried its own uncommitted changes in the same files, the fold refused with git's raw error, the tree parked under "needs attention", and there was nothing to act on because the decision row had just been cleared. A conflict now always names the overlapping files and both ways out, and it is offered as `Keep your version` / `Overwrite from worktree` / `Later` instead of being handed to the agent as a rebase that cannot clear a blocker living in the parent's working tree.

- **A session is no longer a foreign owner of its own work.** The fold-back asked both file-owner lookups with an empty session id, and a claim exists for every write — so every changed path answered with the folding session's own id, the tree waited for "another session" that was itself, and no other session had to be running for it to happen. This affected every session, not one tree.

- **A leftover worktree no longer folds what the parent already has.** A fold that applied its changes and then failed to remove its tree left a leftover whose content was already in the parent; git still rejected the patch because the surrounding code had moved on, so every retry read as a content conflict. Paths that are byte-identical to the parent are now dropped before the patch is applied.

- **Automatic fold-back retries converge instead of repeating forever.** The watcher re-armed the same tree every 30 seconds without a ceiling, and its salvage path rebuilt the row from the snapshot the retry started with — discarding the blockers the refusal had just recorded. Retries now stop after five identical failures and hand over a decision that still names its files.

- **A per-file fold-back decision can no longer delete unfolded commits.** `Keep your version` and `Overwrite from worktree` cover uncommitted changes only, but the path continued into worktree removal and a forced branch delete, destroying every commit the session had made. It now refuses while those commits exist and names both remedies.

- **Shell commands containing an umlaut, an accent or an emoji no longer crash the tool call.** The Windows `nul` redirect rewriter copied the command byte by byte through a string slice, which split the first multi-byte character and panicked the whole call with "is not a char boundary" — with or without a redirect.

- **The composer's Fold back button keeps its size.** With no goals, no changes and no lane to show, the status strip renders nothing and the fixed-size chip inherited the strip's growth rule, stretching into a full-width bar over the composer.

## [0.2.177] - 2026-09-08

### Changed

- **The composer's context gauge opens on click, not on hover.** Moving the pointer across the context fill ring used to unfold a 420px breakdown panel over the composer. The gauge is now a toggle: click opens it, clicking it again or anywhere outside closes it, and Escape closes it too.
- **The Memory panel's subtabs show their own content.** Review and MEMORY.md are content-connected 10px subtabs, and the MEMORY.md tab renders the complete document even when no entry maps to it.

## [0.2.176] - 2026-09-08

### Changed

- **Memory writes are immediate.** Agents can store durable repository or global knowledge directly without a review queue. Historical ungrounded candidates are not silently activated, and automatic reusable-artifact capture is opt-in.
- **Dream uses a model and a fixed interval.** A global app-owned timer classifies eligible memories across repositories with the selected model; session-end triggers are no longer needed. Failed classification preserves the previous conclusions, and Dream cannot overwrite a direct memory just because its title matches.
- **On-demand tools no longer preload their long usage guides.** MCP keeps compact tool summaries; the browser, desktop, research and memory families receive full guidance at activation. Exact names, action schemas and persistent safety boundaries remain available.

### Fixed

- Corrected the fold-back deadline watcher's weak session-registry type so the harness builds without a nested `Arc` mismatch.

## [0.2.175] - 2026-09-08

### Fixed

- **MCP tools no longer need a new session after install.** A catalog refresh (an MCP server installed, a plugin toggled, a settings write) that arrived while a turn was still running was dropped, so the new tools stayed invisible until the user opened a new session — which the install message then told them to do. The refusal is now recorded and settled at the next safe turn boundary: the tools are advertised from the next turn of the same session, and the install message says so.

- **Compaction markers say why they ran and what they freed.** A context compaction in the transcript names its trigger in plain words ("Auto-compacted", "Compacted on request", "Compacted after context overflow", "Compacted to continue the turn") and the token delta before → after. A failed compaction states that the context was left unchanged, and a marker never implies a delta it did not measure.

- **A removed file preview says why it is gone.** The browser runtime records a bounded reason for every removed preview session, so a viewer polling one that was already dropped gets the cause — a window-ownership reap versus ordinary cleanup — instead of a bare "was not found", and the reap can no longer close a session that was started after its window died.

### Changed

- **Yolo mode is permission, not minimalism.** The mode prompt said "make the smallest change that works", which read as a quality cap and produced quick fixes instead of production-ready work. It now frames the mode as pure permission — everything allowed, no gate or ceiling, plan and switch to execution — and asks for a complete, production-quality solution instead of the first patch that touches the symptom.

- **The Quick profile defers verification without lowering the bar.** The verification-policy line now states that it governs only when builds, tests and lints run, never the quality of the change itself: quality comes from how the work is built, not from running checks, and a Quick session ships the same production-ready solution while handing the verification commands to the user instead of running them.

## [0.2.174] - 2026-09-07

### Fixed

- **Pilot reports underlying controller failures instead of hiding them behind a generic stop message.** Provider errors retain bounded details, and interrupted controllers preserve available supervision evidence without claiming that the user pressed Stop.

### Changed

- **Pilot receives bounded desktop tasks rather than whole programming jobs.** Native API and batch artifact preparation stays with the main agent; desktop controllers are instructed to observe the screen before extended planning and work in short UI steps.

## [0.2.173] - 2026-09-07

### Added

- **Detached file previews open at the size they were designed for, and remember where you put them.** A preview opened in its own window derives its placement from the geometry you last gave that window, or from the view's own design size clamped into the monitor's work area, instead of an arbitrary default. Below 860px the secondary header actions collapse into the shared overflow menu while the primary toggles and the window controls stay flat, and a preview session now belongs to the window that started it — closing that window ends it, and a session the runtime no longer knows about shows a designed "session ended" state with Retry instead of a raw error.

### Fixed

- **A message you sent while the agent was idle no longer arrives after the next one.** A steering message that missed the run loop's drain point stayed queued until the following prompt started and was then appended *behind* that newer prompt — measured once at 75 seconds early, delivered 1 millisecond late. Queued messages are now flushed first, in the order the UI shows them, so the transcript matches the order you sent them in.

- **Terminals and shells no longer see the Windows verbatim path spelling.** A canonicalized root (`\\?\L:\Repo`) is correct for comparing two paths and wrong for everything else: PowerShell cannot map it to a drive and rendered the provider-qualified `Microsoft.PowerShell.Core\FileSystem::` prompt, and a terminal group keyed on it silently forked one repository into two — so the new tab was created in a group nothing rendered. The prefix is now stripped once per language at the ingestion points, project entries written by earlier builds are repaired on read, and comparison sites keep canonicalizing.

- **The "Plan ready" card disappears once you answer it.** Accepting or declining a plan the model wrote into chat submits a harness-authored reply rather than a user message, and the check that decides whether a plan is still awaiting an answer only stopped at user messages — so it walked straight past your decision and remounted the card on every state rebuild for the rest of the session.

- **Clicking a folder in the editor opens its entry file instead of claiming "Permission denied".** Windows reports a directory read as access-denied, which surfaced as a file-permission error for paths that were simply directories. Reading a directory now says so, and the editor retries the usual entry files (`index.ts`/`tsx`/`js`/`jsx`/`mjs`/`svelte`, `mod.rs`, `__init__.py`) and opens the one it finds.

### Changed

- **Both Qwen Cloud realms are one brand, and a realm mismatch says so.** The credits-based Token Plan and pay-per-token DashScope International are one product line bought in one place, but the surfaces named them so differently that a valid Token Plan key refused by the metered host read as a broken credential. They are now "Qwen Cloud (Token Plan)" and "Qwen Cloud (Pay-per-token)", listed next to each other in settings and the model picker, and a 401 on either host names the sibling provider as the likely realm. Provider ids are unchanged, so stored accounts and picked models keep working.

- **A session worktree now folds back entirely on its own.** After every turn, a session that was isolated into a managed worktree returns automatically: its commits are cherry-picked onto the branch recorded when the tree was created (switching the checkout back itself when it drifted, never forcing past uncommitted work), the session reopens in the parent checkout, and the worktree and its branch are removed — no button, no dialog. If the fold stops at a real conflict, the session's own agent is woken with a machine instruction to rebase its worktree onto that same recorded branch and resolve the conflicts there; the automatic fold retries the moment that turn ends. Blocked files are retried by the existing release hook the moment their claim drops, and the automatic return survives an app restart. A `Fold back` remains as one action for the times you want it immediately: it runs the same automatic fold and hands a conflict to the session the same way — the choice between "Automatically" and "Via session" is gone, because both ran the same fold and differed only in exactly that handover.

- **Machine-assigned instructions reach the model again.** Instructions the app composes on its own — a plan to execute, a fold-back conflict to resolve — were stored as a message type that was never projected to the model, so the model silently never saw a single one of them. They now ride as a distinct machine message the model reads verbatim, shown in the transcript as a system notice instead of an invented user entry.

- **Session titles are always generated by the session's own model.** The dedicated rename-model setting is gone end to end: auto-rename (and its refresh pass) runs on the model the session is already using, with no configured override and no fallback model in between. The settings UI keeps only the generation's thinking effort.

## [0.2.172] - 2026-09-07

### Added

- **A session folds back only into the branch it left.** Folding a session's work back into its parent checkout now checks the branch recorded when the session started: an automatic fold-back into a parent that switched branches in the meantime is refused, and the explicit path names the mismatch instead of silently writing into the wrong branch. The action also reads the same in every surface now — chat, menus and dialogs share one canonical label. Isolation can no longer nest inside a managed worktree, and sessions isolated at a write seam return to the parent checkout automatically.

- **Worktrees that already gave up their work no longer linger.** When a worker's patch is already applied in the parent, its worktree is recognized as equivalent and cleaned up on close instead of being preserved as "not folded back"; a worker preview shows the parent state before the close decides, a worktree that is still busy reports its path instead of failing anonymously, and a retried worker receives bounded context about what its predecessor changed.

- **The memory store keeps a locator where it used to keep your words.** Evidence that captured verbatim user quotes is scrubbed to a reference to the turn where the words were said, across every memory scope in a one-time migration — and new captures record the reference instead of the raw text.

### Fixed

- **A single question and answer now shows its span and token tally.** The seam between assistant turns only appeared from turn 2 onward, so the most common case — one prompt, one answer — showed neither elapsed time nor cost. The first turn now gets the same seam, measured from the moment the prompt was sent.

- **Parallel worker batches with a shared contract no longer fail on each other's code.** When one worker implements a new interface and its siblings consume it, each consumer's change was compile-checked alone and rejected for missing definitions that existed only in a sibling's unapplied patch. The check now overlays the whole batch, tests the union, and waits within a bound for a sibling that has not delivered yet.

- **A worker integration that goes sideways now says what it did and why.** A worker that broke files it does not own integrates with an explanatory note instead of being silently preserved when the parent workspace is dirty or unmeasurable, and a stalled integration flush reports what it is waiting on — retry state, completed writes, sidecar path — instead of hanging without a word.

- **On Macs, GPU embedding picks a real GPU.** The index's GPU lane could end up on the CPU when adapter selection failed on macOS; it now selects a physical Metal GPU and validates the adapter before running.

## [0.2.171] - 2026-09-07

### Added

- **A fallback vision model can take over when the configured one cannot serve an image.** Settings → AI Agent gains "Fallback vision model" (`visionFallbackModel`): it is tried whenever the primary slot fails — every account of its provider refused, the call errored or timed out, or its own configuration is broken — and a fallback-only selection carries the whole route, so a text-only active model still gets its images read. Pilot tool-result images inherit the same fallback, and a turn whose every attempt is blocked still fails closed, naming both reasons.

- **Deep Research now searches as broadly and as deeply as its depth setting claims.** A job no longer sends four fixed phrasings of one topic to a single page per provider. Query variants are generated per job — the exact phrase, the current and previous year, and the angles a research question actually needs (documentation, comparison and alternatives, limitations, measured performance, migration, how-to) plus sub-questions parsed from your instructions — and every provider is asked for more candidates than the final evidence budget and paginated, so host diversity has something to choose from. Standard depth issues 8 variants and over-gathers 2×; deep issues 12 and 3×.

- **Full text is fetched for the sources that deserve it instead of waiting on the model.** The search wave upgrades the highest-ranked snippet-only sources to full text on its own, preferring one source per independent host before taking a second from any host, and follows primary-source-looking links inside fetched pages. `followLinksDepth` was a setting every job stored and nothing read; it now bounds that chasing.

- **A research job can investigate rather than search once.** Up to two further waves derive their queries from terms that appear across at least two independent hosts and are not already in the topic, and every wave is deduped, host-diversified and domain-filtered by the same rules as the first.

- **Four controls for that breadth and depth**, in Settings → Research and in the per-run dialog: query variants, gather multiplier, fetch depth and expansion rounds. Each defaults to "auto — from depth", each shows the derived value, and each states what it costs in provider requests rather than only what it does.

- **The local half of a research run is held to the same contract as the web half.** `mode: both` is the default, so half of every run is workspace retrieval — it now issues the same generated variants, attaches real file content for its top-ranked hits instead of metadata alone, collapses near-duplicates through one identity, ranks instead of returning whatever came back first, and reports a missing or stale index as a distinct status with a reason.

- **Research quality is measured, not only reviewed.** A new offline evaluation scores a recorded job — citation precision and coverage, host independence, fetched ratio, provenance completeness, engine coverage, identity hygiene, contradiction preservation and cost per cited source — against golden fixtures, so a change to the ranking or the gate produces a number instead of an impression.

### Fixed

- **Vision helpers now rotate provider accounts the way a chat run does.** An image transcription used to resolve one API key and call the provider once, so a rate limit, auth failure or quota error surfaced as a dead vision model while the chat model rotated past the very same account. It now walks the provider's enabled accounts under the executor's own rotation policy, attributes the limit headers to the account that earned them, and names every account spent or skipped — plus how much rotation is left — in the note the model reads.

- **The search scraper tier no longer bypasses the SSRF protections the fetch tier already had.** Public-web scraping used a plain HTTP client that followed redirects with no per-hop address validation, so a redirect or DNS answer pointing at a private or link-local address could be fetched and parsed into evidence. Scraping now goes through the same protected client as page fetches: redirects validated per hop, every DNS answer checked, ambient proxies disabled.

- **A search that ran and found nothing is no longer reported as "skipped".** Engine status now distinguishes failed, zero-result and completed-with-warnings, keeps the provider name with each error instead of discarding it, and never produces an empty reason — so a silently failing search provider shows up in the job instead of looking like an engine you never enabled.

- **The evidence budget can no longer be filled entirely with unfetched snippets.** The rule that at most half of the sources may be snippets was enforced on one insertion path and not on the ones used when appending a source or persisting a search, so a job could finish with nothing but snippets and nothing to cite from.

- **A cited paragraph is no longer excused by the paragraph above it.** The finalization gate skipped headings without closing the current paragraph, so a cited claim, a heading and an uncited claim counted as one cited paragraph. Uncited paragraphs now fail the gate.

- **Job files are written atomically and job ids can no longer alias.** Saving a job used a fixed temporary filename with no sync, beside a correct atomic writer the same code already owned, and two different job ids that sanitize to the same string addressed the same file. Saves now go through the atomic writer, a non-canonical id is rejected before any path is built, the stored id is verified against the requested one, and job files that cannot be parsed are reported as `corruptJobs` instead of silently vanishing from the list.

- **A crashed finalization no longer imports the same report twice.** The intent to import is persisted before the side effect, a retry adopts the document the earlier attempt created, and the import carries a stable identity so the doc side updates the existing page rather than adding a duplicate.

- **Cached and revalidated content says so.** A 304 revalidation was recorded as the source's own status code, making a stale body look like a fresh non-200 response, and a persistent cache hit entered the evidence with no sign it came from cache. The origin status is recorded and a cache hit is annotated with when it was stored and when it expires.

- **Research evidence no longer names a browser engine that does not exist.** Persisted source notes said a page was "rendered with direct Playwright" and a health check reported Playwright as available unconditionally, for a runtime that was removed. Both now name the managed Chromium runtime and report whether it is really reachable.

- **An unterminated `<script>` or `<style>` no longer leaks into extracted text.** Excluded regions were stripped by patterns that required a closing tag, so a truncated page rendered its script body as evidence — a prompt-injection path into a source excerpt. Excluded regions are now removed as whole subtrees, to end of file when the close never arrives.

- **One citation contract, enforced identically in both places.** The research gate and the document import disagreed about what a valid citation is, so a report could pass the gate and then be refused at persistence, failing the job after it was already declared good. Both now reject a bracketed digit-and-separator span such as `[1,2]`, both treat other bracketed prose such as `[v2]` or `[note 1]` as text, and a shared case table is asserted row by row across the two crates.

- **A research status poll no longer stalls the rest of the turn.** Ten read-only research and docs actions were classified as reads but left off the parallel-safe list, which the scheduler treats as a barrier that also blocks every later hoist.

- **Settings number fields clamp what you type.** `min`/`max` attributes are advisory only, so a typed or pasted 99 or 0 was persisted and silently disagreed with the value in effect. The fields clamp in the handler and show the clamped number.

- **Two remaining SSRF edges are closed.** NAT64 addresses such as `64:ff9b::7f00:1` embed an IPv4 address and were passing the IPv6 filter, and the port policy was a silence rather than a decision; the embedded address is now checked with the full IPv4 policy and ports are an explicit allow-list.

- **The NotebookLM engine now says that it cannot see your NotebookLM settings.** It runs with defaults because Deep Research has no way to read the configuration you saved in the NotebookLM panel; if you use the consumer service nothing changes, but a Discovery Engine setup was being ignored without a word. The caveat now rides in the engine status instead of presenting as an unexplained authentication failure.

- **Building from source works again after the native-resolution region-crop change.** A new parameter was not passed at three call sites, which broke compilation for anyone building the workspace. Observation calls that only want window metadata now request no crop.

## [0.2.170] - 2026-09-06

### Fixed

- **Terminal Up/Down history is reliable and shared across every terminal tab.** The frontend no longer replays its own in-memory command list with counted backspaces — a mirror that silently switched to the shell's separate history after any Tab, cursor key or paste, and forgot everything on reload. Arrow keys now always reach the shell, whose history the integration scripts share live between all Unary terminals (PSReadLine incremental shared file, bash `history -a/-n`, zsh `share_history`).

## [0.2.169] - 2026-09-06

### Changed

- **Burn avoids unnecessary work when embedding mixed-length inputs.** The CPU groups similar lengths while preserving caller order; the GPU keeps its existing batch grouping. Both paths copy back only the CLS vectors instead of every token's hidden state. The model, FP32 precision and allocation limits remain unchanged.

### Fixed

- **Human Stop does not silently drain queued input.** Steering and follow-up messages remain held until an explicit prompt or resume; an authorized peer wake can also start a session whose history is still empty without losing its provenance.

- **Original/verifier cleanup cannot close the same actor twice concurrently.** Close operations for one parent session are serialized, and real cleanup failures still propagate.

- **Shared panels and session controls stay consistent across Desktop and IDE.** Operation progress remains visible, unknown Git sync status is not presented as a clean comparison, and detached panels receive the same sync-state information.

- **Older Memory evidence remains readable without weakening quote validation.** Legacy evidence references are normalized to the canonical format, and startup recovery completes privacy cleanup before publishing refreshed context.

- **The direct OpenAI GPT-6 Astra picker exposes its documented Low-through-Max ladder.** Unsupported Off/Minimal choices are not offered for that API model.

- **Concurrent embedding requests no longer starve behind repeated work on the same device.** CPU and GPU admission is FIFO, expired waiters leave the queue cleanly, and the existing request and queue deadlines remain unchanged.

- **The embedding sidecar exits when its parent is already gone.** The parent-process check now runs before loading the model, avoiding an orphaned model load during shutdown.

## [0.2.168] - 2026-09-05

### Changed

- **GPT-6 Astra is available as the new Codex model.** Unary now exposes `gpt-6-astra` through the ChatGPT-account Codex transport and the documented direct OpenAI Responses transport, with its 1.05M context, Low-through-Max reasoning ladder, image input, and provider-specific Fast-mode encoding.

- **The code index no longer has a size ceiling.** The snapshot used to be one pretty-printed JSON file carrying every chunk's source text (264 MiB for this repository, a fifth of it indentation) and refused to index above 512 MiB. It is now a compact metadata snapshot plus an on-demand chunk-content store: huge repositories index, a one-file refresh no longer rewrites hundreds of megabytes, and an open workspace keeps far less resident. Existing indexes migrate in place on first load without re-embedding.

- **Index memory is budgeted, not just counted.** Open workspaces are evicted from the index cache when their resident size exceeds `indexResidentBudgetMb` (default 2048), and Index status shows resident MB per workspace and per-stage times of the last reindex.

- **Index search runs its lanes in parallel** and reports per-lane timings (`laneTimingsMs`) so slow queries can be attributed.

### Fixed

- **macOS release builds include the desktop-only Tauri plugins and sign their updater bundle again.** The desktop plugin dependencies had accidentally fallen under the Windows-only Cargo table, and the shell release script populated an environment variable the Tauri CLI does not consume.

- **The embedding sidecar is honest about GPU trouble.** A recovery episode writes one log line instead of twelve panic records, the lowered attention budget survives a restart instead of being re-learned by panicking, truncated inputs and recovered refusals are reported to the host, a malformed request no longer kills the process, and a request that fails to *send* is counted as a death like one that fails to answer. A corrupt crash log is reported instead of silently re-enabling a GPU lane it had condemned; a request queued behind a stalled one waits two minutes, not thirty.

- **Abandoned index stores are named and reclaimable, and the home directory is refused as a workspace root.** A cancelled index of `C:\Users\<you>` had left 376 MB on disk with no way to see or remove it.

- **`code_context` and `repo_map` stay inside `budgetTokens`** including their structured payload, not only their prose.

- **The `index` tool description no longer advertises a LateOn MaxSim reranker** that was removed on 2026-09-02.

## [0.2.167] - 2026-09-04

### Changed

- **Memory recall no longer runs a reranker model.** The `Shared reranker model` plugin setting is removed; an existing value is ignored on load and dropped on save. Recall keeps its hybrid retrieval order without the per-recall reranker latency.

### Fixed

- **xAI video generation no longer reports Grok Imagine Video 1.5 as unavailable.** The authoritative xAI provider pack now keeps the current video model that the video tool resolves, instead of replacing the built-in catalog with a coding-and-image-only subset.

- **Index panel names a missing workspace instead of a missing plugin.** With no workspace open it reported "Plugin: Missing — the index plugin is not registered" and showed built-in defaults as if they were workspace settings; both now say "No workspace".

## [0.2.166] - 2026-09-03

### Fixed

- **Provider sign-in no longer ends on a refused localhost page when automatic return needs recovery.** The recovery flow now opens its localhost callback before sending you to the provider, finishes and saves the account when the browser returns, and still keeps paste-back available when a firewall or browser blocks local delivery.

## [0.2.165] - 2026-09-03

### Fixed

- **A session working in its own worktree now knows the way back.** Before,
  the only hint a moved session ever got was a one-off “continue in this
  directory”, so one session merged its branch into the shared checkout by
  hand and then told the user to close it and start a new one to work there.
  The system prompt now states on every request that the directory is a
  managed session worktree of the shared checkout, that its commits fold back
  automatically on close, that *Fold back to parent* continues the same
  session in the shared checkout, and that merging by hand or asking for a
  new session is wrong. The working-directory line also follows a session
  that is moved mid-turn instead of staying on the old path.

## [0.2.164] - 2026-09-03

### Fixed

- **“Fold back to parent” shows up for a session that was moved into a
  worktree after it started.** The composer decided from the branch recorded
  when the session was created — the parent’s branch, which the conversion
  never rewrote — so every converted session failed the “is this a managed
  session worktree” check while the header pill already showed its
  `unary/session-…` branch. The button now decides from the live branch of
  the session’s directory — the same branch the fold-back itself checks; the
  stored branch only stands in until the live one is known.

## [0.2.163] - 2026-09-03

### Fixed

- **Region capture works again on Windows.** Clicking the region snip button
  failed with *“Plugin tool `snip` has an unclassified action `snip_region`”*
  before the picker could open: the native capture was missing from both of the
  lists that decide which snip actions may save a capture, so it was refused
  outright. It is now handled like every other saving capture, and a slow
  selection — the picker stays open as long as you hold the mouse — no longer
  reports a failure after a minute while the capture still lands in the
  gallery.

## [0.2.162] - 2026-09-03

### Changed

- **Guardrail profiles: Quick is the default, Standard is now Normal, and
  Strict stopped paying for nothing.** Verification is something you switch
  ON by picking Normal or above; a fresh installation runs Quick. Strict used
  to verify after EVERY edit (a full context re-send per change), demand the
  full repository gate, and reject any ambiguous edit anchor although the
  repair only ever picks the one occurrence whose surroundings are unique —
  it now verifies once at the end at workspace depth and repairs like
  Cautious; what still sets it apart is rejecting a stale edit target and
  asking before recoverable git operations. Saved `Standard`/`Flow` submodes
  and settings files keep resolving to Normal. An installation without a
  `guardrails` block now resolves the default profile in the prompt layer,
  the fold-back check and the edit guard too — previously only the worker
  verifier did, so a default install would have run half a profile.

### Fixed

- **Worker patches no longer end in “conflict” because of their own parent.**
  A second round of workers in one long session was marked failed with
  *“is being written by ‹parent›”* although every patch applied cleanly: the
  parent's own attribution claims from round one were read as a live write
  lease for as long as its turn ran, and the resulting deferral was fed to the
  conflict resolver. Integration now acts for the parent session, so its own
  claims never defer it; a deferral is reported as a deferral and the patch
  waits for the next safe boundary instead of failing. A “worker had
  conflict” badge whose patch was meanwhile applied by hand now clears on its
  own at the next boundary.

## [0.2.161] - 2026-09-03

### Changed

- **Branches panel: three scopes instead of nine sections.** Source Control ›
  Branches now shows Branches (Local, Remote, Pull requests, Stashes), Workers
  (every worker folder under `.unary/worktrees/` in one list, grouped by the
  session that owns it, with running / finished / leftover / conflicts as tags)
  and Snapshots (grouped by session, orphaned ones as their own group). The
  twelve header buttons are gone; every action lives in the ⋮ menu of the
  thing it acts on. **Clean up…** replaces the old remove-all chains with one
  dialog: pick a policy for finished work (merge into main first, or remove),
  tick sessions or single folders, optionally delete their branches and prune
  orphaned snapshots, read the consequences once in a summary block, and
  confirm once. **Start worktree review** — the session that walks through
  every worker folder and proposes what to do — is reachable from the head
  menu, the Workers bar, every session group and the Clean up dialog.

## [0.2.160] - 2026-09-02

### Added

- **Text panel with learning writing styles (Assistant mode).** The
  Desktop Assistant gets a "Text" side panel — a small editor next to the
  chat with grammar, rewrite, shorten, improve and tone actions on the
  selection. Styles carry a name and the user's own description, explicit
  rules, every approved version as an example, and traits derived from
  examples and corrections that the user confirms or rejects.

## [0.2.159] - 2026-09-02

### Changed

- **Memory captures what matters and stays silent about the rest.** The
  agent of the running session is now the primary memory author: a user
  correction, standing preference or durable decision is stored at once as a
  cleanly rewritten rule with the user's exact words kept as evidence, and
  becomes trusted immediately. The old regex preference detector no longer
  promotes anything on its own — a hit becomes a one-shot hidden hint that the
  running agent decides in the same conversation — and the one-off task
  instructions it had written into `MEMORY.md` are demoted on the next start.
- **Session compaction is loud and lazy.** It runs after a session ends or
  sits idle for ten minutes, skips one-turn and worker sessions, falls back to
  the shared knowledge model when the memory model does not answer, and
  reports pending sessions and the last failure (with model and error) in the
  Memory panel status and in the injected memory index instead of failing
  silently.
- **One trust ladder for every automatic memory write.** Rollout distillation
  now produces structured candidates through the same grounding and
  auto-promotion path as compaction artifacts; nothing writes model prose into
  `MEMORY.md` directly.
- **No manual memory mechanics except delete.** Helpful/Not-helpful,
  promote/pin, refresh, compact, rebuild and retention buttons are gone;
  promotion, usefulness (from recall usage), retention, stale sweep,
  embeddings and health run automatically, throttled to once per day per
  repository.
- **Memory panel v2.** Five scopes — Ledger · Session · Repo · Global ·
  Errors — replace the per-scope side rail. Repo and Global show one entries
  surface with a compact Review · Trusted · All switch where Trusted renders
  the composed `MEMORY.md`; the file opens from the head menu. Session shows
  what was loaded and what this session created; Ledger is the session fact
  sheet (worked on, solved, errors fixed, files, commands), now derived
  deterministically even when no model pass ran.
- **RPC sessions end cleanly.** Transport EOF or error now runs the session
  shutdown, so plugins receive `SessionEnd` and repository leases are released.
- GLM-5.3-Flash now uses its exact 1,048,576-token native context window. The
  1,310,720-token figure shown by OpenRouter belongs only to its Cloudflare
  route and is not advertised for direct Z.AI requests.

## [0.2.158] - 2026-09-02

### Changed

- **Claude Fable 5.1 works through Anthropic subscription accounts again.**
  Unary now identifies its OAuth requests with the Claude Code 2.1.258 client
  version required by the model instead of the rejected 2.1.75 version.

- **Product code moved out of the host packages into `shared/`.** Everything
  under `unary-tauri/src/` except the host and IDE layout (`main.ts`,
  `Shell.svelte`, `App.svelte`, `shell/`, `surfaces/`, the window-opening
  `popout/` helpers, the palette UI, `remote/`, the IDE-only `Dock*Panel`
  wrappers and a few IDE-only components) now lives in `shared/app/` — including
  the palette registry, `openTauriPanelWindow.ts` and the four dock panels the
  Desktop also mounts (Browser, Sidebar, Extensions, Git) — and everything
  under `unary-desktop/src/` except its
  `main.ts`, `App.svelte` and `snipWindowControls.ts` now lives in
  `shared/desktop/`; the `@unary/app-src/*`, `@unary/app-api/*`,
  `@unary/app-keymap/*`, `@unary/app-themes/*` and `@unary/desktop/*` aliases
  keep their names and point at the new trees, and the dead git history/graph
  tabs, edge rail, session branch group, markdown performance monitor and
  tree-worker client were deleted.

### Changed

- **The index has three modes and one engine.** Settings › Index now offers
  Lexical only, CPU and GPU. The two model modes run IBM Granite Embedding 97M
  R2 on the bundled pure-Rust Burn sidecar, on the CPU or on the GPU through
  Vulkan, D3D12 or Metal. ONNX Runtime, Dawn, the 311M model, the Qwen
  models, the LateOn late-interaction stage, the static fallback model, the
  per-repository model override, the semantic-search switch and the remote
  embedding ceiling are removed. The sidecar ships as one self-contained
  executable with no runtime libraries beside it. A settings file from an
  earlier build keeps the lane it named: every former CPU preset becomes CPU,
  every former GPU preset becomes GPU. Existing indexes built with the 311M
  model are rebuilt on the next reindex.

### Added

- **A "Lexical only" index mode for machines that cannot carry a model.** It
  loads no embedding model and starts no sidecar; exact symbol search, BM25
  text, path trigrams, the symbol graph, repository map and context packing
  stay, and every search result says that natural-language intent search is
  unavailable. A repository cannot override it.
- **The code index understands 32 more languages.** CSS, JSON, YAML, TOML,
  SQL, Dart, Haskell, OCaml, Objective-C, HCL/Terraform, GraphQL, Julia, R,
  Erlang, Clojure, Nix, PowerShell, CMake, Make, Solidity, Elm, Gleam, Groovy,
  F#, GLSL, HLSL, Starlark/Bazel, Fortran, Verilog, VHDL, GDScript and D now get
  tree-sitter symbols, definition and call tags, symbol-graph edges and
  declaration-sized chunks instead of plain line windows. Bazel `BUILD`,
  `WORKSPACE` and `MODULE.bazel` files are recognised by name.
- **A search on an index without embeddings says so.** When a conceptual
  query planned a semantic lane the profile cannot run, the result now names
  the reason and the repair step in both its text and its structured
  `semanticError` field, instead of answering as a hybrid search with two
  silent empty lanes.

### Fixed

- **Large workspaces no longer take the interface down.** Flat workspace scans
  are bounded again on the host, the Desktop Files tab says when a listing is
  partial, and transcript row limits no longer grow with installed RAM. On
  a machine with a large `target/` folder the previous release scanned millions
  of entries per refresh until the renderer ran out of memory.
- **Opening a workspace with many sessions no longer re-applies plugin settings
  once per session.** A plugin that has already applied exactly the requested
  configuration is skipped, so one slow plugin at startup no longer makes every
  session wait on the full settings timeout.

## [0.2.157] - 2026-09-01

### Added

- **Claude Fable 5.1 is available through Anthropic.** The model includes its
  one-million-token context, 128K output limit, current pricing, always-on
  adaptive thinking, Low-through-Max effort controls, tool search, and safe
  handling when a conversation switches models.

### Fixed

- **Large workspaces no longer freeze the Explorer or disappear behind a fixed
  entry limit.** The shared IDE and Desktop tree now loads direct children in
  cancellable pages, renders the first page immediately, and fetches nested
  folders only when expanded.

## [0.2.156] - 2026-09-01

### Added

- **Tencent HY4 Preview is available through OpenRouter.** The model ships with
  its current text, reasoning, tool-use, context, output-limit, and pricing
  metadata in the seeded OpenRouter provider pack.
- **Unary now has a dedicated Android application target.** The mobile build
  uses its own lightweight entry, registers only the supported sign-in and
  remote-control commands, and validates the Android SDK and NDK explicitly.
- **The Automations workspace is available in both desktop surfaces.** Event
  triggers can be configured from the same shared panel instead of a host-only
  copy.
- **The Index graph shows details for the selected node, relation, or cluster.**
  The explanation stays in a dedicated lower section while the graph remains
  visible.
- **Assistant sessions can switch between Local and Remote at the top of the
  sidebar.** Remote hosts expose their connected, loading, empty, and error
  states without mixing remote sessions into local projects.
- **Managed worktree sessions can fold their completed work back from the
  composer.** The attention action closes the temporary session only after the
  fold succeeds and reports the resulting parent outcome.

### Changed

- **Model, mode, Fast, and effort controls now form one compact inline control
  family.** Fast remains an on/off action while model, mode, and effort keep
  their own menus.
- **GPU Fast indexing now uses Unary's native accelerated model runtime.** The
  legacy browser-style GPU path is gone, and a lost device is reported as an
  explicit GPU-lane failure instead of silently continuing on an unsafe path.
- **Destructive dialog actions are consistently red, and the remaining dialogs
  open as independent windows when the host supports it.**
- **Full Windows releases reuse substantially more completed build work without
  introducing a reduced release mode.** The canonical signed, inspected and
  R2-publishable path now has observable compiler caching, retry-safe build
  caches, bounded temporary Defender exclusions, reusable dependency installs
  and artifacts preserved across packaging. macOS and Linux also avoid the
  duplicate model-runtime build walk and report the same phase timings as
  Windows.

### Fixed

- **A failed local release build no longer burns a version number.** Build,
  gate, packaging, signing, and incomplete publication failures retry the same
  version safely; only a version visible in the live R2 channel is final.
- **Stopping a session is now a hard manual barrier.** Pending background exits,
  continuations, watches, worker completions, and queued input cannot wake a
  session again after the user presses Stop.
- **Anthropic sign-in recovers cleanly from concurrent refreshes and revoked
  credentials.** Refresh-token rotation is preserved across processes, and an
  invalid grant clears the unusable credential instead of failing repeatedly.
- **Pinned and archived chats keep their project context.** Pinned chats are
  grouped by project and then branch, archived chats stay in one nested
  subgroup, and branch groups no longer duplicate their own session rows.
- **A failed fold-back keeps the session available for recovery.** Unary no
  longer closes the worktree session before confirming that its work reached
  the parent.
- **Codex Voice connects through the supported path again and lets the active
  microphone be selected.**
- **Drawing and composer resize affordances are visible and stable again.** A
  buttonless pointer move no longer ends an annotation stroke, and both resize
  grip lines render at the intended contrast.

## [0.2.155] - 2026-09-01

### Fixed

- **Model-only image and video selectors no longer expose an inactive effort
  action.** When reasoning effort is unavailable, both desktop surfaces now omit
  that action instead of wiring an empty handler.

## [0.2.154] - 2026-09-01

### Fixed

- **Image and video model settings no longer block a desktop update.** Their
  model pickers now remain valid when reasoning-effort selection is unavailable.

## [0.2.153] - 2026-09-01

### Fixed

- **Every stored chat message is reachable again — and the first scroll no
  longer jumps.** Long sessions now show explicit controls for older and newer
  history, keep failed loads retryable,
  and preserve your reading position while a page is added. The pinned user
  message also remains authoritative when it is outside the first loaded page;
  clicking it fetches the containing page and lands on the original request
  instead of silently losing it. The IDE and Desktop app use the same production
  chat behavior, with normal-flow rows and a stable reading anchor preventing
  the first real scroll from leaping away from the content you were reading.

- **Long chats compact without forgetting or repeating earlier work.** The exact
  handoff boundary survives an interrupted save and is repaired when the chat is
  opened again, while a failed save cannot leave the live conversation ahead of
  its history on disk. Manual compaction now reports the right cause, shows one
  completion marker, and displays failures instead of hiding them in a log.

## [0.2.152] - 2026-08-31

### Fixed

- **The pinned last user message no longer disappears.** The line above the
  chat that keeps your last message in view could stay empty for a whole run,
  so the only way to see what you had asked was to scroll all the way back up
  to it. It gave up whenever it landed on a moment where the transcript was
  not measurable yet — a freshly opened session, a chat in a background tab —
  and nothing brought it back until the next manual scroll. It now shows your
  newest message whenever it cannot measure, instead of nothing, and it also
  notices a message leaving the top of the view when no scrolling was involved
  at all.

## [0.2.151] - 2026-08-31

### Added

- **Memory entries have categories.** Every remembered item is now filed under
  one of eleven categories — persona, business, rules, design, coding style,
  architecture, repo facts, workflow, pitfalls, environment, other. The
  category is shown and filterable in the memory panel, and the repository
  memory file is grouped by it instead of by entry kind.
- **Memory can be switched off for a single chat.** Using memory and learning
  from a session are now separate switches that apply to that session only,
  without touching your saved settings. A session that pulled in web or MCP
  content can also be excluded from learning entirely — previously, fetched
  page content could end up in a durable memory entry.
- **Existing memory from Claude Code and Codex CLI can be imported.** Their
  memory folders are read and brought in as reviewable candidates with their
  origin recorded, so switching tools no longer means starting from an empty
  memory. Nothing imported becomes active without review.
- **Rule files can be split up.** `AGENTS.md`/`CLAUDE.md`/`UNARY.md` now
  support `@path` imports, and `.unary/rules/*.md` files with a `paths:` glob
  load only when you are working in a matching part of the repository. Large
  rule sets no longer have to sit in the one file that is sent on every
  request.
- **Each distillation run leaves an audit trail.** A consolidation diff records
  what a run added, merged, replaced or retired, and why.

### Changed

- **Memory no longer fills the prompt.** Session start now injects only a
  compact index of what is remembered; the actual entries are loaded on demand
  when they are needed. Memory capacity is also one number now instead of a
  character cap and a token budget disagreeing with each other.
- **Searching dreamed conclusions understands paraphrases.** It used to match
  literal text only, so asking in different words found nothing.
- Consolidated the technical spine and reference units under `docs/spec/` with explicit ownership and plan provenance frontmatter.

## [0.2.150] - 2026-08-30

### Fixed

- **Checkboxes look the same everywhere, with no exceptions left.** Some
  checkboxes — among them the ones in the "Delete all chats" dialog — came out
  as the oversized grey system box instead of the Unary control. Every checkbox
  in the app now draws the same box, including the task-list markers inside
  chat messages.

## [0.2.149] - 2026-08-30

### Changed

- **A dirty file no longer moves a session into a worktree.** Session
  isolation now fires only while another live agent session is actually
  writing the same file. Leftover uncommitted changes, external editors and
  non-Unary tools never force a worktree anymore — git dirt is history, not
  activity — and the per-turn `git status` sweep that fed the old check is
  gone entirely.

### Added

- **The editor resolves file collisions at save and close.** When a file
  changed on disk while it was open — typically because an agent session
  wrote it — saving or closing now opens a conflict view that diffs the disk
  version against yours and asks for an explicit choice (save mine, take
  disk, or for a closing tab discard-and-close) instead of overwriting
  either side silently.

### Fixed

- **"Snip region" shows its drag-selection box again in the IDE app.** The
  overlay window's `/?snipOverlay=` URL matched none of Shell's window routes,
  so the transparent fullscreen windows rendered the Overview surface behind
  the auth gate instead of the selection overlay. Shell now routes snip
  overlay windows to a dedicated surface; both frontends share the one
  overlay-window factory that reports creation failures; mixed-DPI monitors
  are matched by physical position instead of enumeration order; a drag now
  captures the pointer, and a double press of the snip shortcut no longer
  spawns two overlay sets. On the backend, confirming with a mismatched frame
  id no longer destroys the still-valid frozen frame.

- **The pinned last user message shows up without scrolling first.** The
  sticky preview of the last user message resolved its position in a single
  animation frame; right after sending, or right after opening a session, the
  transcript rows had not been measured yet, so the frame concluded "nothing
  to pin" and nothing re-checked until you scrolled by hand. An unmeasured
  frame is now recognised as not-ready and retried.

- **A reopened compacted session shows its full history again.** The chat was
  seeded from the model's context window, which a compaction truncates, so the
  transcript started at the compaction marker; it now reads the session branch
  and shows everything that happened before it.

- **Escape closes the topmost settings overlay again.** The Copilot OAuth and
  hub settings dialogs had lost their modal flag, so the key fell through to
  the dialog underneath.

## [0.2.146] - 2026-08-29

### Changed

- **Long-running workers are judged by evidence instead of silence.** Active
  commands, output, token growth and repository changes now keep legitimate
  work alive for its measured stage duration, while repeated tool loops with no
  effect are surfaced early for a supervisor decision instead of waiting for a
  fixed timeout.
- **Worker limits are predictable.** Per-role and per-dispatch ceilings now use
  wall time and total tokens rather than an estimated dollar value, and a
  paused worker reports the exact total needed before it can resume.
- **Context-fill controls apply immediately.** Changing a session's automatic
  compaction threshold no longer waits behind the prompt that is currently
  running, and both desktop surfaces show the inherited value when no override
  is set.

### Added

- **Knowledge pages can be managed and improved from one panel.** The panel now
  includes its page list, category filters and editor workflow instead of
  splitting those actions across separate surfaces.
- **Source-control rows have complete action menus.** Branch deletion, stash
  actions and the remaining row operations are available from the compact
  overflow controls without stretching the card.

## [0.2.145] - 2026-08-29

### Changed

- **Sync leads the source-control card again.** The Sync button sat in the far
  right corner of the overview card, a full card width away from the ahead and
  behind counters that explain why you would press it. It now renders first in
  that row, with the counters following it. The branch dropdown above it no
  longer stretches across the whole card either: it is only as wide as the
  branch name, capped, and truncates with an ellipsis past that cap — so a
  short branch like `main` stops squeezing the upstream label down to
  `origin/m...`. The commit button now runs to the card's own edges, making the
  control that commits the widest one in the panel.

## [0.2.144] - 2026-08-29

### Changed

- **Your own messages read as one pill again.** A user message in the
  transcript now carries the same surface as the pinned message at the top of
  the panel: one rounded block with a chrome-level fill and a soft lift, the
  avatar chip sitting inline at the start of the text instead of a separate
  name row above it. The previous fill sat under two percent above the
  transcript background with no border, which is what made the block stop
  reading as a container at all.

- **The agent knows what to call you.** The name you configure now reaches the
  system prompt as a session fact, next to the date and the working directory,
  so it survives a custom prompt. A second setting overrides the name used
  there independently of the transcript label; with both blank, no name is
  sent at all. The transcript label itself now defaults to the neutral
  "User" — your account name is no longer borrowed for it, because that label
  is a role marker rather than an identity.

### Fixed

- **The transcript's navigation buttons stop lingering after a click.** Using
  one of them left the rail pinned open until focus happened to move somewhere
  else, because a plain mouse click was treated as a focus hold. Only keyboard
  focus holds the rail now, so a clicked rail fades on exactly the same timer
  as an untouched one.

## [0.2.143] - 2026-08-28

### Changed

- **One markdown renderer for both chat surfaces.** The desktop chat now
  renders through the same canonical pipeline as the IDE — background
  parsing, stable streaming tails, dialogs, and the file-reference menu —
  with thin per-surface adapters for opening and revealing files. Remote
  images from safe sources render on both surfaces now, links whose label
  is a file path resolve like the path itself, and line anchors survive
  the desktop's ordinary click into its preview.

- **The name on your own chat messages is yours to set.** A new setting
  controls the displayed user name; it defaults to your account's full
  display name and applies immediately on both surfaces.

### Fixed

- **Starting Unary twice no longer starts Unary twice.** The launch gate now
  claims its own boot mutex in the first milliseconds of startup instead of
  probing one the app only creates several seconds later, after the backend has
  booted. A second launch that arrived inside that window used to boot all the
  way through and then race the first one, leaving two live instances
  contending over the same data directory until one of them died. A second
  launch now hands over to the running window and waits out a first instance
  that is still booting, instead of dropping the launch after half a second.

- **A development run no longer hands itself to the installed app.** The gate
  used the release identifier in every build, so starting a dev build while the
  installed Unary was running quietly exited the dev process and raised the
  installed window. Each build profile now uses the identifier it was actually
  built with.

- **Crash reports stop inventing Rust panics.** The unclean-exit verdict read
  the modification time of `panic.log` — the same file it appends its own
  reports to — so practically every short-lived run was reported as a panic
  that never happened. The verdict is now read out of the panic records
  themselves; the newest real record in one observed log was 19 days old.

- **Chat scrolling is calmer across the board.** Streaming coalesces to one
  update per frame (an internal timer race meant it practically never did),
  finished blocks stop re-rendering while the tail streams, growing code
  fences reserve their height so late highlighting only paints color,
  images reserve their box before they load, running tool cards hold a
  stable height until they finish, and the native-flow transcript preserves
  reading position while older history loads. Edges feel defined: the
  transcript no longer chain-scrolls surrounding panels, the scrollbar's
  appearance doesn't shift content, and “Scroll to bottom” glides briefly
  and lands pinned.

- **Right-click works on file mentions in the desktop chat.** The
  file-reference menu (Open Preview / Open in Editor / Reveal in File
  Explorer / Copy Path) now opens on both surfaces from one shared
  component.

- **Session switches show the right scrollbar immediately.** Opening another
  session resets the native-flow transcript before the new history paints, so
  stale scroll geometry cannot leak between sessions.

## [0.2.142] - 2026-08-28

### Changed

- **The chat transcript no longer guesses.** The estimate-based virtualizer
  (place rows at a guessed height, reposition after measurement) is gone;
  every loaded row now renders in normal DOM flow, offscreen rows cost
  nothing via `content-visibility: auto`, and the browser's native scroll
  anchoring keeps the reading position while older history loads (with a
  manual fallback where WebKit lacks it). Opening a session lands exactly at
  the bottom on the first paint — no settle frames, no flicker, no jumping
  while scrolling back, and roughly a thousand lines of scroll machinery
  deleted.

- **One stylesheet owns the chat on both surfaces.** The Desktop app's
  hand-mirrored chat CSS layers could override the hosted panel and drift
  from the IDE (two live divergences shipped that way). Desktop-winning
  values were folded into the canonical `AgentChatPanel` styles, the mirror
  layers are scoped to the backend-less mock preview only, and a contract
  test fails on any new unscoped chat selector — a fix on one surface can no
  longer miss the other.

- **User messages carry your name.** The chat bubble's static uppercase
  "USER" marker (right-aligned) is now a left-aligned label showing the
  signed-in account's display name, seeded from the cached auth preview and
  updated on auth changes; it falls back to "User" when signed out.

## [0.2.141] - 2026-08-28

### Fixed

- **Stored sessions open again.** Opening any session died on
  `e.stopSessionOpenBottomFollow is not a function` and left the panel on
  the old view with a "something went wrong" warning. The scroll-follow
  rework had deleted that step everywhere except at the one place every
  session switch runs through, so no stored session could be reopened at
  all. The dead step is gone, and a new gate check now catches a chat
  panel and its controllers drifting apart before a build ships.

- **The snip overlay fails closed on overlay and attachment errors.**

- **A provider rejecting the request body no longer kills the turn
  silently.** A below-floor image embed (16×16 app icons against xAI's
  512-pixel minimum) came back as a 400 that was classified as a generic
  error: it burned the in-place retry budget, rotated an account out of the
  rotation and ended the turn while the model saw the conversation simply
  stop. Request-content 4xx now has its own error class, images below a
  provider's floor are guarded before they are sent, and the rejection
  reaches the agent as a quiet harness note instead of vanishing.

- **The chat Git workspace keeps its head and tab switch pinned.** The
  popover scrolled as one block, so the title row and the Changes/Graph
  switch slid out of view; head, view switch and status row are fixed now
  and only the view body scrolls.

### Changed

- **Unary has one cursor.** Every `not-allowed`, `wait`, `pointer` and
  `grab` cursor is gone from both frontends — disabled and busy states are
  expressed with opacity, fill and spinners, and the pointer the system
  draws is the pointer you keep.

- **Every dismiss button is the same button.** The nine remaining
  hand-rolled × glyphs (AuthGate, live status area, fix-suggestion banner,
  changes review, context transfer, worktree panel, hunk diff, memory
  entries, doc research) render the shared `CloseButton`, and the native
  system notification, which cannot reach the shared control, mirrors its
  exact shape.

- **Checkbox and radio hover is visible again.** The old hover wash sat at
  ~1.05:1 and collapsed entirely on the light theme; hover now uses the
  state-ladder fill plus a halo ring (~1.4:1), and checked boxes get hover
  feedback for the first time.

- **The global Index settings open without a workspace.** Embedding
  hardware, model and thread count are reachable before any project is
  opened.

## [0.2.139] - 2026-08-27

### Changed

- **App and installer icons carry the rounded mark with a small AI
  badge.** The full icon set returns to the rounded-corner artwork
  (white mark on the dark rounded plate) and the app/installer icons add
  the V1 AI badge — the in-app header and the tray stay clean.

### Fixed

- **Detached windows can be dragged again.** Detached Settings and dialog
  windows became unmovable once the WebView2 evergreen runtime activated
  its native draggable-regions feature: the native side swallowed the
  pointer gestures but cannot move wry's frameless windows. Dragging now
  runs through JS everywhere; `app-region: drag` is gone, `no-drag` stays
  as defense.

- **“Open credential vault” now reveals the dock window.** The forwarded
  open worked, but the panel appeared behind the covering detached
  Settings window and looked dead; cross-window opens now unminimize and
  focus the dock window.

- **A vertical mouse wheel scrolls compact horizontal rails.** The
  dominant wheel axis is translated into rail movement, so a conventional
  wheel reaches controls beyond a one-line rail without Shift; trackpads
  keep their genuine horizontal direction, and Ctrl/Cmd+wheel stays a
  zoom gesture.

- **The snip overlay is screen-reader friendly and its recorder buttons
  behave.** The region picker announces instructions and the live
  selection size to assistive tech, the shortcut recorder's Accept button
  is clickable only while a recording with a draft exists (it used to be
  clickable before any recording started), and snip toolbars mounted as
  their own Svelte roots reach the window controls again.

## [0.2.138] - 2026-08-27

### Changed

- **The IDE and the desktop app now share one chat composer.** The message
  box — attachments and their mark-up dialog, the drag-to-resize handle with
  remembered height, paste and drop handling, the plan-mode suggestion, and
  the keyboard behavior while a run is busy — is one component on both
  surfaces now, so a composer fix lands everywhere at once.

### Fixed

- **Streaming no longer trembles at the bottom, and follow truly sticks.**
  Both surfaces run one shared follow policy now: the per-frame tug-of-war
  between scroll writers is gone (including the one-pixel flips on fractional
  display scaling), “Scroll to bottom” enters a follow mode that holds
  through further streaming until you scroll away, and deliberate upward
  scrolling lets go immediately.

- **Opening a session always lands at the newest message.** Late-arriving
  content (images, long histories, code formatting) keeps the view pinned to
  the bottom until your first real scroll — on both surfaces — instead of
  stranding the view somewhere mid-history.

- **Notification banners are never cut off at the bottom.** The banner window
  sizes itself to the card’s real rendered height (the reply-style banner’s
  answer row used to lose its lower half), and bottom-corner banners rise to
  keep their margin.

- **The Goals panel no longer freezes for the length of a work stretch.** A
  2026-08-27 audit found runs whose board was created and then left untouched
  for 20–55 minutes of real work, every checkbox flipped in one batch at the
  end — and the only live push (`GoalsUpdated`) could silently drop under UI
  backpressure. The run loop now injects a bounded “Goals staleness guard”
  reminder every 8 workspace mutations that pass without a `goals` call,
  receipts teach per-transition updates (starting an item counts, not only
  completing it) and call out when nothing is left `in_progress`, the
  settle-side reconciliation checkpoint re-arms once when new mutations pile
  up after an ignored one, the goals push rides the lossless relay instead of
  a zero-timeout send, the goals strip shows “updated Xm ago” plus per-item
  in-progress ages during an active run, and the session debug bundle reports
  `goalsLiveness` numbers (longest stale stretch, nudges fired) so a
  regression is visible in the artifact users already paste.

- **The chat-plan "Plan ready" card no longer goes stale — and all three of
  its buttons now work.** Replying in chat to accept a plan the agent wrote
  ("implementiere das") left the Accept/Revise/Decline card mounted for the
  entire implementation run: mid-turn state pushes only patch streaming
  counters, so the pending-plan-reply flag computed before the run survived
  until turn end. A starting run now clears it and pushes the state change
  immediately. Accept/Revise follow-up prompts queue as follow-ups instead of
  being silently dropped while the session is busy, Decline now reports the
  decision to the model in the IDE (desktop parity), Revise/Decline no longer
  fail with "no active plan" on a plan that exists only as chat prose, and
  declining a chat plan keeps the current mode instead of switching the
  session into Plan mode.

## [0.2.137] - 2026-08-27

### Fixed

- **Reaching the very bottom is reliable again.** The jump-to-bottom settle
  loop stays alive while a running session keeps growing the transcript
  (height-driven budget instead of a flat 24-frame cap), growth without a
  scroll event now updates the jump button and can re-engage follow when the
  user rested on the bottom, and autoloaded newer pages re-pin or preserve
  the position instead of ending the jump mid-transcript.

## [0.2.136] - 2026-08-27

### Fixed

- **Orphaned worker and session worktrees now heal while the app runs.** Four
  leak paths under `.unary/worktrees/` are closed: a watchdog force-terminated
  worker now has its work captured and its tree reaped immediately (the wedged
  runner's settle path never runs, so nothing else ever cleaned it); preserved
  cancel trees age out on the same 72-hour window as unapplied integrations
  instead of living forever; the orphan sweep now repairs failed cleanups under
  a still-open session by trusting that session's own records about which
  trees are disposable; and both the worker GC and the session fold-back retry
  re-arm from every prompt (30-minute gate) instead of only at app start, so a
  deferred fold-back completes once the blocking edit is gone.
- **Snip works in the desktop app again.** 0.2.135 taught the IDE's snip
  toolbar to mint the operationId receipt the backend demands, but the
  desktop app's titlebar and footer toolbars still invoked the plugin tool
  without one, so every region/window/screen capture and gallery write died
  with "mutating plugin tool `snip` requires a registered operationId
  receipt". Both desktop entry points now ride the exact tracked-receipt
  wrapper the IDE uses (`executePluginToolWithMutationReceipt`); the
  plain-browser preview keeps its receipt-free mock no-op.

## [0.2.135] - 2026-08-27

### Added

- **Machine-started sessions can now open quietly.** A prompt composed by the
  app — the sidebar's worktree review, for example — can carry a display
  title; the chat then shows a small "Worktree review" line instead of a fake
  user bubble holding the full generated text. Dev mode still reveals the
  exact prompt the model received. The worktree review also ends by asking,
  in one decision card, what to execute — clean up, salvage, or finish what
  is still missing.

### Fixed

- **Snip region works again.** The operationId receipt gate classified the
  snip plugin's capture_frame/cancel_frame steps as mutating while the snip
  toolbar minted no receipt, so every snip click was rejected in 2 ms with
  "mutating plugin tool `snip` requires a registered operationId receipt" —
  and the error notice rendered off-screen inside the titlebar, so the button
  read as completely dead. The two frame steps are receipt-free reads now
  (they persist nothing), the persisting captures and gallery writes ride the
  tracked-receipt lifecycle, and a failing snip shows its error as a toast.
- **The newest message really is sharp now.** 0.2.134 fixed the mount path,
  but rich rows (markdown, code — every assistant reply) armed at a higher
  CSS specificity carrying blur(5px) than the two-class reveal override
  could beat, so they stayed blurred forever after revealing. The shared
  transcript carries the full-strength reveal overrides again.

## [0.2.134] - 2026-08-27

### Fixed

- **The newest chat message no longer sits blurry at the bottom.** A message
  appended while the viewport rests at the bottom used to stay in the reveal
  animation's pre-state (blur + fade) until the next scroll; rows mounting in
  the bottom band now appear sharp immediately, and streaming no longer
  flashes blur at the bottom edge. The reveal animation remains when
  scrolling back through history.

- **No more trembling just above the bottom while streaming.** Follow-mode
  stopped detaching on the browser's own scroll clamp (fired when content
  above re-measures smaller) and only lets go when a move actually leaves
  the bottom band — the rapid detach/re-engage flicker is gone. Scrollbar
  drags during streaming now detach follow on both surfaces.

- **“Scroll to bottom” really reaches the bottom.** The button used to jump
  to the estimated bottom once; rows below then realized their true height
  and the viewport stopped short. The jump now re-pins until the height is
  stable.

## [0.2.133] - 2026-08-27

### Changed

- **Both chat transcripts now run on one shared scroll engine.** The IDE and
  the desktop app mount the same virtualized transcript component, so height
  estimation with learned row priors, batched measurement, reading-anchor
  restore, history-load preservation, and the scroll flight recorder
  (Ctrl/Cmd+Alt+Shift+D) behave identically on both surfaces.

### Fixed

- **Chat scrolling is steadier.** The desktop app no longer prices every row
  at a fixed guess with a small look-ahead window; growth above the viewport
  is compensated immediately instead of landing as one visible jump after
  scrolling stops; corrections can no longer apply twice around history
  loads; and follow-the-bottom re-engages by scrolling to the bottom on
  Windows displays at fractional scaling (125%/150%).

## [0.2.132] - 2026-08-27

### Changed

- **Work can move between sessions without creating two owners.** Handing off a
  plan now records who may continue it, survives a restart, and notifies the
  receiving session when adoption completes.

### Fixed

- **Peer messages and plan transfers recover instead of disappearing.** Their
  delivery state is stored durably, interrupted transfers can retry or roll
  back, and completed work is not exposed before its shared state is ready.
- **Session instructions keep their real source.** User messages remain user
  messages across forwarding and renaming boundaries, so coordination hints
  cannot be mistaken for instructions merely because their text looks alike.
- **Workspace switches apply one coherent settings snapshot.** Reloading now
  follows the switch authority, while explicit user-selected paths remain
  distinct from paths contained by the active workspace.
- **The Windows terminal closes the complete command tree.** Child processes
  no longer survive when the host cannot assign a nested Windows Job Object.

## [0.2.131] - 2026-08-27

### Changed

- **Work can move between sessions without creating two owners.** Handing off a
  plan now records who may continue it, survives a restart, and notifies the
  receiving session when adoption completes.

### Fixed

- **Peer messages and plan transfers recover instead of disappearing.** Their
  delivery state is stored durably, interrupted transfers can retry or roll
  back, and completed work is not exposed before its shared state is ready.
- **Session instructions keep their real source.** User messages remain user
  messages across forwarding and renaming boundaries, so coordination hints
  cannot be mistaken for instructions merely because their text looks alike.
- **Workspace switches apply one coherent settings snapshot.** Reloading now
  follows the switch authority, while explicit user-selected paths remain
  distinct from paths contained by the active workspace.

## [0.2.130] - 2026-08-26

### Added

- **The Goals panel fills while the agent works, not after.** Sessions often
  ran a whole fix with the panel blank and then flashed a fully completed board
  at the end. The agent is now told at the start of every request when the
  board is still empty, and a run that keeps changing files without tracking
  anything gets one in-flight reminder to put the work on the board — so the
  checkboxes flip live while you watch. Explicit investigate/audit requests
  now count as trackable work too.

### Fixed

- **The scroll-to-bottom button hides when you are at the bottom.** Windows
  fractional display scaling (125 %/150 %) could leave the chat resting a
  fraction of a pixel short of the arithmetic bottom, so the button stayed
  visible while you were already reading the end. The button now tolerates
  that rounding; follow behaviour is unchanged.
- **Settings changes reach running sessions.** Changing the model or agent
  settings used to apply only to sessions started afterwards; live sessions
  now pick the change up. The "Global Settings" button also works from dialog
  windows, and the effort menu's cache warnings state token counts instead of
  dollar figures.
- **The SCM Sync button grays out when the branch is already in sync** instead
  of offering a push that would do nothing.
- **Worktree rows keep their actions in one context menu** instead of a strip
  of icon buttons per row.
- **A finished background shell no longer claims to still be running** in the
  shell supervision list.

## [0.2.129] - 2026-08-26

### Fixed

- **Your sessions follow the folder when you switch branches.** Checking out a
  different branch in place used to leave every earlier session of that folder
  stranded in a group named after the old branch - a group that stayed even
  after the branch itself was deleted. The Dock sessions panel and the Desktop
  sidebar now group a folder's sessions under the branch it is on right now,
  and the branch a session started on is still shown on the row itself. A
  checkout made in a terminal is picked up when the window comes back to the
  front, instead of waiting for the next refresh.
- **Windows shows the application icon on the taskbar again.** The window icon
  set at startup replaced the executable's own icon, so the taskbar button and
  the shortcut disagreed.
- **The trust period in Remote Control settings uses the themed dropdown**
  instead of the unthemed native one.

## [0.2.128] - 2026-08-25

### Fixed

- **Fast scrolling in the Desktop chat no longer loops back over the same
  messages.** When a row's real height is measured while you scroll, the
  correction to the scroll position is now applied in the same instant —
  previously it landed one beat later, so the view could re-render rows you
  had already passed for a frame. Quick scrolling measures rows every frame,
  which turned that one-frame stutter into the visible loop.

## [0.2.127] - 2026-08-25

### Added

- **Scroll diagnostics recorder.** Pressing Cmd/Ctrl+Shift+Alt+D in the chat
  copies the last ten seconds of scroll activity - every scroll event, every
  scroll write with its writer, and the virtual window mapping - so a
  remaining scroll defect can be diagnosed from evidence instead of theory.

## [0.2.126] - 2026-08-25

### Fixed

- **Fast scrolling in the Desktop chat view no longer repeats content.** The
  master-view chat now pays row-measurement shifts above your reading position
  back to the scroll position in the same frame, so flinging quickly through a
  long conversation can no longer re-map the same messages under your finger.
  Slow scrolling was already correct; this closes the fast path.

## [0.2.125] - 2026-08-24

### Fixed

- **Fast scrolling through a long chat no longer repeats the same content.**
  While you scroll, the transcript keeps its row-height predictions frozen and
  re-prices them only after the gesture settles, so the view can no longer
  re-map the same messages under your finger — the “scrolling in a loop”
  effect near the newest message is gone.

## [0.2.124] - 2026-08-24

### Fixed

- **Worker and remote transcripts no longer yank you back to the bottom.**
  The live worker-session view and the remote-session mirror now follow the
  same rule as the main chat: scrolling up takes the view immediately and
  keeps it, a queued refresh can no longer drag you back down, and following
  resumes only when you deliberately return to the newest message.

## [0.2.123] - 2026-08-24

### Fixed

- **The endless jump-back at the bottom is gone.** While the chat follows new
  output, the row-height corrector now stands down completely instead of
  fighting the follow writer frame-for-frame, and it resumes the moment you
  scroll away — so fast scrolling near the newest message no longer loops.

## [0.2.122] - 2026-08-23

### Added

- **Name your devices.** The desktop's Remote Control card and the iPhone's
  Settings gain a device-name field; the name is what paired devices show in
  their lists. The iPhone also now registers as platform `ios` instead of
  `unknown`.
- **Choose how long a pairing is trusted.** The desktop pairing card offers
  1 day / 7 days / 30 days / permanent; the choice travels inside the QR code
  and the scanned device is trusted for exactly that period. Trusted devices
  can be removed from the desktop list as before.

### Fixed

- **Fast scrolling no longer loops back to the newest message.** The follow
  writer now re-checks ownership at the moment it writes, the session-open
  follow yields to the first upward movement, and re-engaging follow requires
  deliberate downward travel — a single momentum jitter can never hand the
  view back to streaming output. Both frontends share the same contract.

- **Delayed reveal jumps respect the user.** Settings search reveals and
  MEMORY entry jumps cancel when you scroll first, and stale retries can no
  longer scroll a later view or session.

## [0.2.121] - 2026-08-23

### Fixed

- **Fast transcript scrolling no longer repeatedly restarts at the bottom.**
  Once a wheel, touch or keyboard gesture moves away from the newest message,
  follow mode stays latched off through subpixel Mac trackpad momentum. It can
  return only after explicit movement toward the bottom or the bottom button.

## [0.2.120] - 2026-08-23

### Changed

- **Worktrees appear once, with actions that match what they are.** The sidebar
  now keeps Session, Subagent, Personal and External worktrees in one clear
  hierarchy, while Running, Uncommitted and Integrated are visible states
  instead of duplicate groups.

### Fixed

- **Worktree review and clean-up are safer.** Review is available from both the
  sidebar and the full overview; Session trees fold back, Subagent branches
  merge, and Personal or External trees are never folded back automatically.
  Uncommitted files are shown and block unsafe integration, and removing a
  worktree clearly preserves its branch.

## [0.2.119] - 2026-08-23

### Added

- **Pair an iPhone by scanning the desktop's QR code.** The phone camera now
  opens above the settings drawer, takes the whole screen while scanning and
  returns cleanly when pairing is done.

### Fixed

- **Conversation scrolling stays where you put it.** A Mac trackpad's first
  fractional movement now takes control before live output can pull the view
  back down, and following resumes only once the native scroller has genuinely
  reached the newest message. Long chats, navigation jumps and rows that finish
  rendering no longer fight the reader.

- **High-resolution scrolling is consistent across the app.** Vertical gestures
  are no longer stolen by horizontal rails, event feeds preserve a reader's
  position, and browser and remote-control views coalesce momentum without
  replaying a delayed backlog after the gesture ends.

- **Sessions remain in the right sidebar group.** A session stays associated
  with its original branch, a parent remains active while its background workers
  run, and inactive-worktree cleanup no longer mistakes live worker folders for
  abandoned ones.

- **Background-worker results describe what actually happened.** Cost reaches
  the final handoff, missing local toolchains are reported as environment
  failures instead of patch conflicts, and several completion/reconciliation
  edge cases no longer strand finished work.

## [0.2.118] - 2026-08-22

### Fixed

- **Die Sidebar zeigt wieder deine ganze Chat-Historie.** Pro Projekt wurden
  nur die 10 neuesten Sessions angezeigt, alles ältere lag hinter einer
  „Load more“-Zeile — bei 23 Chats also 13 unsichtbare. Weil das meist nach
  einem Branchwechsel auffiel, sah es aus, als hätte git die Chats
  verschluckt. Die Voreinstellung steht jetzt auf 50 und wird bei
  bestehenden Installationen einmalig angehoben; ein selbst gesetzter Wert
  bleibt unberührt. Einstellbar unter Einstellungen › Sessions (0 = alle).

## [0.2.117] - 2026-08-22

### Fixed

- **Ältere Chats verschwinden nicht mehr aus der Sidebar.** Die Chatliste zeigt
  pro Projekt nur die 10 neuesten Sessions, der Rest liegt hinter „Load more“ —
  und diese Aufklappung wurde bei jedem Neuaufbau der Liste vergessen. Wer mehr
  als 10 Chats in einem Projekt hat, sah die älteren dadurch immer wieder
  verschwinden, oft direkt nach einem Branchwechsel oder einer neuen Session.
  Der aufgeklappte Zustand bleibt jetzt erhalten. Das Limit selbst steht in
  Einstellungen › Sessions.

## [0.2.116] - 2026-08-22

### Fixed

- **Switching git branch no longer makes your earlier chats disappear.**
  Sessions were filed under the branch they were started on, so a plain
  `git checkout` left every older chat in a group that then folded shut —
  starting one new session made the rest look deleted, and deleting it
  brought them back. Chats now belong to the folder they run in and follow
  it onto the new branch, and a branch group only sorts the list, it never
  hides anything.

## [0.2.115] - 2026-08-22

### Added

- **Clone a GitHub repository by picking it from a list**, with search,
  instead of pasting a URL.

- **The goals list in a chat window shows its items.** Opening it no
  longer leaves a blank card.

### Changed

- **Stable updates now ship the Mac and iPhone work** that lived off the
  main line: conversation scrolling, the jump-to-bottom button, remote
  sessions, and the memory cleanup from the last few releases.

## [0.2.114] - 2026-08-21

### Changed

- **Scrolling a long conversation behaves like it used to again.** Several
  attempts this week to smooth out the transcript ended up fighting the mouse:
  a short scroll up did not really leave auto-follow, so the next streaming
  token pulled the view back down. The scroll logic is restored to the state
  that felt right, while the genuine paging fix and the new bottom-button and
  hover-rail behaviour stay.

## [0.2.113] - 2026-08-21

### Fixed

- **Long conversations can reach their newest messages again.** If the app was
  re-hydrated or you switched sessions while a page of the conversation was
  being read, loading further pages stopped permanently for that chat. The
  newest messages then stayed out of view and the scroll-to-bottom button had
  nothing left to scroll to, which is what made it look dead while "go to top"
  kept working.

## [0.2.112] - 2026-08-21

### Fixed

- **The scroll-to-bottom button works again.** In long conversations the
  button — both the one in the hover rail and the one that stays visible while
  you are away from the bottom — could do nothing at all: it waited for older
  parts of the conversation to be paged back in, and when that could not
  finish it gave up without moving the view. It now always jumps to the end of
  what is loaded, and keeps pulling the newest messages in behind that.

## [0.2.111] - 2026-08-21

### Fixed

- **The chat transcript stays where you put it.** Scrolling near the bottom
  no longer springs back and forth while message rows finish rendering, and
  the navigation controls work again: jumping to the newest message, or
  between your own messages, now holds its landing position instead of being
  dragged away the moment the surrounding rows settle. Until now only "go to
  top" survived that tug-of-war, which is why every other button looked dead.

## [0.2.110] - 2026-08-21

### Fixed

- **Chat navigation, decided.** The jump-to-bottom button is now always
  visible whenever you are away from the newest message — no more hunting
  for it. The slim navigation rail with the prompt ticks is gone; the
  remaining rail appears only while you work the scrollbar with the pointer,
  and it no longer blocks clicks or scrolling when hidden. Scrolling gently
  near the bottom no longer jumps back and forth while message rows settle.

- **Remote sessions load reliably again.** Opening a session on a remote
  host could exceed the relay's message-size limit, so the controller never
  received the transcript, timed out and reloaded forever — stealing the
  input focus on every cycle. Large histories are now trimmed to fit the
  relay budget and paged back like any windowed session.

## [0.2.109] - 2026-08-21

### Fixed

- **The desktop chat finally scrolls the way it should.** Opening a
  conversation no longer flashes the oldest messages before jumping down,
  switching between conversations now starts at the newest message instead
  of inheriting the old scroll position, and jumping to the previous or next
  message stays anchored while older history loads in. Fast trackpad
  direction reversals no longer leave the list leaning the wrong way.

- **The assistant's memory stops hoarding junk.** Questions and problem
  reports were being filed away as permanent preferences, and routine tool
  rejections, probe answers and empty results were being remembered as known
  defects — some of it broadcast into every later prompt. Captures like
  these now wait: nothing reaches the global memory surface without being
  curated first or actually recurring, and uncurated one-offs expire on
  their own.

## [0.2.108] - 2026-08-20

### Fixed

- **No more endless password prompts from the Mac's keychain.** On macOS,
  running the project's own test suites made the system ask again and again
  for permission to read stored credentials — a fresh dialog after every
  rebuild that stole the keyboard focus mid-typing, and „Always Allow“ never
  stuck because each rebuilt test program counts as a new app. Test runs now
  use their own throwaway credential store and never touch the real keychain;
  the app itself keeps reading and storing credentials exactly as before.

## [0.2.107] - 2026-08-20

### Fixed

- **Isolated work sessions clean up after themselves again.** Sessions and
  background workers that run in their own copy of the repository could be
  left behind forever when returning their work hit a snag: an unimportant
  link or a regenerated lock file was enough to make every retry fail the
  same way, and a finished worker whose handoff nobody picked up kept its
  copy for good. Both now resolve themselves: the return merges around
  unrelated churn instead of failing on it, and an unpicked-up handoff is
  wrapped up after three days instead of never — while any work that exists
  nowhere else is kept safe on its branch.

## [0.2.106] - 2026-08-19

### Added

- **The Mac finally reports what the graphics chip is doing.** GPU load was
  simply blank on macOS while every other reading was live, so the one number
  that tells you whether a local model is actually using the hardware was
  missing. It now comes straight from the system and sits next to the others.
- **Preview an HTML file without leaving the app.** Opening one now renders it
  in the same managed browser the agent already uses, instead of handing you a
  wall of markup or pushing you into a separate window.

### Fixed

- **The chat's navigation rail stays reachable.** Moving the pointer toward the
  rail could make it slip away before you arrived, so clicking a marker turned
  into a chase. It now stays open while you approach it and while you are on
  it, fades between states instead of snapping, and tells a screen reader what
  it is and which message you are on.
- **A remote host no longer reconnects into its own ghost.** After a dropped
  connection the app could latch onto the dead half of the previous session and
  sit there looking connected while nothing arrived.
- **Background workers cannot stall past their deadline in silence.** The
  supervision that force-ends a wedged worker is now part of the same code path
  that waits for it, so a worker that stops responding is ended and reported
  instead of holding up everything behind it. This lands the completed version
  of work that was previously reverted here because it did not build on macOS.
- **The research panel no longer breaks on an incomplete configuration.** A
  missing engine list in the footer summary took the whole panel down instead
  of showing what it did know.

## [0.2.105] - 2026-08-19

### Fixed

- **Semantic code search works again on macOS.** The Mac app shipped with a
  local search-assistant program older than the app itself, so every attempt to
  understand your code by meaning failed the moment it started. Nothing said
  so: search quietly fell back to plain text matching and the status panel kept
  naming the model it could not actually use. Searching by intent now works,
  and if that helper ever fails to start again, the status panel says so
  outright instead of reporting everything as ready.
- **Workers can no longer hang silently past every deadline.** A worker
  frozen mid-finalization stayed `running` for 87 minutes while the main
  agent waited, because the supervision ladder was advisory in four
  compounding ways. A blocking `wait`/`wait_all` now sweeps the watchdog
  itself (on entry, per supervision interval, once at the deadline) instead
  of sleeping through worker deadlines, and its timeout carries actionable
  `stall_evidence` for every worker past its deadline or heartbeat grace
  while still non-terminal. Cooperative escalations that fail silently
  (wedged finalization slot, undeliverable interrupt) now increment a
  persisted failure counter; after three consecutive failures the sweep
  force-terminates the worker through the same cancel+abort path a manual
  close uses. The watchdog scheduler thread survives transient panics and
  resolution failures with 60s-backoff re-arm instead of dying permanently
  while its started flag stays true. Stalled heartbeats emit a
  `WorkerDeadlineGrace` event (300s cooldown) that previously had a
  formatter but no producer.

## [0.2.104] - 2026-08-18

### Fixed

- **Session-worktree work now flows back automatically — and is never destroyed
  at close.** An audit found work done in isolated session worktrees NEVER
  returned to the main checkout on its own (in this repository alone: 16
  stranded session branches with 27 unmerged commits), and worse, closing a
  session could silently DELETE its worktree, branch and every commit in it
  before the fold-back ran. Fold-back is now commit-preserving (cherry-pick
  with patch-id de-duplication instead of an all-or-nothing patch), conflict
  partial results are recorded and retryable, quitting the app folds every
  session back, a startup sweep recovers cold trees after a crash, and
  isolating a session moves its claimed files out of the shared checkout so a
  sibling session can no longer commit them as its own.

## [0.2.103] - 2026-08-18

### Added

- **Session templates carry the whole session setup.** A template now spans
  model, tools, worker roles and limits, so starting a recurring kind of work
  is one pick instead of a dozen settings. Both frontends ship a template
  editor and a template picker in the new-session dialog, including
  configurable time and budget limits per template.
- **Memory-pressure admission gate.** After the 2026-08-17 resource-exhaustion
  incident (96 % Windows commit charge, several parallel rustc children at
  6-8 GiB each), new compile jobs are refused while commit charge is critical
  instead of walking the machine past the commit wall. Incidents land in the
  run ledger with app-log and crash-dump plumbing to diagnose them.

### Changed

- **Remote screen capture is damage-tracked.** The remote-admin screen share
  stops doing a full PNG round trip per frame and sends only what changed,
  with ack-based flow control.
- **CPU use is recorded centrally.** Per-session CPU utilization is captured
  durably and one central CPU budget replaces scattered ad-hoc checks.

### Fixed

- **Orphaned session worktrees are visible and integrable.** The overview now
  lists worktrees whose session is gone, with an integrate-all action, and a
  batch of stranded sessions has been merged.
- **Worker terminal status stays terminal.** A finished worker no longer
  flips back to running (zombie revive), a worker that dies on a broken seed
  no longer takes the run with it, and goal reconciliation demands delivery
  evidence before checking an item off.
- **Self-memory writes no longer fail under lock contention.** Store locks are
  fair (ending load-dependent write failures), composition is shard-aware,
  and the legacy user-memory engine is consolidated.
- **The credential vault opens from the detached settings window.** Settings
  runs as its own native window, which previously left the vault unable to
  reach it; app-bound encrypted cookie stores are handled type-safely.
- **A question asked mid-run always gets a visible answer.** User turns that
  arrive while work is in flight are answered instead of being swallowed by
  the run loop.

## [0.2.102] - 2026-08-17

### Changed

- **Compaction handovers carry the model's reasoning — and got smaller.** The
  session ledger now captures a bounded thinking digest per assistant turn, so
  the deterministic handover preserves why decisions were made, not only what
  happened. At the same time the handover's ledger budget was halved (64 →
  32 KB), the user-intent section is byte-bounded (original request and latest
  intent always survive), and a session that withholds tool schemas gets one
  line naming the already-activated tools so the model does not re-activate
  them after a compaction. Anything omitted stays one recovery call away via
  the segment pointers.

### Removed

- **The dead "Compaction model" setting.** Compaction has rendered its handover
  deterministically from the session ledger since 0.2.77 and never calls a
  model, so the setting and its thinking-level dropdown configured machinery
  that could no longer run. The setting, the unreachable LLM-summarization
  code behind it, and background pre-compaction (which only existed to hide
  LLM latency) are gone; a blocked or unset model can no longer fail a
  compaction. Session consolidation commits the same deterministic summary and
  no longer asks you to pick a model.

## [0.2.101] - 2026-08-16

### Added

- **Search panel filter chips.** Results now offer type and folder facets built
  from the results themselves, so narrowing a large result set takes one click.
- **Settings search.** A search box in the settings dialog header jumps straight
  to the group that contains what you typed.

### Fixed

- Agent scopes load without an open workspace, and a control that stays locked
  now says why instead of failing silently.

## [0.2.100] - 2026-08-16

### Fixed

- **Terminal sessions survive a panel switch again.** Open shells are restored
  with their scrollback instead of disappearing when the terminal panel is
  remounted.
- **Sessions no longer get stuck on "New Session".** A lost race between the
  automatic rename and the first turn kept the old placeholder title.
- Notification banners stop stacking and overlapping; their accumulation is
  bounded.
- The chat scroll no longer jumps in the remaining cases found by the scroll
  audit, and toast sizing plus the dialog editors follow the shared panel
  design.
- Index settings are saved by the owning scope again (project vs. global), and
  the index graph actions are exposed under one canonical, singular name.

### Changed

- **Index panel redesigned** around index statistics and the code graph.
- Panel settings live in the three-dots overflow menu across the panels, for
  one consistent place to find them.

### Added

- Providers and their OAuth login can be driven by an extension through
  `unary.providers.controls`, applied fail-closed by the host.

## [0.2.99] - 2026-08-16

### Fixed

- **Interrupting the agent no longer throws away a running command.** A queued
  message used to kill a foreground shell that had been quiet for a few
  seconds. The process is now parked in the background instead: the agent reads
  your message first and can then re-attach, let it keep running, or stop it.
- **Panel buttons work again after a maximized layout is restored.** Opening
  Index, Memory & Dream and the other side panels used to do nothing when the
  saved layout had a maximized tab group; panels are now revealed.
- Failed turns show the plain red error box again, and the model's narration
  between tool calls is normal text instead of a bordered chip.
- GLM-5.3 requests match the current vendor documentation (reasoning effort
  levels and streaming tool-call wire surface).

### Changed

- **Memory panel split by purpose.** Repo scope now shows only what forms
  `MEMORY.md`; bugs, friction and ideas are gathered globally under Errors.
  Global entries use a full-width list, and every button in the panel uses the
  shared UI controls.
- Consistent panel design language across Index, file search, diff and review,
  git worktree, sessions, subagents, automations, browser, debug and remote
  panels — same headers, spacing and controls; the chat composer's active
  switch lost its filled box.
- File search gained tag-based filtering.

### Added

- Provider catalogs can ship as `unary.providers` extension packs, exported
  from the built-in catalog and verified field-for-field on load.
- The plugin creator generates a fuller working plugin scaffold.

## [0.2.98] - 2026-08-15

### Fixed

- **The agent's worker fleet no longer strands after a policy change.**
  Switching the session mode (or any other policy re-apply — a permission
  change, auto-compaction, picking another model) could permanently disable
  spawning subagents with a misleading "only available inside harness-backed
  agent sessions" error, even after conditions returned. The orchestration
  handle now survives every policy apply.

### Added

- **Memory learns across sessions in layers.** At session end the memory
  system now distills related records into higher-level knowledge blocks
  (scenario and persona layers) that are read first at the next session
  start — instead of every repo forever searching only its atomized records.
  One bounded model call per layer per day/week, refusal-safe.
- The agent's `harness_health` self-diagnosis now names the exact running
  build version, so a known-and-fixed defect can be told apart from one that
  is fixed in the tree but not yet in the installed build.

### Changed

- The fast-mode toggle now states honestly, for Codex models, that the
  endpoint accepts the priority tier but does not confirm it and may not
  apply it on every plan.

## [0.2.97] - 2026-08-15

### Added

- **The agent can now debug running code.** It can launch or attach to a
  program, set breakpoints — including conditional and log breakpoints — run
  until one hits, inspect the call stack and variables, evaluate expressions
  on the stopped frame, change variable values, break on exceptions and stop
  the program cleanly. This works in every window where chat runs, the IDE and
  the desktop app alike, with the debug adapters already configured for the
  debugger panel (Python and Go today).
- Extensions can now register their own dock panels and fill them with their
  own UI.
- New **UNARY Studio** theme family: dark and light, each with a glass
  variant.

### Changed

- Notification banners act in place: answer inline and trigger actions
  directly on the banner instead of switching to the session.
- In the desktop app, dialogs moved the close button to the far edge of the
  header.

## [0.2.96] - 2026-08-15

### Added

- The **Search** panel is now available in the desktop app too — the same
  "Search" tab the IDE dock has, with results opening in the file preview.
  Saved layouts are unaffected.

### Changed

- **Memory panel navigation redesigned.** The scope switch (Session, Repo,
  Global) stays on top; each scope's pages — MEMORY.md, Entries, Errors — moved
  from a pill row into a slim rail on the right edge, whose active item looks
  exactly like the active session in the session list. Status became a quiet
  footer line (online state and entry count), and bulk actions live in the
  panel's “…” menu instead of the navigation row. Errors are shown only in the
  Global scope.
- The Knowledge panel's “Manage docs / Improve and version” switch uses the
  same right-hand rail, so both panels navigate the same way.
- Chat rendering polish: assistant messages and tool-call views render richer
  content, run dividers mark where a new run begins, and hover fills follow
  rounded corners.

## [0.2.95] - 2026-08-15

### Added

- **Multi Expert mode**, off by default. A new session mode where every
  request is answered by a roster of models you configure instead of one: each
  expert answers independently, then a judge model compares the answers and
  delivers a single verdict - the winner, a synthesis, and where the experts
  disagreed. The settings block names the roster and the judge and warns
  plainly that a request bills every model on it, so token use multiplies by
  roughly the roster size. When the judge or every expert fails, the error
  becomes the answer - it never quietly falls back to a single model.

### Changed

- Settings groups model providers into visual sections and drops the favorites
  list; every settings gear is the same crisp cog icon, and window controls
  (minimize, maximize, close) are drawn as shapes instead of text glyphs, sharp
  at any size. Maximizing a dialog is opt-in.
- The worktree sidebar keeps one removal path: the row's delete x is gone, the
  kind menu can remove all worktrees at once, and its overview entry works.
- Research settings shows its per-run options with a Save bar, like the rest.
- One checkbox control everywhere - the same control in every panel.

### Fixed

- HTML file previews render like the file does in a browser. A page's own
  stylesheets, images and fonts used to load as broken links, so previews came
  out unstyled; scripts now run behind an explicit per-file toggle instead of
  being silently disabled.
- Renaming a session shows up in the session list immediately, while the
  rename is still being saved.
- The Memory panel's Global tabs read and compose user memory through the same
  path as the rest of the panel, and no longer show status and action columns
  that did nothing there.
- URA scripts get an honest host interface: paths are anchored where they are
  documented to be, return values match their documented shapes, and saved
  state actually persists.
- The branch dialog's MODE switch is only as wide as its content.

## [0.2.94] - 2026-08-15

### Added

- The Git panel has a **Leftover folders** section. A worker checkout whose Git
  registration is gone but whose directory is still on disk appeared in no panel
  at all — every other section walks `git worktree list`, so a folder Git had
  already forgotten was invisible while the sidebar kept warning about it. Six
  of them sat in this repository. Each row names the branch that still holds the
  work, its size on disk and its age, and removes with one button; a checkbox
  deletes that branch along with the folder. The remover re-checks three fences
  itself: inside this project's `.unary/worktrees/`, not registered with Git,
  and no running session working in it.
- Local branches can be cleaned up in bulk. The section header carries
  **Cleanup merged** and **Delete all but current**, the second of which keeps
  the current branch, the main branch and anything checked out in a worktree,
  acts on the branches the active filter is showing, and asks a second time
  before it force-deletes the ones Git refused as unmerged.

### Fixed

- The sidebar's leftover-worktree warning counts the folders that are really
  there. It counted only the removals that had RECORDED a failure, so a folder
  whose registration vanished quietly was warned about by nobody, and its
  tooltip claimed the work was already in the parent branch — true for a
  recorded cleanup failure, unverified for the rest. It now names where to
  remove them instead.

## [0.2.93] - 2026-08-14

### Added

- GLM-5.3 is selectable on the z.ai Coding Plan. It is the model the plan now
  serves to every tier — 1M tokens of context, up to 128K tokens of output, and
  the same two thinking depths as GLM-5.2, so High and Max keep working as
  before.

## [0.2.92] - 2026-08-14

### Changed

- The scroll-in animation feels soft again. Trading the blur for a short fade
  made it read as a pop, so the curve is long and decelerating again and a small
  blur is back — this time on a promoted layer and only for the first 200ms, so
  the GPU softens a texture it already has instead of redrawing the row on every
  frame. Ordinary trackpad and wheel scrolling keeps the animation now; only a
  real flick still skips it.

## [0.2.91] - 2026-08-14

### Fixed

- Scrolling back through a long chat no longer drifts under the cursor. A row
  that resolves above the viewport is compensated the moment it resolves rather
  than after the scroll settles, and the transcript now measures the row spacing
  the theme actually applies instead of assuming it — it assumed 16px while the
  themes ship 10px, so a few hundred rows of history were off by more than a
  screen.
- Code blocks and long messages start rendering before they reach the screen.
  Their preload distance was measured against the window instead of the chat
  scroller, which meant nothing was ever preloaded and code colorized under the
  cursor as it scrolled in.
- A message taller than about eleven screens could stay invisible: the scroll-in
  animation waited for a fraction of the row to be on screen that a row that
  tall can never reach.

### Changed

- The scroll-in animation keeps its look for a fraction of the cost: history
  rows fade and settle without the blur pass that re-rendered a full-width block
  on every frame, the blur stays on the live row at the end of the transcript,
  and nothing animates at all during a fast flick.
- The transcript keeps more rendered rows ahead of the direction you are
  scrolling and fewer behind it, so a flick meets fewer blank gaps for the same
  amount of work.
- Paging is symmetric again: scrolling back down to the end loads the newer
  messages by itself instead of waiting for a button, and jumping to a message
  stops walking there one screen at a time.

## [0.2.90] - 2026-08-13

### Fixed

- Built-in capabilities that come up after a session starts — the code index,
  Research, Memory and the browser — could be offered to the model and then
  refused the moment it asked for one. The list the model is shown and the gate
  that answers for it are now brought together at the one point both are read,
  so what is offered can always be loaded.
- A code search hit now carries a fingerprint of the symbol it found, so an edit
  can be applied straight from a search result without reading the file first.
  It previously carried a fingerprint of the whole file, which no edit ever
  accepts, and on Windows checkouts the line endings made it disagree a second
  time.

### Changed

- Index and Research say what they are: built in and switchable per workspace,
  rather than extensions that look installable.

## [0.2.89] - 2026-08-13

### Added

- Tools can be activated while a run is in progress: a withheld tool's schema
  arrives immediately instead of waiting for the next turn.
- The Assistant's library tabs are one surface again instead of two lists that
  drifted apart.

### Fixed

- A repeated identical call could lock a run in place. Goal ids now resolve from
  a unique prefix and the repeat breaker stops the loop instead of riding it.
- `activate_tool` accepts every tool name the capability map advertises, so a
  card the model was shown could no longer be refused when it asked for it.
- The sidebar's attention badge counts the rows it actually pulls.

## [0.2.88] - 2026-08-13

### Added

- The Git panel has a section of its own for subagent worktrees. Worker trees no
  longer hide among the checked-out branches, and the two cleanup actions moved
  out of a section they were never about into that one, as "Remove all" and
  "All projects".
- One list of every worktree nobody is working in right now, with the ones that
  never reached the parent branch first. Each row opens its session, folds the
  tree back or merges its branch, reviews the diff, or removes the folder.

### Changed

- The Git panel's buttons are round like every other control, and they now carry
  a meaning instead of one uniform look: filled creates, plain opens a dialog,
  and a filter tints itself while it narrows the list.
- Every worktree states what it is - conflict, not folded back, undetermined, or
  merely left over - and the list says the distribution once instead of leaving
  it to be counted. A leftover folder was previously counted on the project row
  but had no row of its own to act on.

### Fixed

- A project on a single branch listed all of its sessions twice, once flat and
  once inside the branch group.

## [0.2.87] - 2026-08-13

### Fixed

- Every build after 0.2.84 started and then froze. The sidebar's branch poll read
  and wrote the same reactive value inside one effect, so the effect re-ran
  itself without end, spawning a git process per project on every pass.

## [0.2.86] - 2026-08-13

### Added

- A `Tools` control sits beside the chat filter. It shows the catalog mode, the
  tool families callable right now and the ones still withheld, and loads a
  withheld family on request.

### Fixed

- Withholding a tool family only ever changed the prose. The prompt told the
  model to load those families first while their full schemas travelled in the
  request anyway, so the catalog saved nothing and the model spent turns opening
  a door it did not need. A withheld family now stays off the wire.
- A family activated during a session kept being listed as withheld in the
  prompt, so the model tried to activate what it already held.

## [0.2.85] - 2026-08-12

### Fixed

- Switching a checkout's branch in place now moves every session of that folder
  with it. The worktree list behind the grouping was read once per project and
  never again, so it kept naming the old branch and the sessions of one folder
  split across two branch groups - which a single directory can never be in.
- The per-worktree menu in the inactive list was invisible: the rule that
  reveals a row's actions on hover did not cover those rows, so the menu
  shipped unreachable.
- Fold-back is only offered where it can work. It applies to a session's own
  tree under `.unary/worktrees/session/`; on a worker tree it could only ever
  answer "not a Unary-managed session worktree". Worker trees now offer merging
  their branch, reviewing its diff, or removing the folder.
- When fold-back is unavailable in bulk, the menu says which trees block it and
  why, instead of restating the rule next to a count of zero.

### Changed

- A session that still owns a worker worktree nobody folded back is marked on
  the whole row, and its branch group carries the same count as the project.
- The project row states the session count and the attention count in one line;
  the separate chip that repeated it is gone.

## [0.2.84] - 2026-08-12

### Fixed

- Removing a worktree failed with "not a git repository" in the installed app.
  Git resolves the repository from the working directory, never from the path
  you hand it, and the app ran the command in its install folder - so every
  removal reported a failure and removed nothing.

### Changed

- Sessions are grouped by the branch their folder is actually on. A directory
  has one branch at a time, so switching in place now moves every session of
  that folder with it instead of leaving them filed under the branch they
  started on; the old branch stays visible as their origin.
- Every branch with sessions is its own named group. Previously one branch was
  a loose list and all others were groups, which required an answer to "which
  one is main?" that a project with several worktrees does not have.
- Worktrees appear exactly once, at their place. "Not folded back" is no longer
  a second list next to the worker trees but a marker on the tree itself, a
  count on the project row that is visible while the project is collapsed, and
  a filter that narrows the same tree.
- A worktree whose worker is still running no longer counts as "not folded
  back". Unfinished work is what a running worker is for.

### Added

- One list of every worktree nobody is working in right now, with the ones that
  never reached the parent branch first. Each row opens its session, folds the
  tree back, inspects the changes, or removes it.
- A new-session button on every branch group, starting the session in the
  folder that branch is checked out in.

## [0.2.83] - 2026-08-12

### Fixed

- A stale worktree could only be deleted after opening its dialog. The row now
  carries the same delete control, and using it no longer toggles the row.
- The hand cursor had reappeared on two desktop shell surfaces.

## [0.2.82] - 2026-08-12

### Fixed

- A worker was offered withheld tools it could not reach. The role filter
  removed the very entry that activates them, so the prompt advertised eleven
  tools and none of them could be loaded.

## [0.2.81] - 2026-08-12

### Fixed

- Turning Unary Flow off left it running. Every check compared against the
  tool's name while the code needed its family, so the switch matched nothing.
- Plugin tools were missing entirely from sessions that load schemas on demand.
  Memory, index, research, browser, desktop and NotebookLM reported that no such
  tool existed, while the prompt still carried full instructions for using them.
  0.2.80 made withholding effective and, in doing so, froze the catalog before
  the plugins had registered.

## [0.2.80] - 2026-08-12

### Fixed

- Turning Unary Flow off did not actually remove it. The switch compared against
  the tool's old name, so the tool stayed in the catalog and its prefix tokens
  were billed on every request of every session that had deliberately switched
  it off.

## [0.2.79] - 2026-08-12

**Withholding actually works now.** A session configured to load tool schemas on
demand kept the schemas off the wire, and then told the model nothing had been
withheld - so the thirteen tools it had held back were unreachable for the rest
of the session. The prompt listed them correctly; only the way back was missing.

### Fixed

- `activate_tool` answered "This session withholds no tools" in sessions that
  were withholding. The dispatcher never received the gate the session had
  built.
- The tool catalog setting showed "Withheld (default)" whether or not anything
  had ever been saved, so a configured session and an untouched one looked
  identical.
- The Flow toggle still called the tool by its old name. It is `ura` now, and it
  runs Lua in a persistent kernel rather than a declarative workflow language.


## [0.2.78] - 2026-08-11

**The agent picks the right tool noticeably more often.** Three tool families
carried descriptions that were accurate and still left the choice ambiguous, and
the measurement named every one of them. `index` had no per-action descriptions
at all. `list_windows` never said it returns nothing about what is inside a
window, so "look at this window and tell me what's on screen" went to the wrong
action. And memory's repo store and personal store both pointed at each other
without saying what actually separates them - a rule worded as a general habit
("I always …") is still a rule about the repository you are in.

Across the five measured models, action-choice accuracy now sits at 96-100 %,
with tool choice at 96-100 %. Every point came from clearer wording: nothing was
renamed, no action was removed, and no test was relaxed.

### Fixed

- The prompt told the model it could load a tool schema through a search this
  build does not ship, so it invented an activation call and lost two turns
  before giving up. It now names the mechanism that exists.
- Arguments a provider sent as JSON *text* were rejected even though the payload
  inside was correct, and the error repeated the schema instead of naming the
  argument. Both are fixed: the wrapper is undone before validation, and what is
  refused now says which argument is wrong and what shape it needs.
- Failed tool calls were filed as known bugs and replayed into every later
  session - including a guard correctly refusing a costly command, a
  read-before-edit precondition, and once a C++ header as the bug title.
- The same call failing twice in the same way is answered immediately instead of
  after five silent turns.
- NotebookLM shipped a full page of instructions even with no account connected.
  It now costs one line saying it is disconnected.
- An empty reasoning block could be sent to the provider, which is exactly what
  breaks conversation replay and prompt caching.
- Two diagnostic counters read as contradictions because their names implied a
  relationship they never had: a context remainder of 0 looked like "no context
  used", and a rendered-row count looked like more messages than exist.

- Asking to list an app's UI-atlas control ids took a screenshot instead of
  reading the atlas.
- A working preference for the current repository could be filed as a global
  fact about you, where it would follow you into unrelated projects.

## 0.2.77

**The tool catalog no longer ships whole on every request.** A session now
starts from a measured core and loads the rest of a tool's schema the moment it
decides to use one. Measured over a 52-turn session: the same tool-choice
accuracy, 1.9 points of action accuracy given up, and 54 % fewer prompt tokens.
Settings › AI Agent lets you choose: withheld (new default), eager (everything
up front, best accuracy), or fixed.

**Compaction stopped calling a model.** It is built from the session ledger
alone, so it costs milliseconds instead of seconds and works with no
summarisation model configured. The handover also stopped inlining tool output —
it cites the call id instead, so a compacted session no longer grows with the
work it did.

**Tested models and providers are grouped first**, with a badge whose tooltip
carries the actual measurement: tool-choice rate, action-choice rate, and the
date of the run. Nothing is hand-curated; a model is listed because it was
measured.

### Fixed

- Small purpose-built sessions (Pilot controller, assistant) could have started
  with an empty catalog under the new default.
- Flow sessions and worker milestone reporting kept their own tools, which the
  measured core did not know about.
