| 1 | # Changelog |
| 2 | |
| 3 | All notable changes to this project will be documented in this file. |
| 4 | |
| 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), |
| 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). |
| 7 | |
| 8 | ## [Unreleased] |
| 9 | |
| 10 | ## [0.10.1] - 2026-10-01 |
| 11 | |
| 12 | Codewhale v0.10.1 focuses on reliability and first-run behavior. Turns that |
| 13 | stall now say so, approvals keep what you approved, plugin suggestions are |
| 14 | quieter, and Fleet runs can be checked before they spend anything. |
| 15 | Scripts that parse `--json` output should read the **Breaking for scripts** |
| 16 | note below before upgrading. |
| 17 | |
| 18 | ### Added |
| 19 | |
| 20 | - Experimental TypeScript extension host. New in this release and off by |
| 21 | default: turn it on with `[features] extension_host = true`. A plugin that |
| 22 | declares a `native` TypeScript or JavaScript entry (the Cordis / DeepSeek |
| 23 | Harness plugin model) can contribute tools, slash commands, pre-execution |
| 24 | policy hooks, additive prompt sections, reviewed skill roots and plugin-local |
| 25 | JSON state. Its code runs in a separate |
| 26 | Node process, never inside Codewhale (Bun is an opt-in through |
| 27 | `[extension_host] runtime`), and every call goes through Codewhale's own gate: |
| 28 | an extension tool is never treated as read-only, so it always meets the |
| 29 | approval gate (Full Access, Bypass or a session grant for that reviewed plugin |
| 30 | can satisfy it), a command runs only when you type it, and a plugin must be |
| 31 | reviewed and enabled first. The host is sandboxed on macOS (Seatbelt) and on |
| 32 | Linux with bubblewrap, with no direct network and no reads of the protected |
| 33 | credential locations (Codewhale's secret stores and the Codewhale, Codex and |
| 34 | DSH homes). A Native extension starts only after that sandbox is verified at |
| 35 | launch: if bubblewrap is missing or its namespace probe fails, activation is |
| 36 | refused with the concrete error. Codewhale's own pinned built-in host modules |
| 37 | keep a diagnosed exception, and every effect still needs a Rust operation |
| 38 | ticket. On Windows a Native extension starts only in a freshly created Less |
| 39 | Privileged AppContainer whose only capability is `registryRead` (Winsock |
| 40 | cannot start without it), after Codewhale checks its token and a real file |
| 41 | and network probe; otherwise activation is refused. |
| 42 | Other files you |
| 43 | can read, such as project `.env` files, stay readable, and plugins sharing the |
| 44 | host can interfere with each other, so enable only plugins you have reviewed |
| 45 | ([docs/EXTENSIONS.md](docs/EXTENSIONS.md)). |
| 46 | - Extension slash commands: a plugin registers one with `ctx.commands.register`. |
| 47 | It runs only when you type it, and it can show text, or submit a prompt as |
| 48 | your next message that then goes through the ordinary turn and its approvals; |
| 49 | it cannot call the model or a tool itself. A command cannot take a built-in |
| 50 | command's name or another plugin's, and a markdown command with the same name |
| 51 | wins. A command has 30 seconds, and commands are TUI only: the Runtime API |
| 52 | does not list or run them. |
| 53 | - Native extension authoring now includes policy listeners through |
| 54 | `ctx.on('tools/pre-execute', ...)`, prompt sections through |
| 55 | `ctx.prompt.registerSection`, and persistent plugin-local state through |
| 56 | `ctx.storage`. Listeners may deny, ask, revise input or annotate; Rust |
| 57 | rechecks revised calls and owns every approval. Prompt sections cannot |
| 58 | replace the system prompt, and state exposes no session history or secret |
| 59 | API. These services share the experimental, off-by-default host's reviewed |
| 60 | owner lifecycle and are withdrawn when their owner unloads or is revoked; |
| 61 | saved state remains available when the plugin reloads. |
| 62 | - Extension tool input is checked against the JSON Schema the tool registered, |
| 63 | before an approval card appears and again before the call reaches the host. An |
| 64 | invalid call comes back to the model as an error naming what to correct, and |
| 65 | the host never sees it. A schema that cannot be compiled, or that refers |
| 66 | outside itself with `$ref`, is refused when the tool registers. |
| 67 | - An extension tool can call eligible core tools with `core/call` while the |
| 68 | ordinary turn is running that extension tool. Rust supplies a temporary |
| 69 | invocation ticket and still owns planning, hooks, permissions, approval and |
| 70 | execution. The ticket is bound to the plugin owner, host process and live |
| 71 | invocation, and expires when that invocation ends or is revoked. Commands, |
| 72 | timers and plugin startup cannot use this path. Approval grants are scoped |
| 73 | to the reviewed extension build; a grant to the model does not cover it. |
| 74 | Shell and network calls require a person's prompt even with a remembered |
| 75 | grant; a permission mode that cannot present that prompt refuses the call. |
| 76 | MCP tools, Computer Use, other extensions, agent/workflow launches and |
| 77 | permission-changing tools remain unavailable through this path. A cancelled |
| 78 | invocation withdraws its pending approvals instead of deciding them for you. |
| 79 | - Extension host identity is checked at startup: its reported trust tier and |
| 80 | built-in module digests must match the process Rust launched. Built-in host |
| 81 | code and third-party plugins have separate process and owner namespaces; |
| 82 | the table pins the MCP protocol module and the execution harness. The |
| 83 | optional Host MCP backend uses the official TypeScript SDK for framing, |
| 84 | with Rust retaining credentials, network/process access, approval and exact |
| 85 | operation tickets. All 30 existing recorded comparisons pass locally. |
| 86 | The Rust backend stays the default until platform and rollout gates pass; |
| 87 | its protocol adapters remain through the compatibility window. |
| 88 | - A plugin can declare several `native` entries (`native.paths`, up to 64). They |
| 89 | activate in order under one owner, so one disable, review change or crash |
| 90 | takes all of them down. If one entry fails to activate, only that entry is |
| 91 | withdrawn: entries that already activated stay registered, and the plugin |
| 92 | fails only when no entry activates. |
| 93 | - Plugin settings and context: `[plugins."<name>".config]` in your own |
| 94 | `config.toml` is passed to the plugin's `apply(ctx, config)` and checked |
| 95 | against its exported `Config` schema; a project's `.codewhale/config.toml` |
| 96 | cannot set it, a change applies at `/plugin reload`, and `/plugin show` lists |
| 97 | the keys, never the values. Tools and commands also receive the workspace of |
| 98 | the session that called them and a private data directory for the plugin under |
| 99 | `~/.codewhale/extension-host/data/plugins/`; no home, credential or other |
| 100 | workspace path is passed. |
| 101 | - `codewhale --enable <feature>` and `--disable <feature>` work from the |
| 102 | `codewhale` command; before, they were rejected. Put the flag before any |
| 103 | subcommand. |
| 104 | - The extension host bundle carries MIT-licensed code (Cordis, Schemastery and |
| 105 | others). Its third-party licence notices are generated from what the bundle |
| 106 | actually contains and written beside the bundle when it is unpacked, and |
| 107 | `THIRD_PARTY_NOTICES.md` lists the packages. |
| 108 | - Extension host runtime: Bun 1.4.0 or newer is an opt-in; Node stays the default. `[extension_host] runtime = "node" | "bun" | "auto"` chooses: unset means `node` (or `bun` when the table sets only a `bun` path), `bun` runs only Bun, and `auto` prefers a supported Bun and uses Node when none is found or the Bun host fails to start. An explicit choice never falls back, and restarts keep the runtime the session first started on; a runtime binary replaced mid-session is refused. A configured `node` or `bun` path is used as given and fails loudly rather than falling through to `PATH`, and a runtime found on `PATH` inside a `node_modules` directory or the working directory is skipped, not run. `codewhale doctor` and `/plugin` show which runtime runs the host, why, and how its memory is capped. Under Bun the host never auto-installs packages and ignores `.env` and `bunfig.toml` in its data directory. Extensions cannot run native code inside the host on either runtime: `bun:ffi`, `Bun.FFI`, `node:ffi`, the SQLite builtins, `process.dlopen`, `process.execve`, Worker threads and `ShadowRealm` are refused, and the host will not start if one of these restrictions does not hold. Known limit: that lockdown covers the native-code entry points found so far (Bun 1.4, Node 22 and 26); one a newer runtime adds is not covered until it is added. The 1 GiB memory cap uses `RLIMIT_DATA` on Linux, the Job Object on Windows and, for a Bun host, a kernel jetsam limit on macOS; a Node host on macOS is checked at each heartbeat. Bun is qualified on macOS only: the Rust host tests, the memory cap included, have not run a Bun host on Linux or Windows (CI runs them with Node, and the JS host suites under Bun 1.4.0 on Linux). `host/hello` reports the runtime and version that actually run. |
| 109 | - `docs/features.toml` lists every user feature with its status, first |
| 110 | release, docs page and owning code. A test fails when a `[features]` flag |
| 111 | and its row disagree, or when a listed docs page or code path is missing. |
| 112 | The configuration reference now lists the `verify_tool`, `vision_model` and |
| 113 | `extension_host` flags, and `config.example.toml` lists `code_mode`. |
| 114 | - A reusable GitHub Action runs PR reviews with a configurable model endpoint |
| 115 | and a checksum-pinned Codewhale binary. It checks the PR's eligibility and |
| 116 | exact revisions before inference; fork events receive no model key |
| 117 | ([#6780](https://github.com/codewhale-hq/Codewhale/pull/6780)). |
| 118 | - An optional, off-by-default shadow Decision Gate classifies the first request |
| 119 | of a turn — tool need, answerability from context, intent — through the |
| 120 | existing System One client and only logs a typed recommendation; it never |
| 121 | changes routing or delays the model call. Configure it with |
| 122 | `SUPERFAST_ENABLED` and `SUPERFAST_PROVIDER` (docs/CONFIGURATION.md) |
| 123 | ([#6603](https://github.com/codewhale-hq/Codewhale/issues/6603), |
| 124 | [#6604](https://github.com/codewhale-hq/Codewhale/pull/6604), thanks @Andrea-Bruno). |
| 125 | - `tool_call_after` hooks for shell tools receive `DEEPSEEK_TOOL_EXECUTION_RECEIPT`: the command that actually ran after admission, its working directory, how it ended, and bounded stdout/stderr previews, so a hook can record exactly what executed ([#6689](https://github.com/codewhale-hq/Codewhale/issues/6689), requested by [@wuisabel-gif](https://github.com/wuisabel-gif)). |
| 126 | Supported settled local shell calls also send a versioned JSON document on |
| 127 | stdin to foreground or background observers, with session/tool-call IDs, |
| 128 | nullable exit status and output truncation flags. Existing environment fields |
| 129 | stay available; unsupported execution paths send no document, and observer |
| 130 | output cannot change the completed call |
| 131 | ([#6582](https://github.com/codewhale-hq/Codewhale/issues/6582)). |
| 132 | - Runtime API: turns now record what they produced. Each item and turn |
| 133 | carries typed artifact references (path, kind, size, revision, and a |
| 134 | restore point when file-revert would accept one) for files a tool wrote, |
| 135 | spilled tool output, and media. |
| 136 | - Once the post-turn snapshot settles, the turn also lists what changed in |
| 137 | the workspace while it ran, including shell and sub-agent writes. It then |
| 138 | publishes `turn.artifacts`. |
| 139 | - `GET /v1/threads/{id}/turns/{turn_id}/artifacts` lists a turn's |
| 140 | references, and `.../artifacts/{artifact_id}` reads one from the |
| 141 | workspace, the post-turn snapshot or the session artifact directory. |
| 142 | - Spills from unbound runtime threads were unreadable before; they are now |
| 143 | readable. |
| 144 | - The legacy `artifact_refs` field is now filled with the workspace files a |
| 145 | tool call wrote, so Preview in current desktop builds shows them |
| 146 | ([#6653](https://github.com/codewhale-hq/Codewhale/issues/6653)). |
| 147 | - Runtime API: git stage, unstage, discard and commit accept optional |
| 148 | `expect` preconditions (full HEAD id, an index token, per-file `rev`, or a |
| 149 | whole-tree `revision`, all read from `GET /v1/git`). When the repository |
| 150 | changed since the client read it, the write does nothing and answers 409 |
| 151 | `git_state_changed` with the current state, so a Review sheet can no |
| 152 | longer stage bytes, discard edits or commit an index the user never saw. |
| 153 | Requests without `expect` behave as before. Path writes now use literal |
| 154 | pathspecs, as the docs already said, and `files[].path` is |
| 155 | workspace-relative in a subdirectory workspace. Guards cover executable |
| 156 | mode, submodule HEAD and changes outside that workspace; oversized or |
| 157 | budget-limited stat-only revisions cannot authorize a guarded write. |
| 158 | Status stays best-effort: unreadable paths, symlinked ancestors, special |
| 159 | files and broken nested repositories withhold only affected row tokens |
| 160 | and the whole-tree revision. Normal Git filters and untracked settings |
| 161 | apply, with directory inventories scoped to the rows or paths that need |
| 162 | them. Untracked workspace files and renames leaving the workspace remain |
| 163 | visible, and broken HEADs cannot satisfy an unborn-HEAD guard |
| 164 | ([#6647](https://github.com/codewhale-hq/Codewhale/issues/6647)). |
| 165 | - Runtime API: `POST /v1/threads/{id}/fork-at-turn` forks a thread at a named |
| 166 | user turn, keeping that turn and every turn before it. The receipt matches |
| 167 | `/undo` and returns the first dropped prompt so a client can put it back in |
| 168 | the composer. Naming the turn replaces a client-computed depth, which could |
| 169 | fork the wrong prefix. The fork leaves the workspace and any running turn |
| 170 | untouched |
| 171 | ([#6580](https://github.com/codewhale-hq/Codewhale/pull/6580), thanks @gaord). |
| 172 | - Official model routing: `/router` (also `/model router`) sets up the Auto |
| 173 | router with presets: Jev (TypeSafe's decision model, via OpenRouter or a |
| 174 | TypeSafe key), your provider's fast tier, Off, or Custom. Jev and Fast each |
| 175 | make one test call before you save, the Turn Inspector (Ctrl+Alt+O or |
| 176 | `/turn inspect`) shows the router's choice, cost and latency, and a failing |
| 177 | router is shown as failing |
| 178 | ([#6525](https://github.com/codewhale-hq/Codewhale/issues/6525)). |
| 179 | - ChatGPT sign-in uses Codewhale-owned protected credentials and a model roster |
| 180 | fetched for the signed-in account. Account, workspace and issuer changes |
| 181 | cannot reuse another roster; a missing or stale roster offers no models. |
| 182 | Authentication failures and subscription limits do not silently fall back |
| 183 | to a paid API route. |
| 184 | - Code mode composes MCP and plugin tools and is on by default: |
| 185 | `execute_tools` programs can call MCP tools, and each nested call passes the |
| 186 | same approval gate as a direct call, pausing the program for approval when |
| 187 | needed. Every nested call keeps its receipt, including calls that finish |
| 188 | before a deadline, and `[features] code_mode = false` stops offering |
| 189 | `execute_tools` up front (it stays reachable through tool search). |
| 190 | `codewhale mcp list` |
| 191 | and `codewhale doctor` warn when a user MCP server duplicates the built-in |
| 192 | Computer Use bundle |
| 193 | ([#6562](https://github.com/codewhale-hq/Codewhale/issues/6562), |
| 194 | [#6509](https://github.com/codewhale-hq/Codewhale/issues/6509)). |
| 195 | - Tsubasa is a bundled OpenAI-compatible provider row: base |
| 196 | `https://api.tsubasa.sh/v1`, key `TSUBASA_API_KEY`, model `tsubasa-pro` |
| 197 | (also `tsubasa-fast`). Its window is 32,768 tokens; set |
| 198 | `providers.tsubasa.context_window` to match |
| 199 | ([#6695](https://github.com/codewhale-hq/Codewhale/issues/6695), thanks @cenab). |
| 200 | |
| 201 | ### Changed |
| 202 | |
| 203 | - The pinned prompt header follows the turn at the top of the viewport, |
| 204 | handing over to the previous prompt as you scroll, and clicking it jumps back |
| 205 | to the message it names |
| 206 | ([#6830](https://github.com/codewhale-hq/Codewhale/pull/6830), thanks @SparkofSpike). |
| 207 | - On Windows, every PowerShell command the shell tool starts now passes |
| 208 | `-ExecutionPolicy Bypass` for that process only, so a local `Restricted` or |
| 209 | `AllSigned` policy no longer blocks multi-line commands. (`.ps1` script tools |
| 210 | still start as `powershell -File` without the flag and remain subject to the |
| 211 | local policy.) A policy set by |
| 212 | Group Policy still wins and the command is refused with PowerShell's own |
| 213 | message. Scripts that a command invokes run under the same process-scoped |
| 214 | setting. To let the machine or user policy apply instead, start Codewhale |
| 215 | with `CODEWHALE_POWERSHELL_EXECUTION_POLICY=inherit`: it then omits |
| 216 | `-ExecutionPolicy`, so a `Restricted` or `AllSigned` policy refuses the |
| 217 | multi-line commands that need a temporary script; any other value keeps |
| 218 | the default. Not verified on a native Windows machine |
| 219 | ([#6745](https://github.com/codewhale-hq/Codewhale/issues/6745)). |
| 220 | - The website's not-found page now uses the Codwhale poster and typo joke, |
| 221 | with English/Chinese recovery links to home and docs |
| 222 | ([#6419](https://github.com/codewhale-hq/Codewhale/issues/6419), |
| 223 | [#6420](https://github.com/codewhale-hq/Codewhale/pull/6420)). |
| 224 | - Script tools can no longer approve themselves or replace built-in tools |
| 225 | (founder decision D4). A `# approval: auto` line in a script under |
| 226 | `~/.codewhale/tools` (or `[tools].plugin_dir`) is ignored: the tool follows |
| 227 | the session's approval setting like a script with no `approval:` line, and |
| 228 | the runtime log and `/plugin tools` name each script that still declares it. |
| 229 | A `[tools.overrides]` entry of `type = "script"` or `type = "command"` keyed |
| 230 | by a built-in tool name is refused, and the built-in stays active; a status |
| 231 | line names the key once per session, and the runtime log records it. `type = "disabled"` still turns a |
| 232 | built-in off, and script or command overrides under a new name still work. |
| 233 | To keep a wrapper such as an audited shell, disable the built-in and give |
| 234 | the wrapper its own name |
| 235 | ([configuration](docs/CONFIGURATION.md#script-tools-and-overrides)). |
| 236 | - Complete the session slash-command group’s shared command boundary, including |
| 237 | `/structcopy`, so all seventeen commands can compile independently of the TUI. |
| 238 | Host operations remain behind capability interfaces; command behavior and |
| 239 | upstream tool-execution identity safeguards are preserved |
| 240 | ([#6792](https://github.com/codewhale-hq/Codewhale/issues/6792), |
| 241 | [#6145](https://github.com/codewhale-hq/Codewhale/issues/6145)). |
| 242 | - The declared minimum Rust version is now 1.89. It said 1.88, which could not |
| 243 | build Codewhale: a locked dependency (`serde-saphyr`) needs 1.89, the version |
| 244 | CI's minimum-version job builds. The install guides and the npm wrapper's |
| 245 | build-from-source hints now say 1.89 too. |
| 246 | - A deferred tool's first call now runs when its arguments already carry every |
| 247 | required field and no field the schema does not declare, instead of costing a |
| 248 | retry turn. Malformed calls still get the schema, and approvals, deny lists |
| 249 | and Plan mode apply first. Argument types are still checked by the tool |
| 250 | itself. Sub-agents preload tools named in `allowed_tools` |
| 251 | ([#6494](https://github.com/codewhale-hq/Codewhale/issues/6494), |
| 252 | [#6437](https://github.com/codewhale-hq/Codewhale/pull/6437)). |
| 253 | - Automatic Git status and review reads need Git 2.31 or newer, because they pin |
| 254 | Git's runtime configuration overrides. With an older Git they refuse with |
| 255 | "upgrade Git (2.31 or newer)". This covers the read-only Git tools |
| 256 | (`git_status`, `git_diff`, `git_log`, `git_show`, `git_blame`, `verify`); Git |
| 257 | writes you ask for keep their existing behavior |
| 258 | ([docs/dependency-maintenance.md](docs/dependency-maintenance.md)). |
| 259 | |
| 260 | ### Fixed |
| 261 | |
| 262 | - Diff lines and tool output wrap at grapheme boundaries, so emoji families, |
| 263 | skin tones and variation selectors no longer split across lines |
| 264 | ([#6829](https://github.com/codewhale-hq/Codewhale/pull/6829), thanks @Lstarsky0). |
| 265 | - Twelve translated packs now translate the context inspector's making-room |
| 266 | and anchors rows, the Ctrl+O hint and the `/turn inspect` and `/advisor` |
| 267 | descriptions instead of showing English |
| 268 | ([#6831](https://github.com/codewhale-hq/Codewhale/pull/6831), thanks @Lstarsky0). |
| 269 | - Optional MCP servers can be found before they connect. `tool_search` matches |
| 270 | the query against configured, enabled server names (or an `mcp_<server>_` |
| 271 | prefix), connects up to eight matches within the existing boot wait, and |
| 272 | returns their real tool schemas. Before, a lazily started server exposed no |
| 273 | tools, so the model could never trigger its connection |
| 274 | ([#6828](https://github.com/codewhale-hq/Codewhale/issues/6828)). Known limit: a |
| 275 | query that names neither the server nor `mcp` does not wake it. |
| 276 | `codewhale mcp connect`, `validate` and `tools` run their own connection and |
| 277 | do not attach to a running session. |
| 278 | - `/undo` and `/restore <N>` refuse while a turn is running in the workspace, |
| 279 | instead of rewriting files under it. |
| 280 | - `--resume <id>` after a crash recovers that session's interrupted turn from |
| 281 | its crash checkpoint, as `--continue` does. |
| 282 | - `/resume <file>` keeps an imported session on the current provider route |
| 283 | instead of a default one. |
| 284 | - When the stall watchdog recovers a turn, the Engine's turn is ended too, so |
| 285 | the next message is accepted |
| 286 | ([#6800](https://github.com/codewhale-hq/Codewhale/issues/6800)). |
| 287 | - A turn you cancel, or one the stall watchdog recovers, releases input at once. |
| 288 | A message still waiting to reach the engine is abandoned and its unsent text |
| 289 | returns to the composer, instead of holding input for up to 60 seconds |
| 290 | ([#6800](https://github.com/codewhale-hq/Codewhale/issues/6800)). |
| 291 | - A transient upstream failure that a gateway reports as an error frame inside |
| 292 | a successful response ("Provider returned an empty response") is retried |
| 293 | under the stream retry budget when nothing had streamed; authentication and |
| 294 | invalid-model frames still fail at once |
| 295 | ([#6795](https://github.com/codewhale-hq/Codewhale/issues/6795)). |
| 296 | - Long sessions no longer start every turn late. Once a workspace held more |
| 297 | than 50 undo snapshots (around the sixteenth turn), each new snapshot rebuilt |
| 298 | the whole snapshot history before the provider request, about 2.8 s per turn |
| 299 | in a small workspace. Old snapshots are now dropped half a window at a time. |
| 300 | - Resuming a crashed session from inside the TUI recovers its interrupted |
| 301 | turn too. |
| 302 | - Release builds compile on Rust 1.99. |
| 303 | - TUI undo and retry rewind the Engine conversation and saved session before |
| 304 | replacement inference. If the conversation or its settings change while |
| 305 | undo is being prepared, it refuses without overwriting that newer state or |
| 306 | changing the draft. Retained compaction summaries survive the rewind and |
| 307 | cannot be selected as editable user prompts |
| 308 | ([#6788](https://github.com/codewhale-hq/Codewhale/issues/6788)). |
| 309 | - `/edit` replaces the exchange it revises through the same rollback: the old |
| 310 | prompt and its answer leave the transcript, the model's context and the |
| 311 | saved session before the edited prompt is sent. |
| 312 | - When the rollback that `/edit` needs is refused, your revised text goes back |
| 313 | to the composer with edit mode still on, instead of being dropped. Opening |
| 314 | `/edit` while you are editing a queued follow-up returns that follow-up to the |
| 315 | queue first. |
| 316 | - A session can still be resumed by its id when a stray copy of its file sits |
| 317 | in the sessions directory; before, the id was reported as ambiguous. |
| 318 | - Agents follow the Permissions you choose while they run: switching to |
| 319 | Full Access reaches an agent that is already working, instead of leaving |
| 320 | it with the Auto-Review guardian that denied it. Tightening reaches it too. |
| 321 | An agent's answer to an approval prompt is delivered while the main |
| 322 | session is busy, and a forced delete inside the workspace is no longer |
| 323 | treated as a catastrophic system delete. On Linux, Full Access switched on |
| 324 | at runtime cannot lift the kernel no-new-privileges flag set at startup, |
| 325 | so `sudo` and setuid helpers still fail; start with |
| 326 | `sandbox_mode = "danger-full-access"` or `CODEWHALE_NO_NEW_PRIVS=0` if |
| 327 | agents need them ([#6787](https://github.com/codewhale-hq/Codewhale/issues/6787)). |
| 328 | - Stream limits and transport settings share a typed `[stream]` configuration |
| 329 | table, including retry budgets, TCP keepalive and HTTP/2 keepalive. Explicit |
| 330 | values take precedence over legacy `[tui]` aliases; omitted values preserve |
| 331 | existing defaults and environment behavior. A configured HTTP/1 pin stays |
| 332 | pinned during recovery. `/config stream_chunk_timeout_secs ... --save` |
| 333 | updates the canonical setting so it survives reopening a configuration |
| 334 | that already had a timeout. Transport changes apply when a client is built |
| 335 | ([#6700](https://github.com/codewhale-hq/Codewhale/issues/6700)). |
| 336 | - Switching providers keeps a model set only in the root `default_text_model` |
| 337 | with the provider it belongs to. Switching away and back (`/provider` in the |
| 338 | TUI, or the desktop app's model chip) used to land on the provider's catalog |
| 339 | default such as `gpt-5.6`, and a pass-through provider switched to in between |
| 340 | inherited the other provider's model, or a stale legacy root `model` that the |
| 341 | root default had been shadowing |
| 342 | ([#6693](https://github.com/codewhale-hq/Codewhale/pull/6693)). |
| 343 | - A turn no longer stops after an hour of work. The cumulative per-turn wall |
| 344 | clock is unlimited by default, like model steps; set |
| 345 | `[tui].turn_wall_clock_secs` to cap it. |
| 346 | - OpenRouter turns are priced again instead of always showing "rate |
| 347 | unavailable". The model-list refresh no longer fails as a whole on one bad |
| 348 | row: `~` "latest" aliases are dropped, routers that publish a `-1` |
| 349 | variable price are listed without a rate, and other malformed rows are |
| 350 | skipped and counted. Main interactive turns now honor a `[[custom_models]]` |
| 351 | rate the same way background work does, a declaration without rates no |
| 352 | longer hides the catalog price, and an explicit declared rate prices a |
| 353 | vendor-pinned OpenRouter route |
| 354 | ([#6690](https://github.com/codewhale-hq/Codewhale/issues/6690)). |
| 355 | - `codewhale exec` can take prompts past the OS argument limit (~128 KiB on |
| 356 | Linux, where larger prompts failed with `Argument list too long` before |
| 357 | Codewhale started): `--prompt-file <PATH>` reads the prompt from a file, and |
| 358 | `--prompt-file -` reads it from stdin; a positional `-` stays literal text |
| 359 | ([#6688](https://github.com/codewhale-hq/Codewhale/issues/6688)). |
| 360 | - Keep reasoning effort labels, including `xhigh` and `ultra`, visible beside |
| 361 | short model names in the 80-column terminal footer. |
| 362 | - First-run TUI startup keeps explicitly configured providers, models and |
| 363 | endpoints (including environment overrides and a legacy top-level |
| 364 | `base_url`), even with a missing key, instead of adopting a detected local |
| 365 | Ollama model. The `default_text_model` line written into the generated |
| 366 | first-launch config is not treated as a choice, so starting Ollama after the |
| 367 | first launch is still detected. Usable configured routes skip the provider |
| 368 | picker and record the provider step as configured, without claiming a |
| 369 | successful check; missing-key recovery focuses the configured provider even |
| 370 | on a fresh home. Switching from that recovery picker (or after Esc) to a |
| 371 | provider that has its key clears the launch "needs a key" state, so the |
| 372 | footer names the route instead of "model not connected" and a detected local |
| 373 | Ollama can no longer take over the provider just chosen. Empty sessions no |
| 374 | longer show a full context window from the startup prompt; a submitted first |
| 375 | turn or reported usage still shows real pressure. |
| 376 | - `/trust on|off` changes file-tool trust for this session. Add `--save` to |
| 377 | persist workspace trust for project skills, commands, hooks, MCP servers, |
| 378 | and project context. Skipped-skill notices stay out of conversation titles |
| 379 | and user bubbles, and trust changes append a correction to the model's history. |
| 380 | - Stored-secret cleanup skips busy Runtime stores and reports unreadable paths |
| 381 | while continuing through other files. Configured storage roots may be symlinks; |
| 382 | discovered symlinks are not followed. Cleanup also masks current configured |
| 383 | credentials, and doctor's bounded scan reserves capacity for saved transcripts |
| 384 | and checkpoints separately from Runtime receipts. |
| 385 | - Hooks: `tool_call_after` and `on_error` now get a shell command's exit code |
| 386 | in `DEEPSEEK_TOOL_EXIT_CODE` on Runtime API threads as well as in the TUI, |
| 387 | and for a failing command as well as a passing one, so `exit_code` |
| 388 | conditions match. The Runtime API path passed no exit code at all, and a |
| 389 | command that exited nonzero, timed out, or was killed reached hooks with no |
| 390 | exit code on either surface. The new `DEEPSEEK_TOOL_STATUS` says how the |
| 391 | command ended (`completed`, `failed`, `timed_out`, `killed`) |
| 392 | ([#6582](https://github.com/codewhale-hq/Codewhale/issues/6582)). |
| 393 | - Scrolling a long transcript repaints the reasoning reveal hint in place |
| 394 | instead of rebuilding the transcript tail. Wheel and scrollbar input use |
| 395 | interactive frame pacing, collapsed tool groups reuse cached summaries, and |
| 396 | height-only resizes keep wrapped history. Width changes still rewrap content, |
| 397 | and other per-frame work still grows with session length |
| 398 | ([#6652](https://github.com/codewhale-hq/Codewhale/issues/6652)). |
| 399 | - A settled transcript frame reuses its existing render plan instead of |
| 400 | rebuilding or moving unchanged history on every poll. New output, selection, |
| 401 | resize and other real changes still invalidate the affected work |
| 402 | ([#6652](https://github.com/codewhale-hq/Codewhale/issues/6652)). |
| 403 | - Workflow progress rows and working, verification and translation indicators |
| 404 | use the pinned Codewhale terminal component kit. Quiet and reduced-motion |
| 405 | working/verification indicators hold its semantic current-work mark. Working |
| 406 | and verification keep their existing delay and cadence, while translation |
| 407 | uses the same earned marker and five-frame-per-second cadence. The Engine |
| 408 | still supplies workflow state, clocks, localized text, custom themes and |
| 409 | terminal adaptation. The composer, transcript viewports, dock tabs, |
| 410 | posture/metrics rows, pending-input cards, approval band, Ocean background |
| 411 | and the whale's Braille raster now also render through the pinned kit. |
| 412 | - Calm transcript previews keep the latest three rows of live thought and a |
| 413 | single duration header when it settles. Successful tool headers are quieter; |
| 414 | failed generic and MCP calls keep a bounded head-and-tail excerpt, with full |
| 415 | output available in details. Existing collapsed groups show their hidden |
| 416 | count and reveal cue, and explicit thought expansion stays available. |
| 417 | - Composer history preserves multiline entries and literal quoted text while |
| 418 | retaining the old history file during migration. An oversized message stays |
| 419 | in the composer if its paste file cannot be saved, with a localized notice; |
| 420 | mouse placement and quoted file mentions handle multibyte text and spaces |
| 421 | ([#6776](https://github.com/codewhale-hq/Codewhale/pull/6776)). |
| 422 | - The notice for an oversized message that cannot be saved as a paste file is |
| 423 | now a short line that fits the footer ("Not sent: over N characters; paste |
| 424 | file not saved."), in every supported language. The full reason, including the |
| 425 | write error, goes to the transcript once. |
| 426 | - Model-facing guidance names callable tools and explains discovery before a |
| 427 | deferred read. The stopship workflow's scout activates the deferred |
| 428 | `grep_files` with one required `tool_search` call, then gathers bounded |
| 429 | `grep_files` evidence from the current workflow source paths |
| 430 | ([#6747](https://github.com/codewhale-hq/Codewhale/issues/6747)). |
| 431 | - Simplified and Traditional Chinese permission, provider and session wording |
| 432 | now follows the current behavior. Chinese guides correct hook receipts, |
| 433 | trusted skills, MCP startup and Windows limitations, preserving the |
| 434 | contributor translations and a shared glossary. |
| 435 | - Unknown website locale segments, including dotted missing paths, return a |
| 436 | real 404 with noindex metadata and no home-page canonical URL. The existing |
| 437 | layout guards now have regression coverage across all registered locales |
| 438 | ([#6786](https://github.com/codewhale-hq/Codewhale/pull/6786)). |
| 439 | - The terminal caret no longer blinks at the hidden composer while a picker, |
| 440 | settings screen or other view covers it; it returns when the view closes |
| 441 | ([#6545](https://github.com/codewhale-hq/Codewhale/issues/6545)). |
| 442 | - On Linux and macOS, a `background: true` shell's process group is now |
| 443 | stopped when the TUI dies without cleaning up (SIGKILL, a crash, or the |
| 444 | signal exit path). The shell and the processes it started used to keep |
| 445 | running as orphans. Processes that move to their own process group or |
| 446 | session, staged services you choose to keep, and `tty: true` background |
| 447 | shells are not covered. Under the bwrap sandbox, the sandboxed command |
| 448 | now also exits when bwrap does |
| 449 | ([#6654](https://github.com/codewhale-hq/Codewhale/issues/6654)). |
| 450 | - Idle task workers stop periodically reloading a settled, unchanged empty |
| 451 | queue, and task listings reuse an unchanged store snapshot. New queue writes |
| 452 | and local notifications still wake workers; recent or unreadable metadata and |
| 453 | failed claims keep bounded retries. This reduces repeated disk work when |
| 454 | several TUIs share a data directory without changing task ownership or |
| 455 | cancellation ([#6573](https://github.com/codewhale-hq/Codewhale/issues/6573), |
| 456 | [#6728](https://github.com/codewhale-hq/Codewhale/issues/6728)). |
| 457 | - Idle task workers check the queue file's metadata about once a second instead |
| 458 | of five times a second, and no longer reloads the store when nothing changed. |
| 459 | An in-process notification still wakes a worker at once; a |
| 460 | write by another Codewhale process that shares the data directory is noticed |
| 461 | within about a second instead of about 200 ms. A worker with pending work, a |
| 462 | retry deadline or a failed claim keeps the short interval |
| 463 | ([#6728](https://github.com/codewhale-hq/Codewhale/issues/6728), |
| 464 | [#6573](https://github.com/codewhale-hq/Codewhale/issues/6573)). |
| 465 | - After five seconds without session activity, the UI loop polls every 250 ms |
| 466 | instead of 48 ms and the automation-panel scan backs off to 15 seconds. After |
| 467 | thirty quiet seconds, the Git probe runs one `git status` every 15 seconds |
| 468 | instead of the full probe every two seconds, unless the Git panel is showing. |
| 469 | User input and engine events restore the active cadence. This reduces idle |
| 470 | work; it does not remove every cost that grows with session history |
| 471 | ([#6728](https://github.com/codewhale-hq/Codewhale/issues/6728)). |
| 472 | - When the task store is busy, the message now names the process that holds its |
| 473 | lock and how long it has held it ("lock held by pid 1234 for 12s"), when that |
| 474 | can be read. A repeated "Task claim unavailable" error is logged once per |
| 475 | episode, then at debug level |
| 476 | ([#6573](https://github.com/codewhale-hq/Codewhale/issues/6573)). |
| 477 | - On Windows, Fleet can read a running worker's log while its writer holds the |
| 478 | file open, and task-store contention can still read the lock-holder record. |
| 479 | These paths previously failed because of whole-file sharing and locking. |
| 480 | - File writes, including legacy `File` and `write_file` calls, stop if the |
| 481 | original contents cannot be read; legacy writers also reject non-UTF-8 |
| 482 | originals, keeping undo and diffs from recording an empty original file. |
| 483 | - Resuming a session preserves user messages that quote a compaction marker. |
| 484 | - Requirements allow-lists now check unset approval and sandbox defaults, |
| 485 | accept equivalent approval aliases, and lock permission posture when sandbox |
| 486 | modes are constrained so saved Full Access and YOLO cannot bypass them. |
| 487 | - Logout completes xAI OAuth revocation and attempts every credential deletion |
| 488 | before reporting remaining credentials with a non-zero exit status. |
| 489 | - ChatGPT and xAI sign-in now show the account the selected route actually |
| 490 | uses, and sign-in names the account it replaces. `/auth chatgpt` and |
| 491 | `/auth xai-device` switch the running session; signing in from a separate |
| 492 | shell requires restarting an already-open session. Subscription-limit errors |
| 493 | name the account that made the request and explain how to switch, without |
| 494 | printing credentials ([#6715](https://github.com/codewhale-hq/Codewhale/pull/6715)). |
| 495 | - `doctor --fix` keeps temporary files modified within the last hour. |
| 496 | - Provider streams stop with a clear error if an SSE line exceeds 8 MiB. |
| 497 | - Recursive `rlm_query` turns inherit the parent's remaining deadline, |
| 498 | bounded by the existing child budget, including asynchronous lock waits, |
| 499 | startup, model requests and Python evaluation. Expired work is refused before |
| 500 | dispatch; a timeout returns the last response with an incomplete-result error. |
| 501 | Nested code and status receipts accompany the enclosing tool result on success |
| 502 | or failure and survive its session save/reopen. In-flight receipts still need |
| 503 | that result to be handed back before they become durable |
| 504 | ([#6511](https://github.com/codewhale-hq/Codewhale/issues/6511)). |
| 505 | - The TUI keeps redrawing while its terminal is unfocused. v0.10.0 held |
| 506 | every frame on focus loss, so on Windows Terminal, macOS and other |
| 507 | terminals a window sitting behind another one looked frozen until you |
| 508 | clicked back into it. Frames are now held only on GTK/VTE terminals, which |
| 509 | replay the damage themselves when they return. That hold was added for the |
| 510 | MATE flicker in [#6311](https://github.com/codewhale-hq/Codewhale/issues/6311) |
| 511 | ([#6651](https://github.com/codewhale-hq/Codewhale/issues/6651)). |
| 512 | - TUI `/undo` now restores only the files the undone tool call or turn |
| 513 | changed, and refuses, changing nothing, when one of them changed since. |
| 514 | Before, it checked out the whole snapshot tree, which also reverted later |
| 515 | edits to other files. It also finds restore points older than the newest |
| 516 | 100 snapshots, and a forked session can undo the turns it inherited. It |
| 517 | waits for a post-turn snapshot that is still being written, leaves a |
| 518 | changed symlink or other non-regular path in place (and says so) instead |
| 519 | of refusing the whole undo, and writes nothing to the snapshot store when |
| 520 | it refuses outside trusted mode |
| 521 | ([#6644](https://github.com/codewhale-hq/Codewhale/issues/6644)). |
| 522 | - On a fixed model, each Ctrl+T press now moves to a different thinking |
| 523 | tier. Ctrl+T and the `/model` picker could list tiers the route treats as |
| 524 | the same one — DeepSeek's `medium` is `high`, and Z.ai GLM-5.2's `low` is |
| 525 | `high` — so some presses changed nothing. They now share one list per |
| 526 | route with one entry per effective tier. Under Auto model routing, Ctrl+T |
| 527 | walks the picker's Auto list instead of a longer private one; the tier is |
| 528 | still settled when the turn is routed, so two neighbouring choices can |
| 529 | land on the same tier. DeepSeek now reports `minimal`, `xhigh` and `ultra` |
| 530 | as the `low`, `high` and `max` it sends, in `/status`, receipts and |
| 531 | `/effort`, and Kimi Code K3 no longer offers `off`, which it always ran as |
| 532 | `low` ([#6650](https://github.com/codewhale-hq/Codewhale/issues/6650)). |
| 533 | - A top-level `base_url` or `api_key` in `config.toml` now means one thing |
| 534 | everywhere. Every reader used its own rule for which routes inherited it, |
| 535 | which is how a DeepSeek endpoint became the Xiaomi MiMo route's and failed |
| 536 | with DeepSeek's 401. Old files keep working: the keys are read as |
| 537 | `[providers.deepseek]` (or the vendor whose official host they name), the |
| 538 | next save moves them there with a one-time backup and a one-line note, and |
| 539 | a value that disagrees with its table is left for `codewhale config migrate |
| 540 | --prefer` to settle. `codewhale config doctor` shows what is in use |
| 541 | ([#6394](https://github.com/codewhale-hq/Codewhale/issues/6394)). |
| 542 | - Setting up a bundled OpenAI-compatible host from `/provider` now shows |
| 543 | that host's key console, docs link and guidance on the setup form, the same |
| 544 | way the built-in providers' key entry does; before, the descriptor file |
| 545 | carried them and nothing read them. AICraft gains all three |
| 546 | ([#6616](https://github.com/codewhale-hq/Codewhale/issues/6616), thanks @BX166). |
| 547 | - Runtime API undo now restores the files of the turns it undoes, for every |
| 548 | kind of thread. Before, a new thread's turns were not linked to their |
| 549 | workspace snapshots, so `patch-undo` returned `201` and rewound the |
| 550 | conversation but left the files changed, and `file-revert` refused. Each |
| 551 | turn record now lists its snapshots in `workspace_snapshots`, the engine runs |
| 552 | under the thread's own id across restarts, and a fork owns the turns it |
| 553 | inherited. `patch-undo` restores only the files the undone turns changed, |
| 554 | including every write in a turn, and leaves later edits by the user or |
| 555 | another thread alone. Every tool call that may write is bounded by its own |
| 556 | snapshots, so a file another thread or an editor changed while the turn ran |
| 557 | is never reverted as the turn's, and a turn's restore points survive the |
| 558 | snapshot count cap. When it cannot restore files (including a write to a |
| 559 | gitignored path) it now refuses with `409` and an `error.code` instead of |
| 560 | returning `201`. A nameless `PUT /v1/sessions` updates the document the |
| 561 | thread is bound to |
| 562 | ([#6621](https://github.com/codewhale-hq/Codewhale/issues/6621)). |
| 563 | - A Runtime thread that is not bound to a saved session keeps one engine |
| 564 | session id, its own thread id, across its first turn, eviction and |
| 565 | restarts. Before, each engine spawn generated a new id, so the thread's |
| 566 | tool-output spills, snapshot tags and shell jobs were scattered across a |
| 567 | different `sessions/<id>/` per spawn |
| 568 | ([#6659](https://github.com/codewhale-hq/Codewhale/issues/6659)). |
| 569 | - Saved sessions no longer go orphaned, and existing orphans are repaired at |
| 570 | launch. Deleting a session now sets aside the Runtime store it was actually |
| 571 | bound to, and switching a conversation to another host's store sets aside the |
| 572 | store it left, unless another session still uses that store or it holds |
| 573 | work. Exporting a thread (`POST /v1/sessions`) updates the thread's own |
| 574 | document instead of creating a new one each time. A thread whose document was |
| 575 | appended to elsewhere keeps loading. A thread whose document was deleted or |
| 576 | rewritten loads from its own turns instead of failing, and threads write |
| 577 | their files under the session they belong to. Each launch and `codewhale |
| 578 | serve` repairs the store in the background: a store holding threads with no |
| 579 | session gets a "Recovered:" session for each thread, and unreadable |
| 580 | documents, unused empty stores and old files no session names move to |
| 581 | `sessions/.set-aside/` with a manifest. Nothing is deleted. `codewhale doctor` |
| 582 | reports the last repair, and `codewhale doctor --repair-sessions [--dry-run]` |
| 583 | runs one now. `PUT` and `DELETE /v1/sessions` refuse a session that another |
| 584 | Codewhale process has open |
| 585 | ([#6144](https://github.com/codewhale-hq/Codewhale/issues/6144)). |
| 586 | - Runtime API: the thread event stream now ends with a typed `stream.end` |
| 587 | frame (reason and resume cursor) whenever the server closes it, including |
| 588 | on shutdown, so clients can tell a Runtime error from a dropped connection |
| 589 | and resume from the right event. A replay worker crash no longer ends |
| 590 | history early and skips events without a detectable gap, and the mobile |
| 591 | page resumes from its last event instead of replaying from zero, with stream |
| 592 | statuses in the configured UI language. Cross-origin clients can read the |
| 593 | stream-end and replay-progress capability headers, and the SDK exports |
| 594 | `isThreadStreamEnd` for TypeScript narrowing. |
| 595 | - `codewhale exec --auto` no longer exits 141 with no output when a child |
| 596 | it writes to, such as a stdio MCP server, closes its pipe early. Headless |
| 597 | exec now ignores SIGPIPE while it runs, as the interactive TUI already did, |
| 598 | and `exec ... | head` still ends quietly. One-shot `codewhale exec` no |
| 599 | longer prints DeepSeek's raw `<||DSML|| calls>` tool-call markup as its |
| 600 | answer: the markup is removed, and an answer that was only a tool call |
| 601 | fails at once with the reason and a pointer to `--auto`, instead of asking |
| 602 | the model again and blaming an incomplete provider response. |
| 603 | - Resuming a session keeps its "Resumed:" confirmation on screen instead of |
| 604 | replacing it with "Make room automatically: on" when nothing was switched. |
| 605 | - Tool output is no longer cut off where you can't get it back. Search |
| 606 | answers, test runs, git, verifier and web results reach the model whole up |
| 607 | to one budget sized to the model's context window, and anything beyond it |
| 608 | can be read back with `retrieve_tool_result`, including read-only tools |
| 609 | executed alone or in parallel. Restored raw results use the |
| 610 | active route's same inline budget; existing recovery receipts stay intact. |
| 611 | Tiny budgets use a compact retrieval reference instead of a long artifact |
| 612 | path and instructions; a complete reference is kept even when it alone |
| 613 | exceeds the allowance. |
| 614 | Native search now asks for answers up to 8,192 tokens (was 2,048–4,096) |
| 615 | and waits long enough for |
| 616 | them to arrive, and an answer the provider still cuts short is marked as |
| 617 | cut ([#6508](https://github.com/codewhale-hq/Codewhale/issues/6508)). |
| 618 | - The installation page is generated from `docs/INSTALL.md`, so the website |
| 619 | and the guide can no longer disagree; broken anchors and unsafe links fail |
| 620 | the build ([#6450](https://github.com/codewhale-hq/Codewhale/pull/6450)). |
| 621 | - `codewhale config set` refuses a value of the wrong type for a known setting |
| 622 | (a word for an on/off switch, text for a number, a choice outside the list) |
| 623 | instead of saving it ([#6568](https://github.com/codewhale-hq/Codewhale/pull/6568), |
| 624 | thanks @dajiaohuang). |
| 625 | - Receipts: `/receipts`, `codewhale receipts [ID|--last] [--format md|json]`, |
| 626 | and `GET /v1/threads/{id}/receipt` (plus a per-turn form) list what a session |
| 627 | did, one line per action: files changed with line counts, commands with exit |
| 628 | codes, web and MCP calls, agents, approvals and who gave them, and failures. |
| 629 | They also count what ran without asking and name the posture each turn ran |
| 630 | under, read from the turn's own record. A call Codewhale blocked before it |
| 631 | started (Auto-Review or guardian, a tool policy, a refused sandbox |
| 632 | escalation, invalid input, a missing tool) is listed as blocked, with the |
| 633 | reason, and is not counted as run or as ran without asking. Only |
| 634 | Codewhale's own refusal text counts: an MCP server, a fetched page, or a |
| 635 | program cannot make a call that ran read as blocked. A terminal |
| 636 | session's receipt also lists the files a command changed in each turn, |
| 637 | from the workspace snapshots taken before and after it (not ignored files |
| 638 | or anything outside the workspace), with control characters in paths |
| 639 | escaped so a file name cannot forge a receipt line. All three read the |
| 640 | records Codewhale already keeps and say what those records do not hold |
| 641 | ([docs/RECEIPTS.md](docs/RECEIPTS.md)). `audit.log` is not that record: it |
| 642 | logs security events, and it logs an approval only when one is requested, |
| 643 | which under Full Access is almost never. |
| 644 | - Approvals now record who decided: you, a session rule, or the posture. An |
| 645 | automatic approval used to be saved exactly like one you gave, and an app |
| 646 | approval that expired was saved as your denial. `GET /v1/approvals` now |
| 647 | returns `decided_by`. |
| 648 | - Network audit lines now go to the same `audit.log` as every other audit |
| 649 | event (`$CODEWHALE_HOME` included), and test runs no longer append to your |
| 650 | real one. |
| 651 | - In the terminal UI, Auto-Review verdicts now reach `audit.log`, as |
| 652 | `/permissions` said they did; before, they were written only when |
| 653 | `CODEWHALE_TOOL_AUDIT_LOG` was set. Headless `exec` and Runtime API sessions |
| 654 | do not write them yet. |
| 655 | - A turn that stops producing output now reports itself: the turn loop records |
| 656 | its phase and last progress, and an overdue phase surfaces instead of |
| 657 | hanging silently until the stream idle timeout. A delegated agent's final result is |
| 658 | never dropped when the host is busy, so a finished child no longer leaves a |
| 659 | ghost Running row behind ([#6184](https://github.com/codewhale-hq/Codewhale/issues/6184)). |
| 660 | - Git commands run by tools never stop to ask for a password, passphrase or |
| 661 | host-key confirmation inside the terminal, and `git_fetch` has a timeout |
| 662 | ([#6184](https://github.com/codewhale-hq/Codewhale/issues/6184)). |
| 663 | - A provider response that ends cleanly with no text and no tool call is |
| 664 | retried before the turn fails, and the failure names how many retries ran |
| 665 | ([#6310](https://github.com/codewhale-hq/Codewhale/issues/6310)). |
| 666 | - The context meter, the point where Codewhale makes room, preflight, |
| 667 | `/context` and turn receipts show one pressure number instead of disagreeing |
| 668 | ([#6407](https://github.com/codewhale-hq/Codewhale/pull/6407)). |
| 669 | - When Codewhale makes room, the note it leaves for the next turn is written in |
| 670 | its own words, under fixed headings: the objective, the user's corrections, |
| 671 | permissions and limits, changed files, what is still running and the checks |
| 672 | left. A message that quotes the note's opening words now stays in the |
| 673 | conversation instead of being dropped. If the summary request itself is too |
| 674 | large, older history is dropped but the previous note is kept, and making |
| 675 | room stops rather than write a new note without it. |
| 676 | - Continuing a conversation that is already open no longer adds a second |
| 677 | thread, and a fork keeps its own session file, so autosave on one side no |
| 678 | longer leaves the other unloadable |
| 679 | ([#6406](https://github.com/codewhale-hq/Codewhale/pull/6406), thanks @gaord). |
| 680 | - Upgrading Codewhale no longer turns off the built-in Computer Use. Each build |
| 681 | writes the built-in bundle to its own directory, so an upgrade used to present |
| 682 | it as never reviewed and disabled. Now the review and enablement carry to the |
| 683 | new build when its capabilities are unchanged. Changed capabilities show |
| 684 | `capabilities-changed` and wait for review, and a revoked trust never carries |
| 685 | ([#6303](https://github.com/codewhale-hq/Codewhale/issues/6303)). |
| 686 | - "Allow for this conversation" records a grant for that tool and argument |
| 687 | class instead of switching the whole thread to Full Access, so the call you |
| 688 | just approved is no longer failed by a Permissions change. An approval |
| 689 | also survives a Permissions change that only widens what is allowed, grants |
| 690 | end when a thread is archived or deleted, and `web.run` open grants are |
| 691 | scoped by host. Full Access covers MCP tools that declare themselves destructive in |
| 692 | every host, including `codewhale exec` |
| 693 | ([#3866](https://github.com/codewhale-hq/Codewhale/issues/3866)). |
| 694 | - `web.run` retries a refused page once with a browser user agent, and one |
| 695 | site's failure no longer fails the whole call or drops its search results. |
| 696 | - Web search no longer stops when DuckDuckGo cannot be reached. After a |
| 697 | connection error, timeout or non-2xx answer, the search tries Bing before |
| 698 | giving up, and the result says it used Bing. A DuckDuckGo that hangs no longer |
| 699 | uses up the whole time budget: when Bing may follow, DuckDuckGo gets 60% of it |
| 700 | and Bing the rest. This also covers the DuckDuckGo step after a configured API |
| 701 | provider. A custom `search_base_url` still has no public fallback and keeps |
| 702 | the full budget. Bing sees the query only after DuckDuckGo has failed or |
| 703 | returned nothing it could read |
| 704 | ([#6746](https://github.com/codewhale-hq/Codewhale/issues/6746)). |
| 705 | - Hooks treat `bash`, `Bash` and `exec_shell` as one tool in `tool_name` |
| 706 | conditions, so the documented example fires. |
| 707 | - macOS no longer reports Codewhale's ordinary heap as GPU (IOAccelerator) |
| 708 | memory. |
| 709 | - Code highlighting uses less memory, and long transcripts, the pager and the |
| 710 | session picker do less work on the event loop; session previews load in the |
| 711 | background ([#6014](https://github.com/codewhale-hq/Codewhale/issues/6014)). |
| 712 | - The composer's send cue follows the draft, not a paste in progress |
| 713 | ([#6397](https://github.com/codewhale-hq/Codewhale/issues/6397)). |
| 714 | - Voice status is localized, ASCII-mode markers are distinct, and the cursor |
| 715 | honours `NO_COLOR` ([#5846](https://github.com/codewhale-hq/Codewhale/issues/5846)). |
| 716 | - `/cache`, `/stash`, `/config`, session prune, `metrics --since` and the |
| 717 | `lane start`/`lane stop --json` flags handle their edge cases. |
| 718 | - Plain `codewhale exec` (no `--auto`) runs one Engine turn with the same |
| 719 | system prompt as every other run, so `--json` no longer changes the model's |
| 720 | instructions. It offers no tools unless a flag grants them (`--auto`, |
| 721 | `--yolo`, `--allowed-tools`, or resuming a session): `--max-turns`, |
| 722 | `--disallowed-tools`, `--append-system-prompt`, `--sandbox` and |
| 723 | `--output-format stream-json` no longer turn a chat call into a tool-using |
| 724 | agent, and tool-only flags passed without a grant print a warning. A reply |
| 725 | cut off at the provider's output limit is continued instead of failing the |
| 726 | run, for at most 8 model steps unless `--max-turns` sets another limit. |
| 727 | Breaking for scripts: the `--json` one-shot receipt no longer has |
| 728 | `stop_reason`, adds the agent receipt's fields (`prompt`, `tools`, |
| 729 | `outcomes`, `status`, `termination_reason`, `error_category`), and leaves |
| 730 | out `usage` when the turn never settled |
| 731 | ([#6510](https://github.com/codewhale-hq/Codewhale/issues/6510)). |
| 732 | - `codewhale review` of a plain diff uses the same review prompt as |
| 733 | `review --pr` and prints the structured review as Markdown, or the model's |
| 734 | prose when it ignores the JSON format |
| 735 | ([#6510](https://github.com/codewhale-hq/Codewhale/issues/6510)). |
| 736 | - A recursive `rlm_query` that runs out of rounds returns its last answer |
| 737 | marked `[rlm_query incomplete: …]` instead of an empty string, its model |
| 738 | calls appear in the parent turn's record, and its history is no longer |
| 739 | trimmed ([#6511](https://github.com/codewhale-hq/Codewhale/issues/6511)). |
| 740 | - Starting without a network connection no longer drops images you attach to a |
| 741 | model that accepts them. The offline model list lagged behind providers and |
| 742 | listed Claude and others as text-only; it can now only say a model takes |
| 743 | images, never that it refuses them, and a provider that does refuse gets one |
| 744 | resend without the image and a message saying so |
| 745 | ([#6396](https://github.com/codewhale-hq/Codewhale/issues/6396)). |
| 746 | - Model prices that a flat rate would get wrong now show as unknown after the |
| 747 | model list refreshes online, as they already did offline: DeepSeek (priced by |
| 748 | time of day, or from Codewhale's reviewed table on hosted providers), Grok and MiniMax M3 (rates rise on long prompts), Xiaomi MiMo |
| 749 | (pay-as-you-go and Token Plan keys look the same), GLM-5.3 and the Alibaba |
| 750 | Model Studio plans (quota or credits, not per-token) and StepFun. DeepSeek's output limit stays at its |
| 751 | published 384K instead of the refreshed 393,216, and the reasoning controls |
| 752 | Codewhale records for Grok, MiniMax, Qwen 3.8 Max, Muse Spark and Step 3.5 |
| 753 | (defaults, always-on thinking, extra effort tiers) survive the refresh. |
| 754 | Committed corrections now fail at load if their provider or model is missing |
| 755 | from the bundled seed; partial live refreshes may still omit those rows |
| 756 | ([#6396](https://github.com/codewhale-hq/Codewhale/issues/6396)). |
| 757 | - The offline model list is now generated from Models.dev instead of edited by |
| 758 | hand, so a fresh install without network sees the same limits, image |
| 759 | support and reasoning controls as an online one. Claude, GPT-5.5, Kimi and |
| 760 | several OpenRouter models now show image input offline, and a model whose |
| 761 | catalog row offers an on/off switch next to its effort tiers keeps Off in |
| 762 | `/effort` and Ctrl+T instead of rounding it up |
| 763 | ([#6396](https://github.com/codewhale-hq/Codewhale/issues/6396), |
| 764 | [#6612](https://github.com/codewhale-hq/Codewhale/pull/6612)). |
| 765 | - Cost estimates for GPT-5.6 and GPT-5.6 Sol use OpenAI's current rates of |
| 766 | $4 input, $0.40 cached input and $20 output per million tokens. They were |
| 767 | still at the older $5, $0.50 and $30 |
| 768 | ([#6396](https://github.com/codewhale-hq/Codewhale/issues/6396)). |
| 769 | - `codewhale integrations dsh` now reads current DeepSeek Harness prerelease |
| 770 | versions such as `0.1.7-alpha.2` as semver. They were reported as `offline` |
| 771 | and refused; they now show as `stale-version` (launchable once connected, |
| 772 | clearly unverified). Only `0.1.0-rc.6` is still the verified version, and text |
| 773 | that is not a version is still `offline`. |
| 774 | - Rule and chain-segment source labels in the project instructions the model |
| 775 | receives (`<project_rule source=...>` and the scoped-instructions comments) |
| 776 | are repo-relative instead of absolute. Moving or recasing a checkout no longer |
| 777 | changes the pinned system prompt prefix or adds a spurious context update |
| 778 | ([#6739](https://github.com/codewhale-hq/Codewhale/pull/6739), thanks @asto18089). |
| 779 | |
| 780 | ### Security |
| 781 | |
| 782 | - On Windows, a broad Node kill (`Stop-Process -Name node`, |
| 783 | `Get-Process node | Stop-Process`, `taskkill /IM node.exe`, and wrapped, |
| 784 | aliased or nested-shell forms) is held by a built-in safety floor: it is |
| 785 | refused in Full Access, Auto-Review and Never, and asks in other modes. With |
| 786 | the npm launcher such a command ended this and every other npm-launched |
| 787 | Codewhale session without cleanup. Stopping a server by PID or port still |
| 788 | works, and the Windows installer and archives have no Node launcher |
| 789 | ([#6827](https://github.com/codewhale-hq/Codewhale/issues/6827), thanks @jayanthvee). |
| 790 | - `code_execution` and `js_execution` now start their Python and Node |
| 791 | interpreters through the same permission-aware launcher as other commands, so |
| 792 | the session's execution policy applies to them. Before, an approved call ran |
| 793 | the interpreter directly, and its working directory was the only boundary |
| 794 | ([#6820](https://github.com/codewhale-hq/Codewhale/pull/6820), thanks @Guan0923). |
| 795 | - A saved task without an `auto_approve` field is no longer treated as |
| 796 | auto-approved. Updates accept HTTPS URLs only from the release-host |
| 797 | allow-list, and the npm release-asset check bounds every request. |
| 798 | - Workspace profile and skill discovery, pasted-image and screenshot writes, |
| 799 | configuration redaction receipts and legacy configuration migration reject |
| 800 | linked paths where they could redirect access outside their intended roots. |
| 801 | Additional `.codewhale` writers use the existing confined filesystem helpers. |
| 802 | The VS Code file opener checks the file's real path, and PowerShell temporary |
| 803 | scripts receive unpredictable names and owner-only permissions. |
| 804 | - Update development tooling to Undici 7.29.1 or newer for |
| 805 | [GHSA-w293-vg96-wgc3](https://github.com/advisories/GHSA-w293-vg96-wgc3), |
| 806 | brace-expansion 1.1.21/5.0.12 for |
| 807 | [GHSA-q2hr-2g5m-vwhr](https://github.com/advisories/GHSA-q2hr-2g5m-vwhr), |
| 808 | and the VS Code extension's markdown-it to 14.3.2 for |
| 809 | [GHSA-253c-mchw-3w2r](https://github.com/advisories/GHSA-253c-mchw-3w2r). |
| 810 | - Harden local runtime browser sessions, fleet SSH trust, agent continuation |
| 811 | ownership, task gate approval, plugin tool registration, bridge action tokens, |
| 812 | and release metadata credential forwarding. Browser sessions recover across |
| 813 | reloads and new tabs, and stream tickets retry after transient failures. |
| 814 | Fleet SSH known-host checks support OpenSSH 7.x and later. SSH host configs |
| 815 | using `host_key_fingerprint` must migrate to `known_hosts` with verified host |
| 816 | keys; the unsupported fingerprint field is now refused when an SSH worker |
| 817 | starts, before any connection is made, instead of being silently ignored. |
| 818 | - Harden workspace instruction, note, and anchor file access with shared |
| 819 | no-follow reads and writes. Compaction loads pinned anchors only from |
| 820 | trusted workspaces. Validate registry skill names before selecting cache paths. |
| 821 | - Tighten approval, execution and endpoint boundaries. Computer control |
| 822 | consent and script calls need an exact decision a person gave on that call's |
| 823 | own approval card. Automatic Git status and review reads go through the |
| 824 | sanitized review command and stay pinned to the checked Git executable. |
| 825 | Config backups, config dumps, MCP listings and notification payloads share |
| 826 | one sensitive-key vocabulary; structured exports now also redact keys ending |
| 827 | in `key`. Python a child model writes during a recursive `rlm` call is |
| 828 | admitted round by round like an inline `repl` block, and Python kernels are |
| 829 | discarded when permissions narrow. Gate commands and the cargo test runner |
| 830 | start inside the session's shell sandbox. Mutable session artifacts are |
| 831 | written and read through pinned session-relative paths. The stdio bridge's |
| 832 | Runtime child chooses and reports its own loopback port. |
| 833 | - Chat bridges (Feishu, Telegram, WeCom, Weixin) accept an approval decision |
| 834 | only from the person who started that turn, for the Runtime's current |
| 835 | pending approval. After upgrading, approvals for turns that were already |
| 836 | running are decided from the TUI, and WeCom `/allow` no longer takes |
| 837 | `remember`. |
| 838 | - More file and network paths are confined. A task or automation created by a |
| 839 | session without full shell access no longer inherits the host's shell default. |
| 840 | The commit planner, oversized-paste backup and project harness notes do not |
| 841 | read or write through links that leave the workspace. On Unix, audit and |
| 842 | approval logs are created owner-only and are not opened through a link; |
| 843 | Windows is unchanged. Lane ids must be plain names. A session file is refused |
| 844 | when it records a different session id than its name. The updater does not |
| 845 | follow a redirect from HTTPS to plain HTTP and stops reading a response larger |
| 846 | than 512 MB. |
| 847 | - Nothing is written through a `.codewhale` that is a link. The workflow run |
| 848 | journal no longer creates `.codewhale/` or its ledger when it is opened, only |
| 849 | when the first record is written, and reads and appends through the same |
| 850 | confined helpers as other state. The sub-agent coordination lock refuses a |
| 851 | linked `.codewhale` or `state` directory before it creates anything. |
| 852 | - On Unix, the runtime log is created owner-only and is not opened through a |
| 853 | link; an existing log from an earlier version is tightened. The |
| 854 | `.reconcile.lock` and `current.json.lock` lock files are created owner-only |
| 855 | too. |
| 856 | - Inline ```` ```repl ```` blocks in a reply now follow the same rules as the |
| 857 | `code_execution` tool. They never run in Plan mode or when |
| 858 | `code_execution` is not on the turn's tool surface, and they are admitted |
| 859 | like a `code_execution` call with the same code: before-tool hooks, |
| 860 | disallowed-tool rules, Auto-Review (including its reviewer) and repository |
| 861 | law all apply, then the same approval under the session's permission |
| 862 | posture (a blocked, denied or unanswerable call skips them with a visible |
| 863 | note). Only a fence that opens its own line counts, here and in the `rlm` |
| 864 | tool's child rounds, so a reply that mentions a fence in prose runs nothing. |
| 865 | An `rlm(...)` call from a fence gets a one-shot child answer rather than a |
| 866 | child that runs its own code. The docs no longer describe the REPL kernel |
| 867 | as sandboxed. |
| 868 | - `codewhale serve --mcp` now exposes only read-only tools by default |
| 869 | (`file_read`, `search`). Tools that write files or run commands are |
| 870 | neither listed nor run unless the operator sets `require_approval = false` |
| 871 | in the MCP server config; a client's own `approved` flag no longer counts |
| 872 | as approval. At startup the server names on stderr each configured tool it |
| 873 | withholds and the setting that allows it. |
| 874 | - A `Bash` entry in the disallowed tools now also blocks `start_mcp_server` |
| 875 | and `start_registry_mcp_server`, which launch local processes. |
| 876 | - An MCP tool call whose connection closes before it answers is no longer |
| 877 | sent again on a new connection, since the server may already have run it. |
| 878 | The same holds for a server error reply that mentions an expired or invalid |
| 879 | session. The call reports an unknown outcome and the next call reconnects. |
| 880 | Only a call the HTTP transport turned away for a stale session, before the |
| 881 | server handled it, is still retried once. |
| 882 | - Durable tasks and scheduled automations created by the agent no longer |
| 883 | carry more authority than the session that created them: requested |
| 884 | `auto_approve`, `trust_mode` and `allow_shell` are capped at what that |
| 885 | session holds, a task's workspace and an automation's directories must be |
| 886 | reachable from the session, and a task's turn runs under the posture pinned |
| 887 | when it was created instead of re-deriving one from the legacy bit or a |
| 888 | legacy mode alias. |
| 889 | - The approval card for creating a task or creating/updating an automation |
| 890 | now lists the requested trust mode, shell, auto-approve, mode and |
| 891 | workspace as labeled lines. |
| 892 | - "Approve for session" on a shell command now covers only a simple, known |
| 893 | command family (`git status` still covers `git status -s`). Compound, |
| 894 | wrapper, interpreter, unrecognised and option-configured commands are |
| 895 | granted as the exact command, and interact/wait calls on a running shell as |
| 896 | the exact call. |
| 897 | - Workflow plan approval flags shell, network and file-write capability for |
| 898 | the `Bash`, `Web` and `File` tool families regardless of letter case. |
| 899 | - An agent session can no longer update, resume or run an automation whose |
| 900 | stored `auto_approve`, `trust_mode` or `allow_shell` is more than the |
| 901 | session holds, unless the same update lowers those fields. |
| 902 | - The approval summary every Runtime client receives for task and |
| 903 | automation create/update now names the requested trust mode, shell, |
| 904 | auto-approve, mode and workspace, from the same fields the TUI card shows. |
| 905 | - A shell session grant keeps its command family only when every option is a |
| 906 | known value-free option such as `--release` or `--porcelain`; other options, |
| 907 | in any spelling, grant the exact command. Families whose arguments are what |
| 908 | runs or is installed (`go run`, `deno run`, `cargo run`, `make`, |
| 909 | `git bisect`, `git submodule`, package installs) grant the exact command. |
| 910 | - Workflow plan approval recognises tool names in any quote style and with a |
| 911 | pattern suffix (`'Web'`, `` `File` ``, `Web(*)`), and flags `rlm`, Git and |
| 912 | GitHub, computer and browser control, and task/automation tools with the |
| 913 | capabilities they carry. |
| 914 | - Model-run code no longer inherits provider credentials or other secrets |
| 915 | from Codewhale's environment. Python `code_execution` (and every other |
| 916 | Python runner), `gate_run` task gates, custom and completion verifier gates, |
| 917 | persistent `terminal` sessions, and `run_tests` now start from the same |
| 918 | scrubbed child environment as `exec_shell`; variables a gate declares are |
| 919 | still passed through. `gate_run` also runs `/bin/sh -c` instead of a login |
| 920 | shell, so profile files cannot re-export what was removed. |
| 921 | - A `workflow` start with `verify: true` now needs approval even for a |
| 922 | read-only plan, because the completion gates run workspace build and test |
| 923 | scripts. |
| 924 | - Git commands no longer hand provider credentials to programs that a |
| 925 | workspace's git config can start (`core.fsmonitor`, hooks, filters) when |
| 926 | they run through Codewhale's shared git helper: those start from the scrubbed |
| 927 | environment plus the ssh agent, global config location and author identity. |
| 928 | Sub-agent worktree provisioning and delivery do not use it yet. The read-only `git_status`, |
| 929 | `git_diff`, history and `verify` tools also disable the workspace's |
| 930 | fsmonitor, hooks and clean/process filters. |
| 931 | - Language servers started for post-edit diagnostics, and every Python and |
| 932 | Node command constructor, start from the scrubbed child environment. |
| 933 | - Proxy URLs passed to model-run children (`HTTP_PROXY`, `HTTPS_PROXY`, |
| 934 | `ALL_PROXY`, `FTP_PROXY`, `CARGO_HTTP_PROXY`) keep their host and port but |
| 935 | lose any `user:password@` part. |
| 936 | - Behaviour change: the scrubbed child environment now keeps non-secret build |
| 937 | configuration — `CARGO_*` (except registry and token-like keys), |
| 938 | `RUSTFLAGS`, `RUST_LOG`, `RUST_BACKTRACE`, `VIRTUAL_ENV`, `JAVA_HOME`, Go |
| 939 | paths, `NVM_*`/`NODE_OPTIONS` and CA-bundle variables — so `run_tests` and |
| 940 | gates keep the user's target dir, job limit and toolchain. Connection |
| 941 | strings such as `DATABASE_URL` are still dropped; set them in the project's |
| 942 | own config, or wrap the command in a script that sets them, when a build |
| 943 | needs them. |
| 944 | - Deny rules in the permission settings now hold for these ways of hiding a |
| 945 | command word until the shell runs it: a variable (`$v`), a substitution, a |
| 946 | glob or brace list, escaped ANSI-C quoting, or a shell reading its script |
| 947 | from a pipe, here-string or process |
| 948 | substitution. Rules in a separate `execpolicy.toml` file are applied when |
| 949 | the command runs, so there such a command is refused at run time rather than |
| 950 | before an approval prompt. While any deny rule is configured in the permission |
| 951 | settings, such a command is refused instead of being checked against text |
| 952 | the shell will rewrite (an |
| 953 | approval-always policy asks instead). This also applies to common forms such |
| 954 | as `source "$HOME/.cargo/env"`, `eval "$(pyenv init -)"` and `$PYTHON -m |
| 955 | pytest`; name the command directly to run it. The same holds when the text |
| 956 | does not parse cleanly (an unterminated quote, substitution or heredoc, a |
| 957 | `case` inside `$( … )`) or when a parse budget runs out. Commands after |
| 958 | `if`, `then`, `while`, `do`, `!` and similar words, `function f { … }` |
| 959 | bodies, and `find -exec` payloads are now checked like any other command. |
| 960 | - Wrapper commands are unwrapped by their real option grammar, so |
| 961 | `chroot DIR cmd`, `sudo --user NAME cmd` and `timeout -s SIG N cmd` expose |
| 962 | `cmd` (and any `-c` payload) to deny rules. Options missing from a wrapper's |
| 963 | table are read both with and without a value, BSD and macOS options are |
| 964 | covered (`env -P`, `xargs -J`, `chroot -u`), and more wrappers are recognized |
| 965 | (`caffeinate`, `arch`, `sandbox-exec`, `nsenter`, `unshare`, `runuser`, |
| 966 | `flock`, `watch`, `wsl`, `noglob`, `nocorrect`), including `.exe` spellings. |
| 967 | Code passed as a string to `trap`, `su -c`, `flock -c`, `script -c`, |
| 968 | `watch`, `cmd /c` and PowerShell `-Command` is checked as a command line. |
| 969 | - `(( … ))` arithmetic no longer reads `<<` as a heredoc that hides the lines |
| 970 | after it, and an `xargs` or `find -exec` replacement string used as the |
| 971 | command or as shell code (`xargs -I{} sh -c {}`) counts as known only at run |
| 972 | time. |
| 973 | - `task_shell_start` and task gate commands are now checked against shell deny |
| 974 | and ask rules, like any other shell command. |
| 975 | - An "approve for session" grant for a shell command covers only flag variants |
| 976 | of that command as written; a command with options before the subcommand, |
| 977 | a chain, or nested code matches only an identical repeat. |
| 978 | - The read-only shell surface for sub-agents rejects a word that starts with |
| 979 | an unquoted `*`, whose matches could be read as options; quote the pattern |
| 980 | or give it a path prefix (`src/*.rs`). |
| 981 | - A trusted or allow prefix such as `git status` no longer covers options |
| 982 | placed before the subcommand (`git -c key=value status`, |
| 983 | `git --exec-path=… status`), nor a command that runs nested code or whose |
| 984 | command word is resolved at run time. Such commands ask instead. Typed deny |
| 985 | rules also match a path-qualified command word (`/bin/rm`). |
| 986 | - Commands containing parentheses are no longer auto-approved as parallel |
| 987 | read-only commands, since some shells treat them as glob qualifiers or |
| 988 | command substitution. |
| 989 | - Sub-agent worktrees stay under the per-repo `.codewhale-worktrees/<repo>/` |
| 990 | root: an absolute `worktree_path` is now held to the same containment as a |
| 991 | relative one, with symlinks resolved before the check. Any start that asks |
| 992 | for a worktree keeps the approval card, even for a read-only role. A |
| 993 | `worktree_base` starting with `-` is refused, and `git worktree add` now |
| 994 | receives its path and base after `--`. |
| 995 | - Fleet and reasoning-router names must be plain file names (optionally |
| 996 | `origin/name`); a name with path separators or `..` is refused before any |
| 997 | file is looked up, through one shared check in the workflow crate. |
| 998 | - `pandoc_convert` and `image_ocr` apply the same read deny-list and |
| 999 | credential-store checks as `read`, through one shared helper, and pandoc |
| 1000 | always runs with `--sandbox`. This needs pandoc 2.15 or newer; an older |
| 1001 | pandoc gets an upgrade message instead of a conversion. |
| 1002 | - Computer Use: screenshot and zoom output paths must be `.png`/`.jpg`/`.jpeg` |
| 1003 | files inside the recordings directory, and zoom always crops the last |
| 1004 | captured raster instead of a caller-named source file. |
| 1005 | - Skill registry sync refuses an index key that is not a single path-safe |
| 1006 | name before it is used as a cache directory, the same check an installed |
| 1007 | skill name already gets. |
| 1008 | - A project's `.codewhale/config.toml` can no longer set `notes_path`; it is |
| 1009 | ignored with the other user-only keys. The `note` tool and `/note` refuse a |
| 1010 | notes file that is a symlink or whose directory resolves outside the |
| 1011 | workspace, and a note is flushed to disk before the tool reports success. |
| 1012 | - Diffs and shows that read repository content (`codewhale review`, the |
| 1013 | `git_diff`/`git_show` tools, verification, delivery, task attempt records, |
| 1014 | `@diff` and the runtime API diff routes) share one flag set: no external |
| 1015 | diff, no textconv, and submodules compared by commit only, so a submodule's |
| 1016 | configured filters and diff drivers never run. Reads of the working tree |
| 1017 | (`git_diff`, `git_show`, `git_blame`, commit planning, verification, task |
| 1018 | attempt records, `@diff`/`@git`) also run through the hardened review |
| 1019 | command, so the repository's clean filters do not run either. `git_blame` |
| 1020 | and read-only shell `git blame` skip textconv, and read-only shell `git` |
| 1021 | reads neutralize the repository's clean filters. |
| 1022 | - `git_fetch` refuses refspecs that would write a local branch or tag: a |
| 1023 | `src:dst` destination must be under `refs/remotes/`, and the two-word |
| 1024 | `tag <name>` form is rejected. |
| 1025 | - Opening a URL on Windows goes through the URL protocol handler instead of |
| 1026 | `cmd /C start`, so characters in the URL are not interpreted by the shell. |
| 1027 | - Skill downloads and the skills registry index are read through a streaming |
| 1028 | size cap shared with the MCP HTTP transport, instead of buffering the whole |
| 1029 | body before checking its size. |
| 1030 | - Durable runtime thread, turn and item ids carry a full UUID instead of 32 |
| 1031 | random bits, so two records can no longer collide and overwrite each other. |
| 1032 | |
| 1033 | ### Removed |
| 1034 | |
| 1035 | - Flags, settings and tool parameters that did nothing are gone |
| 1036 | ([#6516](https://github.com/codewhale-hq/Codewhale/issues/6516)). `--output-mode` |
| 1037 | is hidden. It is still accepted, prints a warning, and is ignored. |
| 1038 | - The dispatcher no longer exports `DEEPSEEK_*` copies of its `CODEWHALE_*` |
| 1039 | variables. A `DEEPSEEK_*` variable you set yourself is still read. |
| 1040 | - `lane start` and `workflow run --runtime vm|ci` are rejected before a lane |
| 1041 | is created. Older lane records for those runtimes still load. |
| 1042 | - The control socket's `relaunch` verb is removed; it always returned an |
| 1043 | error. |
| 1044 | - The `speech` tool drops `stream`. `stream=true` used to fail; it is now |
| 1045 | ignored, a complete audio file is written, and the result no longer carries |
| 1046 | `"stream": false`. The `finance` tool drops `market`, and a call that still |
| 1047 | passes it has it ignored. |
| 1048 | - `[context].enabled`, the seam-manager keys and |
| 1049 | `tui.terminal_probe_timeout_ms` no longer load; old configs that carry |
| 1050 | them still start. The `[workshop]` docs now describe bounded spillover |
| 1051 | instead of a synthesis sub-agent. |
| 1052 | - About 2,650 lines of workflow code that nothing ran are deleted: the replay |
| 1053 | executor, the review-repair loop and experimental search. The |
| 1054 | `replay_diverged` status they produced goes with them. The isolated |
| 1055 | Runtime Chat prompt and the legacy YOLO alias list each have one owner now |
| 1056 | ([#6517](https://github.com/codewhale-hq/Codewhale/issues/6517)). |
| 1057 | |
| 1058 | ### Experience |
| 1059 | |
| 1060 | - Typing a first message with no model connected leaves a line in the |
| 1061 | transcript that says the message was not sent and opens the provider picker. |
| 1062 | - First run picks a chat-capable Ollama model instead of the alphabetically |
| 1063 | first tag, and says plainly when no model is available yet. |
| 1064 | - `codewhale doctor` leads and ends with one verdict and the next step, and |
| 1065 | gives the update command for how you actually installed Codewhale. |
| 1066 | Command-line usage and errors say `codewhale`. |
| 1067 | - The approval card leads with a plain summary of the action, such as |
| 1068 | "Run `cargo test`", and shows workspace-relative paths. The footer labels |
| 1069 | its values. |
| 1070 | - `/status` warns when the session's pinned model is no longer in its |
| 1071 | provider's live model list |
| 1072 | ([#6035](https://github.com/codewhale-hq/Codewhale/issues/6035)). |
| 1073 | - Error messages give one true sentence and one next step. The TUI's English |
| 1074 | copy says agent, Fleet, Permissions and Work consistently, help lists one |
| 1075 | summary per row, provider rows without a key say "needs key", `/setup` says |
| 1076 | what it sets up, and the pet tank rests when it is offline. |
| 1077 | - ACP clients can see the Permissions setting the server started with, |
| 1078 | including Full Access and how to turn it on, but cannot select it |
| 1079 | ([#6310](https://github.com/codewhale-hq/Codewhale/issues/6310)). |
| 1080 | - `GET /v1/commands` tells clients each command's argument shape, so they do |
| 1081 | not re-derive composer behaviour from the usage string |
| 1082 | ([#6230](https://github.com/codewhale-hq/Codewhale/issues/6230)). |
| 1083 | |
| 1084 | ### Fleet and agents |
| 1085 | |
| 1086 | - `codewhale fleet run <spec> --check` runs every validation a real run would |
| 1087 | and stops there: nothing is created, launched or spent. |
| 1088 | - A queued agent says why it is waiting, for example when launches are |
| 1089 | throttled after provider rate limits, and when it stops waiting |
| 1090 | ([#6277](https://github.com/codewhale-hq/Codewhale/issues/6277)). |
| 1091 | - Read-only agents can run chained inspection commands (a leading `cd`, |
| 1092 | `&&`, `;`, `echo` separators, `2>/dev/null`), and a refused command now |
| 1093 | names the rule it broke and what to do instead. Durable Fleet workers |
| 1094 | accept the same read-only commands as in-session agents. An agent's time |
| 1095 | budget starts when it launches, and a queued agent that never gets a slot |
| 1096 | says it never started |
| 1097 | ([#6015](https://github.com/codewhale-hq/Codewhale/issues/6015)). |
| 1098 | - Stopping an agent that writes files keeps and names the work it had |
| 1099 | changed, as a budget stop already did |
| 1100 | ([#5529](https://github.com/codewhale-hq/Codewhale/issues/5529)). |
| 1101 | - `workflow(fleet:)` runs Fleets saved from the Fleet UI, and finds |
| 1102 | workspace Fleets under `.codewhale/fleets`. |
| 1103 | - The runtime API can stop a delegated agent run from the desktop. |
| 1104 | - A finished agent's answer is no longer cut off. Its row and its completion |
| 1105 | notification show the first sentence of its result instead of a |
| 1106 | `## Summary` heading or its last tool, and opening the agent shows the whole |
| 1107 | result, or the full reason it stopped, even when no transcript was captured. |
| 1108 | Each agent also has one name: a workflow task's label or its dispatch name |
| 1109 | appears on the rows, the notification and the runtime API alike, never its |
| 1110 | internal id ([#6565](https://github.com/codewhale-hq/Codewhale/issues/6565)). |
| 1111 | - The mobile page shows the thread's agents: a strip naming each one, its |
| 1112 | state, and what it is doing or what it found, rebuilt when the page |
| 1113 | reconnects. Sub-agent prompt caching now counts toward the session, including |
| 1114 | cache-write-only reports. PRICE and `/cache` show the parent, agents and |
| 1115 | combined hit rates, each labelled and weighted by all input tokens, |
| 1116 | including cache writes, |
| 1117 | and the footer `cache N%` still means this conversation's own requests |
| 1118 | ([#6565](https://github.com/codewhale-hq/Codewhale/issues/6565)). |
| 1119 | - The dock's GIT, FILES and NOTES views are real. GIT shows the branch and |
| 1120 | where it stands against its upstream, the changes (with their paths one |
| 1121 | Enter away), linked worktrees and the last five commits, and it keeps |
| 1122 | updating during a turn while it is open. It says "not a git repository" |
| 1123 | only when that is true, reports failed status probes in the view and composer |
| 1124 | instead of claiming a clean tree, counts every unmerged path as a conflict, and only |
| 1125 | says there are more changed paths when the list is capped. FILES lists the |
| 1126 | files this session edited, including writes without diff receipts, and the |
| 1127 | files it read, with every unique path retained beyond the activity summary's |
| 1128 | twelve-path preview. FILES and its badge refresh from the current session |
| 1129 | even before TASKS opens. Edits with receipts show their size and open their diff. |
| 1130 | NOTES lists your `/note` notes. The git |
| 1131 | badge, the Git view and the model's git line now share one |
| 1132 | `git status --porcelain=v2` call, so there are fewer git processes than |
| 1133 | before ([#6565](https://github.com/codewhale-hq/Codewhale/issues/6565)). |
| 1134 | - Background work tells you when it ends, even between refreshes. Batched |
| 1135 | shell notices cover explicitly backgrounded or detached commands; foreground |
| 1136 | results and old completions from before this TUI session stay quiet. |
| 1137 | Switching sessions does not repeat a completion notice. Batched |
| 1138 | notices count completed, failed and stopped work separately; shell commands, |
| 1139 | task prompts and errors stay in the app, away from lock-screen notifications. |
| 1140 | A running dev server no longer holds the notice back. Failed, killed and |
| 1141 | timed-out shells retain their outcomes, and the last eight finished shells |
| 1142 | stay listed per session. Finished tasks no longer look live or reopen the |
| 1143 | dock. Background labels follow the UI language, long agent previews keep |
| 1144 | their full-result pointer, and the quiet indicator uses the engine's clock |
| 1145 | and limit without marking an active tool as quiet |
| 1146 | ([#6565](https://github.com/codewhale-hq/Codewhale/issues/6565)). |
| 1147 | |
| 1148 | ### Plugins |
| 1149 | |
| 1150 | - Codewhale no longer appends plugin recommendations to your messages to the |
| 1151 | model. Suggestions appear in one place, follow one switch and one budget, |
| 1152 | and never advertise built-in plugins, generic words or plugins for another |
| 1153 | operating system. |
| 1154 | - `/plugin dismissals` lists the plugins suggestions skip, and |
| 1155 | `/plugin dismissals reset [<name>]` brings them back. |
| 1156 | - Tools from reviewed plugins that declare themselves read-only no longer ask |
| 1157 | for approval on every call. |
| 1158 | - The bundled Computer Use plugin is 0.12.0, the published upstream release |
| 1159 | `8435692` ([#6303](https://github.com/codewhale-hq/Codewhale/issues/6303), |
| 1160 | [#5856](https://github.com/codewhale-hq/Codewhale/issues/5856)). On macOS the agent |
| 1161 | uses its own pointer and never drives your cursor. `app_script` refuses shell |
| 1162 | escapes. Clicks on irreversible actions such as |
| 1163 | pay, send or delete need confirmation. Consent decisions cannot ride inside |
| 1164 | `run_actions` or trajectory replay, and trajectories redact secure fields. |
| 1165 | Also new: a shared-computer control lease that pauses agent input while a |
| 1166 | person drives, and a browser attach mode for a shared Chromium. The vendored |
| 1167 | README no longer claims delegated agents share the Computer Use session; they |
| 1168 | never receive its tools. |
| 1169 | - The bundled first-party catalog pins marketplace revision |
| 1170 | `ae3dd2255a9a266365c6125a084f511eb26bc04d`. It lists Computer Use 0.12.0 and |
| 1171 | adds Codewhale for Chrome (Chromewhale) 0.3.0 as a developer preview: you |
| 1172 | load its Chrome extension unpacked, and like every catalog plugin it installs |
| 1173 | disabled and untrusted until you review it. |
| 1174 | |
| 1175 | ### Release reliability |
| 1176 | |
| 1177 | - Upload the complete release into a private draft, verify every asset's size |
| 1178 | and SHA-256 digest, then publish. An interrupted retry cannot reuse stale |
| 1179 | same-size bytes. CNB and GHCR version tags follow canonical publication. |
| 1180 | - Ubuntu Lighthouse bootstrap requires trusted SSH source CIDRs or an explicit |
| 1181 | public-SSH opt-in before changing the host; malformed IPv6 and broad default |
| 1182 | networks are refused. |
| 1183 | |
| 1184 | ### CI |
| 1185 | |
| 1186 | - State-touching command and session tests seal `HOME`, `USERPROFILE` and |
| 1187 | `CODEWHALE_HOME` onto temporary directories. Unsealed session, snapshot, |
| 1188 | artifact, composer-history, audit and built-in-plugin storage resolves into |
| 1189 | an isolated test root; unrelated worker threads cannot borrow another test's |
| 1190 | home seal. A child-process sentinel checks that known command-dispatch and |
| 1191 | session cases leave their ambient home unchanged. |
| 1192 | - Fork pull requests stay under the macOS runner limit and the Actions cache |
| 1193 | stays under its cap. |
| 1194 | - Release candidates and releases share one parity gate, and a release tag |
| 1195 | without a release-candidate receipt is refused. |
| 1196 | - Budget ratchets block same-repository pull requests unless the pull request |
| 1197 | updates the budget with a receipt. |
| 1198 | - A CodeQL advanced-setup workflow is ready for when the repository switches |
| 1199 | from default setup. |
| 1200 | |
| 1201 | ### Contributors |
| 1202 | |
| 1203 | Seventeen contributors and issue reporters are credited below, including |
| 1204 | @cenab's provider report. |
| 1205 | |
| 1206 | - **[@Guan0923](https://github.com/Guan0923)** — accepted case-insensitive HTTP(S) schemes in `config doctor` without rewriting the configured URL ([#6819](https://github.com/codewhale-hq/Codewhale/pull/6819)), and routed the Python and JavaScript execution tools through the session's execution policy ([#6820](https://github.com/codewhale-hq/Codewhale/pull/6820)). |
| 1207 | - **[@harryvgiunta](https://github.com/harryvgiunta)** — added Yolo-Auto as a bundled OpenAI-compatible host, starting on the vendor's recommended `qwen3.8-flash` model ([#6408](https://github.com/codewhale-hq/Codewhale/pull/6408)). |
| 1208 | - **[@asto18089](https://github.com/asto18089)** — contributed the integrated runtime liveness, context, search, JavaScript execution, stopship scout and pet repairs, preserving their original contributor commits ([#6799](https://github.com/codewhale-hq/Codewhale/pull/6799)); made context rule and chain-segment source labels repository-relative ([#6739](https://github.com/codewhale-hq/Codewhale/pull/6739)). |
| 1209 | - **[@qiuYliangM](https://github.com/qiuYliangM)** — made provider-bound project instruction and constitution labels stable across directory moves and kept their absolute paths in operator reports ([#6799](https://github.com/codewhale-hq/Codewhale/pull/6799)). |
| 1210 | - **[@zhuowp](https://github.com/zhuowp)** — supplied the process-scoped PowerShell execution-policy repair adapted for Codewhale, preserving machine and user Group Policy precedence ([#6745](https://github.com/codewhale-hq/Codewhale/issues/6745)). |
| 1211 | - **[@Andrea-Bruno](https://github.com/Andrea-Bruno)** — designed the Superfast Decision Gate and contributed its off-by-default shadow classifier ([#6604](https://github.com/codewhale-hq/Codewhale/pull/6604), [#6603](https://github.com/codewhale-hq/Codewhale/issues/6603)). |
| 1212 | - **[@aiapienthusiast](https://github.com/aiapienthusiast)** — added Cheaper Inference to the bundled provider catalog ([#6761](https://github.com/codewhale-hq/Codewhale/pull/6761)). |
| 1213 | - **[@gaord](https://github.com/gaord)** — let a client fork a thread at a named turn ([#6580](https://github.com/codewhale-hq/Codewhale/pull/6580)), let undo roll back files for the turn it is undoing ([#6483](https://github.com/codewhale-hq/Codewhale/pull/6483)), stopped resume and fork from duplicating threads and sessions ([#6406](https://github.com/codewhale-hq/Codewhale/pull/6406)), exposed user-defined provider routes to native clients ([#6404](https://github.com/codewhale-hq/Codewhale/pull/6404)), and kept a fork going when a turn lost its tool call ([#6664](https://github.com/codewhale-hq/Codewhale/pull/6664)). |
| 1214 | - **[@Lstarsky0](https://github.com/Lstarsky0)** — moved the docs/work, legal, digest and FAQ pages onto the dictionary spine ([#6405](https://github.com/codewhale-hq/Codewhale/pull/6405), [#6417](https://github.com/codewhale-hq/Codewhale/pull/6417), [#6499](https://github.com/codewhale-hq/Codewhale/pull/6499), [#6574](https://github.com/codewhale-hq/Codewhale/pull/6574)), tightened the Chinese-branching ceiling to 18 ([#6403](https://github.com/codewhale-hq/Codewhale/pull/6403)), and made Fleet publish without a two-link window ([#6431](https://github.com/codewhale-hq/Codewhale/pull/6431)). Also moved the constitution page onto the dictionary spine and kept its install link in the selected locale ([#6733](https://github.com/codewhale-hq/Codewhale/pull/6733)), wrapped diff and tool output at grapheme boundaries ([#6829](https://github.com/codewhale-hq/Codewhale/pull/6829)), and translated the context inspector rows twelve packs still shipped in English ([#6831](https://github.com/codewhale-hq/Codewhale/pull/6831)). |
| 1215 | - **[@aboimpinto](https://github.com/aboimpinto)** — restored a green Linux full-workspace test gate without loosening any test, twice ([#6581](https://github.com/codewhale-hq/Codewhale/pull/6581), [#6666](https://github.com/codewhale-hq/Codewhale/pull/6666)). Completed the seventeen-command portable session group, including `/structcopy` ([#6793](https://github.com/codewhale-hq/Codewhale/pull/6793)). |
| 1216 | - **[@dajiaohuang](https://github.com/dajiaohuang)** — `codewhale config set` checks a known setting's value against its schema type before saving it ([#6568](https://github.com/codewhale-hq/Codewhale/pull/6568)). |
| 1217 | - **[@jayanthvee](https://github.com/jayanthvee)** — reported and diagnosed that killing the npm launcher's `node.exe` ends Windows sessions without cleanup, with reproductions and fix directions ([#6827](https://github.com/codewhale-hq/Codewhale/issues/6827)). |
| 1218 | - **[@cenab](https://github.com/cenab)** — requested the Tsubasa provider row and supplied its endpoint, key and model values ([#6695](https://github.com/codewhale-hq/Codewhale/issues/6695)). |
| 1219 | - **[@BX166](https://github.com/BX166)** — reported the AICraft provider row missing its key console, docs link and guidance, and supplied the values ([#6616](https://github.com/codewhale-hq/Codewhale/issues/6616)). |
| 1220 | - **[@Water-Run](https://github.com/Water-Run)** — ingested namespaced model-only catalog entries so models present only in the canonical `models` map reach the offering list ([#6400](https://github.com/codewhale-hq/Codewhale/pull/6400)), and retired the blanket dead-code allowance with its unused feature stages, tightening the budget to match ([#6402](https://github.com/codewhale-hq/Codewhale/pull/6402)). |
| 1221 | - **[@wuisabel-gif](https://github.com/wuisabel-gif)** — designed the `tool_call_after` execution-receipt contract and its tests on a reference branch, which landed re-implemented on the current hook seam ([#6689](https://github.com/codewhale-hq/Codewhale/issues/6689), [#6713](https://github.com/codewhale-hq/Codewhale/pull/6713)). |
| 1222 | - **[@SparkofSpike](https://github.com/SparkofSpike)** — let making room survive a provider request-body limit (HTTP 413) by shrinking, then replacing, inline images for that one summary pass ([#6642](https://github.com/codewhale-hq/Codewhale/pull/6642)). Translated seventeen Tier-2 guides and thirteen developer and internal docs into Simplified Chinese, and connected the localized documentation ([#6662](https://github.com/codewhale-hq/Codewhale/pull/6662), [#6663](https://github.com/codewhale-hq/Codewhale/pull/6663)); added regression coverage for rejecting unknown website locales before dictionary lookup ([#6786](https://github.com/codewhale-hq/Codewhale/pull/6786)); made the pinned prompt header follow the viewport's turn and jump on click ([#6830](https://github.com/codewhale-hq/Codewhale/pull/6830)). |
| 1223 | |
| 1224 | ## [0.10.0] - 2026-09-22 |
| 1225 | |
| 1226 | Codewhale v0.10.0 brings a redesigned terminal workbench, clearer settings, and |
| 1227 | more reliable session and runtime behavior. It supersedes the unpublished |
| 1228 | v0.9.14 candidate. |
| 1229 | |
| 1230 | ### Contributors |
| 1231 | |
| 1232 | - **[@AdityaVG13](https://github.com/AdityaVG13)** — fixed composer wrapping, tab/caret placement, pasted and editor-returned draft history, painted-column transcript copying, explicit terminal foregrounds, headless user-input tool availability, and engine synchronization after importing foreign sessions ([#6369](https://github.com/codewhale-hq/Codewhale/pull/6369), [#6363](https://github.com/codewhale-hq/Codewhale/pull/6363), [#6365](https://github.com/codewhale-hq/Codewhale/pull/6365)). |
| 1233 | - **[@aboimpinto](https://github.com/aboimpinto)** — moved the TUI session-export slice onto shared command contracts (FEAT-025): a session-export contract facet with one shared sanitizer, `/export` routed through the facet, pinned with baseline-captured goldens and gates ([#6096](https://github.com/codewhale-hq/Codewhale/pull/6096)). |
| 1234 | - **[@BX166](https://github.com/BX166)** — contributed the AICraft provider template and its documentation ([#6171](https://github.com/codewhale-hq/Codewhale/pull/6171)). It was closed unmerged, but it is what surfaced the decision to stop special-casing named OpenAI-compatible hosts ([#6289](https://github.com/codewhale-hq/Codewhale/issues/6289)). |
| 1235 | - **[@7jrxt42BxFZo4iAnN4CX](https://github.com/7jrxt42BxFZo4iAnN4CX)** — reported the session-retention defects behind archive-past-the-cap and empty-session cap occupancy ([#6136](https://github.com/codewhale-hq/Codewhale/issues/6136), [#6137](https://github.com/codewhale-hq/Codewhale/issues/6137)), the resume-failure design behind durable transcript errors ([#6138](https://github.com/codewhale-hq/Codewhale/issues/6138)), and the gaps behind the opt-in approval timeout ([#6101](https://github.com/codewhale-hq/Codewhale/issues/6101)), `codewhale exec --hooks` ([#6099](https://github.com/codewhale-hq/Codewhale/issues/6099)), Markdown drag-copy ([#6156](https://github.com/codewhale-hq/Codewhale/issues/6156)), and the browsable, current-aware session picker ([#6014](https://github.com/codewhale-hq/Codewhale/issues/6014)); the goal token-budget hard stop ([#6013](https://github.com/codewhale-hq/Codewhale/issues/6013)) and the fleet no-progress guard shared with child workers ([#6015](https://github.com/codewhale-hq/Codewhale/issues/6015)) landed as first slices of two larger proposals, and the runtime-store session refusal ([#6207](https://github.com/codewhale-hq/Codewhale/issues/6207)). |
| 1236 | - **[@Lstarsky0](https://github.com/Lstarsky0)** — reported TUI tests reading machine state instead of hermetic fixtures; the `lock_test_env` remedy from that report shaped two more hermetic fixes, for the shared UI fixtures and the compaction budget test ([#5359](https://github.com/codewhale-hq/Codewhale/issues/5359)). |
| 1237 | - **[@Lujc0523](https://github.com/Lujc0523)** — reported `/hooks edit` splitting keystrokes between the editor and the composer, fixed by pausing the TUI input pump inside the editor handoff ([#6165](https://github.com/codewhale-hq/Codewhale/issues/6165)). |
| 1238 | - **[@Statter](https://github.com/Statter)** — reported the Gemini `/models` failure that now surfaces the provider's reason instead of an empty error ([#6173](https://github.com/codewhale-hq/Codewhale/issues/6173)). |
| 1239 | - **[@sequico](https://github.com/sequico)** — reported the ACP `session/new` ids that `session/load` could not resolve, fixed by minting resolvable session ids ([#6174](https://github.com/codewhale-hq/Codewhale/issues/6174)). |
| 1240 | - **[@bevis-wong](https://github.com/bevis-wong)** — reported the mid-run engine freeze behind the bounded turn-end foreground-child join, and the resume path that re-ran identical tool-call repair on every load instead of persisting it ([#6184](https://github.com/codewhale-hq/Codewhale/issues/6184), [#6185](https://github.com/codewhale-hq/Codewhale/issues/6185)). |
| 1241 | - **[@gaord](https://github.com/gaord)** — recorded the mode each turn ran in ([#6321](https://github.com/codewhale-hq/Codewhale/pull/6321), harvested), stated the approval posture a task thread starts on ([#6386](https://github.com/codewhale-hq/Codewhale/pull/6386)), and rebuilt the runtime-API thread summary in one store pass ([#6376](https://github.com/codewhale-hq/Codewhale/pull/6376)). |
| 1242 | - **[@zhuowp](https://github.com/zhuowp)** — preserved chat roles across compaction, protected user turns on recompaction, and kept the operate contract intact ([#6286](https://github.com/codewhale-hq/Codewhale/pull/6286)). |
| 1243 | - **[@h3c-hexin](https://github.com/h3c-hexin)** — rate-limit-adaptive subagent launch scheduling: the `DynamicGate` that replaces fixed spawn pacing under provider throttling ([#6055](https://github.com/codewhale-hq/Codewhale/pull/6055), harvested). |
| 1244 | - **[@asto18089](https://github.com/asto18089)** — co-authored the rate-limit-adaptive launch scheduling work ([#6055](https://github.com/codewhale-hq/Codewhale/pull/6055)). |
| 1245 | - **[@yrk111222](https://github.com/yrk111222)** — ModelScope provider support, landed through the shared `ChildGrant` fleet authority ([#6299](https://github.com/codewhale-hq/Codewhale/pull/6299), harvested). |
| 1246 | - **[@xiechimon](https://github.com/xiechimon)** — capped child tool results at capture time rather than at render ([#6294](https://github.com/codewhale-hq/Codewhale/pull/6294), harvested). |
| 1247 | - **[@VincentCorleone](https://github.com/VincentCorleone)** — defined and implemented the weixin-bridge Quick Start so a first run works from the README alone ([#6170](https://github.com/codewhale-hq/Codewhale/pull/6170), harvested). |
| 1248 | - **[@Serendo](https://github.com/Serendo)** — fixed the `/config` theme editor exiting the panel on an arrow key ([#6336](https://github.com/codewhale-hq/Codewhale/pull/6336)). |
| 1249 | - **[@yetuge](https://github.com/yetuge)** — dropped the retired `token_budget` field from the subagent documentation ([#6335](https://github.com/codewhale-hq/Codewhale/pull/6335)). |
| 1250 | - **[@Water-Run](https://github.com/Water-Run)** — translated the local browser client guide into Simplified Chinese ([#6401](https://github.com/codewhale-hq/Codewhale/pull/6401)). Water-Run's catalog and dead-code work (#6400, #6402) landed after the v0.10.0 tag and ships in v0.10.1. |
| 1251 | ### Security |
| 1252 | - Children never inherit desktop or computer-control tools. Desktop control is |
| 1253 | the most machine-wide capability in the catalog, and a verifier child |
| 1254 | inherited it by default: on 2026-09-17 one opened the host Terminal and typed |
| 1255 | a blocked shell command into the user's live session. A family classifier now |
| 1256 | removes those tools when a child's registry is built, so they are neither |
| 1257 | eager nor searchable, and `execute_full` refuses the family at dispatch for |
| 1258 | every child role — visibility is a grant, and hiding is not the only defense |
| 1259 | (#6296). |
| 1260 | - Runtimes can be held to an organization's plugin allowlist. A managed policy |
| 1261 | document (`managed-policy.json` beside `state.json`, or |
| 1262 | `CODEWHALE_MANAGED_POLICY_PATH`) lists the plugin ids a Runtime may run, |
| 1263 | with an `allow_unlisted` flag and a schema version checked exactly like |
| 1264 | `PluginStateFile`. Enforcement sits inside `apply_state`, so a plugin |
| 1265 | enabled before the policy arrived — or hand-edited to `enabled: true` — |
| 1266 | never comes back enabled, and `enable()` re-reads the document so a policy |
| 1267 | landing after discovery refuses with a reason that names it. A malformed |
| 1268 | document fails closed rather than degrading to unenforced. With no policy |
| 1269 | present, behaviour is bit-for-bit what it was. This is the enforcement |
| 1270 | primitive only; the authority that decides the allowlist is still local, |
| 1271 | so it binds a cooperating Runtime, not a hostile one. |
| 1272 | |
| 1273 | - Approving an `apply_patch` "for the session" is now scoped to the file you |
| 1274 | approved. The grouping key that scopes a session grant was built by a second, |
| 1275 | weaker patch parser that read only `+++ b/` headers and the `replace` array: |
| 1276 | it saw no target at all for the documented `apply_patch{path, patch}` |
| 1277 | override, for `--no-prefix` diffs, or for delete-only diffs, and collapsed |
| 1278 | every one of them to a single shared key. One approval therefore pre-approved |
| 1279 | every later patch of that shape, to any file, with no card and no notice. The |
| 1280 | key now comes from the same resolver the executor and the permission path |
| 1281 | already use, and an input that cannot be resolved gets its own key rather |
| 1282 | than a shared one (#6247). |
| 1283 | |
| 1284 | ### Added |
| 1285 | - The statusline's performance readings survive compact mode and are separately |
| 1286 | configurable. Measured TTFT and average output rate are kept when space |
| 1287 | allows, shedding help text and secondary counts first; the existing metrics |
| 1288 | and statusline settings gain individual toggles with a migration that |
| 1289 | preserves a legacy single setting, and the picker takes mouse selection and |
| 1290 | scrolling. |
| 1291 | - Tasks can be given their own run name. `NewTaskRequest`, `TaskRecord` and |
| 1292 | `TaskSummary` carry an optional `name`, stored as given and omitted when |
| 1293 | absent, so queues still fall back to prompt-derived titles; a run started by |
| 1294 | an automation inherits the automation's name. The `tasks` tool's schema |
| 1295 | extends backward-compatibly and legacy records decode through serde defaults |
| 1296 | (APPS-153). |
| 1297 | - The offline catalog seeds Xiaomi's MiMo 2.6 family — `xiaomi/mimo-v2.6-pro` |
| 1298 | and `xiaomi/mimo-v2.6-flash` — so a first boot without network no longer shows |
| 1299 | the 2.5 generation. `DEFAULT_XIAOMI_MIMO_MODEL` stays on `mimo-v2.5-pro`, and |
| 1300 | the rows carry no price because the published rates cover only `sk-` keys. |
| 1301 | - Native memory is a reviewed store, not a model-writable file. `codewhale-memory` |
| 1302 | backs the TUI with SQLite as the authority instead of Markdown, and the |
| 1303 | `remember` tool now only *proposes* candidates — a model can no longer write |
| 1304 | an active memory. `/memory` and the Runtime API commit through |
| 1305 | `remember_reviewed`, and a Context Lens surface (`/v1/memory/lens`, |
| 1306 | `/lens/actions`, `/events`) shows what was kept and why. |
| 1307 | - Code mode (Experimental, default off): `execute_tools` runs a JavaScript |
| 1308 | program against a QuickJS host surface so a model can express several tool |
| 1309 | calls as one program. Nested calls must be read-only and auto-approved; the |
| 1310 | tool is hidden in Plan and refused under worker authority. Enable with |
| 1311 | `[features] code_mode`. |
| 1312 | - Two new built-in providers: **ZenMux** (`ZENMUX_API_KEY`) and **CSDN 星图** |
| 1313 | (`CSDN_API_KEY`, Coding Plan quota billing), each with its own key slot, |
| 1314 | bootstrap model and catalog rows. |
| 1315 | - The Runtime API gained the surface a native client actually needs: jobs with |
| 1316 | stdin, kill and cursor reads; context, secrets, git, diagnostics, targets, |
| 1317 | LSP and voice routes; `GET /v1/commands` for the slash-command catalog; |
| 1318 | `GET /v1/workspace/instructions`; account-wide `GET /v1/approvals`; plan and |
| 1319 | to-do inventory; `/v1/settings/schema`, with `POST /v1/config` now persisting |
| 1320 | every declared `settings.toml` key rather than a curated allowlist; PTY byte |
| 1321 | replay, resize and exit; and tool images as session artifacts. |
| 1322 | - Codewhale holds the host's idle-sleep assertion while a turn is in flight |
| 1323 | (`caffeinate -i` on macOS, `systemd-inhibit` on Linux), so an unattended |
| 1324 | machine no longer sleeps mid-run. You will see one child process per turn. |
| 1325 | - Skills are reachable in one call. The pinned `## Skills` index told the model |
| 1326 | to call `load_skill`, but the tool was deferred behind `tool_search`, so it |
| 1327 | was never in the tool array that instruction was printed beside: using a |
| 1328 | skill cost a discovery hop, a `name="list"` round trip, and a |
| 1329 | `change:tool_surface` re-pin of the whole cached prefix. `load_skill` is now |
| 1330 | eager for the parent and for children — +244B of pinned catalog, measured, |
| 1331 | against a re-prefill avoided every time a skill is used — and it takes a |
| 1332 | `query` that searches names and descriptions, so a truncated index no longer |
| 1333 | forces pulling the whole catalogue to find one skill. The usage line now says |
| 1334 | to load the matching skill by name before starting the work. |
| 1335 | - A fast lane the router cannot serve now says so. `provider_router_candidates` |
| 1336 | answers `cheap: None` for any pair its tables do not know, and a |
| 1337 | `Faster`/`Auto` child on such a pair used to run at the parent's model and |
| 1338 | price with no receipt and no way to tell "single tier by design" from |
| 1339 | misconfiguration. The fallback stays — the router must not invent a model — |
| 1340 | but the spawn receipt now carries a `fallback_note` naming the unserved lane, |
| 1341 | the same field the pinned-provider fallback already uses. `Inherit` and |
| 1342 | served lanes stay quiet: this reports a fallback, it does not nag. |
| 1343 | |
| 1344 | - The runtime API tells a replayed submission apart from a new admission: |
| 1345 | `POST /v1/threads/{id}/turns` answers `200` with `idempotent_replay: true` |
| 1346 | when the operation key was already used, and `201` for a fresh admission, so a |
| 1347 | client that retries after a dropped response can no longer create a second |
| 1348 | turn. The flag is absent on a fresh admission, so responses existing clients |
| 1349 | already parse are unchanged (#76). |
| 1350 | - Event streams resume where they left off: journal frames carry their durable |
| 1351 | `seq` as the SSE event `id:`, `Last-Event-ID` is honoured as the cursor when |
| 1352 | no explicit `since_seq` is asked for, and `RuntimeCapabilities` advertises |
| 1353 | `event_stream_resume` so a client can gate its reconnect controls on the |
| 1354 | capability instead of discovering it from a missing id (#76). |
| 1355 | |
| 1356 | - TTFT and average output rate stay visible in the compact working footer when |
| 1357 | space allows. `/statusline` now controls them separately; existing |
| 1358 | `session_metrics` settings still work. |
| 1359 | - StepFun’s current coding catalog includes Step 5 Preview, Step 3.7 Flash, |
| 1360 | Step 3.5 Flash and its 2603 version, with published reasoning controls and |
| 1361 | PAYG rates. Existing Step Plan routing remains subscription-based. |
| 1362 | |
| 1363 | - `read` responses now always report the file's byte size, line count, and |
| 1364 | whether output was truncated, and truncation footers name the total size |
| 1365 | alongside the continuation offset — so paging through a large file is |
| 1366 | deliberate instead of a surprise (#6283). |
| 1367 | - File edits are parse-gated before the write lands: Rust goes through |
| 1368 | `syn::parse_file` for a grammar-exact `line:column`, and `.toml` / `.json` |
| 1369 | through the parsers already vendored. An edit is refused only when the file |
| 1370 | parsed *before* and would not parse *after* — repairing an already-broken |
| 1371 | file is the commonest reason to edit source at all, so pre-existing breakage |
| 1372 | and new files fail open. The check precedes the write, so a rejection leaves |
| 1373 | the file untouched and `apply_patch` cannot half-apply (#6204, #6206, #6151). |
| 1374 | - Rust files that were already `rustfmt`-clean are re-normalized after an edit, |
| 1375 | so the next patch's anchors still match. Hand-formatted files are never |
| 1376 | rewritten, and every failure path skips and lets the edit land (#6205, #6151). |
| 1377 | - Native clients can finish provider setup without dropping to the CLI: |
| 1378 | `DELETE /v1/providers/{id}/key` clears a Codewhale-owned credential through |
| 1379 | the same shared owner as `codewhale auth clear`, and `GET /v1/providers` |
| 1380 | now carries `credentialSource` / `credentialWritable` (plus a reason) so a |
| 1381 | client disables its control with a truthful explanation instead of letting |
| 1382 | a write fail late. A credential Codewhale does not own — a literal key in a |
| 1383 | config file, or an active external consent — refuses both verbs with `409` |
| 1384 | rather than appearing to succeed against a source that still wins at |
| 1385 | request time (#6179). |
| 1386 | - The interactive approval card can be bounded: `[approval] timeout_seconds` |
| 1387 | resolves an unanswered card to **deny** when the window elapses — the same |
| 1388 | fail-closed decision the external approval path takes — and the transcript |
| 1389 | says the bound denied the call, not the operator. Omitted or `0` keeps |
| 1390 | today's unbounded wait, so nothing changes unless you opt in (#6101). |
| 1391 | - Transcript drag selection copies Markdown source by default: every cell the |
| 1392 | selection touches serializes through the same canonical path `Ctrl-Y` and |
| 1393 | `/copy` use, joined with blank lines, and the toast names the copied cell |
| 1394 | count. A selection that does not cover every touched cell end to end copies |
| 1395 | the exact rendered fragment instead: rounding a pinpoint selection out to |
| 1396 | whole cells meant copying an entire model message (#6228). |
| 1397 | `tui.selection_copy_markdown = false` keeps the rendered-text payload |
| 1398 | (#6156). |
| 1399 | - The Runtime API serves the workspace files a native client browses and edits: |
| 1400 | `GET /v1/workspace/files` lists one directory, `GET /v1/workspace/files/read` |
| 1401 | returns a bounded byte window with a whole-file SHA-256 revision, and |
| 1402 | `PUT /v1/workspace/files` writes atomically through the confined opener with |
| 1403 | revision-checked overwrites (409 on drift). `.git` is never served and |
| 1404 | symlinks are never followed. A saved session's oversized tool outputs are |
| 1405 | served as artifacts at `GET /v1/sessions/{id}/artifacts` and |
| 1406 | `GET /v1/sessions/{id}/artifacts/{artifact_id}`. (#6163) |
| 1407 | - A session that ended mid-turn is no longer invisible to the model. The newest |
| 1408 | workspace-scoped session still holding a crash-recovery checkpoint is |
| 1409 | surfaced as a one-line `## Prior Session` notice in the session-pinned prompt |
| 1410 | prefix — metadata reads only, excluding the live session and any session this |
| 1411 | process instance created. Clean sessions get no block, so their prefix bytes |
| 1412 | are unchanged. Two bounded read-only tools, `session_search` and |
| 1413 | `session_get`, give the model workspace-scoped recall over the same store |
| 1414 | (one-line summaries and an 8-message tail, labeled untrusted user data, read |
| 1415 | on the blocking pool). Resuming stays the user's decision: the hint tells the |
| 1416 | model to offer a continuation, never to silently take one (#5715). |
| 1417 | - `codewhale exec --hooks` opts a headless run into the same `HookExecutor` the |
| 1418 | TUI builds — global config, reviewed plugin snapshots, and trusted project |
| 1419 | `hooks.toml`. Headless runs previously fired no hooks at all. `tool_call_before` |
| 1420 | can still deny and `shell_env` still applies; a hook `ask` resolves |
| 1421 | fail-closed without a terminal. Fleet worker subprocesses never opt in, and |
| 1422 | `permissions.toml` typed rules are unchanged (#6099). |
| 1423 | - `codewhale doctor` flags fleet and profile model pins that the provider's own |
| 1424 | roster no longer offers. A pin is reported only when a *fresh* cached live |
| 1425 | roster for that exact route exists and omits it — stale, failed, or absent |
| 1426 | rosters prove nothing and are counted as `unverifiable` rather than raising a |
| 1427 | false warning. Each row names the route and every owner of the pin; the pin |
| 1428 | is surfaced, never rewritten (#6035). |
| 1429 | - Background-capable clients can enumerate owned work and watch TUI-visible |
| 1430 | conditions: `GET /v1/threads/running` lists threads with queued or |
| 1431 | in-progress turns in one call (one turns scan grouped by thread), and |
| 1432 | `GET /v1/threads/{id}/notices` serves active `subagent-terminal`, |
| 1433 | `elevation-needed`, and `model-notify` notices with thread/turn identity, |
| 1434 | cleared by ack or — for elevation — when the tool call completes (#6180, |
| 1435 | #3757). |
| 1436 | - Sub-agent launches adapt to provider throttling: a `DynamicGate` replaces |
| 1437 | the fixed semaphore so launch capacity adjusts at runtime, and a |
| 1438 | `RateLimitGovernor` halves capacity on 429 pressure, pauses admissions |
| 1439 | past the threshold, and recovers additively; 429 retries honor |
| 1440 | `Retry-After` with jittered backoff, and quota exhaustion keeps the |
| 1441 | failure path (#6055). |
| 1442 | - Turns record the mode they ran in, so mixed-mode sessions stay legible |
| 1443 | after the fact (#6321). |
| 1444 | - Shell spawning refuses NUL bytes in command and cwd before spawn, and |
| 1445 | sub-agent runs fall back loudly past credentialless profile provider |
| 1446 | pins instead of misrouting silently (#5529, #6318, #6320). |
| 1447 | - Children land past a per-step context bound instead of burning |
| 1448 | quadratically, and status rows surface live declared-vs-observed writes |
| 1449 | (#6189, #6194). |
| 1450 | - Queued Agent Mail can be cancelled before delivery, and the TUI |
| 1451 | suspend/resume handshake restores on stop and rebuilds on continue |
| 1452 | (#6176, #6169). |
| 1453 | - MCP connections are supervised: dead servers are probed and reconnected |
| 1454 | with transitions reported, and a failed reconnect keeps the last-good |
| 1455 | catalog instead of dropping tools (#6187, #6142). |
| 1456 | - Web search autodetects Tavily from `TAVILY_API_KEY` (Firecrawl stays the |
| 1457 | default), fleet refusals name the alternative, and verification runs on |
| 1458 | a bounded Git fetch plus a `merge_tree` verify surface (#6298, #6296). |
| 1459 | - Fleet authority projects through one `ChildGrant`, and ModelScope joins |
| 1460 | the built-in providers (#5633, #6299). |
| 1461 | - Child tool results are capped at capture time, and run |
| 1462 | tests/verifiers accept a bounded cwd (#6282, #6294, #6296). |
| 1463 | |
| 1464 | ### Changed |
| 1465 | - SearXNG results rank by the score the instance returns rather than by arrival |
| 1466 | order. Integers, floats and numeric strings are accepted; anything else, |
| 1467 | including NaN and infinity, becomes 0.0, and rows are stable-sorted descending |
| 1468 | before the result cap, so equal scores keep instance order. The docs now spell |
| 1469 | out the self-hosting requirement: the separate process must expose |
| 1470 | `search.formats: [json]` — an HTML-only instance answers 403 — and bind to |
| 1471 | loopback or a policy-allowed host, with no default instance discovered. |
| 1472 | - The bundled skills move to a new generation. social-media and health leave the |
| 1473 | shipped pack (phone-export workflows rather than everyday skills), feedback |
| 1474 | moves to `docs/skills/` beside contributor onboarding, and the exact earlier |
| 1475 | body is retained so only unmodified shipped skills upgrade — a skill you have |
| 1476 | edited is left in place. Google OAuth scopes and client setup, Photos exports, |
| 1477 | forgetting limits, Spotify playback and plugin reload guidance were corrected |
| 1478 | in the same pass. |
| 1479 | - `auto` is a declared default, not a guess about your wording. Reasoning |
| 1480 | effort no longer maps request vocabulary to tiers (debug/error to Max, search |
| 1481 | to Low) and Auto routing no longer infers cheap-versus-big from phrasing: |
| 1482 | both resolve the configured default, with `[auto] cost_saving` as the |
| 1483 | explicit opt-in. The same prompt now costs the same thing twice. |
| 1484 | - A workflow's shared token budget is opt-in. `[workflow] default_token_budget` |
| 1485 | applied a silent 120,000-token cap across a run and all of its children, and |
| 1486 | a fan-out died at the limit with no hand-back; the default is now 0, meaning |
| 1487 | no shared cap. |
| 1488 | - The shipped `deepseek-flash` route speaks the Responses endpoint, and `xhigh` |
| 1489 | effort maps to `high` per the vendor's own table. |
| 1490 | - Streamed text is paced at a steady rate rather than inheriting the provider's |
| 1491 | SSE chunking, so output reveals at a readable beat instead of in bursts. |
| 1492 | - Broadening shell access for a conversation now requires an idle conversation |
| 1493 | and rejects a stale-workspace check before it commits. Engines advertise a |
| 1494 | `thread_shell_consent` capability, so an older Engine reads as unsupported to |
| 1495 | a native consent client instead of silently accepting. |
| 1496 | - One base prompt now serves every host. `HEADLESS_BASE_PROMPT` was a second |
| 1497 | hand-maintained rendering of the same constitution — the drift pattern this |
| 1498 | repo forbids by convention — so headless runs compose the same `BASE_PROMPT` |
| 1499 | plus language and output layers that interactive runs do, skipping only host |
| 1500 | chrome (execution profile, authority recap). Headless and interactive can no |
| 1501 | longer disagree about what the agent is. |
| 1502 | - `BASE_PROMPT` gains a **Bearing** article, which changes how the agent talks |
| 1503 | to you: the user is a peer who gets honesty rather than deference, a blocking |
| 1504 | gate is named plainly instead of dressed up as refusal, bad code is called |
| 1505 | bad, a crude request is carried out without a lecture, and an apology appears |
| 1506 | only when there is something to apologize for — not as punctuation. It also |
| 1507 | states that the request is the whole mandate, so the scope law opens with |
| 1508 | what is yours to do before it reaches the edge. Every pinned kernel invariant |
| 1509 | survives verbatim. |
| 1510 | - The ocean reads as animals rather than a mechanism. The school used to |
| 1511 | translate as one rigid body — bob phase and tail pose were staggered per |
| 1512 | fish, but horizontal position was locked to an exact wedge offset — so each |
| 1513 | fish now eases a dot fore and aft of its slot on its own slow period, and the |
| 1514 | formation breathes while it travels. Bubble emission and the per-animal |
| 1515 | periods are hash-jittered instead of sharing one clock. Amplitude stays an |
| 1516 | order of magnitude under the crossing speed, so no fish travels against the |
| 1517 | school and `facing == velocity` still holds by construction. The species list |
| 1518 | is unchanged. |
| 1519 | |
| 1520 | - Extensions keeps the exact-content plugin review on the panel: confirming |
| 1521 | a bundle's digest re-reads the inventory, so the row you just reviewed |
| 1522 | reports its new trust state and offers Enable instead of leaving you in |
| 1523 | the transcript with a stale "not reviewed" row. |
| 1524 | - Underwater motion ticks at the cadence the frame limiter actually draws |
| 1525 | (the atmosphere interval while only the water moves, the authored 80 ms |
| 1526 | ocean cadence inside the interactive cap while a turn streams), and the |
| 1527 | event loop wakes exactly for the next tick instead of on the next idle |
| 1528 | poll. Idle water no longer requests frames it cannot draw or quantizes its |
| 1529 | cadence to the poll interval; reduced motion, Ghostty, tmux and the |
| 1530 | six-second idle settle are unchanged. |
| 1531 | - The launcher keeps the Codewhale mark while balancing its layout above the |
| 1532 | composer. A single cursor identifies the selected action; MCP faults retain |
| 1533 | their warning color even in compact terminals. Recent-session counts now |
| 1534 | read correctly for a single message. |
| 1535 | - Model and provider settings use quieter selection surfaces, one focused |
| 1536 | cursor, clearer missing-key warnings, compact output limits, and less |
| 1537 | repetitive credential detail. Plugin actions use plain labels. |
| 1538 | |
| 1539 | - The terminal opens on **Shoreline**, the same palette the GPUI client already |
| 1540 | uses: warm charcoal field `#211F23`, a raised plate for panels and the |
| 1541 | composer, one blue for action and selection `#90B9FF`, and the whale's ivory |
| 1542 | `#F2ECE5` for body text, with 4.5:1 floors on every muted step. The old |
| 1543 | saturated navy gradient is not gone — it is a named `underwater` theme, and |
| 1544 | after review it is once again what a fresh 0.10.0 install opens on |
| 1545 | (`DEFAULT_TUI_THEME`); Shoreline is one `/theme` away. Existing installs keep |
| 1546 | whatever theme they have saved (#6222). |
| 1547 | |
| 1548 | - Menu navigation is starting to mean the same thing everywhere. `menu_style` |
| 1549 | already single-sourced how a selected row *looks*; what a key *does* was still |
| 1550 | reinvented per surface — `h`/`l` in the provider picker against `Left`/`Right` |
| 1551 | in the model picker one screen later, `Home`/`End` in one of seven pickers, and |
| 1552 | no paging at all in Fleet's detail view. `list_nav`, which already owned the |
| 1553 | wrap arithmetic, now owns the vocabulary too: one vertical axis, one |
| 1554 | horizontal axis, and two entry points so a picker with a live filter never has |
| 1555 | a letter stolen out of its query. Fleet's detail view adopts it first and |
| 1556 | gains PageUp/PageDown and Home/End in both its lists (#6290). |
| 1557 | |
| 1558 | - Reviewed plugin bundles are no longer re-hashed four times per MCP dispatch. |
| 1559 | `verify_plugin_authority` walks and hashes both the reviewed source and the |
| 1560 | runtime snapshot, and four separate authority checks ran per `tools/call` — |
| 1561 | eight tree walks. Three of them sat one statement after a |
| 1562 | `validate_before_use` on the same source, so `is_ready` re-verified what had |
| 1563 | just been verified; readiness and authority are now separate, and only the |
| 1564 | callers with no preceding check still pay for both. The tool catalog is built |
| 1565 | once per turn instead of twice, which also removes a case where the two |
| 1566 | assemblies could disagree if authority drifted between them. The digest is |
| 1567 | deliberately **not** cached on `(path, mtime, len)`: the reviewed tree is |
| 1568 | user-writable and `utimensat(2)` lets a same-uid process restore an mtime |
| 1569 | after an equal-length rewrite, so a stat-keyed cache would serve a pre-tamper |
| 1570 | digest (#6209). |
| 1571 | - A sub-agent's completion is read from the manager once instead of polled. The |
| 1572 | workflow pump re-read it up to fifty times, sleeping 20ms between attempts, |
| 1573 | waiting for a terminal status that was already committed — every publisher |
| 1574 | commits the status inside the same `&mut self` call that wakes the pump, so |
| 1575 | the write guard spans both and the first read always sees it. A child the |
| 1576 | manager had no record of cost a full second of head-of-line blocking before |
| 1577 | failing; it now fails immediately, and says what actually happened instead of |
| 1578 | claiming the child "did not report a terminal status within 1s" (#6211). |
| 1579 | |
| 1580 | - MCP protocol negotiation: every surface advertised the original 2024-11-05 |
| 1581 | revision and the stdio client required an exact match, so newer servers |
| 1582 | could not connect. The server and both clients now advertise 2025-06-18 |
| 1583 | and negotiate over the supported set (2025-06-18, 2025-03-26, 2024-11-05) |
| 1584 | — the server echoes the client's revision when it is supported and answers |
| 1585 | with the latest otherwise, the stdio client accepts any supported revision, |
| 1586 | and streamable HTTP sends the required `MCP-Protocol-Version` header on |
| 1587 | every post-initialize request (#6280, first half). |
| 1588 | - Configured MCP servers now connect lazily instead of all at session boot. The |
| 1589 | pool owns a `connecting` set marked at spawn and cleared on resolution or |
| 1590 | abort, so "connecting" is no longer inferred as enabled-minus-connected. The |
| 1591 | boot pass scopes to the eager set — `required` servers plus those covered by |
| 1592 | `tools.always_load` / `allowed_tools` — and a turn naming an unstarted server |
| 1593 | spawns its connects alongside, under the existing five-second deadline. A |
| 1594 | configured-but-unstarted server now reads as configured on every surface |
| 1595 | (session-boot rows, Extensions tab, launch card), never as connecting. |
| 1596 | `docs/MCP.md` documents the lifecycle (#6033). |
| 1597 | - The launch card's MCP problems row runs its own remedy. It already printed |
| 1598 | `/mcp login <name>` or `/mcp`; it now joins the shared paint/click/keyboard |
| 1599 | ordering, so Up/Down lands on it and Enter or a click types the printed |
| 1600 | command into the composer for you to send. Typing beats copying: no clipboard |
| 1601 | dependency over SSH, and you see the command before a second Enter runs it |
| 1602 | (#6085). |
| 1603 | |
| 1604 | - Computer Use is the only computer-use product in Extensions and |
| 1605 | `/mcp recommendations`. Cua is no longer suggested as a parallel |
| 1606 | desktop-control MCP; enable the first-party `computer-use` plugin |
| 1607 | instead. The bundled plugin is 0.11.2 — macOS beta, with the Windows and |
| 1608 | Linux backends experimental and source-only. It carries the per-app consent |
| 1609 | ledger, background-by-default control, and a focus lease that refuses rather |
| 1610 | than stealing the foreground, alongside `get_app_state`, `focus`/`get_value` |
| 1611 | and `stop_computer_control`. Shared-desktop pointer gestures stay gated, and |
| 1612 | arbitrary background dragging remains unavailable. |
| 1613 | - The bundled first-party catalog pins marketplace revision |
| 1614 | `d8640b17f27542e7122c76368724196f92a0af61`, so installing Computer Use from |
| 1615 | the Extensions listing fetches the same 0.11.2 source the binary already |
| 1616 | carries. |
| 1617 | - Materializing is not enabling: the built-in bundle is written under |
| 1618 | `$CODEWHALE_HOME/builtin-plugins` on first run but stays `NeverReviewed`, |
| 1619 | so Computer Use is never switched on without an explicit capability review. |
| 1620 | |
| 1621 | ### Removed |
| 1622 | |
| 1623 | - The host no longer parses prose into goals. Ten phrasings and a clause |
| 1624 | allow-list ("make it your /goal to …") were turned into durable goals before |
| 1625 | the provider call; prose now reaches the model, which calls `create_goal` when |
| 1626 | a goal is useful. The deterministic path — a leading `/goals <objective>` — is |
| 1627 | unchanged. |
| 1628 | |
| 1629 | ### Fixed |
| 1630 | - A thinking fold is an absolute choice again. The stored bit was relative to the |
| 1631 | display preference (`folded ^ !(verbose || thinking_default_expanded)`), so |
| 1632 | every recorded choice flipped meaning the moment a preference changed: turning |
| 1633 | `thinking_default_expanded` on closed a block the reader had explicitly |
| 1634 | expanded (#5847). An explicit tri-state intent now records Expanded or |
| 1635 | Collapsed outright, and the absence of an entry means untouched, so the |
| 1636 | preference baseline decides that cell's default. Space still toggles, and an |
| 1637 | untouched cell still follows `verbose || thinking_default_expanded`. |
| 1638 | - A terminal byte-stream cursor past the head is clamped instead of echoed back. |
| 1639 | `read_since` returned a future cursor as `next_cursor`, so a client that |
| 1640 | continued from it skipped every byte the stream produced before reaching that |
| 1641 | position — permanently. The start position now clamps to `total`: a future |
| 1642 | cursor reads nothing, is not a gap, and hands back the head. |
| 1643 | - Language-server startup is bounded and a failed transport now terminates. The |
| 1644 | client waits for successful initialization before sending notifications, |
| 1645 | drains stderr without buffering it, bounds request queueing and replies, caps |
| 1646 | protocol frames, and fails pending requests when the child transport dies. |
| 1647 | - Input no longer freezes for the rest of a turn when the engine's 32-slot op |
| 1648 | mailbox is full. The remaining input-path sends no longer await: droppable ops |
| 1649 | whose rejection is reported and retryable use `try_send` (CancelSubAgent, |
| 1650 | PreviewOutboundRequest, bang shell input, PurgeContext, and the single-op |
| 1651 | settings updates), ops that must land once the UI changed reserve first, and |
| 1652 | `ChangeMode` publishes its live authority even on a full channel. Must-deliver |
| 1653 | ordered transitions still await, and say why at `EngineHandle::send` (#6150). |
| 1654 | - The pet's whale is one body again. The same authored point set is checked in |
| 1655 | three copies plus four fixtures, and the Rust and TypeScript cores disagreed |
| 1656 | on particle positions from frame 0 while agreeing on every channel and |
| 1657 | constant — so the v1 fixtures had never matched what Rust produced and the |
| 1658 | conformance job had never passed. The bodies and the fixtures are reconciled |
| 1659 | and that check now runs green. |
| 1660 | - The context meter and the auto-compact gate share one honest estimator. The |
| 1661 | status bar inflated `ctx %` by about half and disagreed with the gate, so |
| 1662 | "ctx 82%" could sit beside a `/compact` that refused to run; displayed |
| 1663 | percentages now read materially lower because they are correct (#6297). |
| 1664 | - A steer the engine never accepted is queued for the next turn instead of |
| 1665 | being shown as held and then silently dropped with no turn and no answer |
| 1666 | (#6297). |
| 1667 | - Every `reqwest` client routes through `codewhale_release::tls`. A bare |
| 1668 | `Client::builder()` panics under rustls with no installed provider; 17 call |
| 1669 | sites were swept. |
| 1670 | - The bundled OpenAI-compatible hosts have their `/provider` rows back. |
| 1671 | Retiring the `ProviderSetupTemplate` layer moved SenseNova, Baseten, Groq, |
| 1672 | Cerebras, DashScope and Command Code into `provider_descriptors.json` and |
| 1673 | then wired that file to nothing, so six vendors silently lost their picker |
| 1674 | rows; AICraft never had one. Each descriptor is a row again, built through |
| 1675 | the same named-custom-provider builder a configured host uses, so endpoint, |
| 1676 | bootstrap model and "missing `<ENV>`" reporting all come from one place. A |
| 1677 | descriptor whose id or alias already names a `[providers.*]` entry is |
| 1678 | dropped, so a configured row stays the only one. These rows are an |
| 1679 | invitation, not a route: they are not `is_configured`, and only the form's |
| 1680 | submit writes anything (#6289). |
| 1681 | - A StepFun Step Plan subscription reaches its own catalog. A subscriber's |
| 1682 | `base_url` is `https://api.stepfun.ai/step_plan/v1`, but only the |
| 1683 | pay-as-you-go `/v1` host was recognised as official, so the Step Plan host |
| 1684 | read as a custom endpoint, the catalog was withheld, and the picker showed |
| 1685 | `0 bundled` and a guessed context window for a route whose console |
| 1686 | advertises `step-5-preview` at 1M context. The model was in the seed the |
| 1687 | whole time. All four StepFun hosts — global (.ai) and China (.com), each |
| 1688 | with a `/v1` and a `/step_plan/v1` surface — are now recognised; a host |
| 1689 | StepFun does not own stays custom and keyless, since this predicate also |
| 1690 | scopes credentials. |
| 1691 | - The send cue stopped strobing while you type. `[↵]` flickered between dim |
| 1692 | `[·]` and bold blue once per character at an ordinary typing pace. The cue |
| 1693 | was not lying — Enter really does insert a newline during the ~120 ms |
| 1694 | paste-safety window, which every keystroke re-armed — but that window only |
| 1695 | exists for terminals that deliver a paste as a burst of ordinary keystrokes. |
| 1696 | Ghostty, iTerm2, WezTerm, Windows Terminal and Terminal.app now skip the |
| 1697 | heuristic from the first keystroke instead of waiting for proof by paste. |
| 1698 | - Shift+Tab sets the permission posture in Plan. Tab cycles the mode and |
| 1699 | Shift+Tab cycles Ask/Auto-Review/Full Access, but Plan refused the second |
| 1700 | one outright, so the key silently did nothing there and the two axes read as |
| 1701 | welded together. Plan's read-only guarantee comes from the mode, not the |
| 1702 | posture — `authority` maps `(Plan, _, Bypass)` to `SandboxPolicy::ReadOnly` |
| 1703 | and `tool_catalog` gates every write tool on `mode != Plan` — so the cycle |
| 1704 | now moves the durable Act/Operate baseline while Plan's live policy stays |
| 1705 | `Suggest`, and a toast says the posture lands when the mode leaves Plan. |
| 1706 | - A steer delivered mid-turn now clears its pending card. The transcript |
| 1707 | showed the message and the model answered it, while the "sending into this |
| 1708 | turn" card still listed it as pending: `turn_loop` commits a steer trimmed, |
| 1709 | but the UI handed the engine the untrimmed text and kept that same copy for |
| 1710 | matching, so a composer newline made the two differ by whitespace alone and |
| 1711 | the steer was never promoted to a transcript cell. The text is trimmed once |
| 1712 | at the source that feeds both, so they are the same string by construction; |
| 1713 | the match stays an exact `==`. |
| 1714 | |
| 1715 | - A Xiaomi MiMo key no longer fails verification with another vendor's 401. |
| 1716 | The legacy top-level `base_url` is a DeepSeek field, and a route without an |
| 1717 | endpoint of its own inherited it — so a config carrying |
| 1718 | `base_url = "https://api.deepseek.com"` made that host the MiMo route's |
| 1719 | endpoint. The custom-endpoint guard correctly withheld the MiMo credential |
| 1720 | from a host the route does not own, and the setup wizard's probe, which |
| 1721 | bypassed the guard, sent the key as `api-key:` — a header DeepSeek ignores. |
| 1722 | The result was `HTTP 401 Unauthorized: Authentication Fails (governor)`, |
| 1723 | DeepSeek's *unauthenticated* 401, shown to someone who believed they were |
| 1724 | testing their own key. Every layer that reads the root now inherits it only |
| 1725 | when the URL belongs to that provider's own official endpoint family; |
| 1726 | DeepSeek, which owns the field, is unchanged, and any other host is still |
| 1727 | expressible on `[providers.xiaomi_mimo] base_url`. Key verification |
| 1728 | failures now also name the endpoint that was probed, so a wrong endpoint |
| 1729 | reads as a wrong endpoint instead of a bad key. |
| 1730 | - The Extensions panel can act on the rows it shows. Every plugin now carries |
| 1731 | its on/off switch — Space, or `e` — including one that has never been |
| 1732 | reviewed: `/plugin enable` already routes an unreviewed bundle into the |
| 1733 | exact-capability review and only flips the switch once you confirm the |
| 1734 | digest, so withholding the control bought no safety and left the shipped |
| 1735 | `computer-use` bundle reading `disabled` with nothing that could enable it. |
| 1736 | - The panel stopped saying "untrusted". A bundle that is waiting on its |
| 1737 | capability review now reads `needs review` — `off · needs review` when the |
| 1738 | switch is off too — and its detail line says what Codewhale is withholding |
| 1739 | and which key ends the wait, instead of restating an internal pair of |
| 1740 | booleans. Enter's verb on that row is `review`, not `inspect`. |
| 1741 | - MCP servers say where they live, and mutations write there. Each row is |
| 1742 | labelled `global`, `project`, or `plugin: <name>`. Enabling, disabling or |
| 1743 | removing a workspace-scoped server previously edited the user's global file |
| 1744 | and failed with "MCP server '<name>' not found" on a row the panel had just |
| 1745 | offered; the write now lands in the file that declares the server, and a |
| 1746 | plugin-contributed server says it is switched off by disabling its plugin. |
| 1747 | - The permanent "Plugins · Problems: N" footer chip is gone. It could not be |
| 1748 | acted on from the footer, and its count and the Plugins tab disagreed by |
| 1749 | construction — the chip counted bundles waiting on a review while the tab's |
| 1750 | Problems group lists only registry-level diagnostics, so the rows behind the |
| 1751 | number were never the rows you found. A bundle waiting on a review is a row |
| 1752 | with an action, and `/plugins` states it per bundle next to the key that |
| 1753 | resolves it. |
| 1754 | - The Extensions marketplace no longer advertises what it cannot install. |
| 1755 | Browser Use and the sandbox runtime were pinned rows whose only possible |
| 1756 | action was `unavailable`; they are removed, along with the browser-driver |
| 1757 | and sandbox-runtime component vocabulary that existed solely to describe |
| 1758 | them. |
| 1759 | |
| 1760 | - Configuration parsing keeps the parsed base config boxed, so loading a |
| 1761 | profile no longer carries the full `Config` by value through the |
| 1762 | deserializer and overflows a default 2 MiB test-thread stack; the |
| 1763 | runtime-store binding test that also overflowed is split into phases and |
| 1764 | pinned to that budget so CI's larger stack cannot mask a regression |
| 1765 | ([#6362](https://github.com/codewhale-hq/Codewhale/issues/6362)). |
| 1766 | - Stopping a turn revokes its pending approvals. A late approval cannot resume |
| 1767 | the cancelled action or save an automatic approval for later turns. |
| 1768 | - Expanding and collapsing selected reasoning now matches its rendered state |
| 1769 | when verbose mode and the default-expansion preference are both enabled. |
| 1770 | |
| 1771 | - Branch navigation preserves sibling histories, stable entry IDs and timestamps |
| 1772 | through autosave, resume and forks, and synchronizes the selected branch into |
| 1773 | the live engine. Thanks to @7jrxt42BxFZo4iAnN4CX for the report (#6367). |
| 1774 | - Compaction now writes local diagnostic records for completed passes and |
| 1775 | automatic refusals. `codewhale metrics` reports them with summarizer token |
| 1776 | usage; text-mode exec retains its session after attempting compaction. |
| 1777 | Historical artifacts are not backfilled. Thanks to @7jrxt42BxFZo4iAnN4CX |
| 1778 | for identifying the missing producer (#6368). |
| 1779 | - The opening workbench retains the canonical Codewhale mark in a responsive |
| 1780 | header while keeping recent-session titles full-width and actions clickable. |
| 1781 | - `serve --acp` no longer ignores the approval posture. The ACP adapter |
| 1782 | hardcoded `ApprovalMode::Suggest`, so `--yolo` (and any configured |
| 1783 | `approval_policy`) never reached admission: every mutating tool parked |
| 1784 | behind a permission request no unattended client answers, and sessions |
| 1785 | executed zero tools. Posture now derives from server config — `--yolo` |
| 1786 | pre-approves prompts and flows into the sandbox policy — while hard blocks |
| 1787 | (safety floor, repo law, reviewer consult) and the Plan read-only guardrail |
| 1788 | stay intact (#6337). |
| 1789 | - Plain agent spawns could not resolve. `built_in_members()` seeded both |
| 1790 | `general` and `worker`, and the role parse boundary migrates `worker` to |
| 1791 | `general`, so both canonicalized to the same role — and `role:general`, the |
| 1792 | selector the roster advertises for the default posture, matched two members |
| 1793 | and raised `Ambiguous` every time, permanently. The duplicate built-in is |
| 1794 | gone. The legacy name still resolves: `general`, `member:general`, |
| 1795 | `role:general` and `default` all land on the `worker` posture through the |
| 1796 | identity selector rather than through a second member, which is what allowed |
| 1797 | the duplicate to be removed (#6244). |
| 1798 | - Clicking a `path:line` in tool output no longer spawns `$EDITOR` detached |
| 1799 | while the TUI still owns the terminal, and no longer spawns one editor per |
| 1800 | matching line. The launch goes through the single terminal-handoff path, and |
| 1801 | a click is one request to open one file (#6235). |
| 1802 | - A write-scope contention refusal now names a remedy that works. The `agent` |
| 1803 | tool's description claimed `release` was "the remediation a write-scope |
| 1804 | contention refusal names"; the refusal did not name it, and pointing back at |
| 1805 | it would have been worse, because `release` only clears claims whose owner is |
| 1806 | no longer running while a contention refusal names a live one. The refusal |
| 1807 | itself now says to wait for that owner to settle or cancel it (#6272). |
| 1808 | - The session picker no longer refuses a saved session whose Runtime store |
| 1809 | exists but holds nothing. A force-quit leaves the store on disk, ownerless |
| 1810 | and empty, and the switch path refused it because recovery only covered a |
| 1811 | *missing* store. A switch now also adopts a store that is provably empty |
| 1812 | (every work directory, plus the event sequence that remembers pruned |
| 1813 | appends) *and* provably unheld (the process-owner lock, which a live |
| 1814 | manager holds from open to close), with no automation pinned to its |
| 1815 | execution scope — and the save gate treats that shape as abandonable too, |
| 1816 | so the repaired binding persists. The first fix was reverted on a race |
| 1817 | (emptiness without liveness); this reland checks the lock first (#6207). |
| 1818 | - Double-tap Enter now sends every queued follow-up into the running turn, |
| 1819 | oldest first. The second Enter used to steer only the most recent message |
| 1820 | and leave older ones queued; a failed steer restores the failed message |
| 1821 | plus everything unattempted in original order, so nothing is lost or |
| 1822 | reordered. |
| 1823 | - Only the most recently sent prompt carries the elevated-surface background |
| 1824 | now; every older prompt renders on the bare ground. The fill used to sit |
| 1825 | behind every user row (striping), then behind none; newest-only keeps the |
| 1826 | eye on the turn in play. Sending a new prompt moves the highlight and |
| 1827 | un-highlights its predecessor. |
| 1828 | - Diff rows tint whole: added/deleted line numbers now share the row's green |
| 1829 | / red background instead of sitting bare next to a painted body. Context |
| 1830 | rows stay on the bare ground. |
| 1831 | - MCP connections are supervised now: a background task notices a dead |
| 1832 | server within one sweep, reconnects on the existing backoff ladder, and |
| 1833 | reports each transition, so Extensions rows flip with liveness instead |
| 1834 | of parking on stale-ready or a silent [reconnect]. Five consecutive |
| 1835 | failures park the server with a notice naming `/mcp retry`; an explicit |
| 1836 | retry or a fresh connection resumes watching. Tool calls also retry |
| 1837 | once across a dead pipe/socket (not just stale sessions), and a |
| 1838 | reconnect that fails reports both errors instead of swallowing the |
| 1839 | original (#6187; `list_changed` catalog refresh stays open). |
| 1840 | |
| 1841 | - A steer the engine never delivered is no longer reported as sent. The runtime |
| 1842 | API persisted the steer item as already-`Completed` and emitted |
| 1843 | `turn.steered` + `item.completed` the moment the text entered the engine's |
| 1844 | mailbox — before the engine decided anything. The engine discards a steer |
| 1845 | whose turn has moved on, and an interrupted or failed turn drops whatever it |
| 1846 | had queued, so a GUI could show "Guidance sent", clear the composer, and lose |
| 1847 | the user's words. The engine now returns a verdict for every steer on every |
| 1848 | exit path, the item settles `completed` or `canceled` to match, a dropped |
| 1849 | steer emits `turn.steer_dropped` and answers `409` so a client can resend, |
| 1850 | and `steer_count` counts steers the model actually received (#6276). |
| 1851 | - `<recommended_plugins>` suggestions stop nagging: a plugin id is now |
| 1852 | injected at most once per engine lifetime, and a plugin whose name a |
| 1853 | loaded skill already covers is never suggested — the local skill owns |
| 1854 | the domain, so the nudge was noise. Dismissals still apply, and the |
| 1855 | fragment stays append-only on the user turn (#6274). |
| 1856 | - A canceled automation run now settles with a transcript receipt that names |
| 1857 | the cancellation (by request, cancel timeout, or shutdown) instead of |
| 1858 | vanishing from the live band silently. The receipt wears attention ink and |
| 1859 | never lights the failure demand; the run record keeps the cancellation |
| 1860 | reason as its error detail. (#6162) |
| 1861 | - A failed workflow run no longer settles silently: its terminal failure |
| 1862 | raises a sticky error toast naming the cause (dispatch, schema, or script |
| 1863 | errors), alongside the existing panel state (#5528). |
| 1864 | - MCP OAuth re-login now forces the provider's consent screen: logout only |
| 1865 | clears the local token, so without a prompt the provider silently |
| 1866 | re-granted the same account/workspace and a re-login could never change |
| 1867 | it. `/mcp logout` and `codewhale mcp logout` also say plainly that they |
| 1868 | clear local credentials only (#6040). |
| 1869 | - Session retention no longer deletes transcripts once the store reaches the |
| 1870 | cap: the oldest active session is archived — still openable from the |
| 1871 | picker's archived view — instead of being unlinked, and archived records |
| 1872 | sit outside the cap until they are pruned (#6136). |
| 1873 | - Empty auto-created "New Session" stubs are capped separately (the ten |
| 1874 | newest are kept) and can no longer occupy a real transcript's slot in the |
| 1875 | session cap (#6137). |
| 1876 | - A failed resume or session load is now a durable transcript error instead |
| 1877 | of a status line the next footer update replaces, so a resume that cannot |
| 1878 | restore its target no longer looks like a silent new session (#6138). |
| 1879 | - Compaction no longer retains a tool result whose tool call was summarized |
| 1880 | away: an older turn that mixes text with a tool result keeps its text and |
| 1881 | drops the orphaned result blocks, which providers reject outright (#6119). |
| 1882 | - Automation runs that need a tool approval no longer die as silent |
| 1883 | idle-timeout cancels: a pending approval suspends the idle watchdog for its |
| 1884 | decision window, and an unanswered window settles the run Failed with the |
| 1885 | recorded reason instead of a silent Canceled (#6118). |
| 1886 | - `/mcp` no longer freezes the console while a turn is running: the panel |
| 1887 | opens immediately from the last known MCP snapshot with a receipt naming |
| 1888 | the wait, and live-pool mutations say their refresh is deferred instead of |
| 1889 | parking the UI event loop behind the running turn (#6159). |
| 1890 | - MCP OAuth login no longer fails with "Authorization server response missing |
| 1891 | required issuer" against servers that implement RFC 9207, such as |
| 1892 | Cloudflare's `mcp.cloudflare.com`. The local callback listener now keeps the |
| 1893 | `iss` parameter from the redirect and hands it to the token exchange so the |
| 1894 | callback binds to the discovered issuer; servers that do not send `iss` |
| 1895 | keep working unchanged. (#6157) |
| 1896 | |
| 1897 | ## [0.9.13] - 2026-09-13 |
| 1898 | |
| 1899 | Codewhale v0.9.13 addresses integrity issues in 0.9.12: |
| 1900 | multiline paste is one paste again, truncated tool arguments can no longer execute, strict |
| 1901 | ACP clients connect again, concurrent instances stop destroying each |
| 1902 | other's queued text, and the Computer Use bundle includes plugin 0.3.1 |
| 1903 | with an accessibility-first pointer that no longer steals focus. DeepSeek V4.1 Flash |
| 1904 | (`deepseek-flash`) is the default DeepSeek model, reasoning-capable routes |
| 1905 | keep reasoning out of the answer even when a model id carries no version |
| 1906 | number, and `/mcp reload` no longer freezes the interface while servers |
| 1907 | reconnect. The Codewhale pet arrives with `/pet`: a full-screen habitat that |
| 1908 | shows what the Engine is doing and reveals the answer when it is done. |
| 1909 | |
| 1910 | ### Added |
| 1911 | |
| 1912 | - `/pet` turns the terminal over to the Codewhale pet. `/pet on` (or bare |
| 1913 | `/pet`) gives the habitat the whole content viewport now and on every |
| 1914 | accepted turn, reveals the actual answer or error when the turn completes, |
| 1915 | and Escape returns to the composer without cancelling anything. `/pet off` |
| 1916 | closes the view and stops automatic entry while the durable companion keeps |
| 1917 | the pet alive; `/pet appearance|window|source|sound|export|status` address |
| 1918 | the shared companion. The pet no longer lives in the workbar: the Watch |
| 1919 | panel and `/workbar watch …` are gone (#6109, #6110). |
| 1920 | - Codewhale Computer Use 0.3.1 ships as its own notarized Mac app. Download |
| 1921 | the disk image from [codewhale.net/computer-use](https://codewhale.net/computer-use) |
| 1922 | or the [v0.3.1 release](https://github.com/Hmbown/codewhale-cu-plugin/releases/tag/v0.3.1) |
| 1923 | (`Codewhale-Computer-Use-0.3.1-macos-universal.dmg`, drag into |
| 1924 | Applications; the ZIP stays for the in-app updater). The bundled plugin and |
| 1925 | the first-party marketplace pin the same 0.3.1 sources, so the app, the |
| 1926 | `computer-use` plugin and `/mcp` see one implementation. |
| 1927 | |
| 1928 | ### Fixed |
| 1929 | |
| 1930 | - The website's Computer Use download page resolves its state without the |
| 1931 | GitHub API (using `GITHUB_TOKEN` only when bound), and every page regenerates |
| 1932 | on the Worker again: the Open Graph image route read brand SVGs at import |
| 1933 | time, which the Workers runtime cannot do, so codewhale.net had been serving |
| 1934 | its build-time snapshot. |
| 1935 | - Operate can run structured workflows directly, with named phases, model |
| 1936 | assignments from Fleet, prerequisite results and shared budgets. Independent |
| 1937 | steps run together; dependent work waits for its required results and gates. |
| 1938 | Detached runs return their outcome to the owning conversation, and headless |
| 1939 | sessions stay alive between phases until the final handback is consumed. |
| 1940 | - Computer Use 0.3.1: mouse actions no longer steal focus or reclaim the |
| 1941 | foreground when the user switches apps mid-action; background typing, |
| 1942 | scrolling and selection use semantic input, and screenshots stay scoped to |
| 1943 | the targeted app. The bundled plugin and the first-party marketplace pin |
| 1944 | carry the same 0.3.1 sources. A registered macOS helper stays in charge of |
| 1945 | input through its Pause and Stop controls; an unavailable registered helper |
| 1946 | produces an error instead of silently bypassing those controls. |
| 1947 | - The Fleet editor uses the standard model picker to manage sub-agent model |
| 1948 | and thinking assignments. Enter edits the selected row without changing the |
| 1949 | running session's model. Unconfigured providers are refused, failed saves |
| 1950 | retain the previous assignment, and a changed or removed team file must be |
| 1951 | reopened before a pick can overwrite it. |
| 1952 | - The provider catalog includes Baseten and the other compatible-provider |
| 1953 | templates as selectable rows, opening their existing prefilled setup forms. |
| 1954 | DeepSeek routes with clock-based pricing show the current peak or off-peak |
| 1955 | tier beside session cost, with translated labels. |
| 1956 | - Extensions, teams, workflows and automations support mouse-wheel scrolling. |
| 1957 | Plugin and MCP rows have keyboard enable/disable controls and two-step |
| 1958 | removal; MCP OAuth can retry with narrower scopes after a scope rejection. |
| 1959 | - Healthy sub-agents continue after an ordinary parent reply. Headless runs |
| 1960 | keep the existing Engine alive for child results within the run deadline. |
| 1961 | Explicit cancellation remains authoritative when result queues are full or |
| 1962 | a completion starts a followup turn. |
| 1963 | - Sub-agent followup supports multiple targets and all parked children, keeps |
| 1964 | old IDs connected to their current continuation, and saves continuation |
| 1965 | identity before starting work. Repeated followup does not fork duplicates. |
| 1966 | - Sub-agents validate declared output files and distinguish real edit claims |
| 1967 | from file citations and unrelated workspace changes. Disjoint file claims |
| 1968 | can run together; overlapping writers receive the actual conflict and remedies. |
| 1969 | Explicit read-only shell analysis requires an enforcing native sandbox and |
| 1970 | refuses execution when that protection is unavailable. |
| 1971 | - Delegation depth stays absolute through saved profiles, nested workers and |
| 1972 | continuations. Per-call token, step and time limits narrow inherited limits; |
| 1973 | continuation retains ancestor usage and deadlines. Workers reserve room for |
| 1974 | one tools-disabled partial report inside those limits, then run the declared- |
| 1975 | output checks. Missing usage or unavailable reporting room produces an |
| 1976 | explicit fallback; partial work is never marked complete. |
| 1977 | - Agent rosters and detail pages have bounded output, visible continuation and |
| 1978 | descendant relationships, and usable handles for full diagnostic evidence. |
| 1979 | Completion receipts include measured worker and descendant token usage, |
| 1980 | count each continuation once, and distinguish unreported usage from zero. |
| 1981 | - Localization and native helper builds resolve the active checkout when the |
| 1982 | build script runs, so a shared Cargo target keeps working after a worktree |
| 1983 | moves or is removed. |
| 1984 | - Selecting a saved agent profile that is malformed, unreadable or duplicated |
| 1985 | now fails before any child request, including when its name matches a |
| 1986 | built-in role; the parent's default route is never substituted silently. |
| 1987 | `agent(action: "roster")` lists affected profile identities and paths, Fleet |
| 1988 | run creation performs the same check, and `docs/SUBAGENTS.md` documents the |
| 1989 | valid personal profile format with `[permissions]` (#6117, thanks |
| 1990 | @Gabriel-Degret). |
| 1991 | - Interactive startup no longer mistakes worker scheduling delays for an |
| 1992 | unresponsive terminal. Terminal ownership checks and shutdown cleanup remain |
| 1993 | enforced (#5929). |
| 1994 | - Interrupted conversations whose saved runtime store is missing recover into a |
| 1995 | fresh scope without restoring old tasks or approvals. Stale session saves |
| 1996 | cannot resurrect the broken binding (#6102). |
| 1997 | - Permission checks distinguish literal heredoc data from executable commands, |
| 1998 | including substitutions and shell stdin (#6098). |
| 1999 | - Automatic compaction runs quietly from live context pressure, preserving the |
| 2000 | current task and recent tool exchanges while keeping the system/tool prefix |
| 2001 | stable. Original history and the handoff are saved before context replacement; |
| 2002 | failed or canceled compaction retains the conversation (#5620, #6047). |
| 2003 | - Custom and gateway providers can override context limits for each exact model, |
| 2004 | so switching models also switches the meter and compaction budget (#6108). |
| 2005 | - Plugin suggestions explain their matching term and remember explicit dismissals |
| 2006 | across restarts. Generic words and repository-host domains no longer trigger |
| 2007 | unrelated installation prompts (#6031). |
| 2008 | - Plugin trust and automation deletion have keyboard and mouse confirmation |
| 2009 | controls bound to the exact reviewed content; users can still copy the command |
| 2010 | and changed content requires a fresh review (#6039). |
| 2011 | - The model-facing MCP start tool can reconnect an existing configured name after |
| 2012 | login without changing its credential key or restarting healthy siblings (#6030). |
| 2013 | A decreasing token-expiry countdown no longer makes a revoked credential look |
| 2014 | like a new login from another session. |
| 2015 | - Gemini setup uses the official endpoint's supported reasoning-effort field, |
| 2016 | avoiding the rejected top-level Google thinking object. Gemini 2.5 and 3 keep |
| 2017 | their supported effort ranges; signed tool history still survives reasoning |
| 2018 | changes and restart (#6018, thanks @vmakarov-uk). |
| 2019 | - Missed automation occurrences coalesce without overlapping a running job; |
| 2020 | restart reconciles durable receipts without replaying accepted work. Damaged |
| 2021 | neighboring records are isolated while preserving their original bytes. |
| 2022 | - The bundled first-party marketplace lists the actual plugin bundles and uses |
| 2023 | the existing install, review, trust and update paths. A read-only connection |
| 2024 | check verifies catalog and skill mirrors on changes and weekly. Already present |
| 2025 | bundles lead to their local review and management controls; catalog installs |
| 2026 | refuse name collisions before downloading, without overwriting or granting trust. |
| 2027 | - Windows deny checks preserve native path separators while retaining the |
| 2028 | conservative POSIX scan for shell wrappers and substitutions. |
| 2029 | - The config example agrees with the telemetry disclosure: usage analytics are |
| 2030 | optional and enabled by default; local diagnostics do not require telemetry (#6011). |
| 2031 | |
| 2032 | - Sub-agents enforce the session's typed shell and file deny rules, including |
| 2033 | Full Access, delegated edits, and policy updates after a child starts (#6097). |
| 2034 | - Live permission edits reach running engine clones atomically. Deny rules |
| 2035 | support token wildcards and Windows command spellings while keeping POSIX |
| 2036 | arguments literal (#6054, thanks @h3c-hexin and @asto18089). |
| 2037 | - Tool-result images use the existing typed inline path and are fully decoded |
| 2038 | under size and allocation limits before admission or provider projection. |
| 2039 | Invalid images keep a visible omission receipt alongside the text result |
| 2040 | (adapted from #6053, thanks @h3c-hexin and @asto18089). |
| 2041 | |
| 2042 | - A lone `y`, `Y`, or `r` remains composer input after selecting transcript |
| 2043 | text. Clicking the composer releases transcript and dock focus. |
| 2044 | - The Agents register updates from live worker events while the parent is |
| 2045 | busy, including when the register opened before the workers spawned. |
| 2046 | - Ghostty no longer shows a second graphical whale over the launch mark. |
| 2047 | The selected model stays visible before the first message; unused session |
| 2048 | metrics stay quiet. Scheduled counts open `/automation` directly. |
| 2049 | - Marketplace installation accepts compatible Claude plugin bundles and roots |
| 2050 | their relative sources outside `.claude-plugin`; unsupported components fail |
| 2051 | explicitly. Native trust and enablement review still applies. |
| 2052 | - Config table and nested reads work consistently and redact credentials. |
| 2053 | Unsupported dotted writes fail without changing the file, and `config doctor` |
| 2054 | no longer labels runtime settings as never applied (#6083). |
| 2055 | |
| 2056 | - Esc during a worker fanout keeps the parent stopped when cancelled workers |
| 2057 | finish. Their receipts remain available for the next explicit user turn. |
| 2058 | - Undo preserves messages even when older state lacks a timestamp. Session |
| 2059 | journal entries retain their append-time stamps when saved again. |
| 2060 | - Extension actions refresh in place, and inspection output uses the text |
| 2061 | pager. The empty launch shell hides unused metrics and keeps recovery hints |
| 2062 | readable when several MCP servers need attention. |
| 2063 | - The large-output router defaults to bounded spillover; adaptive routing |
| 2064 | remains opt-in through `CODEWHALE_ADAPTIVE_OUTPUT_ROUTING=1`. |
| 2065 | - Direct composer paste (`Ctrl-V`) preserves rich clipboard headings, lists, |
| 2066 | links, tables and code as Markdown, with plain-text fallback. Whole-answer |
| 2067 | copy preserves authored Markdown without terminal wrapping; settings fields |
| 2068 | still paste literal text. |
| 2069 | - The embedded Computer Use bundle includes the marketplace's JPEG capture |
| 2070 | and bounded-payload fixes, so new built-in installations receive them too. |
| 2071 | - A provider's missing-`thought_signature` HTTP 400 now explains how to recover: |
| 2072 | use the built-in Google provider and start a new session, or verify the |
| 2073 | gateway's signature handling. Working gateways are not blocked by a broader |
| 2074 | preflight check (#6048, #6081, thanks @nightt5879). |
| 2075 | - Chinese documentation links resolve to the contributor guide and Windows |
| 2076 | screenshots from their translated paths (#6080, thanks @c020627). |
| 2077 | - GLM-5.3 reasoning controls follow the forced-thinking contract on Z.ai and |
| 2078 | BigModel routes, including low effort when a prior configuration requested |
| 2079 | thinking off (#6051, thanks @h3c-hexin and @asto18089). |
| 2080 | - Finance calls respect the session network policy, and model-facing shell, |
| 2081 | verifier, notification and Fleet guidance matches executable contracts |
| 2082 | (#6052, thanks @h3c-hexin and @asto18089). |
| 2083 | - The sandbox-elevation prompt shows every option, `Abort` included. The card |
| 2084 | was a fixed 22 rows centred on the frame; inside its border and padding that |
| 2085 | left at most 18 usable rows against 20 to 23 rows of content, with no scroll |
| 2086 | rail and no truncation hint. The safe exit — the one choice that grants |
| 2087 | nothing — was painted past the bottom edge at every terminal size. The card |
| 2088 | is measured from its content now and reserves the option rows before the |
| 2089 | denial detail, which is what shortens; below roughly 60x24 the per-option |
| 2090 | descriptions shed and every choice keeps its row. Option hitboxes were also |
| 2091 | counted in unwrapped source lines, so a description that wrapped put every |
| 2092 | hitbox below it out of step and a click committed a different choice than the |
| 2093 | one under the pointer. |
| 2094 | - `d` in the Hotbar setup modal asks before it clears every slot. It persisted |
| 2095 | `hotbar = []` on the first keystroke, in a view that takes bare letters as its |
| 2096 | filter — the destructive key and the search key were the same press. It arms a |
| 2097 | confirmation that owns every key until answered, and the prompt takes the |
| 2098 | intro's place in the header so it cannot be the line that falls off a |
| 2099 | five-row budget. |
| 2100 | - Failure red means failure again. The metrics line painted the context reading |
| 2101 | in the error colour from 80 %, while the posture bar one row above called the |
| 2102 | identical threshold Attention; the workflow panel painted a `Waiting` row like |
| 2103 | a crashed one, though its own `is_running` counts Waiting as healthy; and the |
| 2104 | work surface spent `error_fg` on to-dos that were merely waiting, blocked or |
| 2105 | stale, and on the routine approach to auto-compaction. `WorkTone` has a real |
| 2106 | `Failure` variant now, and a guard test holds the reservation across every |
| 2107 | selectable theme rather than the default alone. |
| 2108 | - The command palette runs the row you highlighted. `refilter` clamped the |
| 2109 | selection index but never re-anchored it, and every keystroke re-sorts the |
| 2110 | list, so refining a query could move the highlight to an unrelated entry that |
| 2111 | Enter then ran. Long labels also overran their column and pushed the |
| 2112 | description off the card, because the padding never truncated and the capacity |
| 2113 | was measured against the popup rather than the content area. |
| 2114 | - The work surface's first `Down` reaches the first row. Nothing is selected |
| 2115 | when the dock opens, and that resolved to "row 0 is selected", so the first |
| 2116 | press moved to row 1 and row 0 could not be reached by pressing Down at all. |
| 2117 | - Auto-compact could not fire mid-turn. The gate read `max(last billed |
| 2118 | prompt, /4 estimate of the whole list)`, so as soon as the estimator |
| 2119 | undercounted the full list below the last bill, every tool result appended |
| 2120 | after that prompt was invisible to it, and a long turn could exhaust the |
| 2121 | context window with nothing compacted. It now reads live tokens — the |
| 2122 | billed prompt plus the growth since it, watermarked when the parent usage |
| 2123 | is recorded — and is still evaluated at the pre-request boundary after |
| 2124 | tools complete, never mid-tool-call. |
| 2125 | - Esc or Ctrl+C during a compaction that is serving an in-flight turn now |
| 2126 | stops the turn. It previously cancelled only the compaction pass, so the |
| 2127 | turn resumed against the context that had just failed to shrink. A manual |
| 2128 | `/compact` with no request in flight still cancels only the pass. |
| 2129 | - The `request_user_input` dialog is a bottom-anchored sheet instead of a |
| 2130 | centered 22-row overlay. It leaves the transcript visible above it, grows |
| 2131 | with its content, and scrolls internally so the highlighted option and the |
| 2132 | custom response being typed stay on screen at 141x38 and 80x24. Left arrow |
| 2133 | or `h` goes back to the previous question; Esc still cancels the whole |
| 2134 | request. PageUp/PageDown, Home/End and modified arrows now review the |
| 2135 | transcript while the sheet stays open; the mouse wheel scrolls the surface |
| 2136 | under the pointer. Wheel browsing preserves the answer, and option navigation |
| 2137 | or typing restores the focused content to view. The transcript viewport ends |
| 2138 | above question and approval prompts, so End keeps the newest rows visible. |
| 2139 | Documented in GUIDE.md and KEYBINDINGS.md (#6045). |
| 2140 | - `/mcp reload` no longer freezes the interface. The reload was awaiting the |
| 2141 | whole reconnect batch on the TUI event loop; it now joins the same |
| 2142 | supervised background pass the session boot uses, the status chip counts |
| 2143 | the batch down live, and the finished receipt arrives as an event. With |
| 2144 | 23 configured servers (11 live, 10 awaiting auth, 2 failing) the first |
| 2145 | echoed keystroke after a reload lands in ~5 s instead of ~42 s (#5974). |
| 2146 | - The posture bar no longer states the same duration twice on a first turn |
| 2147 | (#6041). |
| 2148 | - Reasoning-capable models whose id carries no version substring |
| 2149 | (`deepseek-flash`) keep `reasoning_content` in the thinking block instead |
| 2150 | of the answer text. The gate only ever matched the literal `deepseek-v4` |
| 2151 | version string, so it now consults the model catalog as well; the older |
| 2152 | literal arms remain for the V4 aliases they were written for (#6044). |
| 2153 | - `codewhale model resolve` accepts a provider's declared default even when |
| 2154 | its registry row is missing — `deepseek-flash` failed resolution against |
| 2155 | the provider that declares it as default — and a test now resolves every |
| 2156 | provider's `DEFAULT_*_MODEL` for its own provider (#6043). |
| 2157 | - A configured `default_text_model` is honored when a new thread's route is |
| 2158 | resolved. That path consulted only the provider's catalog default, so a |
| 2159 | config naming one model silently created threads on another, and the |
| 2160 | unset default disagreed with the shipped one; the active provider's |
| 2161 | configured default now wins, matching `provider_default_model`, and both |
| 2162 | unset defaults name `deepseek-flash` (#6043). |
| 2163 | - Markdown `_italic_` requires both delimiters to be flanking per CommonMark, |
| 2164 | so math subscripts no longer italicize the prose between them |
| 2165 | (`[t_, b_p]. Actually — hold on, do we even tile all the way from t_?` |
| 2166 | rendered 60 characters italic) (#6042). |
| 2167 | - An MCP server configured for OAuth that answers 401 before its first login |
| 2168 | now points at `/mcp login <name>` in the failure hint instead of a bearer |
| 2169 | token that does not exist (#6030). |
| 2170 | - Cancelling a foreground shell wait stops its owned process group even when |
| 2171 | the tool future is dropped. Explicitly backgrounded jobs retain their |
| 2172 | ownership. Interrupted tool receipts distinguish work that started from |
| 2173 | calls skipped before execution, and returned tool failures remain errors in |
| 2174 | the next model request. |
| 2175 | - Saved Fleet model identifiers retain exact spelling through selection, |
| 2176 | role pins, and roster changes, so changing one saved model does not modify |
| 2177 | another identifier that differs only in letter case. |
| 2178 | - Chat wrapping reserves its scrollbar gutter consistently, keeping long |
| 2179 | identifiers readable when the viewport changes. |
| 2180 | - The Engine keeps large send-message futures off the event loop's stack, |
| 2181 | preventing stack exhaustion when a restored session starts a provider turn. |
| 2182 | - New, imported, and live session titles skip runtime handoffs and use the |
| 2183 | first real user prompt. Explicitly renamed titles retain priority |
| 2184 | (#6012, thanks @SparkofSpike). |
| 2185 | - UI dispatch acceptance now precedes Engine execution, so a delayed acceptance |
| 2186 | callback cannot overwrite a turn that has already started or completed. |
| 2187 | Cancelling before acceptance preserves the prompt and leaves the next |
| 2188 | dispatch usable. |
| 2189 | - Bottom-chrome effort is omitted when the route cannot prove an effective |
| 2190 | tier; `/status` retains the full explanation. Cost remains visible when |
| 2191 | known, and `cost: unknown` remains on metered routes lacking a reading (#5950). |
| 2192 | |
| 2193 | - Pasting multiline text is one paste again. 0.9.12 gated the |
| 2194 | paste-burst heuristic off whenever bracketed paste was *requested*, but |
| 2195 | a terminal can accept `EnableBracketedPaste` and still deliver a paste |
| 2196 | as individual keystrokes — on those terminals (observed on Windows 11) |
| 2197 | every pasted line was submitted as its own message. The heuristic is |
| 2198 | again armed whenever `tui.paste_burst_detection` is on, and the |
| 2199 | existing `bracketed_paste_seen` guard still disarms it for the rest of |
| 2200 | the session once a real `Event::Paste` arrives, so fast typing on |
| 2201 | terminals with working bracketed paste is unaffected (#5981, thanks |
| 2202 | @nsfoxer). |
| 2203 | - `serve --acp` no longer breaks strict JetBrains clients: the |
| 2204 | `initialize` response advertised `sessionCapabilities.list` as a |
| 2205 | boolean and carried an undefined nested `load` capability; it now |
| 2206 | sends `{"list": {}}` with no `load` key, per the ACP schema (#5969, |
| 2207 | reported by @Lujc0523). |
| 2208 | - Concurrent Codewhale instances no longer destroy each other's queued, |
| 2209 | unsent text. The offline input queue was one global file that boot |
| 2210 | cleared on session-id mismatch, so a second instance deleted the |
| 2211 | first's parked messages. Queues are now keyed per session (mirroring |
| 2212 | per-session checkpoints), an existing global file is adopted by its |
| 2213 | owning session rather than discarded, and the adoption race between |
| 2214 | two instances of the same session tolerates the loser's cleanup. |
| 2215 | - A tool call truncated at the provider's output limit can no longer be |
| 2216 | repaired into valid JSON and executed: repairs that had to synthesize |
| 2217 | structure (append or discard closers) are routed to the existing |
| 2218 | malformed-arguments path so the model is asked to re-issue — including |
| 2219 | when the stream is cut before the closing content-block event (#5986). |
| 2220 | - `codewhale metrics` reads Codewhale's own receipts again: the |
| 2221 | deepseek-home fallback resolved `$HOME/.deepseek` unconditionally, so |
| 2222 | the rollup reported all zeros from a directory nothing has written |
| 2223 | since 2024. The Codewhale audit log is primary, with a checked legacy |
| 2224 | fallback. |
| 2225 | - The goal-continuation loop's promised stall bound actually bounds |
| 2226 | stalls now, and undeclared fleet role names fail closed to read-only |
| 2227 | `explore` in both fleet drivers instead of resolving to write-capable |
| 2228 | customs in one and not the other. |
| 2229 | - `allow_insecure_http = true` under a `[providers.<name>]` table works |
| 2230 | again. 0.9.12 tightened plain-HTTP base URL handling in a way that |
| 2231 | silently dropped the per-provider key, leaving the process-wide env |
| 2232 | var as the only opt-in — LAN llama.cpp and internal-gateway users |
| 2233 | had to export `CODEWHALE_ALLOW_INSECURE_HTTP=1` to connect at all. |
| 2234 | The key is honored again (parsed, settable and unsettable through |
| 2235 | `codewhale config set providers.<name>.allow_insecure_http`, and |
| 2236 | listed in the custom-provider field hint), it stays distinct from |
| 2237 | `insecure_skip_tls_verify`, and the refusal message now leads with |
| 2238 | the config key. Loopback hosts remain auto-allowed and telemetry |
| 2239 | endpoint validation deliberately still consults neither switch |
| 2240 | (#5991, thanks @Gabriel-Degret). |
| 2241 | - A Fleet task that selects a roster member with `worker.agent_profile` now |
| 2242 | runs with that member's posture. The launch-time resolver only consulted the |
| 2243 | resolved member when the legacy `worker.role` label was absent, so a task |
| 2244 | labelled `manager` that selected `member:reviewer` ran as a write-capable |
| 2245 | manager instead of a reviewer and was never leased. The member's canonical |
| 2246 | slot now wins whenever one resolved; the label remains the posture only when |
| 2247 | no member resolved at all. To keep the fix from widening authority in the |
| 2248 | mirror case (a read-only label on a write-capable member), a spec whose |
| 2249 | `worker.role` names a different posture than the selected member's role is |
| 2250 | rejected at run creation with a message naming both postures; casing and |
| 2251 | legacy aliases of the member's own role are still accepted (#5945, thanks |
| 2252 | @gaord). |
| 2253 | - A queued message keeps one transcript entry from queue through steer to |
| 2254 | dispatch. It no longer reads as delivered while it is still pending, and the |
| 2255 | second Enter the strip prompts for no longer paints a duplicate bubble. |
| 2256 | - The Tasks rail panel no longer swallows the first keystroke of typed input: |
| 2257 | bare `y`/`Y` yank only when the work surface holds keyboard focus, so a |
| 2258 | message that starts with "yes" stays intact (#2000). |
| 2259 | - `wait` results reach the parent intact. The parent-context summarizer |
| 2260 | projected every `agent` tool result through the sub-agent snapshot renderer, |
| 2261 | which replaced a wait envelope's `settled`, `still_running`, `timed_out`, |
| 2262 | `waited_ms`, and `note` with `unknown (agent) status=unknown`. Only |
| 2263 | snapshot-shaped results are summarized now. |
| 2264 | - A sub-agent's final summary uses the same adaptive tool-result budget as |
| 2265 | every other tool result (`tool_result_max_bytes`, 12k floor, 2 MiB ceiling) |
| 2266 | instead of a hardcoded 12k/4k/4k copy that cut a 12,001-character report to |
| 2267 | 8,000. |
| 2268 | - The metrics line no longer carries a permanent `/help` hint. The route still |
| 2269 | appears until its binding has been used and then retires with the other |
| 2270 | footer hints, so the row stays quiet once help is learned. |
| 2271 | - `request_user_input`'s description names when asking is the right move |
| 2272 | (ambiguous scope, an irreversible or expensive choice, a missing preference) |
| 2273 | and when it is not, so the model stops guessing at discoverable facts. |
| 2274 | - `config.example.toml` states the real search default (keyless Firecrawl, not |
| 2275 | DuckDuckGo) and the preferred `CODEWHALE_SEARCH_*` environment names. |
| 2276 | - Startup type-ahead is preserved whole, and a slash command interrupted by |
| 2277 | startup keystrokes is no longer re-read as prose and sent to the model |
| 2278 | (#5925). |
| 2279 | - The model picker renders a large catalog without lag and supports per-column |
| 2280 | sort and mouse selection (#5975). |
| 2281 | - Session metrics report effective request throughput from provider receipts |
| 2282 | instead of a live estimate divided by the whole turn, and cost stays honest |
| 2283 | when a route has no price reading (#5976, #5977). |
| 2284 | - An offline-queue submit delivered as late raw keystrokes no longer wedges the |
| 2285 | composer behind stacked session notices (#5999). |
| 2286 | - Fleet setup with a model filter that matches nothing renders a hint instead |
| 2287 | of panicking (#5953), and shortlist enrollment plus authoritative role pins |
| 2288 | are honored on dispatch (#5915). |
| 2289 | - A mid-turn MCP catalog refresh keeps the tool pool deferred and the active |
| 2290 | set narrow (#5939). |
| 2291 | - Computer Use on macOS verifies application activation before sending |
| 2292 | keystrokes and guards input by the frontmost app (#5927). |
| 2293 | - Onboarding tests isolate `CODEWHALE_HOME`, so a fixture provider can no |
| 2294 | longer leak into the real setup state (#5932). |
| 2295 | - Snapshot availability is retained with one warning per session, and a |
| 2296 | diverged engine session id is a visible notice rather than a log line |
| 2297 | (#5930). |
| 2298 | |
| 2299 | ### Changed |
| 2300 | |
| 2301 | - How long Codewhale waits for a human is configurable. `[tools] |
| 2302 | user_input_timeout_seconds` governs the wait for an approval decision or a |
| 2303 | `request_user_input` answer; it was a hardcoded 300 seconds, which silently |
| 2304 | cancelled the work of anyone who stepped away mid-task. An explicit `0` |
| 2305 | waits indefinitely, the value is clamped to 24 hours, and omitting the key |
| 2306 | keeps the previous 300-second default. Documented in |
| 2307 | `docs/CONFIGURATION.md` ([#6003](https://github.com/codewhale-hq/Codewhale/issues/6003)). |
| 2308 | - `docs/PROVIDERS.md` lists every beginner setup template, not the four it |
| 2309 | happened to mention when the page was written. Baseten, Groq, Cerebras and |
| 2310 | Command Code have shipped as supported OpenAI-compatible hosts for a while |
| 2311 | and appeared nowhere in the provider documentation, which reads from outside |
| 2312 | exactly like not supporting them. The page now carries the full table — |
| 2313 | host, default model and key env for each — and states the rule it follows: |
| 2314 | a plain Chat Completions backend is a template row, while `ProviderKind` is |
| 2315 | reserved for distinct wires. A test now fails if a shipped template is |
| 2316 | missing from that page. |
| 2317 | - Reasoning capability for the Kimi coding routes and the qwen3.x Model Studio |
| 2318 | deep-thinking ids is catalog data now rather than hardcoded match arms, and |
| 2319 | `model_reasoning_capability` reports a model nothing knows about as unknown |
| 2320 | instead of silently not reasoning-capable. `model_supports_reasoning` keeps |
| 2321 | its `bool` shape for existing callers, where unknown still reads as false. |
| 2322 | The ids that have no cited source yet keep their literal arms (#6032). |
| 2323 | - The website uses Shannon Sans with versioned local font assets and retained |
| 2324 | serif, monospace, and language fallbacks. Terminal fonts are unchanged. |
| 2325 | - `codewhale metrics` reports recorded model requests and stream recovery |
| 2326 | separately from provider-reported token usage, with coverage for missing |
| 2327 | and duplicate receipts. Status messages and cumulative snapshots do not |
| 2328 | add requests or count tokens again. |
| 2329 | - Runtime turn receipts retain the Engine's terminal model-request, stream-retry, |
| 2330 | and resume counters separately from displayed status and provider-reported |
| 2331 | usage. These counters do not count HTTP retries inside a provider client or |
| 2332 | establish provider billing. |
| 2333 | - Initial tool definitions no longer repeat shell interpreter guidance and |
| 2334 | agent lifecycle/scope instructions in multiple description fields. Parameter |
| 2335 | schemas, approval rules and dispatch behavior are preserved. This reduces |
| 2336 | prompt schema size; it does not establish a provider billing regression. |
| 2337 | |
| 2338 | - The built-in Computer Use plugin bundle is refreshed to the standalone |
| 2339 | plugin's 0.2.1 runtime (vendored from `Hmbown/codewhale-cu-plugin` |
| 2340 | at `724ad258`): the native macOS accessibility backend with an |
| 2341 | a11y-first pointer strategy (covered points are refused, previews are |
| 2342 | drawn), the permission-owning desktop-app socket transport, remote |
| 2343 | computers over ssh and HarmonyOS HDC with contained temp handling, |
| 2344 | truthful win32 PowerShell failure reporting, and the shared |
| 2345 | allow-listed request handler for the app socket and ssh agent. |
| 2346 | The bundle retains the hardening port from |
| 2347 | [standalone plugin PR #12](https://github.com/Hmbown/codewhale-cu-plugin/pull/12). |
| 2348 | Single left clicks on macOS element targets now revalidate and press |
| 2349 | the observed element directly, without substituting a point hit-test |
| 2350 | or raw-pointer fallback. Explicit event clicks retain the app-ownership |
| 2351 | guard; a sent press still requires visual verification. Background mode |
| 2352 | permits application-bound keys and accessibility actions while refusing |
| 2353 | shared-pointer gestures; it does not provide an isolated desktop. The |
| 2354 | embed list gained the five new runtime files, and a consistency test |
| 2355 | now pins the embed list to the vendored tree so the bundle cannot rot |
| 2356 | silently again. Because the bundle's content hash changes, Computer |
| 2357 | Use deactivates and asks for a fresh review after upgrading — that is |
| 2358 | the designed fail-closed path for a desktop-driving plugin. The |
| 2359 | current macOS source candidate also embeds the compiled native helper, |
| 2360 | so its bundled server can run directly without a separate Computer Use |
| 2361 | app or a compiler on the user's machine. Accessibility and Screen |
| 2362 | Recording permissions belong to the hosting app or terminal and remain |
| 2363 | user-controlled. The CLI's Computer Use server requires Node.js 20 or newer. These are source |
| 2364 | candidate changes; they do not establish published-package or platform |
| 2365 | qualification. See the [included plugin guide](crates/tui/plugins/computer-use/README.md) |
| 2366 | for platform requirements and limitations. |
| 2367 | - `/statusline` drives the bottom chrome again. Since the 0.9.12 shell |
| 2368 | redesign the posture bar and the metrics line were built independently of |
| 2369 | `tui.status_items`, so every toggle in the picker except the balance fetch |
| 2370 | was decoration. Each remaining item now shows or hides exactly one thing: |
| 2371 | `model`, `context_percent`, `cost`, `balance`, `cache`, `tokens` and |
| 2372 | `session_metrics` are metrics-line segments, and `mode` is the posture |
| 2373 | bar's plan/act/operate chip. The `status`, `agents`, `reasoning_replay`, |
| 2374 | `prefix_stability`, `git_branch`, `last_tool_elapsed` and `rate_limit` |
| 2375 | items drove nothing and are retired; an existing `config.toml` still loads |
| 2376 | and those keys are ignored (#5950, #5962). |
| 2377 | - The context reading is back on screen at every fullness. 0.9.12 painted |
| 2378 | `ctx NN%` only from 50% up, which left most of a session with no context |
| 2379 | signal at all; it now paints from 0% and keeps its warning colour from 80% |
| 2380 | up (#5950). |
| 2381 | - A child agent parked because its parent's turn ended is shown as `parked` |
| 2382 | in the Agents panel, the sidebar and Agent Details, with `resume_from` / |
| 2383 | `cancel` as the recovery, instead of wearing the same "waiting for input" |
| 2384 | label as a child that asked a question. Parked work sorts below live and |
| 2385 | answerable work and no longer inflates the `blocked` chip; the receipts |
| 2386 | roster and the wire `state` gain `parked` (#5906, #5921). |
| 2387 | |
| 2388 | - `codewhale account keys set|remove|list` no longer carry a hardcoded |
| 2389 | eight-provider list. Provider ids come from the control plane's public |
| 2390 | catalog (`GET /api/model-providers`), are validated locally against |
| 2391 | `^[a-z0-9][a-z0-9-]{0,63}$` before they reach a URL path, and `list` shows |
| 2392 | every catalog provider with its label and stored-key state. `--from-local` |
| 2393 | maps a catalog row onto the local runtime provider through the catalog's own |
| 2394 | `runtimeProvider` field, so a newly supported provider needs no CLI release. |
| 2395 | |
| 2396 | - `/mcp` lists the servers that need a login first, as their own |
| 2397 | `Needs login` group above `Needs attention`, and opens with the cursor |
| 2398 | already on the first such row so the Enter the screen advertises runs |
| 2399 | `/mcp login <server>` straight away; translated in all 15 packs. A |
| 2400 | snapshot test pins the footer shape the chip landed with (`MCP · N |
| 2401 | connected · N ◆ auth required · N failed`) so an expired login never |
| 2402 | regresses into the failed count (#5926). |
| 2403 | |
| 2404 | ### Fixed |
| 2405 | |
| 2406 | - Five of the load-flaky tests tracked in #5929 no longer depend on shared |
| 2407 | state or live local daemons. Background-hook capture tests wait for the |
| 2408 | capture file to hold bytes instead of merely existing (the shell's `>` |
| 2409 | redirection creates the file empty before `cat` writes, which read as |
| 2410 | `valid JSON: EOF` under load); the session-picker acceptance test drives |
| 2411 | the real picker over a private store instead of a process-global |
| 2412 | `CODEWHALE_HOME` redirect that concurrent tests could observe mid-flight; |
| 2413 | the DeepSeek-Anthropic translate test holds the test env barrier so its |
| 2414 | request-time and assertion-time `max_tokens` reads cannot straddle another |
| 2415 | test's `CODEWHALE_MAX_OUTPUT_TOKENS` override; the unit-test binary no |
| 2416 | longer probes a real local Ollama daemon (`127.0.0.1:11434`) from the |
| 2417 | fire-and-forget provider catalog refresh, whose merged tags could flip |
| 2418 | another test's live-snapshot assertions; and the tmux clipboard test's |
| 2419 | attach/OSC 52 wait bounds tolerate a fully loaded machine (3s -> 30s) |
| 2420 | without changing what they verify (#5929). |
| 2421 | - The posture bar states how long the session has been working and how long |
| 2422 | the current turn has run, distinguishing actively working from waiting on |
| 2423 | a tool, a sub-agent or the operator; the 0.9.12 shell had dropped the overall |
| 2424 | working-time indicator from the place a glancing user checks (#5914). |
| 2425 | - A background runtime turn whose own store record could not be read, parsed |
| 2426 | or written (`Failed to read turn …`, `Failed to read item …`) was only a log |
| 2427 | line. The runtime now publishes a `runtime.store_failure` event naming the |
| 2428 | file, the root cause and the next action (move the file aside, or check free |
| 2429 | space and permissions); the TUI shows it as a warning toast and a transcript |
| 2430 | line, the task timeline records it, and the runtime API streams it. A turn |
| 2431 | whose own record is unreadable or unwritable is reported as terminal, so its |
| 2432 | task fails at once instead of idling out (#5931). |
| 2433 | |
| 2434 | - An MCP token refresh that fails to parse the provider's answer keeps the |
| 2435 | endpoint's receipt — status line, content type, and a 200-byte excerpt |
| 2436 | with every credential-shaped value (`access_token`, `refresh_token`, |
| 2437 | `client_secret`, `id_token`, bearer schemes) masked before the cut — |
| 2438 | instead of rmcp's bare `Failed to parse server response`, so a provider |
| 2439 | outage answering an HTML 502 reads differently from a parser defect, and |
| 2440 | the login remedy stays named (#5926; remedy wording landed in #5959). |
| 2441 | |
| 2442 | ### Added |
| 2443 | |
| 2444 | - `POST /v1/threads/{id}/file-revert` restores exactly one file from the |
| 2445 | exact `tool:`/`pre-turn:` snapshot the client selected, checking the |
| 2446 | reviewed file hash before and after the mandatory safety snapshot. Literal |
| 2447 | file names, regular files only, thread trust and active-turn admission are |
| 2448 | enforced, and `patch-undo` no longer forks a conversation whose file |
| 2449 | rollback failed (#6111, thanks @gaord; engine half of |
| 2450 | HengQuWorld/CodeWhale-VSCode#3). |
| 2451 | - Authenticated Runtime API workspace file suggestions reuse TUI `@file` |
| 2452 | matching and discovery, with bounded queries/results and workspace-contained |
| 2453 | relative paths only (`GET /v1/workspace/files/search`, #6095, #6120, thanks @wuisabel-gif; reported by @LmeSzinc). Shared discovery |
| 2454 | now honors disabled symlink following for AI-tool directory scan roots too. |
| 2455 | - Serply is available as an opt-in `[search]` provider for the Web tool |
| 2456 | (`provider = "serply"`, key from `[search] api_key` or `SERPLY_API_KEY`). |
| 2457 | Preflight fails closed without a key; Firecrawl remains the default and |
| 2458 | existing configurations are unchanged (#6100, thanks @googio). |
| 2459 | - Linux terminals: finishing a transcript or composer mouse selection copies |
| 2460 | the text to the PRIMARY selection without touching the regular clipboard, and |
| 2461 | middle-click inside the composer pastes PRIMARY at the pointer without |
| 2462 | submitting. Native X11 and Wayland data control are used through one bounded |
| 2463 | background worker; SSH sessions without a forwarded display keep their |
| 2464 | terminal's own selection behavior (#6116, thanks @dmt4). |
| 2465 | - `codewhale sessions export <id-or-unique-prefix>` saves a `.tar.xz` archive |
| 2466 | with the durable record, portable session container, manifest and artifacts. |
| 2467 | Prefix exports preserve unfinished tool calls; confined reads reject linked |
| 2468 | artifact roots, and existing outputs require `--force`. Archives retain |
| 2469 | unredacted content; `/load` opens the extracted record without installing |
| 2470 | extracted artifacts (#6056, thanks @h3c-hexin and @asto18089). |
| 2471 | |
| 2472 | - `deepseek-flash` (DeepSeek V4.1 Flash: 1M-token context, |
| 2473 | reasoning and tool calls) joins the catalog as DeepSeek's declared default, |
| 2474 | and the offline catalog seed matches it; the DeepSeek Pro listing no longer |
| 2475 | overstates the published price (#6025). |
| 2476 | - DeepSeek's September 11 reversal is reflected in provider notices and cost |
| 2477 | estimates: V4 Pro remains available after September 14 at Pro rates. Explicit |
| 2478 | Pro selections remain unchanged; Flash remains the default (#6025, thanks @ronohara). |
| 2479 | - Native plugin authoring guides now cover English and Chinese. The explicit |
| 2480 | offline converter supports selected portable Skills and static Streamable |
| 2481 | HTTP MCP declarations from OpenCode and DSH. Unsupported executable hooks, |
| 2482 | automatic OAuth and policy-bearing configurations are refused; generated |
| 2483 | bundles still require native installation, review and trust. Legacy SSE |
| 2484 | fallback is not reproduced (#5827, requested by @giancarlocp). |
| 2485 | |
| 2486 | - Signed cloud model facts can refresh provider capabilities and prices while |
| 2487 | preserving verified cached data when a refresh fails. A dispatched request |
| 2488 | keeps its selected price snapshot so later catalog updates cannot change its |
| 2489 | recorded cost (#5752). |
| 2490 | - Saved sessions preserve exact provider routes. Auxiliary model calls settle |
| 2491 | their usage once against the route and price snapshot that executed them, |
| 2492 | including recovery, rather than resolving a new price at completion |
| 2493 | (#5726, #5848). |
| 2494 | - `[tui].posture_bar` and `[tui].metrics_line` accept `full`, `compact`, or |
| 2495 | `hidden`, also available through `/config`. Compact preserves the existing |
| 2496 | rows' essential fields; hidden returns their space to the transcript (#5973). |
| 2497 | - Optional model-bound tool-output redaction opt-out, with two explicit startup |
| 2498 | confirmations and a receipt bound to the readable config contents and |
| 2499 | modification time. Unconfirmed requests keep masking enabled; routing and |
| 2500 | stored goal summaries remain redacted (#5982, thanks @SparkofSpike). |
| 2501 | |
| 2502 | - The `rusty-alloc` cargo feature on `codewhale-tui` and `codewhale-cli` |
| 2503 | opts the binaries into the `rusty_alloc` global allocator (the mimalloc |
| 2504 | v2.4.5 architecture remade in pure Rust — no C compiler or build script |
| 2505 | on that path) instead of the default mimalloc. It is off by default and |
| 2506 | the default build is unchanged; build with |
| 2507 | `cargo build -p codewhale-tui --features rusty-alloc` (#5872). |
| 2508 | - The `/theme` picker now discovers valid user-authored `custom:<name>` |
| 2509 | overlays, previews their colors, highlights the active overlay, and preserves |
| 2510 | it when the picker is opened and committed without navigation (#5901). |
| 2511 | - Compaction has two standing knobs next to `[context]` in config.toml: |
| 2512 | `[compaction] summary_instructions` (appended to the summarizer prompt on |
| 2513 | every manual and automatic pass; `/compact <focus>` still composes after |
| 2514 | it) and `[compaction] retained_user_message_tokens` (default 20 000, |
| 2515 | clamped 2 000..=200 000) for the verbatim user-message budget. Both are |
| 2516 | absent by default and absent means the pre-existing behavior. The |
| 2517 | `/compact` receipt names the effective budget and whether operator |
| 2518 | instructions applied (#5956). |
| 2519 | - `[tools] user_input_max_questions` (default 6, 1..=10) and |
| 2520 | `[tools] user_input_max_options` (default 4, 2..=10) replace the hard-coded |
| 2521 | `request_user_input` limits; the validator, the tool schema and its |
| 2522 | description read one value, spawned children inherit the parent's ceilings, |
| 2523 | and a rejected payload names the ceiling it hit and the key to raise (#5949). |
| 2524 | - The slash menu shows a command's usage line and its subcommands as soon as |
| 2525 | a space is typed after the verb, filtered by what follows, so Tab completes |
| 2526 | `/workspace wor` to `/workspace worktrees`; `/help` states the focused |
| 2527 | command's usage in its detail slot (#5952). |
| 2528 | - The three `/fleet` views (roster, live workers, saved teams) are one |
| 2529 | back-navigable stack: `Esc` in workers or saved teams returns to the roster |
| 2530 | with its cursor intact and still closes the window at the root or on direct |
| 2531 | entry; the `Esc` footer hint says `back` or `close` accordingly (#5954). |
| 2532 | - `/fleet` presents its prioritized core (`members`, `setup`, `teams`, |
| 2533 | `workers`, `help`); every other verb stays dispatchable and is documented |
| 2534 | under explicit groups in `/fleet help`. The roster no longer shows the |
| 2535 | untouched built-in `general` alias next to `worker` (#5888). |
| 2536 | - `codewhale` provider: account-backed model access over the provider keys a |
| 2537 | customer connected to their Codewhale account. One base URL |
| 2538 | (`https://api.codewhale.net/v1`, overridable with `CODEWHALE_API_BASE`; |
| 2539 | HTTPS required except on loopback), one `cwc_key_…` account API key with the |
| 2540 | `models:infer` scope (`CODEWHALE_API_KEY`), and a per-model wire chosen from |
| 2541 | the account's authenticated `GET /v1/models`: ids are `provider/model` and |
| 2542 | each row states `chat-completions` (`/v1/chat/completions`) or |
| 2543 | `anthropic-messages` (`/v1/messages`). Both protocols authenticate with |
| 2544 | `Authorization: Bearer`, never `x-api-key`. The key is read from |
| 2545 | `CODEWHALE_API_KEY`, the `codewhale` secret-store slot, or |
| 2546 | `[providers.codewhale] api_key` / `api_key_env`, and a missing key fails |
| 2547 | before any request instead of dispatching unauthenticated. If the catalog |
| 2548 | cannot be fetched the route falls back to three bootstrap ids and says so. |
| 2549 | - `codewhale account api-keys create --scope` now accepts `models:infer` |
| 2550 | alongside `account:read` and `agent:run`, and an omitted `--scope` sends all |
| 2551 | three explicitly. `--use` saves the new secret as this machine's local |
| 2552 | `codewhale` provider credential in the same secret store `codewhale auth` |
| 2553 | uses; nothing is uploaded. |
| 2554 | - `Git` grows a `commit_plan` action: a propose-only planner that splits the |
| 2555 | working tree into ordered atomic commits (#3999). It groups whole files — |
| 2556 | lock files ride with their manifest, tests ride with the source they name — |
| 2557 | orders the groups so a commit that defines a symbol lands before the commit |
| 2558 | that uses it, and refuses the whole plan when that dependency graph has a |
| 2559 | cycle. It reads `git diff HEAD` plus the untracked-file list and writes |
| 2560 | nothing: no `git add -N`, no `git apply --cached`, no `git commit`, so |
| 2561 | staging and committing stay with the ordinary `git add` / `git commit` shell |
| 2562 | path where the approval gate already applies. Thanks |
| 2563 | [@goransh-walia](https://github.com/goransh-walia) for the original |
| 2564 | implementation (PR #5870, fixes #3999). |
| 2565 | |
| 2566 | ### Contributors |
| 2567 | |
| 2568 | - **[@LmeSzinc](https://github.com/LmeSzinc)** — requested Runtime API access to the TUI's fuzzy file search ([#6095](https://github.com/codewhale-hq/Codewhale/issues/6095)). |
| 2569 | - **[@googio](https://github.com/googio)** — added the Serply web-search provider ([#6100](https://github.com/codewhale-hq/Codewhale/pull/6100)). |
| 2570 | - **[@dmt4](https://github.com/dmt4)** — requested Linux copy-on-select and middle-click paste ([#6116](https://github.com/codewhale-hq/Codewhale/issues/6116)). |
| 2571 | - **[@Gabriel-Degret](https://github.com/Gabriel-Degret)** — reported that saved agent profiles were silently ignored when spawning sub-agents ([#6117](https://github.com/codewhale-hq/Codewhale/issues/6117)). |
| 2572 | - @nightt5879 — Gemini signature recovery guidance and transport regressions (#6081). |
| 2573 | - @c020627 — Chinese documentation link repairs (#6080). |
| 2574 | - @h3c-hexin and @asto18089 — GLM-5.3 reasoning controls and tool-gating/documentation fixes (#6051, #6052). |
| 2575 | - @Hmbown — dependency updates (#6057) and the Gemini signature recovery report (#6048). |
| 2576 | - **[@gaord](https://github.com/gaord)** — contributed the file-scoped restore endpoint and the trust-gated whole-tree rollback ([#6111](https://github.com/codewhale-hq/Codewhale/pull/6111)), Fleet schema inspection, role precedence and worker deliverable receipts, and linked the community VS Code frontend ([#5944](https://github.com/codewhale-hq/Codewhale/pull/5944), [#5945](https://github.com/codewhale-hq/Codewhale/pull/5945), [#5946](https://github.com/codewhale-hq/Codewhale/pull/5946), [#5992](https://github.com/codewhale-hq/Codewhale/pull/5992)). |
| 2577 | - **[@goransh-walia](https://github.com/goransh-walia)** — contributed the propose-only commit-planning rework ([#5870](https://github.com/codewhale-hq/Codewhale/pull/5870)). |
| 2578 | - **[@7jrxt42BxFZo4iAnN4CX](https://github.com/7jrxt42BxFZo4iAnN4CX)** — documented turn budgets and goal configuration, and reported gaps in command discovery, Fleet navigation, human waits, state hooks, history and provider routing ([#5996](https://github.com/codewhale-hq/Codewhale/pull/5996), [#5952](https://github.com/codewhale-hq/Codewhale/issues/5952), [#5954](https://github.com/codewhale-hq/Codewhale/issues/5954), [#6003](https://github.com/codewhale-hq/Codewhale/issues/6003), [#6004](https://github.com/codewhale-hq/Codewhale/issues/6004), [#6006](https://github.com/codewhale-hq/Codewhale/issues/6006), [#6007](https://github.com/codewhale-hq/Codewhale/issues/6007)). |
| 2579 | - **[@SparkofSpike](https://github.com/SparkofSpike)** — contributed two-stage consent for opting out of model-bound credential redaction ([#5982](https://github.com/codewhale-hq/Codewhale/pull/5982)). |
| 2580 | - **[@aboimpinto](https://github.com/aboimpinto)** — moved session lifecycle and session-control commands onto shared command contracts ([#5902](https://github.com/codewhale-hq/Codewhale/pull/5902), [#5951](https://github.com/codewhale-hq/Codewhale/pull/5951)). |
| 2581 | - **[@EvanProgramming](https://github.com/EvanProgramming)** — reported Windows input and CRLF-write defects, and contributed CRLF preservation and an injectable Windows input runner ([#5908](https://github.com/codewhale-hq/Codewhale/issues/5908), [#5909](https://github.com/codewhale-hq/Codewhale/issues/5909), [#5910](https://github.com/codewhale-hq/Codewhale/pull/5910), [#5911](https://github.com/codewhale-hq/Codewhale/pull/5911), [#5912](https://github.com/codewhale-hq/Codewhale/pull/5912)). |
| 2582 | - **[@wuisabel-gif](https://github.com/wuisabel-gif)** — exposed workspace file suggestions through the Runtime API ([#6120](https://github.com/codewhale-hq/Codewhale/pull/6120)) and added custom-theme discovery, preview and selection in the theme picker ([#5907](https://github.com/codewhale-hq/Codewhale/pull/5907)). |
| 2583 | - **[@zhuowp](https://github.com/zhuowp)** — matched model-visible shell guidance to the interpreter selected for execution ([#5900](https://github.com/codewhale-hq/Codewhale/pull/5900)). |
| 2584 | - **[@nsfoxer](https://github.com/nsfoxer)** — reported the multiline-paste regression and incomplete provider model lists ([#5981](https://github.com/codewhale-hq/Codewhale/issues/5981), [#6009](https://github.com/codewhale-hq/Codewhale/issues/6009)). |
| 2585 | - **[@Nefelibata1024](https://github.com/Nefelibata1024)** — confirmed the multiline-paste regression's impact ([#5981](https://github.com/codewhale-hq/Codewhale/issues/5981)). |
| 2586 | - **[@Gabriel-Degret](https://github.com/Gabriel-Degret)** — reported the loss of the allow_insecure_http provider setting ([#5991](https://github.com/codewhale-hq/Codewhale/issues/5991)). |
| 2587 | - **[@Lujc0523](https://github.com/Lujc0523)** — reported the ACP initialize schema violation affecting strict IDE clients ([#5969](https://github.com/codewhale-hq/Codewhale/issues/5969)). |
| 2588 | - **[@mo-vic](https://github.com/mo-vic)** — proposed storing evicted context on disk so it can be retrieved later ([#6008](https://github.com/codewhale-hq/Codewhale/issues/6008)). |
| 2589 | - **[@giancarlocp](https://github.com/giancarlocp)** — requested a plugin authoring guide and OpenCode plugin conversion ([#5827](https://github.com/codewhale-hq/Codewhale/discussions/5827)). |
| 2590 | - **[@hxfhd](https://github.com/hxfhd)** — supplied a Windows reproduction of a turn stopping before its stated next tool action ([#6010](https://github.com/codewhale-hq/Codewhale/discussions/6010)). |
| 2591 | |
| 2592 | ### Notes |
| 2593 | |
| 2594 | - **DeepSeek V4 Pro continues after September 14.** The vendor reversed its |
| 2595 | earlier retirement notice. Codewhale preserves Pro selections and Pro pricing; |
| 2596 | `deepseek-flash` remains the default for new direct DeepSeek configurations. |
| 2597 | - Upgrading from 0.9.12 with Computer Use trusted and enabled: the |
| 2598 | bundle's content hash changes with the 0.2.1 refresh, so the plugin |
| 2599 | deactivates and asks for a fresh review — that is the designed |
| 2600 | fail-closed path for a desktop-driving plugin. Re-trust it from the |
| 2601 | Plugins page. |
| 2602 | - The multiline-paste fix restores v9.11 behavior on terminals that |
| 2603 | accept `EnableBracketedPaste` but deliver pastes as keystrokes |
| 2604 | (reported on Windows 11 / PowerShell). Verified at the input-contract |
| 2605 | level and in CI; a manual paste check on a real Windows terminal is |
| 2606 | still welcome — please comment on #5981 with your terminal if anything |
| 2607 | still misbehaves. |
| 2608 | |
| 2609 | ## [0.9.12] - 2026-09-03 |
| 2610 | |
| 2611 | Codewhale v0.9.12 puts computer use in the binary, opens two new routes — |
| 2612 | Alibaba Model Studio through the data-driven provider table and Concentrate |
| 2613 | as an opt-in BYOK Responses gateway — and adds cloud dispatch plus a |
| 2614 | config-gated per-session control socket. The shell is the other half of the |
| 2615 | release: a new launch card, the work surface docked under the composer, one |
| 2616 | focus owner for Tab, tool cells that carry their own state, and `fleet` as |
| 2617 | the public word for the live collective. The complete item-level change |
| 2618 | record is retained below the categorized release highlights. |
| 2619 | |
| 2620 | ### Added |
| 2621 | |
| 2622 | - Computer use ships with the binary. The `computer-use` plugin — 38 tools |
| 2623 | across macOS, Windows, Linux and HarmonyOS, accessibility-first observation |
| 2624 | with pixel fallback, screenshots, zoom, screen recording, and registered |
| 2625 | remote computers over ssh and hdc — is embedded in Codewhale and written to |
| 2626 | `$CODEWHALE_HOME/builtin-plugins` on first run, so every install channel |
| 2627 | carries it. It lists as `builtin · not-reviewed` and stays disabled until |
| 2628 | you review and enable it: shipping it is not consenting to it. The |
| 2629 | stdlib-Python computer-use server it replaces is gone. |
| 2630 | - Alibaba Model Studio joins the data-driven provider table as an |
| 2631 | `openai-compatible` descriptor: international compatible-mode endpoint, |
| 2632 | `DASHSCOPE_API_KEY` credential, live `/v1/models` discovery. Qwen 3.8 |
| 2633 | Flash and Qwen 3.8 Max arrive through the catalog authority — never a |
| 2634 | hard-coded id. |
| 2635 | - Concentrate: first-class opt-in BYOK Responses gateway with live models |
| 2636 | discovery and typed SSE streaming (#5725). |
| 2637 | - Cloud dispatch: remote runner offloads coding agent tasks to isolated |
| 2638 | cloud sandboxes with machine token auth and structured job tracking |
| 2639 | (#5701, #5712). |
| 2640 | - Per-session control socket: config-gated `[control_socket]` table binds |
| 2641 | `<sessions-dir>/<session-id>/control.sock` per running session, exposing |
| 2642 | message, interrupt, relaunch, and status JSON-RPC verbs (#5533, #5831). |
| 2643 | |
| 2644 | ### Changed |
| 2645 | |
| 2646 | - **Anonymous usage counting is on by default.** The 0.9.11 release asked |
| 2647 | first; 0.9.12 counts the same aggregate version/platform, session, feature |
| 2648 | and error totals unless you turn it off, and says so once at first launch |
| 2649 | (policy notice version 5, schema 3, `notice_version` replacing |
| 2650 | `consent_version`). Every recorded opt-out stays off: a durable |
| 2651 | `telemetry = false`, a decline recorded under the old opt-in notice, |
| 2652 | unreadable privacy state, and the `CODEWHALE_TELEMETRY=0` / `--telemetry |
| 2653 | false` kill switches. Showing the disclosure records only that it was |
| 2654 | shown, never an acceptance. `codewhale config set telemetry false` turns |
| 2655 | it off and wipes queued counts; `codewhale config set telemetry true` |
| 2656 | deliberately re-enables it. Nothing new is collected: no conversations, |
| 2657 | code, prompts, files, names, model content, credentials, or IP. |
| 2658 | |
| 2659 | - The launch screen is our own card take: a thin top line |
| 2660 | `⑂ branch path`; a centred bordered card with the whale mark, |
| 2661 | `Codewhale` + version, one announcement line only when it is true (the |
| 2662 | no-model warning, or MCP news), and the menu New worktree / Resume |
| 2663 | session / Changelog / Quit with their real chords right-aligned. Enter |
| 2664 | runs the highlighted entry, Up/Down move it, and typing goes straight to |
| 2665 | the composer. The card dissolves on the first keystroke or command |
| 2666 | (≤240 ms, instant under reduced motion) (#5826, #5801, #5815, #5286). |
| 2667 | - The work surface sits under the composer by default, keeping history |
| 2668 | readable and leaving the stage unencumbered (#5809). |
| 2669 | - Skills command shapes: FEAT-022 command shapes and retained-host |
| 2670 | validation (#5825, #5829). |
| 2671 | - After the card dissolves, the working screen shows `⑂ branch path` with |
| 2672 | `⋮ MCP n/m` on the right, the transcript starts with the |
| 2673 | `◆ session_start` receipt (naming the configured session-start hooks), |
| 2674 | and the composer's bottom rule carries `model (effort) · permission` — |
| 2675 | the route's one launch reading. The posture bar and metrics line appear |
| 2676 | only once a session exists. |
| 2677 | - Vocabulary: `fleet` is the public term and `Pod` is retired from copy — |
| 2678 | roster, setup, detail, worker-runtime and managed-API messages now say |
| 2679 | Fleet (`/fleet` canonical, `/pod` alias). The workflow wire accepts the |
| 2680 | canonical role spellings (general/explore/planner/reviewer/implement/ |
| 2681 | test/advisor) with the pre-rename ones kept as load-time aliases, and |
| 2682 | serializes canonical names. |
| 2683 | - The Operate mode-picker hint is shortened to fit 80 columns. |
| 2684 | |
| 2685 | - The footer always shows the permission posture; when only one chip |
| 2686 | fits, the permission chip outranks the mode word (#5796). |
| 2687 | - Local Ollama: the header names a model only when the local catalog can |
| 2688 | serve it, and says `unknown` until it knows. The startup mark, web and |
| 2689 | app icon carry the new side-view prompt-eye whale (#5795). |
| 2690 | - One focus owner: Tab and Shift+Tab work regardless of what is in the |
| 2691 | composer; Alt shortcuts survive mid-draft; Ctrl+Tab no longer cycles the |
| 2692 | mode by accident (#5798). |
| 2693 | - Tool cells carry their own state: a running, failed or warned tool |
| 2694 | reads as such in the transcript itself, with per-entry rail dots and |
| 2695 | family-coloured glyphs (#5799). |
| 2696 | - Web: docs hub with task search, shared empty/loading/error states, an |
| 2697 | offline-to-back-online banner, `/changelog` in every locale, and real |
| 2698 | 404s with correct metadata (#5743). |
| 2699 | - Web: the app's colours come from one file generated from the TUI whale |
| 2700 | palette; re-typing a colour by hand fails web CI (#5797). |
| 2701 | - Web: a one-way ceiling on `isZh` branching outside the i18n spine — |
| 2702 | the count may only go down (#5805). |
| 2703 | - An internal agent handoff doc was removed from the public tree and |
| 2704 | `.playwright-mcp/` is now ignored (#5800). |
| 2705 | - First run paints the composer immediately: the Welcome/language/provider/ |
| 2706 | trust gates no longer precede the first keystroke. Missing-key and |
| 2707 | workspace-trust recovery stay for returning users; language and provider |
| 2708 | remain in `/setup`. |
| 2709 | - The canonical whale-tile mark propagates beyond web to the exact-raster |
| 2710 | surfaces that can carry it (#5738). |
| 2711 | - Dead-code sweep: delete proven-unreferenced helpers (unused builders, |
| 2712 | wrappers, and leftover identifiers) and drop stale `#[allow(dead_code)]` |
| 2713 | where the item is production-called or test-exercised. No runtime behavior |
| 2714 | change (#5791, #5587). |
| 2715 | - Remote-control recovery gives every fresh pre-dispatch attempt a new lease |
| 2716 | generation while preserving that generation across its typed start (#5605). |
| 2717 | |
| 2718 | - Public roster language is Pod. `/pod` is the customer surface; fleet remains |
| 2719 | the internal wire, storage, and migration name (#5776). |
| 2720 | |
| 2721 | - Compaction replacement history keeps a bounded last user round (assistant + |
| 2722 | tool results) instead of dropping them behind a summary. `/context` names |
| 2723 | the compaction path and `/anchor` survival. Failed compact still does not |
| 2724 | replace live history (#4394). |
| 2725 | - Provider catalogs: compatible hosts (Baseten, Groq, Cerebras, SenseNova, |
| 2726 | Command Code) no longer compile a frozen model roster. Descriptors name the |
| 2727 | wire, URL, and env; live `GET /v1/models` and a Codewhale-owned catalog |
| 2728 | layer are the offering list. Command Code is a catalog/descriptor row, not |
| 2729 | a `ProviderKind`. Catalog presence is not an availability, entitlement, or |
| 2730 | provider-acceptance claim (#5783). |
| 2731 | |
| 2732 | - Provider selection no longer probes or adopts an external CLI credential on |
| 2733 | ordinary picker use. Reuse requires an explicit "Use external CLI credentials" |
| 2734 | choice, exact-path confirmation, and Codewhale-owned revoke (#5772). |
| 2735 | |
| 2736 | - TUI: startup no longer presents an approximate ASCII or block-glyph whale as |
| 2737 | the product mark. It keeps the direct Tideline prompt while exact-raster |
| 2738 | surfaces remain responsible for the canonical asset. |
| 2739 | |
| 2740 | - TUI: the active-session composer paints the same three-cell `[↑]` send |
| 2741 | target as Startup and clicks it through the existing Enter submit |
| 2742 | dispatcher (#5771). Compact/quiet composers still omit the control. |
| 2743 | |
| 2744 | - TUI/CLI: Pod is the public roster surface. User-facing Fleet wording |
| 2745 | moves to Pod; durable receipt keys stay compatible (#5776). |
| 2746 | |
| 2747 | ### Contributors |
| 2748 | |
| 2749 | - **hexin ([@h3c-hexin](https://github.com/h3c-hexin))** — provider-native web |
| 2750 | search across four routes (#5682, #5683, #5685, #5687), authoritative |
| 2751 | edit-last-turn boundaries (#5621), Kimi Code k3-256k (#5622), |
| 2752 | post-compaction input-token reporting (#5623), and preserving the scheduled |
| 2753 | model selection in automations (#5650). |
| 2754 | - **秋月凉梦 ([@qiuYliangM](https://github.com/qiuYliangM))** — co-authored the |
| 2755 | edit-last-turn boundary fix (#5621), Kimi Code k3-256k support (#5622), and |
| 2756 | post-compaction input-token reporting (#5623). |
| 2757 | - **Isabel Wu ([@wuisabel-gif](https://github.com/wuisabel-gif))** — live |
| 2758 | session token totals (#5624), persisted context-pressure warnings (#5629), |
| 2759 | discoverable Fleet roster editing (#5604), the capability-gated cursor |
| 2760 | accent (#5599), and `/copy` for the latest completed response (#5692). |
| 2761 | - **Paulo Aboim Pinto ([@aboimpinto](https://github.com/aboimpinto))** — |
| 2762 | Windows verbatim-path operands preserved through POSIX word splitting |
| 2763 | (#5610), the plugins group moved onto the command shapes (#5657), FEAT-022 |
| 2764 | skills command shapes with retained-host validation (#5825), and FEAT-020 |
| 2765 | plugin command shapes re-landed on main (#5865). |
| 2766 | - **Alex Musichen ([@musichen](https://github.com/musichen))** — a stable |
| 2767 | DeepSeek heading in the configured-view model picker, keeping every official |
| 2768 | catalog model for the active provider visible (#5689). |
| 2769 | - **[@gaord](https://github.com/gaord)** — the `GET /v1/fleet/profiles` |
| 2770 | runtime API endpoint, reusing the FleetManager validation path (#5688). |
| 2771 | - **Sh1Zuku ([@SparkofSpike](https://github.com/SparkofSpike))** — corrected |
| 2772 | English documentation inaccuracies and the first zh_hans translations for |
| 2773 | the Tier-2 docs (#5613). |
| 2774 | - **[@M-Maciej](https://github.com/M-Maciej)** — goal continuation cadence |
| 2775 | (#5591) and the per-session control socket (#5533, #5831). |
| 2776 | - **Serephus ([@serephus](https://github.com/serephus))** — nixpkgs update |
| 2777 | (#5669). |
| 2778 | - **[@whp233](https://github.com/whp233)** — `wire = responses|anthropic` for |
| 2779 | openai-compatible custom routes and opencode-zen muse-spark (#5716, landed |
| 2780 | as #5719). |
| 2781 | - **Gabriel Degret ([@Gabriel-Degret](https://github.com/Gabriel-Degret))** — |
| 2782 | found the reasoning-only retry gap and built the first fix; landed as the |
| 2783 | `[reasoning_only]` retry ceiling with a request-scoped nudge (#5867). |
| 2784 | - **[@huangxianzhan](https://github.com/huangxianzhan)** — the |
| 2785 | `x-opencode-session` header for OpenCode Go and Zen gateways (#5868). |
| 2786 | - **[@zhuowp](https://github.com/zhuowp)** — task origin preserved in job |
| 2787 | snapshots (#5869). |
| 2788 | - **AdityaG ([@AdityaVG13](https://github.com/AdityaVG13))** — a ten-commit |
| 2789 | performance pass: a zero-copy LaTeX fast path for streaming render, |
| 2790 | single-pass token accounting on the per-turn pressure paths, memoized |
| 2791 | provider resolution in the catalog cutline, parsing the bundled and |
| 2792 | on-disk models.dev catalogs once per process (interactive boot -70%), |
| 2793 | adaptive poll cadence for foreground shell completion, and worker caps |
| 2794 | across the read-only diagnostic family. |
| 2795 | - **Nightt ([@nightt5879](https://github.com/nightt5879))** — isolated remote |
| 2796 | recovery lease generations (#5790). |
| 2797 | - **[@yiheng-kkk](https://github.com/yiheng-kkk)** — replaced stale todo |
| 2798 | transcript snapshots so a rewritten todo list renders its current tasks |
| 2799 | (#5871, #5873). |
| 2800 | - **[@Lfanxing](https://github.com/Lfanxing)** — Moonshot routes now degrade |
| 2801 | incompatible tool definitions per request instead of failing the turn. |
| 2802 | - **WissssleyL ([@Lstarsky0](https://github.com/Lstarsky0))** — moved |
| 2803 | `docs/subagents` and `docs/mcp` onto the dictionary spine (#5337), with the |
| 2804 | metaTitle probe that keeps them there. |
| 2805 | |
| 2806 | Reports and reproductions that shaped this release: |
| 2807 | |
| 2808 | - **[@slowly247](https://github.com/slowly247)** — reported the Ollama input |
| 2809 | budget collapsing to 1,024 tokens on 32K local models (#5820). |
| 2810 | - **[@ronohara](https://github.com/ronohara)** — reported the engine stopping |
| 2811 | after recoverable network errors, with the reproduction that pinned the |
| 2812 | discarded approval (#5769), and surfaced DeepSeek's model-service notices and the subsequent reversal |
| 2813 | retaining V4 Pro (#6025). |
| 2814 | - **[@Lujc0523](https://github.com/Lujc0523)** — asked for ACP session |
| 2815 | configuration of mode and model (#5863). |
| 2816 | - **[@senka9h](https://github.com/senka9h)** — reported that `serve --acp` |
| 2817 | lacked `session/list` and `session/load` (#5864). |
| 2818 | |
| 2819 | ### Added |
| 2820 | |
| 2821 | - Native ChatGPT sign-in for the `openai-codex` route: `codewhale auth |
| 2822 | chatgpt` opens a browser PKCE flow and stores refreshable tokens in |
| 2823 | Codewhale-owned credentials — no Codex CLI install required. |
| 2824 | `/auth chatgpt-revoke` clears them off the event loop (#5784, #5778). |
| 2825 | - MCP servers and plugins can be connected self-serve from the session: a |
| 2826 | unified auth flow with rotation-safe token handling, a spoken authorization |
| 2827 | URL, and catalog refresh when stored credentials stop working (#5747). |
| 2828 | - `/operate` reads match the landed CWC `OperateRecord` contract: fetching an |
| 2829 | absent record returns a truthful not-found view instead of a fabricated |
| 2830 | operation, and an empty evidence path is rejected rather than resolving to |
| 2831 | the workspace directory (#5703). |
| 2832 | - TUI: scheduled automations project into the top strip |
| 2833 | (`⏱ N scheduled · M running`, compact `⏱ N·M`) with typed |
| 2834 | `HistoryCell::Automation` receipts when a run this session watched settle. |
| 2835 | `/automation` acknowledges failures. The merged footer does not carry the |
| 2836 | work fact (#5748). |
| 2837 | - The app-server can listen on a unix domain socket and advertise a |
| 2838 | `daemon/attach` handshake, so a local client can attach to an already-running |
| 2839 | engine instead of spawning its own. The socket is created with |
| 2840 | owner-only permissions and stale sockets are reclaimed on start. Non-unix |
| 2841 | hosts return a typed unsupported-platform refusal; the Windows named-pipe |
| 2842 | endpoint is named but not yet implemented (#5749). |
| 2843 | - The engine's internal `Op`/`Event` types and the wire protocol's `Op`/ |
| 2844 | `EventMsg` now carry a compile-enforced twin for every variant: adding an |
| 2845 | engine variant without a protocol counterpart fails the build instead of |
| 2846 | drifting silently. Internal durability work — no user-visible surface |
| 2847 | change yet (#5751). |
| 2848 | - Machine tokens: with `CODEWHALE_API_KEY` set, the CLI authenticates as the |
| 2849 | Codewhale account with no local session file and no browser — the CI |
| 2850 | authentication path, with a typed token shape and redaction (#5721). |
| 2851 | - Compaction publishes a structured survival contract for session-tree |
| 2852 | journal entry types (`crates/tui/src/compaction/SURVIVAL_CONTRACT.md`) and |
| 2853 | fails closed when the last user round, tool results, `/anchor` text, or |
| 2854 | checkpoint receipt would vanish (#4394, #5782). |
| 2855 | - Internal: `codewhale-config` gains `RouteAuthoritySnapshot`, one immutable |
| 2856 | authority that owns a compiled provider catalog together with the route |
| 2857 | resolver projected from it, so a picker, a readiness view, and an execution |
| 2858 | path can no longer resolve against different catalog snapshots without a |
| 2859 | type-level signal. Resolution still goes through the sole resolver; the |
| 2860 | returned receipt distinguishes an exact catalog row, a custom-endpoint route |
| 2861 | whose provider facts are deliberately not reused, and an allowed |
| 2862 | pass-through route with no catalog row. All state is secret-free. No call |
| 2863 | site changed and no user-visible behaviour changed yet (#5766). |
| 2864 | |
| 2865 | - Computer session records now count only time a provider actually accepted the |
| 2866 | session as active, at per-second granularity. Idle, queued, stopped, and |
| 2867 | teardown time are excluded, and a session whose allocation does not match a |
| 2868 | standard profile is refused rather than recorded approximately. Covered by |
| 2869 | hermetic fixtures; no live provider call and no deploy (#5781). |
| 2870 | |
| 2871 | - Website: the public site moves to the Tideline deep-ocean design language |
| 2872 | (dark by default with an opt-in light documentation sheet, palette grounded |
| 2873 | in the TUI's WHALE_* tokens) and the new whale brand mark across the favicon, |
| 2874 | app icons, web manifest, nav wordmark, and social card (#5573). |
| 2875 | |
| 2876 | - Add `codewhale dispatch` / `/dispatch` so a local session can propose a |
| 2877 | Codewhale cloud agent against an explicit `github`, `cnb`, or `gitee` remote. |
| 2878 | Confirmation is required; missing credentials fail closed; cloud jobs share |
| 2879 | the existing `/jobs` surface as `kind=cloud`. See |
| 2880 | [DAYTONA_CLOUD_DISPATCH.md](docs/DAYTONA_CLOUD_DISPATCH.md). |
| 2881 | - `/login` reports the Codewhale account session and provider-key next |
| 2882 | steps. The internal cloud-agent credential is not user surface: there is |
| 2883 | no `auth set-slot`/`auth clear-slot` command, no hint, and no completion |
| 2884 | entry for it — signing in with `codewhale login` is the only door. |
| 2885 | - Add the Tideline component family from the ratatui translation spec |
| 2886 | (#5698's screens, riding the #5699 work-strip layout): hero startup |
| 2887 | surface with quick actions and option strip, notifications inbox, merged |
| 2888 | footer band, pod ledger, receipt |
| 2889 | stream, theme list with motion toggles, live preview, settings rail, |
| 2890 | and the left rail — each a standalone render module pinned by 28 new |
| 2891 | byte-exact golden buffers. Frame wiring follows the Tideline acceptance |
| 2892 | gate; `NO_COLOR` is now honored by palette depth detection. |
| 2893 | - Route Contract Phase 1: `RouteResolver` is the runtime path for |
| 2894 | `resolve_runtime_options`; `codewhale providers export --json` ships the |
| 2895 | owned descriptor catalog; CLI `--provider` accepts any catalog route id |
| 2896 | (the closed `ProviderArg` enum is deleted). Catalog layers are |
| 2897 | bundled → models.dev → provider `/v1/models` → config.toml → user, with |
| 2898 | policy DENY last and never overridden. |
| 2899 | - Add provider-native web search for documented Xiaomi MiMo 2.5 Pro and 2.5 |
| 2900 | chat routes while keeping neighboring models and custom gateways fail-closed. |
| 2901 | - Add structured provider-native web search for exact Z.AI global and Zhipu |
| 2902 | China general API routes, using each site's documented search engine value. |
| 2903 | Existing `open.bigmodel.cn` configurations now share Z.AI's official model |
| 2904 | namespace and credential scope; unknown model IDs still pass through. |
| 2905 | - Add provider-native web search for documented Qwen models on ModelStudio |
| 2906 | Token Plan's Responses Harness, without enabling Coding Plan or Anthropic |
| 2907 | routes. |
| 2908 | - Added `/copy` to place the latest completed assistant response on the |
| 2909 | clipboard without copying tools, system messages, hidden reasoning, or |
| 2910 | active partial output (#5668). |
| 2911 | - Add provider-native web search for documented DeepSeek V4 routes through the |
| 2912 | Responses API, with fail-closed capability gating for compatible custom |
| 2913 | endpoints. |
| 2914 | - Add provider-native search for exact Moonshot K3 Formula, legacy K2.6 |
| 2915 | built-in search, and Kimi Code membership `/search` routes. Treat the exact |
| 2916 | Moonshot China endpoint as a first-party direct route. |
| 2917 | - Z.ai `GLM-5.3-Flash` and OpenRouter `z-ai/glm-5.3-flash` are first-class |
| 2918 | picker rows (`/model GLM-5.3-Flash`). Flash is the faster/explore sibling |
| 2919 | of `GLM-5.3`; the Z.ai default stays `GLM-5.3`. List price is $0.15/$0.50 |
| 2920 | per 1M (durable; the 50% promo through 2026-09-09 is not the catalog row). |
| 2921 | - Baseten, Groq, and Cerebras are bundled OpenAI-compatible setup templates |
| 2922 | (`[providers.<id>] kind = "openai-compatible"`), not new `ProviderKind` |
| 2923 | variants. `/provider` fills URL, model, and env from one catalog row. |
| 2924 | - MCP manager copy now names the server, the failure, and one recovery |
| 2925 | command (`The X MCP server requires OAuth reauthentication. Run /mcp login X`). |
| 2926 | - Settings Advanced exposes clickable MCP Connect, Reconnect, and Diagnose |
| 2927 | actions, while Extensions and Problems route recovery through the existing |
| 2928 | `/mcp login`, `/mcp reload`, `/mcp validate`, and `/plugin validate` commands |
| 2929 | (#5643, #5655). |
| 2930 | - Plugin prompt matching (#5579): sending a task can toast the next review |
| 2931 | step when the prompt strongly matches an installed-but-idle plugin or a |
| 2932 | marketplace catalog you added (for example a Supabase prompt suggesting |
| 2933 | `/plugin trust supabase`). A live composer CTA offers the same review |
| 2934 | command while you type, matching turns append a bounded |
| 2935 | `<recommended_plugins>` user block, and `request_plugin_install` surfaces |
| 2936 | review without installing. `/plugin suggest` now ranks manifest keywords and |
| 2937 | catalog candidates, never auto-installs, and on-disk plugin changes also |
| 2938 | nudge `/plugin reload` between turns. |
| 2939 | |
| 2940 | |
| 2941 | - Added `/import-claude` (#5557): reads `~/.claude.json` and |
| 2942 | `~/.claude/settings.json` read-only and renders an explicit, reviewable |
| 2943 | migration plan plus a written report. MCP servers route through the |
| 2944 | existing `/mcp import <name> --approve` consent flow, allowlisted env keys |
| 2945 | become an unapplied portable bundle for `codewhale config import`, and |
| 2946 | permissions/hooks map to manual follow-ups; secret-shaped values are named |
| 2947 | but never echoed or imported. |
| 2948 | - Added the managed Chat relay: account-owned Chat commands now execute on the |
| 2949 | native runtime thread engine through a new `runtime_chat_relay` module |
| 2950 | instead of a second execution path. Each Chat thread is a dedicated, |
| 2951 | isolated runtime thread with an empty model-visible tool allowlist, a |
| 2952 | chat-only system prompt, and no workspace, memory, skill, credential, or |
| 2953 | local-path context; the active interactive TUI thread is never reused. The |
| 2954 | relay keeps one durable state file per scope behind a session-wide owner |
| 2955 | lock, binds a saved session permanently to its first remote target, replays |
| 2956 | exact duplicate commands from retained results instead of starting a second |
| 2957 | inference turn, terminalizes orphaned reservations on restart, and rejects |
| 2958 | (never queues into) a busy local Work turn with an immediate retryable |
| 2959 | result. Stop commands require the exact run and turn identity, and a worker |
| 2960 | aborts on any account or target mismatch during token refresh. |
| 2961 | |
| 2962 | - Added a verified Omarchy/AUR packaging path: `packaging/aur` now carries a |
| 2963 | `PKGBUILD` template, `.SRCINFO` renderer and tests, release-candidate |
| 2964 | render step, and docs; the live AUR compatibility alias `codewhale-tui -> |
| 2965 | codewhale` is preserved, AUR dependencies match the live package, and the |
| 2966 | self-updater refuses to fight an Omarchy/package-manager installation. |
| 2967 | - Added a Fleet run-wide cost/token usage ceiling (R6, #5567): an accumulator |
| 2968 | plus admission gate and alert bound a whole run's spend across workers. |
| 2969 | - Added the real provider cache hit rate to `/context` (C3, DSH #3): the |
| 2970 | token-weighted provider-reported rate from the same telemetry `/cache` |
| 2971 | aggregates, plus an honest "no cache telemetry yet" state when nothing is |
| 2972 | recorded. |
| 2973 | - Added per-step cost movement: `TurnUsage` receipts are priced as they land |
| 2974 | so the live cost surface moves during long agentic turns instead of only at |
| 2975 | `TurnComplete` (#5578), and the footer now honestly shows `cost: unknown` |
| 2976 | when nothing can be priced instead of hiding the line. |
| 2977 | - Added the underwater session surface: the ambient water reads session state |
| 2978 | from across the room, its animation shape follows live agent activity, and |
| 2979 | attention tints are steady (no breathing) with a distinct reading treatment |
| 2980 | and no mid-water seam on tall windows. |
| 2981 | - Added `@path:START-END` ranged line mentions (#5550, picker half to follow), |
| 2982 | a predictable last-copy backup file for clipboard exports with the path |
| 2983 | named when the clipboard fails (#5555), `wait` on multiple background shell |
| 2984 | tasks with `until=any|all` (#5549, named-kill half to follow), and composer |
| 2985 | double-click word / triple-click line selection. |
| 2986 | - Added workflow parallel-`schema` slot partial success (#5583): a slot that |
| 2987 | produces a schema-valid partial result no longer fails the whole parallel |
| 2988 | branch. |
| 2989 | - Added plugin load-failure startup hints (#5579) and OpenRouter app |
| 2990 | attribution headers on outbound requests. |
| 2991 | - Added `codewhale doctor --fix` (with `--yes` for non-interactive consent): |
| 2992 | the doctor now computes a concrete repair plan — delete stale `.tmp*` |
| 2993 | leftovers from interrupted atomic writes, tighten secret-store file |
| 2994 | permissions to `0600`, disable structurally broken (Error-status) MCP |
| 2995 | entries through the atomic MCP save path, and scaffold missing user-global |
| 2996 | `skills`/`tools`/`plugins` directories — shows it, and applies it only after |
| 2997 | explicit consent. Every action is narrowly scoped and idempotent; JSON and |
| 2998 | context-JSON modes stay read-only and conflict with `--fix` (#5552, v1). |
| 2999 | - Added `/context` reporting of the real provider prompt-cache hit rate (C3) |
| 3000 | alongside token pressure. |
| 3001 | |
| 3002 | ### Changed |
| 3003 | |
| 3004 | - Provider-native web search now applies domain constraints before accepting an |
| 3005 | attempt, discards generated answers when returned citations violate those |
| 3006 | constraints, and preserves the caller's configured/local timeout as an |
| 3007 | independent fallback budget (#5681). |
| 3008 | - Idle session metrics omit zero facts (`0 turns`, `LLM 0s`) until the |
| 3009 | runtime has evidence. Working chrome says `in the current` instead of a |
| 3010 | generic `working`. |
| 3011 | - Deleted nine uncompiled `runtime_contract/` staging files. Live contracts |
| 3012 | remain `model.rs` and `termination.rs`. |
| 3013 | |
| 3014 | - The first #5587 dead-code sweep converts audited test-only helpers to |
| 3015 | `#[cfg(test)]`, keeping production builds free of test-only APIs without |
| 3016 | changing runtime behavior. |
| 3017 | - `/plugin reload` is now discoverable when on-disk plugin bundles change: the |
| 3018 | next send and `/plugin list` nudge once with `Run /plugin reload to apply` |
| 3019 | instead of silently keeping the stale catalog (#5579). Trust is unchanged; |
| 3020 | this does not auto-reload. |
| 3021 | - Context-pressure warnings and critical alerts now remain visible in sticky UI |
| 3022 | status until compaction or explicit dismissal, instead of disappearing into |
| 3023 | scrolling turn metadata (#5620). |
| 3024 | - The Runtime thread store defaults to a per-session root |
| 3025 | (`$CODEWHALE_HOME/sessions/<id>/runtime`) so multiple Codewhale processes on |
| 3026 | one machine no longer share one owner lock (#5630). The exclusive lock is |
| 3027 | unchanged; `CODEWHALE_RUNTIME_DIR` still selects a shared root when that is |
| 3028 | intended. |
| 3029 | - Session token totals now include display-only per-model-call deltas while a |
| 3030 | turn is running, including input/output and cache-class counters; the |
| 3031 | authoritative `TurnComplete` totals still reconcile exactly once (#5581). |
| 3032 | - Transcript focus now exposes per-block actions: `y` copies content, `Y` |
| 3033 | copies the rendered metadata view, Enter opens a fullscreen block pager, and |
| 3034 | `r` opens raw detail; the existing Tasks rail shortcuts remain unchanged |
| 3035 | (#5551). |
| 3036 | - Provider neutrality (#5588): model resolution of omitted/aliased models is |
| 3037 | now provider-relative, OpenAI-native defaults no longer route through |
| 3038 | another provider's table, CLI credentials stay provider-scoped, and NVIDIA |
| 3039 | credentials no longer leak into the DeepSeek keychain. Neutrality test |
| 3040 | matrices exercise several providers instead of standing in with one. |
| 3041 | - The workflow engine module was decomposed out of its 3k-line mega-file into |
| 3042 | `journal`, `usage`, and `report` modules plus a module directory (#5586 |
| 3043 | slices 1a/B/C/D), a semantic-free move verified by normalized-content hash. |
| 3044 | - Compaction refusals are now always named (#5577): silent holds under context |
| 3045 | pressure are gone, the context meter honors the same provider-billed prompt |
| 3046 | the trigger uses (T1), and prune outcomes are projected without cloning the |
| 3047 | transcript. |
| 3048 | - Step budgets now end honestly: an ~80% soft landing nudges the model to |
| 3049 | write its final report, and exhaustion grants exactly one bounded |
| 3050 | report-on-exhaustion turn instead of dying silently (A1/A2). |
| 3051 | - Contributor credit: recognized agent contributors (e.g. `Codewhale Agent`) |
| 3052 | may now carry `Co-authored-by` trailers; unknown bot/tool trailers are |
| 3053 | still rejected by the credit gate. |
| 3054 | |
| 3055 | ### Fixed |
| 3056 | |
| 3057 | - Read-only Fleet workers no longer send `"action": {"enum": null}` in their |
| 3058 | projected `bash` schema. The read-only projection probed the action enum |
| 3059 | with a mutating index, which auto-vivified the key on schemas that have no |
| 3060 | action property, and strict OpenAI-compatible validators then rejected the |
| 3061 | whole request (`null is not of type "array"`). The probe is non-mutating |
| 3062 | now, in both the read-only projection and the `Run` arm next to it, and a |
| 3063 | regression test walks the whole projected catalog for nulls |
| 3064 | (#5944, thanks @gaord). |
| 3065 | - Fast typing no longer corrupts the composer. The paste-burst heuristic ran |
| 3066 | on every session until a real bracketed paste arrived, holding, buffering, |
| 3067 | retro-grabbing, and absorbing Enter on timing guesses; it is now |
| 3068 | fallback-only (gated off when the terminal provides bracketed paste), the |
| 3069 | retro-grab is deleted, and Enter on held command text flushes and submits. |
| 3070 | - Ctrl+C works on the pre-session launch menu and speaks everywhere: the |
| 3071 | first press arms the two-second exit window with a visible localized |
| 3072 | "Press Ctrl+C again to quit" hint (previously silent), the second exits. |
| 3073 | The worktree name input keeps Ctrl+C as cancel-input. |
| 3074 | - Fresh interactive sessions no longer leave a phantom one-message duplicate |
| 3075 | behind. The TUI claimed one session id (Runtime store lock, turn-start crash |
| 3076 | checkpoint) while the engine minted a second one; the first `SessionUpdated` |
| 3077 | re-keyed the App, the completion commit cleared only the engine id's |
| 3078 | checkpoint, and `codewhale --continue` later "recovered" the orphaned |
| 3079 | checkpoint as a duplicate session instead of the real one. The engine now |
| 3080 | adopts the host-owned id at spawn (`EngineConfig::session_id`) and `/clear` |
| 3081 | mints the next id in the App like `/new`. A non-TTY `--continue` no longer |
| 3082 | promotes and consumes the crash checkpoint before failing the terminal |
| 3083 | check, and the root `codewhale --resume <id>` / `--session-id <id>` flags |
| 3084 | documented in the operations runbook now parse instead of being swallowed |
| 3085 | as a prompt. |
| 3086 | - Website: `/signin`, `/signup`, and `/auth/callback` are locale-aware public |
| 3087 | routes instead of localized 404s. Sign-in and create-account send the person |
| 3088 | to the CWC app; OAuth callbacks hop to `app.codewhale.net` with the query |
| 3089 | intact; `/login` and `/register` are aliases. Local CLI use is not presented |
| 3090 | as requiring an account (#5767). |
| 3091 | - The sandbox read deny-list matches a rule's resolved path as well as its |
| 3092 | literal spelling. On macOS `/etc` and `/var` are symlinks into `/private`, |
| 3093 | so a read of `/private/etc/sudoers` walked around the `/etc/sudoers` rule, |
| 3094 | and a rule written against a symlinked directory never fired for the real |
| 3095 | path that `canonicalize` and the process cwd hand back. |
| 3096 | - Background shells are first-class work-strip rows (`▾ Shells N`) you can |
| 3097 | open, watch, and cancel by the `shell_*` id on the row. `/jobs cancel all` |
| 3098 | cancels running shells; it no longer looks up a task named `all`. The |
| 3099 | composer hourglass crumb no longer stands in for a shell surface. |
| 3100 | - `codewhale logout` and `/logout` now clear the Codewhale account session |
| 3101 | and the Daytona secret slot, not only provider API keys. The TUI crate's |
| 3102 | leftover `login --api-key` path no longer claims to save a key. |
| 3103 | - Account sessions no longer read the macOS Keychain. Unsigned or rebuilt |
| 3104 | `codewhale` binaries were a new Keychain ACL principal every time, so |
| 3105 | `codewhale web` and the TUI popped a password dialog on start. Sessions |
| 3106 | now use `~/.codewhale/secrets/secrets.json` (mode 0600), the same store |
| 3107 | as provider keys. Extracted from the Keychain-retirement half of #5632. |
| 3108 | - Hardened the dispatcher-side config parse the same way: `ConfigStore` |
| 3109 | loads and project-config parsing now deserialize `ConfigToml` on a |
| 3110 | dedicated 16 MiB-stack thread (the guided-setup save path could overflow |
| 3111 | a 2 MiB worker stack the same way the TUI's `ConfigFile` parse did), and |
| 3112 | the #5585 setup-confirm toast test runs its runtime on an equally sized |
| 3113 | thread instead of overflowing the default libtest stack. |
| 3114 | - Fixed detached interactive agents reporting worker usage after the parent |
| 3115 | turn ends with the usage missing from the session/live `/cost` total |
| 3116 | (#5597): interactive turns acquire an owner-scoped runtime usage lease, |
| 3117 | late usage enters the session cost pool without reopening the sealed |
| 3118 | mailbox, and worker/session/reload accounting share one hashed response |
| 3119 | identity so retried deliveries stay exactly-once. |
| 3120 | - Fixed the sub-agent fiasco class: in-workspace absolute `git -C` no longer |
| 3121 | trips the read-only child shell gate with a coherent bounded gate (#5595), |
| 3122 | turn end parks turn-owned children resumably instead of silently cancelling |
| 3123 | them (#5596), stale write-claims are released by liveness with coordinate |
| 3124 | release (#5562), and the verifier role description matches its real |
| 3125 | surface (#5562). |
| 3126 | - Fixed workflow responseSchema failure handling (#5583): bounded repair with |
| 3127 | typed receipts (kind + attempt), raw-output receipts persisted as artifacts |
| 3128 | that survive reload, and failures surfaced instead of null success (#5528). |
| 3129 | Degraded owner snapshots no longer project as ordinary Completed runs |
| 3130 | (#5582), typed task error kinds enable fail-fast parallel/pipeline (R9), and |
| 3131 | `/workflow confirm` finds the draft despite interleaved messages. |
| 3132 | - Fixed the DeepSeek session that never auto-compacted at 842k/1M (#5577): the |
| 3133 | exact `billed_842k_on_a_1m_window_compacts_despite_a_small_estimate` |
| 3134 | regression pins the trigger. |
| 3135 | - Fixed sandbox escapes and authority gaps: workspace-write tools resolve |
| 3136 | hard-linked files before writing (S2, #5569), an opt-in read deny-list |
| 3137 | bounds full-disk reads in any posture (S1, #5568), and session grants match |
| 3138 | the command family instead of widening the whole tool (R2). |
| 3139 | - Fixed provider-transport robustness: non-streaming HTTP requests are bounded |
| 3140 | by a read timeout (R4), and Chat-Completions mid-stream error frames surface |
| 3141 | instead of hanging (R3). MCP OAuth expiry now reacts to 401/403 with a named |
| 3142 | recovery path and login hint instead of looking like a broken server (T4, |
| 3143 | #5572). |
| 3144 | - Fixed Fleet lifecycle gaps: detached workers are reaped when their manager |
| 3145 | dies (R7) and the per-task wall-clock timeout is enforced (R5); the local |
| 3146 | Fleet host compiles on non-Unix targets; detached schema repair stays within |
| 3147 | the runtime budget. |
| 3148 | - Fixed prompt-cache correctness: the tool catalog is fingerprinted in |
| 3149 | provider wire order (C1), prefix changes between requests are always |
| 3150 | declared (C5) — including the newly named mid-turn `change:tool_surface` |
| 3151 | reasons for deferred-tool admission, tool-search activation, and runtime MCP |
| 3152 | tool arrival — and a reasoning-only response stopped at the output limit now |
| 3153 | fails the turn honestly instead of re-issuing a request that can only |
| 3154 | reproduce the stop. |
| 3155 | - Fixed docs/public-surface drift: REBRAND.md no longer presents |
| 3156 | `api.deepseeki.com` as a China fallback (#5564), and the web facts/tool |
| 3157 | counts match the repository. |
| 3158 | |
| 3159 | - Heavy pull requests now run the real Linux workspace nextest, doctest, and |
| 3160 | lockfile lanes directly on GitHub Actions instead of reporting a green |
| 3161 | placeholder while waiting for a branch-specific CNB mirror (#5547). |
| 3162 | - Fleet roster members in a selected Fleet now expose a visible edit affordance |
| 3163 | and a direct `m` model-picker shortcut, while the coordinator row remains |
| 3164 | read-only (#5604, covers #5589). |
| 3165 | - The context inspector now attributes bounded tool-schema cost to the built-in |
| 3166 | catalog and each discovered MCP server without changing prompt assembly or |
| 3167 | cache behavior (#5553). |
| 3168 | - The goal-continuation quiet period (`[goal] continuation_delay_seconds`, |
| 3169 | added in #5508) now applies on every dispatch path. Previously the |
| 3170 | within-turn dispatch hook fired the next continuation prompt immediately |
| 3171 | whenever a model step ended with the goal still active, so CLI-resumed and |
| 3172 | host-managed sessions never observed the configured delay (measured |
| 3173 | end-to-start gaps of ~9 s with a 300 s delay configured). The wait now |
| 3174 | runs unconditionally inside `goal_continuation_message_if_needed`, |
| 3175 | remains cancellable, and pause/clear/terminal `update_goal` calls still |
| 3176 | cancel a pending pass (#5534). |
| 3177 | - Two unit tests no longer depend on process-global environment state that |
| 3178 | sibling tests mutate concurrently. |
| 3179 | `route_budget::tests::v4_trigger_uses_window_percent_when_it_fits_spendable_input` |
| 3180 | asserted no-override output-budget values while reading |
| 3181 | `CODEWHALE_MAX_OUTPUT_TOKENS` / `DEEPSEEK_MAX_OUTPUT_TOKENS` without |
| 3182 | holding `lock_test_env()`, so a concurrent writer could flip the value |
| 3183 | mid-assertion (the order-dependent full-suite flake). |
| 3184 | `prompts::tests::system_prompt_prefix_never_leaks_private_content` read the |
| 3185 | real home via `HOME`/`USERPROFILE`, so a machine with |
| 3186 | `~/.codewhale/instructions.md` leaked its absolute path into the prompt and |
| 3187 | failed the no-private-paths assertion unless a sibling's temporary `HOME` |
| 3188 | guard happened to be live. Both tests now hold the env barrier and pin the |
| 3189 | variables (the route-budget test removes the overrides; the prompts test |
| 3190 | points `HOME`/`USERPROFILE` at a scratch dir). Assertions unchanged. |
| 3191 | |
| 3192 | - TUI sessions now apply a subtle OSC 12 cursor accent only on explicitly |
| 3193 | supported terminals and restore the terminal default through normal, panic, |
| 3194 | and signal cleanup paths (#5554). |
| 3195 | |
| 3196 | ## [0.9.11] - 2026-08-22 |
| 3197 | |
| 3198 | Codewhale v0.9.11 tightens the long-running agent loop, makes workflow |
| 3199 | failures visible instead of successful-looking, adds an experimental |
| 3200 | vision-capable DeepSeek route, and prepares reproducible Codewhale-versus-Pi |
| 3201 | evaluation without publishing a result before a real run. The complete |
| 3202 | item-level change record is retained below the categorized release highlights. |
| 3203 | |
| 3204 | ### Added |
| 3205 | |
| 3206 | - Added first-party `deepseek-v4-flash-vision-exp` discovery and selection for |
| 3207 | DeepSeek, including the `flash-vision` alias, bundled offline metadata, |
| 3208 | registry and picker entries, and image-input capability on the chat route. |
| 3209 | Context and output limits inherit from V4 Flash until DeepSeek publishes |
| 3210 | distinct values; pricing remains unknown rather than guessed. |
| 3211 | - Added a provider-controlled Codewhale-versus-Pi parity harness with three |
| 3212 | hermetic coding tasks, route and reasoning-effort receipts, doctor/dry-run |
| 3213 | modes, and bounded result artifacts. The repository ships the harness, not a |
| 3214 | benchmark verdict; comparable real runs remain an acceptance gate. |
| 3215 | - Added portable, secret-free config export/import with a reviewable plan, |
| 3216 | explicit headless consent, backup and rollback, and idempotent re-import. |
| 3217 | - Added bounded multi-file diagnostics through the existing model-facing `lsp` |
| 3218 | tool without increasing the tool-catalog count. Thanks to **Isabel Wu |
| 3219 | ([@wuisabel-gif](https://github.com/wuisabel-gif))** for PR #5524. |
| 3220 | - Added portable presentation, media-attachment, and operation-digest facets to |
| 3221 | the command contract, then moved all seven utility handlers onto the |
| 3222 | contract-backed dispatch path. Thanks to **Paulo Aboim Pinto |
| 3223 | ([@aboimpinto](https://github.com/aboimpinto))** for PR #5525. |
| 3224 | |
| 3225 | ### Changed |
| 3226 | |
| 3227 | - Sub-agent, Fleet-worker, workflow-task, and thread-runtime model turns no |
| 3228 | longer inherit a hidden role-based step ceiling. An omitted or zero |
| 3229 | `max_steps` is unbounded; a positive user/config value remains an explicit |
| 3230 | cap and is still clamped to the runtime safety ceiling. Wall-clock, provider, |
| 3231 | heartbeat, cancellation, and admission safeguards are unchanged. |
| 3232 | - `/rc` now mirrors one shared session rather than transferring terminal |
| 3233 | ownership: local and web prompts remain available while idle, approvals use |
| 3234 | first-decision-wins semantics, and transport/integrity failures remain |
| 3235 | fail-closed. |
| 3236 | - The terminal status rows around the composer are now two stable bands: |
| 3237 | `provider · model · thinking level` is the persistent identity row below |
| 3238 | the composer in every phase, and a separate activity row above the |
| 3239 | composer carries the live phase, notices, and cost/metrics. Sending a |
| 3240 | prompt no longer relocates the route identity above the composer, and |
| 3241 | neither row ever duplicates it. |
| 3242 | - The embedded local Web client now uses the current CWC Ocean hierarchy and |
| 3243 | readable control sizing, follows the shared Enter/Shift+Enter composer |
| 3244 | grammar, and chooses a provider plus model per new thread without mutating |
| 3245 | Runtime defaults. Exact image-input capability is labelled honestly; a |
| 3246 | vision-capable route does not imply that browser attachments exist. |
| 3247 | - The runtime now has one authoritative model-turn loop. The placeholder |
| 3248 | `crates/core` engine tree is gone, while the active TUI loop and its extracted |
| 3249 | tool-call stages retain existing policy, hook, cancellation, and budget |
| 3250 | behavior. Thanks to **Sun Zhenyuan |
| 3251 | ([@bistack](https://github.com/bistack))** for PR #5523. |
| 3252 | |
| 3253 | ### Fixed |
| 3254 | |
| 3255 | - Chat Completions streams now require terminal proof from `[DONE]` or a |
| 3256 | non-empty `finish_reason`. Protocol-only frames no longer count as answer |
| 3257 | content or time-to-first-token, and a provider continuation that ends after |
| 3258 | tool results with no answer or tool call fails durably instead of producing |
| 3259 | a false `Completed` receipt. |
| 3260 | - A selected v2 Fleet now drives one bounded, deterministic Agent roster across |
| 3261 | terminal and runtime surfaces. Fleet operator/member/explicit-route |
| 3262 | precedence, resolved member identity, and exact `vision` requirement |
| 3263 | admission now fail visibly instead of silently falling back, first-matching, |
| 3264 | or rerouting. |
| 3265 | - A workflow whose `task()` dispatch was rejected no longer loses that failure |
| 3266 | inside a `parallel()` null slot or presents a successful-looking run. Rejected |
| 3267 | dispatches now fail the run, persist as typed bounded receipts with an exact |
| 3268 | count, and appear in transcript, activity detail, and workflow-panel views. |
| 3269 | - Provider readiness, credential-source explanations, focused-agent scrolling, |
| 3270 | compact `/status` and `/help` rendering, shell/web output bounds, MCP |
| 3271 | lifecycle reporting, and narrow-terminal onboarding received the detailed |
| 3272 | fixes recorded below. |
| 3273 | - Portable config import/export now preserves typed tables, arrays, numbers, |
| 3274 | booleans, and datetimes without stringifying them, while refusing |
| 3275 | machine-bound trust overlays, credential readers, automatically executable |
| 3276 | hooks/LSP definitions, local-path authority, machine-local network proxy |
| 3277 | routes, cookies, redaction placeholders, and nested or camel/dotted |
| 3278 | credential keys. Project and global bundle operations now load and validate |
| 3279 | the document for their actual scope in both directions, including a |
| 3280 | workspace whose document still lives under the legacy app directory. |
| 3281 | - `codewhale login` now means Codewhale account sign-in (the same browser |
| 3282 | device flow as `codewhale account login`, with `--no-open` and |
| 3283 | `--timeout-seconds`); provider API keys are configured exclusively through |
| 3284 | `codewhale auth set --provider <provider>`, and the hidden legacy |
| 3285 | `--api-key`/`--provider` flags redirect loudly instead of silently writing |
| 3286 | a key. |
| 3287 | - Account sessions prefer the OS credential manager and now fall back |
| 3288 | automatically to the private `0600` Codewhale secrets file on headless |
| 3289 | hosts, SSH boxes, and containers; the `CODEWHALE_CLOUD_ALLOW_FILE_SESSION_STORE` |
| 3290 | opt-in is deprecated and ignored. |
| 3291 | - `/update` gained a `Ctrl+Shift+U` install chord (catalogued in |
| 3292 | `docs/KEYBINDINGS.md`, localized in all 15 packs) and a startup hint that |
| 3293 | names the previous and current version on the first launch of a newer |
| 3294 | build, pointing at `/change`. |
| 3295 | - Fleet product-model copy pass: the TUI, docs, and locale packs now use |
| 3296 | Fleet / Member / Role / Model / Access / Saved consistently so a user can |
| 3297 | say "scout", "DeepSeek V4 Flash", or the member name and mean the same |
| 3298 | thing. |
| 3299 | - A reasoning model that returns only hidden reasoning and a clean stop (no |
| 3300 | answer, no tool call) is now re-requested automatically up to twice before |
| 3301 | the turn fails, instead of dead-ending with "the provider response was |
| 3302 | incomplete." The retry reuses the cached prefix so it is cheap; an |
| 3303 | output-length stop (`length`/`max_tokens`) is never retried, and a |
| 3304 | persistently answerless model still fails honestly after the bound. |
| 3305 | - Model-bound tool results now use a credential-shaped redaction policy: |
| 3306 | only values that look like secrets (known prefixes, JWTs, bearer tokens, |
| 3307 | PEM private-key blocks, long opaque strings) are masked before a `read` or |
| 3308 | shell result reaches the model, so code such as `password: |
| 3309 | credentials?.password` or `"password-validator": "^5.3.0"` stays byte-exact |
| 3310 | for edits and read-back. Exact configured credential values are still always |
| 3311 | replaced, and logs/previews/exports keep the broad key-based scrubber. (#5546, |
| 3312 | reported by @ronohara) |
| 3313 | - Terminal input shutdown no longer waits forever on a wedged TTY read, |
| 3314 | Windows launch receipts can atomically replace an existing record, and the |
| 3315 | complete `/status` report now follows the active locale without rewriting |
| 3316 | exact custom-provider identities that contain brace-like text. |
| 3317 | - Localized READMEs again match the English install and third-party-notice |
| 3318 | surface, including shell-completion guidance in all 18 translations. |
| 3319 | |
| 3320 | ### Security |
| 3321 | |
| 3322 | - Unified OAuth device-code polling now validates verification URLs before |
| 3323 | opening them, redacts token-bearing types, honors server slowdown intervals, |
| 3324 | and keeps credential save/logout mutations serialized. |
| 3325 | - Project instructions, rules-directory traversal, secret-shaped config data, |
| 3326 | URL fingerprints, and shell network authority now retain the explicit bounds |
| 3327 | and fail-closed behavior described in the detailed record. |
| 3328 | |
| 3329 | ### Contributors |
| 3330 | |
| 3331 | - **Sun Zhenyuan ([@bistack](https://github.com/bistack))** — tool-call stage |
| 3332 | extraction with the existing execution and policy contracts preserved |
| 3333 | (#5523). |
| 3334 | - **Isabel Wu ([@wuisabel-gif](https://github.com/wuisabel-gif))** — bounded |
| 3335 | multi-file `read_lints` support (#5524), plus independently reviewed |
| 3336 | completion-routing overlap in #5530. |
| 3337 | - **Lstarsky0 ([@Lstarsky0](https://github.com/Lstarsky0))** — maintainer review |
| 3338 | hardening for truthful per-file states and truncation metadata in #5524. |
| 3339 | - **Paulo Aboim Pinto ([@aboimpinto](https://github.com/aboimpinto))** — portable |
| 3340 | presentation/media/digest facets and the seven utility-handler migrations |
| 3341 | (#5525). |
| 3342 | - **RepentStar ([@RepentStar](https://github.com/RepentStar))** — reported and |
| 3343 | reproduced the stale completion-generator path and missing `codew` |
| 3344 | registration fixed for #5526. |
| 3345 | |
| 3346 | ### Detailed change record |
| 3347 | |
| 3348 | The notes below are preserved in full so the categorized highlights do not |
| 3349 | erase behavior, migration, security, compatibility, or verification details. |
| 3350 | |
| 3351 | - Provider completion is now evidence-based. A Chat Completions stream reaches |
| 3352 | `MessageStop` only after `[DONE]` or a non-empty `finish_reason`; raw EOF |
| 3353 | without either is a typed failure. Message-start, ping, usage/terminal |
| 3354 | deltas, block-stop, and message-stop frames do not count as productive |
| 3355 | content or mint time-to-first-token. After tool results, a terminal provider |
| 3356 | step with no answer or tool call now emits a durable failed turn and never |
| 3357 | fabricates an empty assistant message. |
| 3358 | |
| 3359 | - A selected v2 Fleet is the single effective Agent roster across terminal, |
| 3360 | Runtime threads, direct Workflow, Fleet execution, doctor, and |
| 3361 | setup/readiness; legacy profile layers are consulted only when no Fleet is |
| 3362 | selected, and invalid selections fail visibly with bounded, redacted errors. |
| 3363 | Member references resolve exact id first and otherwise require a unique |
| 3364 | display name, role, pinned model, offline model name, or provider/model route; |
| 3365 | `agent action=roster` exposes that same bounded roster. The Fleet operator |
| 3366 | supplies fresh-root and inherited-member routing unless an explicit launch |
| 3367 | route or member pin wins, the resolved member is shown separately from the |
| 3368 | requested alias, and `requires = ["vision"]` is admitted only on an exact |
| 3369 | route with verified offline `image_input` support—never by silent rerouting |
| 3370 | or custom-proxy inference. Fleet selection remains an explicit user/folder |
| 3371 | contract independent of legacy project-profile loading. |
| 3372 | |
| 3373 | - **Breaking (app-server):** `/prompt`, `prompt/request` and `prompt/run` now |
| 3374 | execute a real model turn instead of reporting success for work they never |
| 3375 | did. `Runtime::handle_prompt` called no model: it resolved config, ran a |
| 3376 | local `ModelRegistry` lookup, emitted three canned hook events |
| 3377 | (`ResponseDelta` was literally the string `model-selected`), and returned |
| 3378 | HTTP 200 with `output` set to a stringified JSON echo of the caller's own |
| 3379 | routing metadata — the prompt included. Worse, when a `thread_id` was |
| 3380 | supplied it appended a real user row, flipped the thread to `Running`, and |
| 3381 | then wrote that echo into durable history as an **assistant message** plus a |
| 3382 | `prompt_response` checkpoint. Nothing marked the row synthetic and nothing |
| 3383 | ever moved the thread out of `Running`. All three endpoints now route |
| 3384 | through the same `RuntimeBridge` that stdio `thread/message` has always |
| 3385 | used, so `output` is the model's streamed text, `model` is what the runtime |
| 3386 | reports for the thread that ran the turn, and `events` are the real |
| 3387 | streaming frames. `Runtime::handle_prompt` and its synthetic history write |
| 3388 | are gone. |
| 3389 | |
| 3390 | - **Breaking (app-server):** a failed prompt is now a typed failure rather |
| 3391 | than a success-shaped body. `POST /prompt` returns |
| 3392 | `{"error":{"code":...,"message":...}}` with `400` (invalid request), `404` |
| 3393 | (thread not found), `503` (`runtime_unavailable`) or `500`, instead of HTTP |
| 3394 | 500 carrying a `PromptResponse` with the error text stuffed into `output` |
| 3395 | where model text belongs. The stdio surface gained JSON-RPC `-32005` |
| 3396 | `runtime_unavailable` for "the turn engine could not be reached, so nothing |
| 3397 | ran" — distinct from `-32603`, and retryable. There is no configuration in |
| 3398 | which a prompt silently echoes instead of running. |
| 3399 | |
| 3400 | - **Breaking (app-server):** `POST /thread` with a `Message` body runs the |
| 3401 | turn. It previously replied `status: "accepted"` with a |
| 3402 | `ResponseDelta("queued")` frame while starting no worker and calling no |
| 3403 | bridge — the stdio path for the same request has always done real work, so |
| 3404 | the two transports disagreed about what `accepted` meant. HTTP now replies |
| 3405 | `status: "completed"` once the turn reaches a terminal state, with the |
| 3406 | streamed frames in `events` and the turn id in `data`. `Runtime::handle_thread` |
| 3407 | no longer accepts `ThreadRequest::Message` at all: it owns thread |
| 3408 | bookkeeping, not the turn engine, and returns an error naming |
| 3409 | `POST /v1/threads/{id}/turns` rather than a canned acceptance. |
| 3410 | |
| 3411 | - **Breaking (app-server):** `AppRequest::SubmitUserInput` now refuses |
| 3412 | explicitly (`ok: false`, `error: "user_input_reply_unsupported"`) instead of |
| 3413 | returning `resolved: true` and filing the answers in a map that had no |
| 3414 | reader anywhere in the crate — every answer submitted was silently |
| 3415 | discarded. It cannot be made to work on this transport: while a turn |
| 3416 | streams, the stdio loop executes only `thread/interrupt` and queues |
| 3417 | everything else, so an answer sent there would wait on the very turn |
| 3418 | waiting for it. The refusal names the surface that does accept it, |
| 3419 | `POST /v1/user-input/{thread_id}/{request_id}` on the runtime API. The |
| 3420 | client-visible refusal is whitespace-clean, and the `/tool` path that mints |
| 3421 | the `UserInputRequest` is unchanged and still genuine. |
| 3422 | - Split the coordination ledger out of `tools/subagent/coord.rs` into |
| 3423 | `tools/subagent/coord/ledger.rs`. The file held two unrelated things: the |
| 3424 | model-facing `agents/*` tool wrappers, and the durable decision/claim/ |
| 3425 | contention records those wrappers happen to write — records whose consumers |
| 3426 | are mostly *not* in the tool layer (`tui::coordination_detail`, |
| 3427 | `tui::work_surface`, `tui::ui::tests`, `core::engine::tests` all name these |
| 3428 | types). At 3.8k lines, reading either one started by scrolling past the |
| 3429 | other. A pure move with a glob re-export from `coord`, so every |
| 3430 | `crate::tools::subagent::coord::{…}` path still resolves and no consumer file |
| 3431 | was edited; the only content change the move required is one constant going |
| 3432 | from private to `pub(super)` because its caller stayed behind. `coord.rs` is |
| 3433 | now 2.3k lines and `ledger.rs` 1.6k. |
| 3434 | |
| 3435 | - `agent` is now the only sub-agent tool the model can see. `AGENTS.md` has |
| 3436 | said "the model-facing sub-agent surface is `agent` only" since the lifecycle |
| 3437 | tools were removed, but six more were reachable: `agents/list`, |
| 3438 | `agents/message`, `agents/followup`, `agents/interrupt`, `agents/coordinate`, |
| 3439 | and `agents/wait` all defaulted to model-visible, so they shipped in the |
| 3440 | catalog and `tool_search` could load any of them — and the `agent` |
| 3441 | description told the model they existed. They now declare |
| 3442 | `model_visible() -> false`, the same shape `rlm` and `exec_shell` use: still |
| 3443 | registered, still executable by name so a persisted transcript replays |
| 3444 | against the same implementation, never advertised and never returned by |
| 3445 | either `tool_search` matcher. |
| 3446 | |
| 3447 | Five of the six were already duplicates of an `agent` action. The sixth was |
| 3448 | not: `agents/coordinate action=claim` was the *only* way to widen a write |
| 3449 | claim, and write enforcement fails closed, so hiding it would have left a |
| 3450 | refusal ("expand it first with…") pointing at a tool the model could no |
| 3451 | longer call. `agent` gains one action, `claim`, taking the write scope |
| 3452 | vocabulary `action=start` already uses (`write_roots`, plus parse-accepted |
| 3453 | `exact_files` and `coordination_contracts`). It keeps `agents/coordinate`'s |
| 3454 | `Auto` approval — gating it deadlocks autonomous fan-in — and it can only |
| 3455 | widen the caller's own scope; peer contention still fails. A scopeless claim |
| 3456 | is refused rather than reported as granted, because `expand_write_claim` |
| 3457 | returns the unchanged claim with `Ok` when every list is empty. |
| 3458 | |
| 3459 | Collapsing six tools into one action set also collapses the gating: `agent` |
| 3460 | is deliberately exempt from both name-keyed gates (`posture_permits_tool` |
| 3461 | short-circuits it so delegation depth governs spawning, and |
| 3462 | `execution_envelope` classifies it `Bounded` so a read-only member can fan |
| 3463 | out read-only work), so a capability folded into it inherits no gate. `claim` |
| 3464 | is therefore gated per action, reproducing the envelope check that kept |
| 3465 | `agents/coordinate` off a read-only role's catalog — in the catalog and again |
| 3466 | at dispatch, since catalog shaping is not an authority boundary. The other |
| 3467 | actions keep exactly the visibility they had. |
| 3468 | - One placement table now decides which wire channel a message role belongs |
| 3469 | in, and unrepresentable role/dialect pairs are refused at the outbound seam |
| 3470 | (`DeepSeekClient::prepare_outbound_request`) instead of at the provider. |
| 3471 | Chat Completions and OpenAI Responses used to drop an unfamiliar role |
| 3472 | silently, Anthropic Messages forwarded `message.role` verbatim and took an |
| 3473 | opaque provider 400 for it, and Google cloud-code was alone in failing |
| 3474 | closed. Positioned `system` and `developer` history — including compaction |
| 3475 | and branch summaries — is carried natively by Chat Completions and Responses |
| 3476 | and projected, in place, onto Anthropic's user channel. It is neither |
| 3477 | hoisted nor dropped. Genuinely unknown roles keep the previous |
| 3478 | dialect-specific fail-closed/omit behavior, now decided in one table. The |
| 3479 | dead `"tool"` arm in the Responses adapter is gone — nothing constructs that |
| 3480 | role. |
| 3481 | |
| 3482 | - Message roles are a closed `Role` enum (`crates/core/src/role.rs`) instead of |
| 3483 | a free-form `String` on `Message`. Four wire adapters each decided |
| 3484 | independently what an unfamiliar role meant, and a typo in a role string was |
| 3485 | a silent transcript edit rather than a compile error. `Role` keeps an |
| 3486 | `Unrecognized(String)` variant and serializes via `as_str()`, so a saved |
| 3487 | session's bytes are unchanged, a transcript written by a newer build still |
| 3488 | loads here, and `assistant_interrupted` stays a distinct session item — no |
| 3489 | session schema bump and no migration ladder. |
| 3490 | |
| 3491 | - Portable config bundles: `codewhale config export --portable` writes a |
| 3492 | deterministic, secret-free bundle (credential and machine-specific keys |
| 3493 | dropped), and `codewhale config import <FILE|URL|->` applies one with a |
| 3494 | strict versioned envelope, a printed added/changed/skipped/conflicting/ |
| 3495 | rejected plan, consent gating (`--yes` required headless), a timestamped |
| 3496 | backup with rollback, and idempotent re-import. Credential-shaped entries |
| 3497 | are rejected by key name and value shape — rejections name the field, |
| 3498 | never the value. Remote imports revalidate the HTTPS-or-loopback-HTTP policy |
| 3499 | on every same-scheme redirect hop, and duplicate keys across applicable |
| 3500 | section labels fail before any backup or write instead of silently resolving |
| 3501 | by section order. Structured TOML values round-trip with their original |
| 3502 | types and exact named-provider identity; recursive sanitization covers |
| 3503 | arrays/tables and camel-case, dotted, cookie, and access-key spellings while |
| 3504 | retaining ordinary token-count metrics. Machine-bound project trust, |
| 3505 | credential-source consent, automatic hook/LSP execution, and local-path |
| 3506 | authority are non-portable and fail before mutation. A missing target is |
| 3507 | created transactionally and removed again on rollback, and project/global |
| 3508 | scope validation rejects the wrong document before import or export. |
| 3509 | Imported tables deep-merge portable fields into the target, so omitted |
| 3510 | machine-local provider credentials, endpoints, and executable definitions |
| 3511 | remain intact instead of being erased by a sanitized bundle. |
| 3512 | |
| 3513 | - `/rc` is now a shared-session mirror instead of a terminal takeover. |
| 3514 | Attaching the web app no longer locks the local composer or hides |
| 3515 | approvals: both surfaces can prompt while idle (one turn runs at a |
| 3516 | time), approval cards stay visible in the terminal and are shared with |
| 3517 | the web with first-decision-wins semantics (the losing side is told, a |
| 3518 | web decision dismisses the local card), and structured questions are |
| 3519 | answered locally instead of cancelled. Fail-closed behavior survives — |
| 3520 | the post-failure reconnect lockout, integrity-gated `/rc stop`, and the |
| 3521 | fail-closed shared-approval channel on transport loss are unchanged. |
| 3522 | The takeover vocabulary ("web owns prompts and approvals") is gone from |
| 3523 | every surface. |
| 3524 | |
| 3525 | - Auto-mode provider readiness no longer reports "key saved · not checked" |
| 3526 | forever. Readiness checks are recorded against the concrete model the |
| 3527 | router ran, but auto-mode reads resolved against the literal `auto` |
| 3528 | identity, which never matched any recorded check — so the setup receipt, |
| 3529 | model picker, and fleet setup view showed an eternal unchecked badge |
| 3530 | even after hundreds of successful turns. The read now falls back to the |
| 3531 | most recent check on the same route (provider + endpoint + auth class); |
| 3532 | concrete-model reads keep exact per-model scoping. |
| 3533 | |
| 3534 | - The focused sub-agent transcript now scrolls like the main transcript. |
| 3535 | The frame renderer sampled the ocean column through a `ChatWidget` whose |
| 3536 | constructor consumed `pending_scroll_delta` — every PageUp/PageDown and |
| 3537 | wheel event was swallowed by an invisible widget before the focused pane |
| 3538 | could read it. The delta is now parked across the sample; the pane pins |
| 3539 | on user scroll-up, follows new child activity at tail, and |
| 3540 | jump-to-bottom releases the pin. |
| 3541 | |
| 3542 | - Every Codex OAuth Responses request carried `max_output_tokens`, a parameter |
| 3543 | that endpoint rejects outright ("Unsupported parameter: max_output_tokens"), |
| 3544 | so every gpt-5.6-sol turn — including every sub-agent on that route — failed |
| 3545 | at the first request. Codex Responses bodies now ship without a client-side |
| 3546 | output cap; the backend applies its own. Every other Responses route keeps |
| 3547 | the central cap on the wire, exactly as before. |
| 3548 | |
| 3549 | - The model-facing `lsp` tool now supports a bounded `read_lints` operation |
| 3550 | for multi-file, workspace-relative LSP diagnostics without adding another |
| 3551 | tool catalog entry (#4070). |
| 3552 | |
| 3553 | - HTTP 400 classification no longer calls an unsupported-parameter error a |
| 3554 | context-window overflow. Responses shape errors such as "Unsupported |
| 3555 | parameter: max_output_tokens" name a token-shaped field, which the generic |
| 3556 | keyword rules read as prompt-size exhaustion and pointed users at compaction |
| 3557 | that could never help. Such responses now classify as invalid requests. |
| 3558 | |
| 3559 | - xAI device login validated nothing about the URL it opened. The |
| 3560 | `verification_uri` from the device-code response went straight to |
| 3561 | `webbrowser::open` with no parse, no scheme check and no credential check, so a |
| 3562 | spoofed or compromised issuer could hand the platform's "open this" call a |
| 3563 | `file:` path, a custom application scheme (`vscode://`, `slack://`), or a |
| 3564 | credential-bearing URL. The shared primitive now refuses anything that is not a |
| 3565 | web page before the URI is printed or opened. **Behaviour change:** a |
| 3566 | non-loopback plain-`http:` verification URI now aborts login where it |
| 3567 | previously opened; `http:` on a loopback host is still allowed, because local |
| 3568 | runtimes legitimately use it. |
| 3569 | - The xAI OAuth types no longer print bearer material through `Debug`. Five types |
| 3570 | holding tokens (`GrokAuthEntry`, `TokenResponse`, `DeviceCodeResponse`, |
| 3571 | `DeviceCodeGrant` and the poll outcome) either redact or no longer derive |
| 3572 | `Debug` at all, so a token has no printable path through a `{:?}` on any |
| 3573 | surrounding struct. The shared `DevicePollOutcome` derives nothing, which the |
| 3574 | compiler enforces. |
| 3575 | - **Behaviour change:** an `interval` of `0` from the authorization server now |
| 3576 | falls back to RFC 8628's five-second default rather than a one-second floor, |
| 3577 | in both the xAI and account device flows. |
| 3578 | |
| 3579 | - OAuth device-code login is now one implementation. xAI/Grok device login and |
| 3580 | Codewhale account login each carried their own hand-rolled RFC 8628 polling |
| 3581 | loop with nothing shared between them; both now call a single primitive |
| 3582 | (`codewhale-config`'s `device_code`), ported from pi. Three fixes come with |
| 3583 | it. `slow_down` now honours a server-supplied `interval` instead of always |
| 3584 | adding five seconds, which is what stops polling from running early forever |
| 3585 | under WSL and VM clock drift. Timing out after a `slow_down` now says so and |
| 3586 | names clock drift, rather than reading as a plain timeout. And the xAI |
| 3587 | verification URI is validated before it is handed to the browser opener — |
| 3588 | Codewhale previously opened whatever the device-code response said, so a |
| 3589 | spoofed or compromised issuer could point the platform "open this" call at a |
| 3590 | `file:` path or a custom application scheme. It must now be `https:`, or |
| 3591 | `http:` on a loopback host for self-hosted issuers. Stored credential files |
| 3592 | are unchanged and existing logins keep working. MCP OAuth is untouched: it |
| 3593 | delegates to `rmcp`/`oauth2` and was never hand-rolled. |
| 3594 | - Shell output truncation now stays inside its own budget. A truncated shell |
| 3595 | result keeps a 6 KB head, a 24 KB tail, and any high-signal lines rescued |
| 3596 | from the omitted middle — but that rescued block was bounded only by a line |
| 3597 | count. One rustc `error:` line carrying a long inferred type or a minified |
| 3598 | bundler frame is routinely hundreds of kilobytes, so a "30 KB" result could |
| 3599 | arrive at 430 KB with the omitted line pasted back in whole. Each rescued |
| 3600 | line is now clipped and the block has a 4 KiB ceiling; the signal survives, |
| 3601 | the payload does not. |
| 3602 | |
| 3603 | - Fetched web pages in non-Latin scripts no longer arrive half-read. Page text |
| 3604 | was reflowed against a column budget measured in bytes, so Cyrillic and Greek |
| 3605 | wrapped at roughly half the intended width and CJK at two thirds — and since |
| 3606 | the page view is delivered by line count, the surplus lines pushed real |
| 3607 | content off the end of the window. A Russian or Japanese URL returned a |
| 3608 | fraction of the text an English one did, for the same call. Wrapping now |
| 3609 | measures display width. |
| 3610 | |
| 3611 | - The `bash` tool no longer tells the model it has no default timeout when it |
| 3612 | does. An omitted timeout has always been bounded at 120 seconds and the |
| 3613 | command killed there, but the tool description and its `timeout` field both |
| 3614 | claimed otherwise — steering the model away from the one parameter that |
| 3615 | would have saved a longer build. Both now name the real bound. |
| 3616 | - MCP servers no longer restart because an unrelated setting was saved. The |
| 3617 | lazy config reload re-reads every watched source whenever one of their |
| 3618 | mtimes moves and keeps the live connections only when the content hash |
| 3619 | matches — but the hash was taken over `serde_json` bytes produced straight |
| 3620 | from the config's `HashMap`s, and two `HashMap`s with identical contents do |
| 3621 | not iterate in the same order. Any touch of any watched file therefore hashed |
| 3622 | differently, tore down every connection, and SIGTERMed and respawned every |
| 3623 | stdio child. Keys are now sorted before hashing. |
| 3624 | |
| 3625 | - An MCP server marked `required` now still tells you *why* it failed to start. |
| 3626 | `connect_all` appended a generic "required MCP server failed to initialize" |
| 3627 | entry after the real per-server error, and the snapshot folds those pairs into |
| 3628 | a map keyed by server name — so the contentless entry replaced the diagnosis |
| 3629 | and /mcp showed the marker instead of "No such file or directory". The marker |
| 3630 | is now only synthesized when nothing else reported a cause. |
| 3631 | |
| 3632 | - A crashed stdio MCP server is now rebuilt instead of being handed back dead. |
| 3633 | A failed transport *read* disconnected the connection; a failed *write* did |
| 3634 | not, so after the child exited the connection stayed `Ready`, the pool reused |
| 3635 | it on every later tool call, and /mcp kept listing the server as connected. |
| 3636 | |
| 3637 | - An MCP response carrying neither `result` nor `error` is now an error rather |
| 3638 | than an empty success. It previously reached the model as a successful tool |
| 3639 | call with a `null` payload, indistinguishable from a tool that did nothing. |
| 3640 | An explicit `"result": null` is still a valid empty success. |
| 3641 | - Stdio MCP server requests are answered while the client is idle instead of |
| 3642 | blocking behind the zero-capacity response rendezvous until an unrelated |
| 3643 | client call. `ping` receives its prompt empty result, unsupported methods |
| 3644 | receive JSON-RPC `-32601`, and the reader keeps only a weak stdin handle so |
| 3645 | dropping the client still delivers graceful EOF. |
| 3646 | - `base_url_fingerprint` is a persisted-key change for two input shapes. |
| 3647 | The digest is serde-serialized into `ProviderCatalogCache` and |
| 3648 | `LiveOffering`, pricing defect receipts, and |
| 3649 | `TurnRecord.routed_usage_source_ids` — it is not an in-memory-only cache |
| 3650 | label. Empty or whitespace-only values (and scheme-less query-only strings |
| 3651 | that strip to an empty authority) now hash the invalid-or-secret-bearing |
| 3652 | sentinel instead of SHA-256 of the empty string. Scheme-less URLs that |
| 3653 | contain `@` now strip `userinfo` before hashing, matching the |
| 3654 | scheme-bearing branch, so a typed `user:pass@host/v1` no longer embeds the |
| 3655 | password in a stored digest. `routed_usage_source_fingerprint` feeds |
| 3656 | arbitrary scheme-less source ids into the same function, so a turn |
| 3657 | rehydrated from an older build can fail to dedupe one routed-usage row. |
| 3658 | Recovery is a cache miss and a re-fetch, not corruption. Empty input was |
| 3659 | not restored to the old digest: an empty authority is not a usable |
| 3660 | endpoint, and mapping it to the same sentinel the scheme branch already |
| 3661 | uses for an empty host keeps invalid inputs from minting a unique cache |
| 3662 | scope. |
| 3663 | |
| 3664 | - Diagnostic lines that mention token *counts* are no longer swallowed by |
| 3665 | secret redaction. A stream error such as `max tokens = 8192 but budget = |
| 3666 | 4096` was matching the `token` hint as a substring of the English word |
| 3667 | `tokens`, and the spaced-assignment pass then dropped the rest of the |
| 3668 | line, leaving `max tokens = [redacted]`. Token counts are not credentials; |
| 3669 | the hint now matches a credential identifier (`token`, `api_token`) rather |
| 3670 | than an English word, so the numbers survive while `token = Bearer …` is |
| 3671 | still redacted. |
| 3672 | - Dashboard thread search no longer loads every thread's transcript to decide |
| 3673 | whether the row matches. `GET /v1/threads/summary?search=` walked the full |
| 3674 | thread list and called `get_thread_detail` on each row before matching, and |
| 3675 | that detail read is itself a whole-store walk of every turn JSON and every |
| 3676 | item JSON. A non-matching keystroke was therefore |
| 3677 | O(threads × (all_turns + all_items)) file reads — on the order of 10^8 JSON |
| 3678 | parses at a few thousand threads. Search now matches `id`, title, and model |
| 3679 | from the thread record (and, when the title is unset, the single latest-turn |
| 3680 | file that supplies the displayed title) and loads detail only for matches, so |
| 3681 | preview stays a display field rather than a search key. Session summary |
| 3682 | already refused to search last-message text for the same reason. |
| 3683 | |
| 3684 | - Silent `#[allow(dead_code)]` suppressions on the modules AGENTS.md warns |
| 3685 | auditors not to delete — prompt zones, context budget, the route seam — |
| 3686 | and on the next-largest holders (palette tokens, hotbar actions, core |
| 3687 | events) are now `#[expect(dead_code)]`, or gone where the lint was already |
| 3688 | stale. A suppression that stops matching the lint fails the `-Dwarnings` |
| 3689 | gate instead of sitting quiet. The same gate is recorded in |
| 3690 | `[workspace.lints]` so member crates inherit it from the manifest rather |
| 3691 | than only from CI `RUSTFLAGS`. |
| 3692 | - "missing key" now says where it looked. The provider picker reported |
| 3693 | credential readiness as the bare strings `missing key` / `key:not-set`, |
| 3694 | which named no source at all — so a home whose secret store held a working |
| 3695 | DeepSeek key could show `DeepSeek missing key` in the picker while a real |
| 3696 | turn from that same home completed, and nothing on screen said which layer |
| 3697 | disagreed. Every row now resolves through one sourced resolver and states |
| 3698 | the place its credential came from ("OPENROUTER_API_KEY", `secret store |
| 3699 | "deepseek"`, `[providers.x] api_key`, "xAI OAuth", a consented external CLI |
| 3700 | file); a row without a credential lists the places that were probed, in |
| 3701 | precedence order, and the command that fixes the first of them. Where a |
| 3702 | durable slot is deliberately *not* read — an inactive provider whose config |
| 3703 | table carries no api-key marker — the row says so rather than implying an |
| 3704 | empty slot. |
| 3705 | |
| 3706 | - Provider credential precedence is now stated once, in a doc comment beside |
| 3707 | the single resolver that enforces it, instead of being implied by a |
| 3708 | 150-line cascade of provider special cases. No precedence decision changed: |
| 3709 | `has_api_key_for` is now a wrapper over that resolver, and a test asserts |
| 3710 | the two agree for every provider. |
| 3711 | |
| 3712 | - Credential saves and logouts no longer interleave. Both took a snapshot of |
| 3713 | the durable slot, wrote it, mutated the config document, and rolled back on |
| 3714 | failure, with no lock held across the sequence — so a save racing a logout |
| 3715 | on the same slot could leave the secret store and the config file |
| 3716 | disagreeing. Both now hold that provider's credential write lock for the |
| 3717 | whole read-modify-write. |
| 3718 | |
| 3719 | Design ported from pi-mono (MIT, Copyright (c) 2025 Mario Zechner); see |
| 3720 | `docs/THIRD_PARTY_NOTICES.md`. |
| 3721 | |
| 3722 | - Enumerating stored credentials no longer fails closed on one bad slot. |
| 3723 | Listing used to propagate a backend read error, so a single unreadable |
| 3724 | secret-store entry made `/provider` and logout treat every other stored |
| 3725 | credential as missing. Enumeration now skips the unreadable slot and |
| 3726 | continues, matching the probe loop it replaced. |
| 3727 | |
| 3728 | - The first screen of first run no longer cuts its own headline. The welcome |
| 3729 | and ready titles, and the provider-step heading, were emitted as single |
| 3730 | unwrapped lines while the sentence beneath them wrapped, so at 40 columns |
| 3731 | German read "Codewhale arbeitet mit dir in diesem O", Russian lost its final |
| 3732 | stop, and Japanese lost "します。". Headings are prose and now wrap like it, |
| 3733 | in every shipped locale. |
| 3734 | |
| 3735 | - The workspace-trust screen no longer cuts its own question in half on a small |
| 3736 | terminal. The question, the prompt-injection risk hint, and the trust-effect |
| 3737 | hint were each pushed as one unwrapped line, so at 40 columns the screen read |
| 3738 | "Should Codewhale work with the instruc" — severed mid-word with nothing |
| 3739 | marking the cut, while the workspace path directly beneath it wrapped |
| 3740 | correctly. Asking someone to grant filesystem trust while the question itself |
| 3741 | is truncated is the worst place in the product for that to happen. All three |
| 3742 | now wrap through the same helper the rest of onboarding uses, which also |
| 3743 | means they wrap correctly in Japanese and Chinese. Verified across all |
| 3744 | fifteen shipped locales at 40, 60, 80 and 120 columns. |
| 3745 | - `codewhale completions <shell>` generated a script for the wrong program. |
| 3746 | The subcommand forwarded to the in-tree `codewhale-tui` binary, which |
| 3747 | rendered completions from *its own* clap tree under *its own* name, so the |
| 3748 | output ended in `complete -F _codewhale__tui ... codewhale-tui` (bash), |
| 3749 | `#compdef codewhale-tui` (zsh), and |
| 3750 | `Register-ArgumentCompleter -Native -CommandName 'codewhale-tui'` |
| 3751 | (PowerShell). Sourcing it registered nothing for `codewhale` or `codew` — |
| 3752 | the two commands current installers expose — so tab completion appeared to |
| 3753 | do nothing. The forwarded tree was also stale against the real CLI: it offered |
| 3754 | `pr`, `scorecard`, and `session-diagnostics`, which `codewhale` does not |
| 3755 | have, and omitted `run`, `rc`, `config`, `model`, `thread`, `lane`, |
| 3756 | `workflow`, `web`, `account`, `app-server`, `mcp-server`, `metrics`, |
| 3757 | `update`, `cloud`, `completion`, and `lane-log-proxy`, which it does. |
| 3758 | Completions are now rendered in-process from the CLI's own command tree, |
| 3759 | and `completions` is an alias of the existing |
| 3760 | `completion` subcommand rather than a second, divergent path. Regenerate any |
| 3761 | script you installed from an earlier release. Reported by **RepentStar** |
| 3762 | (#5526); part of the `deepseek-tui`-era identifier retirement in #5443. |
| 3763 | |
| 3764 | - Completion scripts now fire for the `codew` shorthand as well as |
| 3765 | `codewhale`. Releases publish `codew` as a byte-identical copy of the |
| 3766 | `codewhale` binary, so a script bound to only one of the two names was half |
| 3767 | installed for anyone who types the short one. Each shell gets its own |
| 3768 | idiomatic hook rather than a second copy of the script: bash re-binds the |
| 3769 | generated function, zsh widens the `#compdef` tag line to |
| 3770 | `#compdef codewhale codew`, fish adds `complete -c codew -w codewhale`, |
| 3771 | PowerShell registers `-CommandName 'codewhale','codew'`, and Elvish aliases |
| 3772 | the completer with |
| 3773 | `set edit:completion:arg-completer[codew] = $edit:completion:arg-completer[codewhale]`. |
| 3774 | |
| 3775 | - Documented shell completions. `docs/INSTALL.md` § 8 now gives the generate |
| 3776 | and install commands for bash, zsh, fish, PowerShell, and Elvish, with a |
| 3777 | note to regenerate after upgrading and to delete scripts produced by |
| 3778 | v0.9.10 or earlier. There was previously no completion documentation |
| 3779 | anywhere in the repository, which is how #5526 was reported as three |
| 3780 | problems instead of one. |
| 3781 | - `/status` was 31 rows. On an 80x24 terminal the transcript viewport is 18, so |
| 3782 | typing `/status` landed you on the *tail* of the report: the version, route, |
| 3783 | directory, mode and sandbox rows had already scrolled past, and what stayed on |
| 3784 | screen was five `not reported` rows and a `$0.0000`. The report is 18 rows on a |
| 3785 | fresh session — `Window override:` is present unless the value is already |
| 3786 | configured. That is the viewport's height, so once `/status` itself occupies a |
| 3787 | history cell the title row still scrolls off; it does not fit that terminal |
| 3788 | whole. Provider, model and reasoning effort are one `Route:` lockup, the way |
| 3789 | the header rail already writes them. Mode and its permissions are one statement |
| 3790 | of posture. `Rate limits:` is gone — it was a `push_row` of a string literal |
| 3791 | and could never say anything but "not available from provider telemetry". The |
| 3792 | per-turn token ledger is gone too, because `/tokens` is that ledger's whole |
| 3793 | subject and `/status` was printing six rows of it at the same weight as the |
| 3794 | sandbox policy; the two facts that lived nowhere else, the cumulative in/out |
| 3795 | split and the cumulative cache totals, survive on one `Session tokens:` row. |
| 3796 | `Footer items:` no longer prints ten internal config keys across the full |
| 3797 | width — `/statusline` owns them, and the report now points there in the same |
| 3798 | row that points at `/tokens`. Two blank gutters do the grouping; the |
| 3799 | `===================` rule under the title is gone. |
| 3800 | |
| 3801 | - The `/status` window-override key has its own labelled row. It used to be |
| 3802 | parenthesised onto the end of the provenance row, which pushed |
| 3803 | `context_window in config.toml` past the right edge at 80 columns and wrapped |
| 3804 | the sentence. `Window source:` states the provenance and `Window override:` |
| 3805 | names the exact key — and the override row is omitted entirely when the value |
| 3806 | is already configured, rather than advising you to set what you have set. |
| 3807 | |
| 3808 | - `/help` no longer truncates anything. Every label and description used to run |
| 3809 | through a `truncate_to_width` that appended `…`, which in a two-hundred-row |
| 3810 | list promises text no keystroke can reveal and lands mid-token: |
| 3811 | `(aliases: /qin…` left the parenthesis hanging open. Descriptions now shed |
| 3812 | whole fields — the alias parenthetical first, then trailing clauses at their |
| 3813 | own joints, and only where there is no joint at all, the sentence's short form |
| 3814 | on a whole word with no mark, keeping the head noun of a simple verb + |
| 3815 | modifier + noun phrase rather than the adjectives that qualified it. The |
| 3816 | focused row's description is restated under the filter at the panel's full |
| 3817 | width, *only when the row itself could not hold it*, so a wide terminal does |
| 3818 | not say the same sentence twice. At 60 columns that restatement is itself |
| 3819 | shed — the `/advisor` detail stops before `session` — so the detail is longer |
| 3820 | than the row, not a copy of the original sentence. |
| 3821 | |
| 3822 | - The `/help` label column is measured instead of assumed. It was a flat 28 |
| 3823 | columns at every terminal size, so at 60 columns twenty blank cells sat |
| 3824 | between `/advisor` and a description cut down to 21. Each group now sizes its |
| 3825 | column to the labels it actually holds, which nearly doubles the description |
| 3826 | column on a narrow terminal, and the label — the string you have to type — |
| 3827 | reads one step brighter than the description that qualifies it. |
| 3828 | |
| 3829 | - `/help` stopped spending rows on itself. The match count moved onto the filter |
| 3830 | row it describes, the blank spacer under it is gone, and the footer no longer |
| 3831 | repeats `type to filter` while the filter box says `Type to filter` two lines |
| 3832 | above — at 60 columns that duplicate was what pushed the footer onto a second |
| 3833 | row. A group header also stopped printing `▸ ▾`: the selection cursor and the |
| 3834 | collapsed chevron are the same glyph, and a focused collapsed group was |
| 3835 | showing it twice for two different facts. Help now opens focused on the first |
| 3836 | entry rather than the header above it. |
| 3837 | |
| 3838 | - The bottom status rail is no longer one run-on sentence. At 120 columns it |
| 3839 | read `▌· idle · Ollama · deepseek-v4-flash · max · Anonymous usage counts are |
| 3840 | on. … ⌥V:output · /context:context · fn+F1:keys` — live state, route |
| 3841 | identity, a telemetry consent notice, and keyboard hints all strung together |
| 3842 | by the same middle dot in the same ink, so nothing was grouped and the eye |
| 3843 | had nothing to skim by. At 80 columns it simply stopped mid-notice, and at 60 |
| 3844 | the row overflowed and was clipped by the terminal mid-word. The rail now |
| 3845 | divides its groups with a blank gutter instead of another dot (the dot is |
| 3846 | kept for peers *inside* a group), the model name reads one step brighter than |
| 3847 | the qualifiers that narrow it, and `Esc to interrupt` reads in the same hint |
| 3848 | weight as the right-hand chords rather than in the separator weight. |
| 3849 | |
| 3850 | - Nothing on the status rail is ever truncated now. A notice sheds whole |
| 3851 | sentences to fit, and if one sentence is still too long it sheds at the inner |
| 3852 | joints — a colon, a semicolon — with the trailing mark cut so the phrase that |
| 3853 | survives does not itself advertise that more was coming. Route identity sheds |
| 3854 | the provider, then the reasoning effort, rather than rendering |
| 3855 | `deepseek-v4-flash-prev…`; a clipped model name is worse than no model name |
| 3856 | because routes share prefixes. Clauses rejoin without a Latin space after a |
| 3857 | full-width stop, so the Japanese receipt reads as Japanese. |
| 3858 | |
| 3859 | - A notice now stands the standing facts down instead of queueing behind them. |
| 3860 | Route identity and the ledger chips are still there in ten seconds; the |
| 3861 | notice is not, so it takes the row and the key hints yield last. This is what |
| 3862 | makes the telemetry receipt readable at 80 columns, where it used to be |
| 3863 | simultaneously always present and never legible. |
| 3864 | |
| 3865 | - The status rail no longer advertises `/context:context`. It was spending |
| 3866 | eighteen columns of a 24-row screen to name a slash command that announces |
| 3867 | itself the moment you type `/`; the rail advertises chords you cannot |
| 3868 | discover any other way. The rail now reads the same at 80 columns as at 200. |
| 3869 | |
| 3870 | - The idle screen no longer has an absolute path stretched across it. The |
| 3871 | workspace caption between the wordmark and "What do you want to accomplish?" |
| 3872 | was composed at full length and then truncated to the lane width, which made |
| 3873 | the centering inset `(width - caption.width()) / 2` evaluate to zero — so a |
| 3874 | line that was written to be centered rendered flush-left and full-bleed, |
| 3875 | cutting the centered whale/wordmark/prompt composition in half. The clipping |
| 3876 | also destroyed the information it was supposed to carry: at 80 columns the |
| 3877 | line read `/private/tmp/claude-501/-Volumes-.../34267917-11f4-4d15-911a-…`, |
| 3878 | which tells the reader nothing about where they are. The caption now sheds |
| 3879 | detail instead of being cut — MCP count first, then branch, then leading path |
| 3880 | components — so it always fits with room to center, and the folder you are |
| 3881 | standing in is the last thing to go. Elisions land on a path separator rather |
| 3882 | than mid-directory. |
| 3883 | |
| 3884 | - Removed the placeholder engine tree in `crates/core/src/engine/`. Its |
| 3885 | `Engine::run` accepted `Op::SendMessage`, appended to a journal, and emitted |
| 3886 | `TurnComplete { status: "completed" }` without ever contacting a model, and |
| 3887 | `TurnExecutor` was a struct with a field-copy constructor and a |
| 3888 | `step < max_steps` comparison. Nothing in the workspace referenced any of it — |
| 3889 | the only mention of `codewhale_core::engine` anywhere was a doc comment inside |
| 3890 | the tree itself — but its comments ("the real turn loop is wired here in the |
| 3891 | next slice") were what `docs/ARCHITECTURE.md` leaned on to claim that |
| 3892 | `crates/core` owns the agent loop. There is now exactly one turn loop in the |
| 3893 | workspace, `Engine::run_turn`, and a guard test fails if a second one appears. |
| 3894 | `docs/ARCHITECTURE.md` and `AGENTS.md` now say where it actually lives. |
| 3895 | |
| 3896 | - First-run onboarding no longer silently truncates its explanation in |
| 3897 | languages that do not put spaces between words. `wrap_words` split on |
| 3898 | whitespace, so a Japanese sentence arrived as a single token, the |
| 3899 | line-break check (which only fires once a line is non-empty) never |
| 3900 | triggered, and the over-wide line was clipped by the terminal. At 80 |
| 3901 | columns the provider screen read |
| 3902 | "Hosted providers need a key, but loca" and stopped — losing exactly the |
| 3903 | half that tells the reader local runtimes need no key, on the screen where |
| 3904 | they choose a provider. Space-less scripts now break by display width on |
| 3905 | grapheme clusters, and a line may not begin with closing punctuation |
| 3906 | (`。`, `、`, `」`, `)` and friends). Wrapping for languages that do use |
| 3907 | spaces is unchanged. |
| 3908 | |
| 3909 | - Project instructions are bounded by one budget and no longer treat other |
| 3910 | agents' files as law by default. Previously `.claude/instructions.md` and |
| 3911 | `CLAUDE.md` sat at ranks 2 and 3 of the canonical instruction list — *above* |
| 3912 | Codewhale's own `.codewhale/instructions.md` — `.claude/rules/` was an |
| 3913 | auto-discovered rules directory, and `.cursorrules`, `.cursor/rules`, |
| 3914 | `.clinerules`, `.windsurf/rules`, `.gemini`, `.github/copilot-instructions.md` |
| 3915 | and `.github/muse-instructions.md` were all imported into the system prompt |
| 3916 | with no opt-in. Dropping a `CLAUDE.md` written for a different tool into a |
| 3917 | repository silently made it standing authority here, which is an injection |
| 3918 | surface rather than a convenience. Codewhale now reads `AGENTS.md`, the |
| 3919 | cross-agent `.agents/AGENTS.md`, and its own instruction files by default; |
| 3920 | every other agent's format is opt-in by name through |
| 3921 | `project_instruction_imports` (env `CODEWHALE_PROJECT_INSTRUCTION_IMPORTS`), |
| 3922 | imported files rank *below* Codewhale's own, and a workspace that contains an |
| 3923 | un-imported format says so in a warning naming the exact setting. |
| 3924 | - Separately, a symlinked candidate rules directory — `.cursor/rules`, |
| 3925 | `.windsurf/rules`, or `.gemini` pointing outside the workspace — was |
| 3926 | traversed and its contents imported as instruction authority, because the |
| 3927 | directory check followed the link while only the files inside it were |
| 3928 | checked. The two instruction loaders now apply the same no-follow rule that |
| 3929 | `.codewhale/rules/` already had. |
| 3930 | - The three separate ceilings on standing instructions (200 KiB for the |
| 3931 | root->workspace chain, 500 KiB for the rules block, 40 KiB for imported |
| 3932 | fragments, and a global layer that was merged in after the chain budget had |
| 3933 | already closed and so counted against nothing) are replaced by a single |
| 3934 | 48 KiB aggregate budget covering all of them together. Instructions claim it |
| 3935 | before rules, and are trimmed from the broadest scope inward so the |
| 3936 | nearest-scope file is the last thing dropped rather than the first thing |
| 3937 | stranded. Truncation still leaves an explicit marker. |
| 3938 | |
| 3939 | - Editing the workspace no longer grants the shell outbound network access. |
| 3940 | `workspace-write` sandboxes are created network-restricted; `curl`, package |
| 3941 | installs, and `git fetch` inside a sandboxed shell are denied by the OS |
| 3942 | sandbox unless network is granted explicitly. This closes a real gap rather |
| 3943 | than tightening a working boundary: the elevation added in #273 was justified |
| 3944 | by the application-level `NetworkPolicy` remaining "the only outbound |
| 3945 | boundary", but that policy governs `fetch_url`, `web_search`, and MCP HTTP |
| 3946 | and never constrained shell subprocesses, so workspace-write turns had |
| 3947 | unrestricted egress with nothing enforcing anything. Network now comes from |
| 3948 | one of three explicit places: the new `sandbox_network_access` config key |
| 3949 | (also `CODEWHALE_SANDBOX_NETWORK_ACCESS`), a `danger-full-access` posture, or |
| 3950 | the existing post-denial elevation prompt that grants network for a single |
| 3951 | call. Yolo and `--yolo`/Bypass are unchanged — they resolve to |
| 3952 | `danger-full-access`, which applies no sandbox at all. `external-sandbox` |
| 3953 | reports the network it was actually granted instead of hardcoding `true`, and |
| 3954 | `/status` reads the flag instead of printing "network on" for every |
| 3955 | workspace-write policy. Platforms with no sandbox backend (default Linux |
| 3956 | without bubblewrap, and Windows) still enforce nothing, and both `/status` |
| 3957 | and `doctor` continue to say so. |
| 3958 | |
| 3959 | - The nightly Windows ARM64 artifact build works again. Every nightly from |
| 3960 | 2026-08-16 failed while compiling `codewhale-tui`, deterministically on the |
| 3961 | same codegen unit across all three build attempts, with |
| 3962 | `thread 'optimize module codewhale_tui...-cgu.13' has overflowed its stack`. |
| 3963 | The trigger is stack depth in the LLVM worker threads that run per-codegen-unit |
| 3964 | optimization, not the workflow's `lto=off` override: holding the crate and |
| 3965 | every flag fixed and varying only `RUST_MIN_STACK` on aarch64 shows 1 MiB |
| 3966 | crashes rustc while 2 MiB and 4 MiB succeed. Unix std defaults to 2 MiB and |
| 3967 | passed; the Windows ARM64 runner sat under the requirement. Nightly now sets |
| 3968 | `RUST_MIN_STACK` explicitly for every target, because the requirement follows |
| 3969 | from the size of `crates/tui` rather than from the platform. The redundant |
| 3970 | `codegen-units` override is gone -- `[profile.release]` already sets 16, so |
| 3971 | restating it never changed anything. Shipped binaries were never affected; |
| 3972 | `release-artifacts.yml` builds `--profile dist` with fat LTO and |
| 3973 | `codegen-units = 1`. |
| 3974 | |
| 3975 | - Test debt: the transcript history-cell suite has been rebuilt. It was 123 |
| 3976 | tests across 3,964 lines, and about a third of it pinned the current skin |
| 3977 | rather than any behavior -- `assert_eq!(spans[1], "⣤")` for the |
| 3978 | reduced-motion marker, `title_span.style.fg == theme.tool_title_color`, |
| 3979 | `visible[1] == "▏ done: scan repo"`, four separate tests each asserting one |
| 3980 | shape of fenced code never takes the transcript rail, and one test whose |
| 3981 | only assertion was `!text.is_empty()` under a name promising it checked the |
| 3982 | rendered tool id. Assertions like those break on every legitimate visual |
| 3983 | change and catch nothing a reader of the transcript would notice, which is |
| 3984 | the liability `d64b9429b` named. The replacement is 40 tests, each named |
| 3985 | for the property it protects and asserting the property instead of the |
| 3986 | token: reduced motion is checked by rendering the same running card at two |
| 3987 | different elapsed times and requiring the frames to match -- which also |
| 3988 | catches an animation leak the glyph constant missed -- and a frozen marker |
| 3989 | must stay visible rather than landing on the spinner's invisible blank |
| 3990 | (U+2800). Severity colors are checked by requiring warning not to read as |
| 3991 | error rather than by naming a palette entry. A streaming assistant glyph |
| 3992 | must actually pulse when motion is allowed, checked against |
| 3993 | `pulse_brightness` rather than by sleeping on the 2s sine. Each of the |
| 3994 | invariants claimed was verified to fail the new suite when deliberately |
| 3995 | broken in the renderer. |
| 3996 | ## [0.9.10] - 2026-08-19 |
| 3997 | |
| 3998 | - Show the full slash-command or `/model` completion row in a bounded, wrapping hover popover whenever narrow terminals truncate it, closing the remaining scoped gap from [#998](https://github.com/codewhale-hq/CodeWhale/issues/998). Thanks [@AiurArtanis](https://github.com/AiurArtanis) and [@formp3](https://github.com/formp3) for identifying the affected surfaces. |
| 3999 | - `registry_sync` no longer ships the full MCP Registry catalog into the |
| 4000 | conversation. It takes a required query, scores the local snapshot |
| 4001 | host-side, and returns at most eight matches; the complete catalog stays on |
| 4002 | disk, and the compaction and spillover exemptions that let a multi-hundred- |
| 4003 | kilobyte dump reach the model unchanged are gone. |
| 4004 | - Providers that mirror the outgoing `(reasoning omitted)` replay placeholder |
| 4005 | back as a reasoning delta no longer have that echo ingested as real |
| 4006 | thinking: the exact transport placeholder is dropped on arrival, so live |
| 4007 | sessions stop showing a stream of placeholder reasoning blocks and saved |
| 4008 | transcripts stay free of them. |
| 4009 | - Mid-stream connection drops during an interactive turn no longer persist a |
| 4010 | synthetic `[runtime]` user message. Retry state is a typed engine-internal |
| 4011 | descriptor; a thinking-only drop re-issues the request without claiming a |
| 4012 | partial reply was preserved, the retry budget is enforced in mechanism, and |
| 4013 | recovery produces exactly one authoritative final answer. |
| 4014 | |
| 4015 | Codewhale v0.9.10 is a retention, identity, and product-clarity release: the shell and |
| 4016 | transcript can no longer retain unbounded tool output in memory or on disk, |
| 4017 | mid-turn history inserts no longer strand in-flight tool rows, every agent |
| 4018 | that ran this session is visible from `/agents list`, the PTY acceptance |
| 4019 | lane has a stall watchdog and bounded CI steps, approval outcomes are |
| 4020 | durable and fail closed (cyq1017, #5360), and three $HOME disk leaks are |
| 4021 | reclaimed. Extension surfaces now name their real state and act only |
| 4022 | through the reviewed install and trust flows, and sub-agent, shell, task, |
| 4023 | and workflow state is owned by the session that created it (#5518). Test |
| 4024 | threads get an 8 MiB stack so the lib suite can no longer |
| 4025 | abort under load. |
| 4026 | |
| 4027 | ### Fixed |
| 4028 | |
| 4029 | - First run starts on the welcome screen again. A missing key no longer |
| 4030 | skips Welcome and auto-opens the local-provider list: Enter walks to the |
| 4031 | calm provider explanation, then Enter opens the picker so a first API key |
| 4032 | can be set. Returning missing-key recovery still opens the picker on |
| 4033 | launch. |
| 4034 | - A foreground `bash` command that named no timeout is bounded again. The |
| 4035 | model-facing `bash` tool left an omitted `timeout_ms` at the internal |
| 4036 | ceiling (~24.8 days) instead of the 120 s default its own schema |
| 4037 | advertises, so a CLI that blocked on an interactive prompt or a hung |
| 4038 | network call held the turn open indefinitely — one report sat on a single |
| 4039 | unauthenticated CLI call for over two hours with the tool row simply |
| 4040 | counting seconds. The advertised default now applies, which arms the |
| 4041 | existing recovery: the process is killed and the model is told to rerun |
| 4042 | with `background=true` and poll with `action="wait"`. An explicit |
| 4043 | `timeout_ms` is still honored for genuinely long foreground work, and |
| 4044 | background and interactive runs keep their own lifetimes. |
| 4045 | - The Extensions (`/plugin`) Marketplace is no longer a read-only list. |
| 4046 | Every recommendation and stored candidate names its truthful state and |
| 4047 | primary action — Add, Enable, Configured, or Unavailable — and Enter or a |
| 4048 | mouse click runs that action through the existing reviewed `/mcp add |
| 4049 | recommended`, `/mcp enable`, and `/plugin` install/trust controllers, so |
| 4050 | no second trust path exists. Browser Use and Sandbox Runtime stay |
| 4051 | honestly Unavailable with their real setup routing instead of implying an |
| 4052 | install Codewhale cannot perform. |
| 4053 | - The Extensions MCP tab now renders one honest inventory: the header count |
| 4054 | and the visible rows derive from the same configured-server set, so |
| 4055 | `MCP (6)` can no longer sit above two rendered rows. Disabled servers |
| 4056 | stay visible and labeled disabled instead of silently disappearing, and |
| 4057 | configured servers absent from the live snapshot list as not-yet-inspected |
| 4058 | with their own explicit reload affordance through the MCP command |
| 4059 | controller. |
| 4060 | - Installed plugin rows now act on their real state: Enter opens an active |
| 4061 | bundle (`/plugin show`), offers Enable for a trusted-but-disabled bundle, |
| 4062 | or routes an untrusted bundle to the existing trust review — through the |
| 4063 | same confirmation and persistence controllers as the slash commands. |
| 4064 | - Sub-agent handoffs and rosters, background shell jobs, durable tasks, |
| 4065 | delayed continuations, and workflow controls are now scoped to the |
| 4066 | session that owns them. Records carry immutable root-session ownership, |
| 4067 | stale completion-channel payloads are rejected before deduplication, |
| 4068 | background work drains and reports only to its owning session, and |
| 4069 | legacy ownerless jobs fail closed (#5518 failure class reported by |
| 4070 | @hxfhd; the report's exact JavaScript provenance was not claimed as |
| 4071 | reproduced). |
| 4072 | - The resolved route envelope now reaches every outbound model call: all |
| 4073 | wire dialects and auxiliary calls clamp at the shared transport seam |
| 4074 | under one wire/reservation budget, provider input limits are honored, and |
| 4075 | switching models on the same protocol no longer inherits the previous |
| 4076 | model's limits (#5516, #5518). |
| 4077 | - First-run continuity: the chosen onboarding provider persists across |
| 4078 | restarts, a missing first-run config no longer interrupts the flow, and |
| 4079 | the automatic working-agreement checkpoint renders as a standalone setup |
| 4080 | handoff instead of regressing the onboarding rail to the full wizard's |
| 4081 | 4/10 progress. |
| 4082 | - Explicitly worded natural-language `/goal` declarations now create a |
| 4083 | durable goal in the provider-neutral engine before model dispatch, while |
| 4084 | ordinary tasks and quoted transcripts stay out of goal mode and prose |
| 4085 | acknowledgement alone can no longer stand in for goal creation. |
| 4086 | - `/model` now keeps the current Z.ai default (`GLM-5.3`) visible when an |
| 4087 | older installation has an explicit `GLM-5.2` route saved. The saved 5.2 |
| 4088 | route remains exact; choosing 5.3 sends and remembers the distinct 5.3 ID. |
| 4089 | - The constitution checkpoint now leads with the bundled balanced agreement; |
| 4090 | the default path writes no custom constitution. The startup launch surface |
| 4091 | distinguishes read-only Chat from folder-bound, approval-gated Work. |
| 4092 | - Tabby and other IME bridges no longer observe a stale visible caret while a |
| 4093 | frame diff is being painted; Codewhale hides the cursor during the diff, |
| 4094 | restores the canonical composer cell, and only then reveals it again |
| 4095 | (BrathonBai, #5023). |
| 4096 | - Pre-header HTTP/2/SSE transport failures get one bounded HTTP/1.1 retry; |
| 4097 | authentication, provider-semantic, response-body, and already-pinned HTTP/1 |
| 4098 | failures remain fail-closed (demian-welt, #4683). |
| 4099 | - MCP `tools/call` images now travel as bounded typed content instead of |
| 4100 | leaking base64 through model-visible JSON. Direct and parallel calls share |
| 4101 | the same MIME, size, validation, and one-image boundary (PR #5515 by |
| 4102 | @cacdcaecawae). |
| 4103 | - Linux npm installs and updates race GitHub Releases against the CNB mirror |
| 4104 | at the checksum-manifest layer, then download from the first verified source |
| 4105 | without making users wait through a doomed slow-source timeout. |
| 4106 | - `CODEWHALE_PREFER_BWRAP` now applies the documented Linux sandbox override, |
| 4107 | and Codewhale-era names own build metadata, hook session/tool-call IDs, and |
| 4108 | sandbox child markers. The corresponding `DEEPSEEK_*` names remain as 0.9.x |
| 4109 | compatibility aliases (#5443). |
| 4110 | - Windows default launch prefers Windows Terminal: zip archives ship |
| 4111 | `codewhale.bat` (CRLF, `wt.exe` then the exe), `install.bat` copies that |
| 4112 | launcher, and the NSIS Start Menu shortcut opens it instead of the raw |
| 4113 | binary (#1854). |
| 4114 | - `fix(tui): make the header status mark honour its setting` — `status_indicator` |
| 4115 | did nothing for three of its four documented values. The header hardcoded a |
| 4116 | leading `cw` span *and* asked for a second mark beside the effort chip, then |
| 4117 | filtered the second one against the literal `"cw"`; because `cw`, the legacy |
| 4118 | `whale` opt-in, and every unknown value all normalize onto that same mark, |
| 4119 | the filter discarded them and left `off` with nothing to turn off. `cw`, |
| 4120 | `whale`, `off`, and a typo all rendered byte-identical headers. There is one |
| 4121 | mark now and the setting owns it: `cw`/`whale` draw the typographic mark, |
| 4122 | `dots` draws the activity frames, `off` removes it (thejayjetson, #5512). |
| 4123 | - `fix(tui): rebase active-cell tool bindings on every mid-turn history |
| 4124 | insert` — `/rename` mid-turn left the running tool row spinning forever |
| 4125 | (#5478). |
| 4126 | - `fix(tui): bound what the shell and transcript retain from tool output` — |
| 4127 | a 1.1 MB Bash call kept over a megabyte resident for up to an hour; raw |
| 4128 | streams now cap at 16 MiB in flight and release delivered output, and |
| 4129 | retained tool outputs cap at 64 KiB per record / 8 MiB per transcript |
| 4130 | (#5472). |
| 4131 | - `fix(tui): reclaim the three $HOME disk leaks` — orphaned session dirs, |
| 4132 | the unbounded audit.log, and stranded writer temp files. |
| 4133 | - `fix(tui): persist approval outcomes before execution` (cyq1017) — |
| 4134 | approval receipts are committed to a session-owned log before execution |
| 4135 | proceeds; unpersistable evidence blocks the tool; resume reconstructs |
| 4136 | closed and interrupted approvals (#5360). |
| 4137 | - `test(tui): break the LazyLock/env-barrier deadlock in the test harness`. |
| 4138 | - `ci: give test threads the 8 MiB stack they need` — the lib suite aborted |
| 4139 | with SIGABRT under load on the default 2 MiB stack. |
| 4140 | - YOLO entry points honor a locked approval policy: `--yolo`, `/mode yolo`, |
| 4141 | `/zidong`, and Alt+Y can no longer set Full Access + trust + shell when |
| 4142 | config or managed requirements own the posture. |
| 4143 | - Terminal PTY tools fail closed without a sandbox backend under a narrowed |
| 4144 | filesystem posture, and otherwise start `$SHELL -i` through |
| 4145 | `SandboxManager::prepare` like `bash`. |
| 4146 | - Skill update refuses to replace a directory that has no `.installed-from` |
| 4147 | marker — same ownership gate plugins already used. |
| 4148 | - `cp`/`mv` are workspace-safe only when every path operand stays inside |
| 4149 | the workspace — Auto-Review no longer auto-allows `cp /etc/passwd .`. |
| 4150 | - Main CI no longer shares one concurrency group per branch: each SHA |
| 4151 | gets a verdict instead of a cancelled pending run. A hermetic Safety |
| 4152 | gate job runs authorization tests in under 15 minutes (test bankruptcy |
| 4153 | restructuring — no tests deleted). |
| 4154 | - Config-fixture tests no longer honor `lock_test_env` as a license to |
| 4155 | read a populated `~/.codewhale/config.toml`; they need an `EnvVarGuard` |
| 4156 | like settings already did. Safety-gate and CNB workspace tests pin a |
| 4157 | hermetic `CODEWHALE_HOME`. `exec_persistent_service` is serialized in |
| 4158 | nextest and inside the cargo-test binary instead of dropped (#5355). |
| 4159 | - Short CLI no longer waits up to three seconds for a telemetry POST on |
| 4160 | exit; `session_end` is recorded and the buffer ships on the next |
| 4161 | interactive session. |
| 4162 | - Bare `/` now opens a deliberately small starter set: `/help`, `/setup`, |
| 4163 | `/model`, `/settings`, `/resume`, and `/rc`. The full command inventory |
| 4164 | remains searchable through `/help`, the command palette, and direct prefix |
| 4165 | typing, without front-loading the entire control surface (#5442, #5439). |
| 4166 | - First run now asks only for decisions needed to become usable, keeps the |
| 4167 | offline route explicit, and leaves optional provider, tools, policy, and |
| 4168 | appearance work in the progressive `/setup` repair guide. The idle aquarium |
| 4169 | asks one task-oriented question instead of advertising a tutorial or command |
| 4170 | billboard, and the localized telemetry choice appears after the workspace is |
| 4171 | ready without blocking the composer. |
| 4172 | - Provider, active model, and reasoning effort moved out of the crowded header |
| 4173 | into a quiet, width-aware footer identity. Compact layouts keep model and |
| 4174 | effort before provider detail and shed whole low-priority groups instead of |
| 4175 | clipping the composer or control hints. |
| 4176 | - The model picker no longer re-parses `~/.codewhale/config.toml` once per |
| 4177 | provider when deciding who has a saved key. |
| 4178 | |
| 4179 | ### Added |
| 4180 | |
| 4181 | - `/workflows` opens a live run dashboard over this workspace's durable |
| 4182 | workflow journal: every retained run with status, phases, child roster, |
| 4183 | progress, and host-side cancel — observation only, it never launches a run. |
| 4184 | - Repository instructions now assemble from the actual containing checkout: |
| 4185 | applicable `AGENTS.md` files resolve repository-root to current-directory in |
| 4186 | order under one aggregate budget, a linked worktree is its own root, and |
| 4187 | scope is never inferred from path mentions or whichever branch is named |
| 4188 | `main`. |
| 4189 | - `/goal` is a codex-style control plane: setting an objective dispatches it |
| 4190 | to the engine, which owns the goal and starts the first goal turn itself — |
| 4191 | the objective is never echoed back as the user's own message, pause/resume |
| 4192 | are real control ops, and the hunt-era vocabulary and trophy cards are |
| 4193 | gone. |
| 4194 | - `/extensions` and `/plugins` open one localized inventory for Hooks, |
| 4195 | Plugins, local Marketplace catalogs, Skills, and MCP. Reviewed suggestions |
| 4196 | include Playwright, Chrome DevTools, Cua Computer Use, Browser Use, and the |
| 4197 | sandbox runtime without granting trust or installing anything on open. |
| 4198 | - Turn Inspector now opens the newest turn and pages across complete recorded |
| 4199 | user, reasoning, tool/subagent, and assistant output with page-scoped search, |
| 4200 | copy, and export (sky-sun-moon, #1682). |
| 4201 | - Background tasks have bounded incremental persistence, durable terminal |
| 4202 | reasons, truthful timeout/cancellation receipts, restart recovery, and |
| 4203 | interruptible continuous-goal delays (#5497, #5508). |
| 4204 | - `/title` once again controls the terminal window title independently from |
| 4205 | `/rename`, survives session save/load, and sanitizes control, bidi, and |
| 4206 | zero-width characters (PR #5509 by @SparkofSpike). |
| 4207 | - MCP snapshots preserve whether capabilities were advertised by the server, |
| 4208 | discovered through the bounded legacy fallback, or not observed (#4170). |
| 4209 | - `codewhale auth status --diagnostic` reports canonical paths, isolation |
| 4210 | source, backend class, and value-free provider-source presence without |
| 4211 | opening credential stores or creating/migrating state (#2369). |
| 4212 | - `codewhale doctor --probe-search` performs an explicit credential-free, |
| 4213 | policy-checked transport probe for the selected search provider; ordinary |
| 4214 | doctor and JSON output remain offline (#5442). |
| 4215 | - The safe deferred `read_media` tool is available to supported read-only |
| 4216 | roles, and history receipts distinguish localized tool execution outcomes |
| 4217 | without exposing raw payloads (#5102). |
| 4218 | - **npm Linux x64 first-party source selection.** The wrapper concurrently |
| 4219 | fetches the GitHub Releases and CNB checksum manifests for the exact |
| 4220 | package version, locks the first source whose HTTP response and manifest |
| 4221 | validate, and downloads binaries only from that source. Explicit |
| 4222 | `CODEWHALE_RELEASE_BASE_URL` / `CODEWHALE_USE_CNB_MIRROR=1` still skip the |
| 4223 | race; other targets stay on GitHub. |
| 4224 | - `/workflow <objective>` and `/workflow run <path>` now produce a bounded, |
| 4225 | tool-less proposal for review. Only `/workflow confirm` can launch that |
| 4226 | reviewed draft; status, cancel, settings, and the `/workflows` dashboard stay |
| 4227 | host-owned and do not spend a model turn (#5439). |
| 4228 | - `feat(tui): add cancellable cadence to continuous goals` (M-Maciej) — |
| 4229 | `[goal] continuation_delay_seconds` gives coordinator goals a visible quiet |
| 4230 | period between successful turns while reusing the existing coalesced goal |
| 4231 | continuation token; Esc, Ctrl+C, pause/done/blocked/clear cancel before the |
| 4232 | next provider request, and failures never continue (#5508). |
| 4233 | - `feat(tui): add command context adapters and migration gate (FEAT-015)` |
| 4234 | (aboimpinto) — TUI-owned capability facets, a dual-path dispatch seam, and |
| 4235 | source-aware CI enforcement so a command slice cannot claim to be migrated |
| 4236 | while it still accepts concrete `App`. Zero production commands migrate in |
| 4237 | this slice (#5316). |
| 4238 | - `feat(web): move docs/hooks and docs/troubleshooting onto the dictionary |
| 4239 | spine` (Lstarsky0) — both pages now read copy from the locale dictionaries |
| 4240 | instead of inline bilingual literals (#5337). |
| 4241 | - `feat(web): move docs/constitution and docs/runtime-api onto the dictionary |
| 4242 | spine` (Lstarsky0) — both pages now read copy from the locale dictionaries |
| 4243 | instead of inline bilingual literals; another incremental phase of #5337, |
| 4244 | not completion of the full epic (#5517). |
| 4245 | - `docs(i18n): complete Tier 1 of Chinese docs localization` (SparkofSpike) — |
| 4246 | Chinese and Indonesian docs move to `docs/zh_hans/` and `docs/id/`, with |
| 4247 | redirect stubs at the old paths for one release cycle (#5482). |
| 4248 | - `feat(tui): show repository context in git chrome` (wuisabel-gif) — the TUI |
| 4249 | header now identifies the active repository or linked worktree before the |
| 4250 | branch and dirty marker, so operators can see where the agent is working |
| 4251 | without opening the worktree manager (#5437). |
| 4252 | - `feat(tui): formalize the status-bar color grammar` — seven semantic |
| 4253 | families live in `docs/design/STATUS_BAR_COLOR_GRAMMAR.md` and |
| 4254 | `palette::grammar`; header and phase-strip ink resolve through named |
| 4255 | `ChromeInk` slots so chrome cannot invent an eighth meaning or spend |
| 4256 | Failure red on a dirty worktree or selected mode. The footer's session |
| 4257 | metrics strip resolves through the same inks, and the red reservation is |
| 4258 | checked against every selectable theme, not just the whale default; |
| 4259 | typed footer toasts resolve through the grammar too. |
| 4260 | Repo/worktree chrome stays metadata and still renders when Git names a |
| 4261 | location but not a ref (#5437). |
| 4262 | - `feat(tui): first slice of the agents roster` — every agent that ran this |
| 4263 | session, receipts-only, via `/agents list` and the sidebar fan-out rows |
| 4264 | (#5479 spec items 1 and 5). |
| 4265 | - `ci: bound PTY acceptance and add a stall watchdog to the harness` — |
| 4266 | QA_PTY_STALL_TIMEOUT_SECS aborts a wedged PTY run with a diagnostic; |
| 4267 | the isolated PTY step is capped at 15 minutes; Windows NSIS provisioning |
| 4268 | gets a bounded retry (#5496). |
| 4269 | - `chore(scripts): dev-cache warns before it fills a disk` (#5465 class). |
| 4270 | |
| 4271 | ### Contributors |
| 4272 | |
| 4273 | - [Sh1Zuku](https://github.com/SparkofSpike) (`@SparkofSpike`) — restored |
| 4274 | `/title` as an independent, persistent terminal-window title in PR #5509, |
| 4275 | in addition to the Tier 1 Chinese and Indonesian documentation work below. |
| 4276 | - [Sun Zhenyuan](https://github.com/bistack) (`@bistack`) — extracted the |
| 4277 | turn-loop stream processor in PR #5514 while preserving retry, cancellation, |
| 4278 | usage, TTFT, steering, and partial-response behavior. |
| 4279 | - [OctoBored](https://github.com/OctoBored) (`@OctoBored`) — supplied the |
| 4280 | working no-token Star History mirror used across the localized README set |
| 4281 | after the canonical chart endpoint began returning a restricted placeholder |
| 4282 | (#5510). |
| 4283 | - [cacdcaecawae](https://github.com/cacdcaecawae) (`@cacdcaecawae`) — added |
| 4284 | provider-neutral typed MCP image forwarding in PR #5515; the harvested |
| 4285 | version also makes malformed image fields produce a visible omission receipt. |
| 4286 | - [DingYong4223](https://github.com/DingYong4223) (`@DingYong4223`) — reported |
| 4287 | the narrow-terminal completion truncation closed by the bounded hover reveal |
| 4288 | (#998). Thanks also to @AiurArtanis and @formp3 for identifying the affected |
| 4289 | completion surfaces. |
| 4290 | - [sky-sun-moon](https://github.com/sky-sun-moon) (`@sky-sun-moon`) — reported |
| 4291 | the missing full per-turn input, reasoning, tool, and assistant pages that |
| 4292 | shaped Turn Inspector navigation (#1682). |
| 4293 | - [cy2311](https://github.com/cy2311) (`@cy2311`) — reported the Windows launch |
| 4294 | path that now ships and installs a Windows Terminal-aware batch launcher |
| 4295 | (#1854). |
| 4296 | - [demian-welt](https://github.com/demian-welt) (`@demian-welt`) — provided the |
| 4297 | reproducible pre-header SSE transport failure behind the bounded HTTP/1.1 |
| 4298 | retry (#4683). |
| 4299 | - [BrathonBai](https://github.com/BrathonBai) (`@BrathonBai`) — reported the |
| 4300 | Tabby/CJK IME candidate-window jump that led to the hide-diff-position-show |
| 4301 | cursor transaction (#5023). |
| 4302 | - M-Maciej (@M-Maciej) — the real-world organization-coordinator use case and |
| 4303 | 5–30 minute cadence requirement behind cancellable cross-turn goal delays |
| 4304 | (#5508). |
| 4305 | - cyq1017 (@cyq1017) — approval outcomes are persisted before execution can |
| 4306 | proceed: receipts commit to a session-owned log first, unpersistable |
| 4307 | evidence blocks the tool, stale decisions are rejected, and resume |
| 4308 | reconstructs closed and interrupted approvals (#5491, closes #5360). |
| 4309 | - aboimpinto (@aboimpinto) — the TUI-owned dependency-injection and migration |
| 4310 | infrastructure that makes slash-command extraction safe: seven capability |
| 4311 | facets, a dual-path dispatch seam, and source-aware CI enforcement so a |
| 4312 | command slice cannot claim migration while it still accepts concrete `App` |
| 4313 | (#5506, EPIC-005/FEAT-015 under #5316, which they also filed). |
| 4314 | - wuisabel-gif (@wuisabel-gif) — the TUI header now names the active |
| 4315 | repository or linked worktree before the branch and dirty marker, derived |
| 4316 | from Git's common directory and capped by shell density tier (#5511, the |
| 4317 | repo/worktree slice of #5437). |
| 4318 | - SparkofSpike (@SparkofSpike) — Tier 1 of the Chinese docs localization: |
| 4319 | Chinese and Indonesian documentation moves to `docs/zh_hans/` and |
| 4320 | `docs/id/` with redirect stubs held at the old paths for one release cycle |
| 4321 | (#5507, epic #5482, which they also filed). |
| 4322 | - Lstarsky0 (@Lstarsky0) — `docs/hooks` and `docs/troubleshooting` move onto |
| 4323 | the dictionary spine, retiring their inline bilingual literals in favor of |
| 4324 | locale dictionaries with token-aware code spans (#5504, closes #5337, which |
| 4325 | they also filed). |
| 4326 | - Lstarsky0 (@Lstarsky0) — `docs/constitution` and `docs/runtime-api` follow |
| 4327 | the same dictionary spine: 28 inline `isZh` branches become typed English |
| 4328 | and Chinese dictionaries held to key and token parity, while the other |
| 4329 | sixteen locales keep the English fallback (#5517, a further phase of #5337). |
| 4330 | - @thejayjetson — the header status-indicator report that pinned the |
| 4331 | regression to a specific setting, with every value, theme, and |
| 4332 | `fancy_animations` combination already ruled out (#5512). |
| 4333 | - hxfhd (@hxfhd) — reported the deterministic cross-session contamination |
| 4334 | class behind this release's session-ownership boundary, plus route |
| 4335 | budgeting evidence (#5518). |
| 4336 | - sfdzhmr (@sfdzhmr) — reported the route budgeting root causes that exact |
| 4337 | route-limit propagation now closes (#5516). |
| 4338 | |
| 4339 | ## [0.9.9] - 2026-08-18 |
| 4340 | |
| 4341 | Codewhale v0.9.9 is a truth-and-resilience release: the shell tool can no |
| 4342 | longer wedge a session when the host runs out of disk or descriptors, |
| 4343 | unverified context windows and output ceilings are labeled honestly at every |
| 4344 | surface, DeepSeek V4 is priced on the published peak/off-peak tiers, SSE |
| 4345 | UTF-8 fails closed in every dialect, Fleet shadowing is visible, bwrap gets |
| 4346 | container essentials and extra roots, the `dsh` skin rides the bundle |
| 4347 | profile, the `agent` tool schema is down to 12 fields, and README/website |
| 4348 | locales grow to 18 and 8. |
| 4349 | |
| 4350 | ### Fixed |
| 4351 | |
| 4352 | - The lowercase `bash` tool no longer wedges when its complete-output spill |
| 4353 | file cannot be created: a full temp volume or exhausted descriptor table |
| 4354 | used to fail *every* call — `echo ok` included — with the harness-internal |
| 4355 | "Failed to create streaming shell output" and never recover until the |
| 4356 | host was cleaned up. The spill is now best-effort (the bounded tail is |
| 4357 | still returned and the truncation notice says why the full-output path is |
| 4358 | missing), and any remaining spawn/stream failure names the exhausted |
| 4359 | resource — disk, file descriptors, memory — and says the next call is safe |
| 4360 | to retry (#5465; the wedge that took out the owner's own 0.9.9 session). |
| 4361 | - A concrete route/offering output limit now outranks the conservative |
| 4362 | 8,192-token compatibility guess for an uncatalogued model. Routes that |
| 4363 | publish no output limit remain fail-closed, documented model ceilings stay |
| 4364 | authoritative, and a route limit can never raise the requested cap (#5460). |
| 4365 | - Context-window honesty at every surface (#5239, #5441): the |
| 4366 | `model-name hint` and `fallback` rungs of the context-window ladder are |
| 4367 | guesses, and every surface that renders one now says so — the status line, |
| 4368 | `/status`, `/config`, the context-pressure message, the model picker chips, |
| 4369 | and the auto-router inventory. Unverified windows still drive real budgets |
| 4370 | (compaction trigger, context meter, output reservation); they just stop |
| 4371 | reading as capabilities anyone checked. A window parsed from an `_Nk` |
| 4372 | model-name suffix (`qwen3-32b-256k` → 256K) is now its own |
| 4373 | `model-name hint` rung below `catalog`, because it is optimistic rather |
| 4374 | than conservative — a catalog or provider-reported value beats it. The |
| 4375 | `[providers.<name>] context_window` override remains the hard fix and |
| 4376 | renders as `configured` with no marker. |
| 4377 | - Output-ceiling honesty (#5440): an Anthropic-family model the catalog does |
| 4378 | not describe keeps the 64K Messages floor as its clamp and the ChatGPT/ |
| 4379 | Codex OAuth route keeps its 4K policy, but `OutputCeilingSource` gained an |
| 4380 | `unverified` rung for both, so exec-stream receipts and the model picker |
| 4381 | label them `unverified`/"assumed floor" instead of `documented`. Clamp |
| 4382 | values are unchanged. |
| 4383 | - Telemetry default-on is visible (#5441): `codewhale doctor`'s |
| 4384 | runtime-posture section gained a `telemetry=on (default)`-style row with |
| 4385 | the source that decided it (cli | env | config | default), and |
| 4386 | `codewhale config get telemetry` reports the resolved consent with its |
| 4387 | source instead of `key not found` on a machine whose batches ship. Truth |
| 4388 | change only; resolution and behavior are untouched. |
| 4389 | - Fleet: a scout's read-only shell carve-out (#5428) is now honored by both |
| 4390 | the posture gate and the execution envelope, so `git log`, `find | head`, |
| 4391 | `npm view` and the other bounded read-only commands run in-place instead |
| 4392 | of being refused as "Executes" (#5426). Delegation still never widens |
| 4393 | authority: the role-isolation test and docs/SUBAGENTS.md pin that a child |
| 4394 | cannot exceed its parent's posture (#5426, #5435). |
| 4395 | - `/rename` and `/title` now apply mid-first-turn: the session file does |
| 4396 | not exist until the first autosave, so the rename fell through with |
| 4397 | NotFound; the shared path now prefers the per-session checkpoint and |
| 4398 | rebuilds from App state, with a PTY regression test through the live |
| 4399 | event loop (#5430). |
| 4400 | - `integrations dsh plan` no longer refuses DeepSeek's default |
| 4401 | Responses-dialect route (`deepseek-v4-flash`); Responses and |
| 4402 | Anthropic-Messages routes are carried through pi-ai |
| 4403 | `openai-responses` / `anthropic-messages` instead of being approximated |
| 4404 | or refused; only credentialed base URLs are still refused, with an error |
| 4405 | that names provider and model (#5434). |
| 4406 | - Session cost no longer sits at `unverified_live_pricing` when live pricing |
| 4407 | cannot be verified (control-plane 503, Models.dev capabilities-only |
| 4408 | overlays): provider-docs bundled fallback rates for the DeepSeek V4 |
| 4409 | family on Fireworks / OpenCode Zen restore a usable figure, live |
| 4410 | per-provider rows still win, and `kimi-k3` stays unpriced until a |
| 4411 | published rate exists (#5241; harvested from #5402). |
| 4412 | - Release assets: `release.yml` asset-freshness checks compare against the |
| 4413 | release job's own `started_at`, so job-level reruns of the npm step are no |
| 4414 | longer poisoned by earlier uploads (#5429). |
| 4415 | - macOS CI: the `agent_focus_pty` auto-review receipt test waited on a |
| 4416 | worker that had already completed and raced the rail's focus; it now holds |
| 4417 | the child's wrap-up and waits for a settled live row (refs #5056, #5403). |
| 4418 | - DeepSeek V4 pricing follows the published peak/off-peak tiers (peak |
| 4419 | 01:00–04:00 and 06:00–10:00 UTC; off-peak is half of peak) for |
| 4420 | `deepseek-v4-flash` and `deepseek-v4-pro` in USD and CNY, resolved from |
| 4421 | each turn's recorded time; the stale single-tier rows understated cost up |
| 4422 | to ~4×. Because every direct DeepSeek first-party rate is now |
| 4423 | time-windowed, the scorecard fails closed (`missing_recorded_time`) on an |
| 4424 | undated DeepSeek turn instead of guessing a tier (#5470; #5241 follow-up, |
| 4425 | verified against api-docs.deepseek.com on 2026-08-17). |
| 4426 | - SSE UTF-8 split across HTTP/2 DATA frames now fails closed in every |
| 4427 | streaming dialect: a shared strict decoder, tail flush, and |
| 4428 | `decode_failed` propagation (`InvalidSseUtf8`) replace the per-dialect |
| 4429 | approximations, with byte-chunk decoder tests (#5374; supersedes draft |
| 4430 | #5404). |
| 4431 | - CI: `release_four_read_only_fleet_roles_launch_with_canonical_prompts` |
| 4432 | answered Fleet children with SSE while they call the blocking JSON path; |
| 4433 | the parse failure was retried and double-counted the worker on slow macOS |
| 4434 | runners (#5471; refs #5056). |
| 4435 | - Context: every web tool surface (`Web`, `web_search`, `web.run`, |
| 4436 | `fetch_url`) now uses the noisy-result soft limit, so large fetches are |
| 4437 | compacted like shell output instead of consuming the ordinary hard limit |
| 4438 | (#5474, thanks @h3c-hexin). |
| 4439 | - Routing: a lowercase saved selector such as `glm-5.2` resolves against the |
| 4440 | owning Z.ai / DeepSeek catalog row (case-fold fallback, only when exactly |
| 4441 | one provider-owned wire id matches) instead of being classified as another |
| 4442 | provider's bare model (#5475, thanks @h3c-hexin; diagnosis by @asto18089 |
| 4443 | in Pinvou/CodeWhale#14). |
| 4444 | - Model catalog brought current as of 2026-08-17 against the official |
| 4445 | pricing pages: gpt-5.6-terra / gpt-5.6-luna rates, `claude-sonnet-5` keeps |
| 4446 | $2/$10 (the announced September increase was withdrawn), `claude-opus-5` |
| 4447 | added, `kimi-k3` and `kimi-k2.7-code-highspeed`, `MiniMax-M2.7-highspeed`, |
| 4448 | Mistral first-party rows, xAI `grok-4.5` / `grok-4.3` with long-context |
| 4449 | tiers, Gemini and Qwen limits, and RedNote's `dots3-note` preview as an |
| 4450 | OpenRouter row (no first-party API exists yet) — every number carries its |
| 4451 | source and a pinned test (#5485). |
| 4452 | - Website: copy on codewhale.net rewritten in plain declarative sentences — |
| 4453 | one idea per sentence, numbers from the generated facts, no self-narration |
| 4454 | — with a voice sheet at docs/design/WEB_VOICE.md (#5483). |
| 4455 | - CI: the release workflows no longer restore npm/cargo caches after |
| 4456 | checking out a caller-supplied SHA — the CodeQL cache-poisoning Highs |
| 4457 | #88–#107 are closed with a contract test over the workflow files (#5463). |
| 4458 | - Compact TUI rows below 60 columns no longer reserve a hidden session-metrics |
| 4459 | strip, so narrow terminals reclaim the row instead of clipping the |
| 4460 | transcript (#5486). |
| 4461 | - Ghostty's truecolor underwater field now uses a dedicated synchronized |
| 4462 | 60 FPS lane instead of the legacy 30 FPS compatibility cap, with continuous |
| 4463 | caustic fades replacing visibly stepped color changes. |
| 4464 | - Live reasoning's advertised `Space:expand` action now runs before the |
| 4465 | composer's first-character paste-burst hold, while spaces in an active paste |
| 4466 | remain payload. The newest reasoning preview also spends only genuinely free |
| 4467 | viewport rows before truncating instead of stopping at the fixed 10/12-row |
| 4468 | fallback on roomy terminals. |
| 4469 | - Strict `cargo doc` builds no longer fail on bare URLs in rustdoc comments; |
| 4470 | the remaining links are explicit Markdown targets (#5489). |
| 4471 | |
| 4472 | ### Changed |
| 4473 | |
| 4474 | |
| 4475 | - The model-facing `agent` tool advertises exactly 12 fields — `action`, |
| 4476 | `prompt`, `type`, `profile`, `name`, `agent_id`, `message`, `until`, |
| 4477 | `detached`, `worktree`, `write_roots`, `resume_from` — down from 33 |
| 4478 | (#5324, refs #5123). Budgets (`max_steps`, `wall_time_secs`, `max_depth`), |
| 4479 | routing overrides (`model`, `model_strength`, `thinking`), worktree-path |
| 4480 | knobs, the deliberate/spawn-contract fields and the wait/status/interrupt |
| 4481 | extras moved off the advertised schema. Every removed field stays |
| 4482 | parse-accepted and honored unchanged (same contract as `token_budget`), so |
| 4483 | saved transcripts, ACP/MCP clients and Fleet configs replay as-is; the |
| 4484 | #5426/#5435 containment clamps are untouched. Child budgets now resolve |
| 4485 | from role defaults (60/120 turns, 1800 s wall time, unchanged clamps) and |
| 4486 | new `[subagents]` keys `default_max_steps` / `default_wall_time_secs`. |
| 4487 | Because the tool catalog is part of the session-pinned prompt prefix |
| 4488 | (docs/CACHE.md), upgrading re-fills the KV prefix once per session. |
| 4489 | - TUI prose — user messages, assistant answers, and reasoning/thinking — |
| 4490 | now wraps at the full content width on wide terminals, matching |
| 4491 | tool/status cells, instead of stopping at a 105-column rail that left a |
| 4492 | dead right margin on ultrawide displays (#5436). |
| 4493 | - Configured skill prompts are stable across session roots and operating |
| 4494 | systems: only custom configured roots hide their physical path, ordinary |
| 4495 | workspace/global skills keep a discoverable privacy-safe path, warning |
| 4496 | replacements are boundary-aware (including non-UTF-8 Unix paths), and |
| 4497 | Windows separators render as `/`. The skills prompt is also 50 bytes |
| 4498 | leaner without raising a runtime-contract ceiling (#5492, #5473). |
| 4499 | - Auto-router classifier requests accept `[auto.router] timeout_secs`, while |
| 4500 | preserving the existing default when the key is absent (#5494). |
| 4501 | - Every `ci.yml` job now has an explicit 10–90 minute timeout appropriate to |
| 4502 | its workload, bounding stale assigned runners instead of inheriting |
| 4503 | GitHub's six-hour default (#5495). |
| 4504 | - The docs shell and shared web components now route localized copy through |
| 4505 | the typed dictionary spine; these are two incremental phases of #5337, |
| 4506 | not completion of the full epic (#5488, #5490). |
| 4507 | - Dependency: rusqlite 0.40.2 (#5391). |
| 4508 | - Documentation: stale A/B/C-tier references, provider defaults, module |
| 4509 | descriptions, and line anchors now match the current code (#5481). |
| 4510 | |
| 4511 | ### Added |
| 4512 | |
| 4513 | - `[transcript] prose_measure` (positive integer, optional): caps prose |
| 4514 | wrap at N columns for owners who want a bounded reading measure on |
| 4515 | ultrawide terminals. `0` or absent keeps the full width; negative or |
| 4516 | non-integer values are rejected with a clear config error. Tool, diff, |
| 4517 | and status cells never inherit the cap (#5436). |
| 4518 | - Localization: README translations for Français, Deutsch, 繁體中文, हिन्दी, |
| 4519 | Türkçe, Italiano, Polski, العربية and Català join the existing nine |
| 4520 | (#5451); codewhale.net routes fr, de, ca, hi, tr, it, pl and ar (with |
| 4521 | `dir="rtl"` plumbing) as partial locales (#5453). |
| 4522 | - Docs: README Integrations section (incl. the DeepSeek Harness `dsh` plugin |
| 4523 | path, docs/INTEGRATIONS_DSH.md) localized across all READMEs; RFC keeping |
| 4524 | the deterministic-first auto-review hybrid (#5427); Claude Code parity |
| 4525 | reference for agents/workflows/plugins/skills |
| 4526 | (docs/design/CLAUDE_CODE_PARITY.md); config.example.toml / SUBAGENTS.md / |
| 4527 | TOOL_LIFECYCLE.md brought back in line with the code (#5447). |
| 4528 | - `dsh` integration: the Codewhale palette is applied through the bundle |
| 4529 | profile via dsh's documented `overrideTokens` (on by default; |
| 4530 | `codewhale integrations dsh update --skin false` turns it off), replacing |
| 4531 | the 0.9.8 exported-CSS skin that dsh's inline body variables overrode |
| 4532 | (docs/design/DSH_BUNDLE_SKIN.md, docs/INTEGRATIONS_DSH.md) (#5469). |
| 4533 | - `dsh` integration: an ambient ocean scene behind the DSH web UI — slow |
| 4534 | whale silhouettes, a school of `><>` glyph fish, bubbles — drawn on a |
| 4535 | canvas under a translucent veil of the Codewhale palette, plus an explicit |
| 4536 | responsive `WHALE BROTHERS / CODEWHALE × DEEPSEEK HARNESS` lockup; light |
| 4537 | and dark, ~30 fps capped, paused when hidden, a static frame under |
| 4538 | `prefers-reduced-motion`; on by default with the skin, |
| 4539 | `codewhale integrations dsh update --ocean false` turns it off (#5484). |
| 4540 | - Fleet: agent shadowing is visible — a roster-row badge, a Layers block in |
| 4541 | agent detail, and a `doctor` "Fleet roster layers" section (JSON |
| 4542 | `operate_fleet.roster.multi_layer`), in all 15 TUI locales. Layer collapse |
| 4543 | and `[fleet.profiles]` migration stay for 0.9.10 (#5098). |
| 4544 | - Sandbox: bwrap containers get the `--dev/--proc/--tmpfs` essentials plus |
| 4545 | configurable extra roots (`bwrap_ro_roots` / `bwrap_dev_roots`) so |
| 4546 | toolchains that live outside the workspace stay reachable read-only |
| 4547 | (#5410). |
| 4548 | - Tests: `crates/tui/tests/README.md` states the keyless assembled-journey |
| 4549 | rule and maps the Auto-Review guardian acceptance items to the engine |
| 4550 | journeys that exercise them (#5361). |
| 4551 | - OrcaRouter's default endpoint is classified as an aggregator billing |
| 4552 | surface, so pricing and session-cost reporting use the correct billing |
| 4553 | posture instead of treating it as a first-party provider (#5493). |
| 4554 | - Dependencies: ratatui 0.30.2, thiserror 2.0.20. |
| 4555 | |
| 4556 | ### Removed |
| 4557 | |
| 4558 | - `dsh` integration: the exported-CSS skin file and its "skin export" status |
| 4559 | line (superseded by the bundle-applied `overrideTokens` skin, #5469). |
| 4560 | |
| 4561 | ### Contributors |
| 4562 | |
| 4563 | - hexin (@h3c-hexin) — a concrete route/offering output limit outranks the |
| 4564 | 8,192-token compatibility guess for an uncatalogued model (#5461, closes |
| 4565 | #5460); web tool results use the noisy soft limit (#5474); owned direct |
| 4566 | model casing resolves safely (#5475); and configured-skill prompts stay |
| 4567 | stable across ephemeral roots and operating systems (#5492, #5473). |
| 4568 | - Gabriel-Degret (@Gabriel-Degret) — configurable auto-router classifier |
| 4569 | timeout (#5494; first contribution). |
| 4570 | - @asto18089 — diagnosed the Z.ai `glm-5.2` casing collision and wrote the |
| 4571 | first provider-scoped fix in Pinvou/CodeWhale#14 (carried upstream in |
| 4572 | #5475). |
| 4573 | - Reports and reproductions that shaped this release: @hardy922 (context- |
| 4574 | window honesty, #5239), @redstar (bwrap extra roots, #5410), @all-lopezg |
| 4575 | (SSE UTF-8 garbling on DeepSeek Flash, #5374), @alitvak69 (unverified live |
| 4576 | pricing, #5241), and @wuisabel-gif (the macOS filtered-suite hang |
| 4577 | investigation on #5056). |
| 4578 | |
| 4579 | ## [0.9.8] - 2026-08-16 |
| 4580 | |
| 4581 | Codewhale v0.9.8 ships the remaining assigned finish. Remaining web |
| 4582 | settings polish moves to v0.9.9. Prefab third-party templates that have |
| 4583 | a published OpenAI-compatible host ship here (#5350). |
| 4584 | |
| 4585 | ### Fixed |
| 4586 | |
| 4587 | - `sudo` (and `su`/setuid helpers) work again for wheel-group administrators |
| 4588 | who want Codewhale to be able to escalate: the Linux startup hardening's |
| 4589 | irreversible `PR_SET_NO_NEW_PRIVS` flag — inherited by every child process — |
| 4590 | is now skippable with `CODEWHALE_NO_NEW_PRIVS=0` (#5413). The flag stays on |
| 4591 | by default; the no-ptrace and no-core-dump measures are never skipped. |
| 4592 | |
| 4593 | - Abort-class process deaths no longer poison the terminal (#5424). A |
| 4594 | stack overflow, allocation failure, or double panic skips the panic hook |
| 4595 | and every cleanup guard, which is how a v0.9.7 user's mid-turn exit left |
| 4596 | mouse capture leaking SGR sequences into their shell. An |
| 4597 | async-signal-safe handler now restores the terminal modes and appends a |
| 4598 | one-line cause marker to `~/.codewhale/crashes/last-fatal-signal.log` |
| 4599 | before re-raising, keeping the honest 128+signal wait status. A SIGKILL |
| 4600 | (OOM killer) remains uninterceptable by design. |
| 4601 | |
| 4602 | ### Changed |
| 4603 | |
| 4604 | - Prompt-cache prefix is pinned for the session. The tool loop no longer |
| 4605 | recomposes the system prompt from disk on every model step, so an agent |
| 4606 | writing a file no longer busts the provider KV prefix cache mid-turn. The |
| 4607 | system prompt and tool catalog are re-composed only on a declared header |
| 4608 | change (`/model`, mode, goal, session resume), which re-pins under a logged |
| 4609 | reason; an undeclared change is reported as drift and the original pin is |
| 4610 | kept instead of silently becoming the new baseline. Workspace, AGENTS.md, |
| 4611 | skills, memory, and goal drift now reaches the model as one bounded |
| 4612 | `<context_update>` user message at the next user turn — a history append, |
| 4613 | not a header rewrite. `/cache stats` shows the pin reason, the last-miss |
| 4614 | reason, the undeclared-drift count, and the context-update count. See |
| 4615 | [docs/CACHE.md](docs/CACHE.md). |
| 4616 | |
| 4617 | - Plugin compatibility is now per-component. A reviewed, trusted, enabled |
| 4618 | bundle that mixes Skills or MCP with unsupported commands, agents, hooks, |
| 4619 | LSP, native, filesystem-roots, or lifecycle-mutation declarations keeps the |
| 4620 | supported adapters active and reports the rest as inactive (`full` / |
| 4621 | `partial` / `unsupported`). All-unsupported bundles still cannot be enabled. |
| 4622 | The capability hash is now v2 and binds this build's activation policy, so |
| 4623 | older v1 receipts and any later adapter-enablement change fail closed as |
| 4624 | needs-review. Skills and each MCP transport re-request their own capability |
| 4625 | at the consumption boundary. |
| 4626 | |
| 4627 | ### Added |
| 4628 | |
| 4629 | - Opt-in multiline composer mode (`composer_multiline_mode = true`) makes |
| 4630 | Enter insert a newline and Shift+Enter send. Alt+Enter, Ctrl+J, and supported |
| 4631 | Ctrl+Enter/Cmd+Enter behavior stays unchanged (#5345, @AiurArtanis). |
| 4632 | |
| 4633 | - `/plugin marketplace add|list|show|remove|install` completes the |
| 4634 | federated marketplace journey (#5311). `add` reads one LOCAL catalog |
| 4635 | document in the real published schemas (Kimi, Claude, Codex, or |
| 4636 | Codewhale native) — no network, regular files only — and persists it |
| 4637 | beside the plugin state with the same hardened, fail-closed store. |
| 4638 | `list`/`show` render every candidate with per-entry diagnostics, |
| 4639 | display-only tiers, and honest install plans that say when Codewhale |
| 4640 | cannot fetch a source; `install` routes through the existing reviewed |
| 4641 | installer, so installed bundles still enter disabled and untrusted. |
| 4642 | Foreign auto-install policy (Codex `INSTALLED_BY_DEFAULT`) is visibly |
| 4643 | ignored; nothing is auto-installed, auto-trusted, or granted vendor |
| 4644 | trust. |
| 4645 | |
| 4646 | - `/rc` attach now includes an observed `owner/name` git remote when the |
| 4647 | folder has a GitHub, CNB, or Gitee origin, so CWC can label the paired |
| 4648 | session. Paths stay off the wire. Reconnect after both this client and |
| 4649 | CWC #202 land to backfill existing empty rows. |
| 4650 | |
| 4651 | - The local Runtime web client keeps the thread rail clipped so **New |
| 4652 | thread** cannot paint over the session fact chips. Chips wrap instead |
| 4653 | of sliding under the rail. |
| 4654 | |
| 4655 | - Z.ai `GLM-5.3` is live on the Coding Plan and is now the default direct |
| 4656 | Z.ai model: `DEFAULT_ZAI_MODEL` resolves to `GLM-5.3` in both |
| 4657 | `codewhale-tui` and `codewhale-config`, and it is the first `/model` row |
| 4658 | after `/provider zai`. Explicit `GLM-5.2` selections (`model = "GLM-5.2"` |
| 4659 | and its `glm-5.2` aliases) keep their own id — only the default moved. |
| 4660 | Limits and reasoning options still inherit from `GLM-5.2` until Z.ai |
| 4661 | publishes distinct 5.3 numbers. No USD price is claimed. A live call |
| 4662 | can still 429 with entitlement code 1311 on accounts that are not |
| 4663 | provisioned for 5.3. |
| 4664 | |
| 4665 | - The TUI transcript renders Markdown blockquotes (`>` lines) with a quote |
| 4666 | rail — nested quotes, inline bold/code/links, wrapped continuation rows, and |
| 4667 | selection copy that keeps the quote text and skips the rail chrome. |
| 4668 | |
| 4669 | - Sub-agent details show the resolved model, fleet role, and type. Labels |
| 4670 | use the session/role name instead of a generic Agent N (#5371, #5287). |
| 4671 | |
| 4672 | - Documented catalogue output ceilings (including DeepSeek V4's 384K maximum) |
| 4673 | remain authoritative bounds, while ordinary requests start at a safe 64K |
| 4674 | cap and explicit overrides can raise it within the resolved route window. A |
| 4675 | clean output-limit stop continues the turn instead of killing it (#5373, |
| 4676 | #5516, #5518). Thanks @sfdzhmr and @hxfhd for the route evidence. |
| 4677 | |
| 4678 | - Ollama Cloud is a first-class hosted provider (`/provider ollama-cloud`) |
| 4679 | on the official OpenAI-compatible `https://ollama.com/v1` route. Local |
| 4680 | Ollama stays keyless. The exact released `ollama` + Cloud URL tuple keeps |
| 4681 | a bounded compatibility path across saved sessions, Fleet, and nested |
| 4682 | subagents; neighboring remotes stay custom and fail closed against |
| 4683 | inherited official credentials. |
| 4684 | |
| 4685 | - Homebrew ships a `codewhale` formula. `brew tap Hmbown/deepseek-tui && |
| 4686 | brew install codewhale` is the install path; `brew upgrade codewhale` |
| 4687 | updates it. The legacy `deepseek-tui` formula remains a deprecated alias |
| 4688 | for one overlap release. |
| 4689 | |
| 4690 | - `/title [name|off]` sets a per-session tab/window title, shown as |
| 4691 | `[title] …` in front of the terminal window title (`Codewhale` / |
| 4692 | `reasoning…` / `using tool…` / `done`). The `title` config key supplies |
| 4693 | the default (`/config title … --save` persists it); multi-window |
| 4694 | workflows can tell parallel sessions apart at a glance. `/title` is |
| 4695 | independent of `/rename`, which keeps naming the session in the picker |
| 4696 | and composer. Control, bidi, and zero-width format characters are |
| 4697 | stripped from both the saved session name and the window title, so the |
| 4698 | picker, the Runtime API, `codewhale sessions`, and the OSC 0 tab title |
| 4699 | all carry the same escape-free text (#5419, #5430). |
| 4700 | - Eden AI is a named OpenAI-compatible Chat Completions provider (`edenai`, |
| 4701 | aliases `eden-ai` / `eden_ai`) with `EDENAI_API_KEY`, global and EU base-URL |
| 4702 | overrides, a live provider-scoped model catalog, and |
| 4703 | `deepseek/deepseek-v4-pro` as the verified default. Generic reasoning fields |
| 4704 | stay omitted because Eden AI routes multiple upstream model families |
| 4705 | (#5422, Kai Nacke). |
| 4706 | - Children (sub-agents and Fleet workers) inherit the session's permission |
| 4707 | posture faithfully: Auto-Review's deterministic floor and model guardian |
| 4708 | decide a worker's held calls (fail closed when unavailable, never a |
| 4709 | prompt); under Ask a held call is raised in the parent's approval UI and |
| 4710 | the worker waits visibly; Full Access still fails closed on the safety |
| 4711 | floor. Each prompt-less decision is a one-line note in that worker's |
| 4712 | transcript (focus mode) and an audit-log record. |
| 4713 | - Worker role defaults keep what the role does not intend to withhold: |
| 4714 | every built-in role keeps network reads; `planner` may run read-only |
| 4715 | shell probes; `custom` inherits the parent's write/network/shell posture |
| 4716 | and is narrowed only by its explicit tool list or the spawning call. |
| 4717 | Read-only roles (`scout`, `reviewer`, `planner`, `verifier`, |
| 4718 | `consultant`) still never write the workspace. The focused worker's |
| 4719 | header states its effective posture from the runtime snapshot. |
| 4720 | - `/workflow status`, `/workflow cancel [run_id]`, `/workflow settings`, and |
| 4721 | `/workflow help` are answered by Codewhale itself from the run journal and |
| 4722 | live run state — no model turn — and `/workflow run <path>` launches a |
| 4723 | checked-in workflow as-is. `/config workflow` and `/config goal` explain |
| 4724 | the effective tables. The workflow tool now honors the session `[workflow]` |
| 4725 | table (`automatic`, `auto_start_read_only`, `require_approval_for_writes`, |
| 4726 | limits) instead of product defaults. |
| 4727 | - Goal mode enters as readily as DeepSeek Harness: the agent may create the |
| 4728 | session goal when a direct request describes a verifiable multi-turn end |
| 4729 | state, and Codewhale shows a one-line `Goal set` receipt with how to pause |
| 4730 | or clear it. Bare `/goal` shows plain progress (and how to continue when no |
| 4731 | turn is running), prints usage on an empty session instead of asking the |
| 4732 | model, and `/goal help|status` are reserved words. |
| 4733 | |
| 4734 | - Whale Teams in the terminal: the six Signal Cut whale identities (Scout, |
| 4735 | Patch, Harbor, Echo, Keel, Lantern) appear as species badges on `/fleet` |
| 4736 | roster rows and worker rows, with an identity portrait in the roster detail |
| 4737 | pane and a six-state word (Resting, Thinking, Working, Waiting for you, |
| 4738 | Blocked, Offline) derived only from the child's real runtime status. Colors |
| 4739 | come from the theme tokens, every glyph has an ASCII fallback, and the |
| 4740 | working wake animates only under full motion. See |
| 4741 | `docs/design/WHALE_TEAMS_TUI.md`. |
| 4742 | - A session metrics strip on the phase row (`4 turns · 108 steps │ LLM |
| 4743 | 11m46s · Tool call 1m52s │ TTFT avg 1.5s · 120 tok/s │ Cache hit 99% │ |
| 4744 | Input 9.3M`), on by default as the `session_metrics` footer item |
| 4745 | (`/statusline`, `[tui].status_items`). Every value comes from engine |
| 4746 | receipts — turn starts, per-model-call usage with stream time, |
| 4747 | time-to-first-token and whole-call time, tool start/complete edges, and |
| 4748 | provider-reported cache and input tokens. Cells without evidence are |
| 4749 | omitted, never estimated. `/status` prints the untrimmed line; the phase |
| 4750 | row sheds its lowest-value groups to fit the columns it actually has. |
| 4751 | - Auto-Review decisions nobody was prompted for are now visible in the |
| 4752 | transcript as one-line notes: model-guardian allow/deny verdicts with |
| 4753 | their risk tier and stated reason, guardian failures (denied, fail |
| 4754 | closed), deterministic policy blocks, and holds Auto-Review denied |
| 4755 | without pausing. The audit log keeps the full record. `/permissions` |
| 4756 | ends with the active posture, what it decides on its own versus never, |
| 4757 | and the audit-log path. The footer's `Esc to interrupt` hint is |
| 4758 | localized. See `docs/design/AUTO_MODE_PARITY.md` for the Claude Code / |
| 4759 | Kimi Code parity ledger and follow-ups. |
| 4760 | - `codewhale integrations dsh status|plan|connect|update|launch|disable|enable|remove` |
| 4761 | connects an existing official DeepSeek Harness (`dsh` 0.1.0-rc.6, verified) |
| 4762 | through Codewhale using only its documented seams: a `--patch` overlay that |
| 4763 | pins the exact Codewhale provider/model/endpoint identity (native |
| 4764 | `deepseek-official` route, or a hand-declared `openai-completions` route |
| 4765 | named `codewhale-<provider>` for OpenAI-compatible providers), the |
| 4766 | Codewhale permission posture exported as `DSH_PERMISSION_MODE`, and an |
| 4767 | append-only receipt. Codewhale writes only under |
| 4768 | `$CODEWHALE_HOME/integrations/dsh/`, never copies API keys or edits DSH |
| 4769 | files, never broadens permissions (`--allow-full-access` only mirrors an |
| 4770 | existing Codewhale full-access posture), and reports not-installed / |
| 4771 | offline / incompatible / detected / connected / stale-config / |
| 4772 | stale-version / disabled honestly. Anthropic Messages and OpenAI Responses |
| 4773 | routes are refused as not carriable. The documented DSH plugin path is an |
| 4774 | explicit opt-in: `install-bundle` materializes a Codewhale bundle package |
| 4775 | (`codewhale-dsh-bundle`, MIT notice retained) and installs it with |
| 4776 | `dsh plugin --profile codewhale add <path>` into a dedicated `codewhale` |
| 4777 | profile (pnpm required, reported truthfully when missing; `web`/`headless` |
| 4778 | untouched), so `dsh --profile codewhale` alone carries the identity; |
| 4779 | `update` regenerates the bundle patch and `remove-bundle` reverses it, |
| 4780 | leaving the DSH-owned profile directory in place. `/setup tools` and `codewhale doctor` |
| 4781 | show the read-only detection state; `doctor` also lists the DSH read-only |
| 4782 | credential consent alongside Codex and Grok. The optional `--skin` export |
| 4783 | writes a Codewhale token stylesheet generated from the TUI palette |
| 4784 | (Blue Stage dark/light, ombre water column, mode/permission/state colors, |
| 4785 | reduced-motion fallbacks); DSH exposes no custom-theme API, so the sheet is |
| 4786 | labeled an unsupported overlay and is never injected. See |
| 4787 | `docs/INTEGRATIONS_DSH.md`. |
| 4788 | |
| 4789 | ### Fixed |
| 4790 | |
| 4791 | - Selecting the `google` provider kind resolved to the `antigravity` |
| 4792 | TUI identity (and vice versa): the agy provider entry was inserted at |
| 4793 | different positions in the config-level enum and the TUI's |
| 4794 | discriminant-indexed lookup table. The table now matches the enum, so |
| 4795 | provider pickers, sorted display, and kind round-trips are correct. |
| 4796 | |
| 4797 | - The provider picker's key-entry stage accepted typed input and pastes |
| 4798 | for OAuth-only providers after `antigravity` declared OAuth |
| 4799 | acquisition; those gates now key off the OAuth acquisition class |
| 4800 | instead of a hard-coded provider identity. |
| 4801 | |
| 4802 | - The webhook hook sink no longer panics when its HTTP client fails to |
| 4803 | build; it falls back to a default client (#5381, EvanProgramming). |
| 4804 | |
| 4805 | - Session-index JSONL writes are serialized behind a process-wide mutex |
| 4806 | so concurrent state stores cannot drop an append during compaction |
| 4807 | (#5382, EvanProgramming; complements the cross-process file lock). |
| 4808 | |
| 4809 | - A billed `max_tokens` stop followed by a transport error fails the turn |
| 4810 | instead of continuing into a second request. A clean output-limit stop |
| 4811 | still continues. Mid-size context windows keep the ordinary 65K internal |
| 4812 | reservation so compaction does not collapse to the 1K headroom floor |
| 4813 | when the catalogue documents a matching output ceiling. |
| 4814 | |
| 4815 | - Thinking cycle, `/effort`, and Settings now walk each model's real ladder |
| 4816 | instead of the DeepSeek off/high/max shortcut. Grok 4.6 is |
| 4817 | auto/low/medium/high/xhigh (cannot disable); Grok 4.5 is |
| 4818 | auto/low/medium/high; first-party DeepSeek keeps a documented `low` tier. |
| 4819 | `/effort` persists and receipts through the same path as Ctrl+T. |
| 4820 | |
| 4821 | - Google Gemini is its own backend (`/provider google`) on the official |
| 4822 | OpenAI-compatible route with thought-signature capture/replay and |
| 4823 | fail-closed replay for thinking models. Antigravity (`agy` 1.1.13) is |
| 4824 | a separate provider: consent-gated read-only import of the official |
| 4825 | CLI's login, then a text-only cloud-code stream |
| 4826 | (`/v1internal:streamGenerateContent`). Tools, images, and unknown SSE |
| 4827 | shapes fail closed. Gemini 3.7 Flash is not advertised until a live |
| 4828 | turn succeeds on this wire. The website 44-count still excludes |
| 4829 | Antigravity. |
| 4830 | |
| 4831 | - DeepSeek Flash SSE on macOS no longer turns mid-character HTTP/2 |
| 4832 | flushes into U+FFFD replacement characters (#5374). Invalid UTF-8 |
| 4833 | fails the line instead of using lossy decode. |
| 4834 | |
| 4835 | - `[workshop] read_result_max_bytes` and `tool_result_max_bytes` raise |
| 4836 | the model-visible read/tool-result floor; they never lower the |
| 4837 | compile-time defaults and cap at 2MiB (#5367). |
| 4838 | |
| 4839 | - Fireworks and OpenCode Zen DeepSeek V4 Flash/Pro keep a bundled |
| 4840 | family rate when the live control plane is down, so session cost is |
| 4841 | not stuck on `unverified_live_pricing` (#5241). `kimi-k3` stays |
| 4842 | unpriced until a published rate exists. |
| 4843 | |
| 4844 | - Provider setup ships a typed beginner template catalog (#5350). OpenCode |
| 4845 | Zen/Go stay first-class key-only rows with their documented hosts and |
| 4846 | curated models. SenseNova fills a named OpenAI-compatible table on the |
| 4847 | published `https://token.sensenova.cn/v1` host (`S` or `/provider setup |
| 4848 | sensenova`). Agnes is listed as unpublished because this repository has |
| 4849 | no published URL. `/provider` `P` and Settings → beginner templates open |
| 4850 | the list; `T` tests `/models` and refreshes status without treating 2xx |
| 4851 | as model-ready. `/model` names a failed Models.dev refresh as |
| 4852 | `refresh failed; catalog available` instead of `cache failed`. |
| 4853 | |
| 4854 | - Privileged release workflows no longer restore rust-cache, sccache, |
| 4855 | or npm caches after checking out a caller-supplied SHA (CodeQL |
| 4856 | cache-poisoning #88–#106). Catalog drift no longer prints raw |
| 4857 | bundled/upstream blobs (#107). |
| 4858 | |
| 4859 | - Cancelling a turn now cancels its foreground child agents with it. |
| 4860 | |
| 4861 | - Empty compaction no longer wipes conversation history. |
| 4862 | |
| 4863 | - Wide terminals and tmux panes fill the full available width again for the |
| 4864 | transcript and composer (#5322). The brief v0.9 session-shell side gutter |
| 4865 | is gone so expanding a pane rematerializes layout the same way shrinking |
| 4866 | does. |
| 4867 | |
| 4868 | - The agent tool schema rejects empty calls. |
| 4869 | |
| 4870 | - The local web client keeps recovered stream gaps closed, user questions |
| 4871 | answerable, manual bootstrap access intact, and streamed prose quiet for |
| 4872 | assistive tech. |
| 4873 | |
| 4874 | - Website zh-Hans copy now says 宪章, matching the TUI pack (#5397, |
| 4875 | Lstarsky0). |
| 4876 | |
| 4877 | - Public website provider facts include Google Gemini and Ollama Cloud |
| 4878 | (44 runnable routes). Antigravity stays credential-plane-only. |
| 4879 | Harvested from #5398 (Lstarsky0) with that correction. |
| 4880 | |
| 4881 | - The website models page carries a truthful read-only settings preview |
| 4882 | built from repository facts; it never implies the site can change local |
| 4883 | configuration (#5370, #5411, mvanhorn). |
| 4884 | |
| 4885 | - The canonical `ultra` reasoning effort now maps to each provider's |
| 4886 | maximum tier alongside the legacy `ultracode` alias, instead of being |
| 4887 | silently dropped (#5303, #5409, buiducnhat). |
| 4888 | |
| 4889 | - Session titles truncate by character count, not byte offset, so |
| 4890 | multi-byte titles (CJK, emoji) cut at the intended width and word |
| 4891 | boundary instead of past the limit (#5415). |
| 4892 | - Wide terminals and tmux panes fill the full available width again for the |
| 4893 | transcript and composer (#5322). The brief v0.9 session-shell side gutter is |
| 4894 | gone so expanding a pane rematerializes layout the same way shrinking does. |
| 4895 | - The background verifier test drives the current libtest executable |
| 4896 | instead of the rustup `rustc` shim, so the TUI suite no longer depends |
| 4897 | on `$HOME` or holds the process-wide test environment lock across an |
| 4898 | async wait (#5056, #5423, Isabel Wu). |
| 4899 | |
| 4900 | ### Removed |
| 4901 | |
| 4902 | - The source-structure budget ratchet (CI step, checker, baseline JSON). |
| 4903 | It measured line counts, not quality: every legitimate feature required |
| 4904 | a hand-edited ceiling and the accompanying "review" was self-review, so |
| 4905 | it bought ceremony, not protection. Behavior-measuring gates (dead-code, |
| 4906 | runtime-contract, persistence-backlog) stay enforced. |
| 4907 | - DeepSeek can reuse a key already stored by official DeepSeek Harness |
| 4908 | (`dsh`) after |
| 4909 | `codewhale auth external-consent --provider deepseek --mode read-only`. |
| 4910 | Codewhale reads only `DEEPSEEK_API_KEY` from the exact granted |
| 4911 | `$DSH_HOME/.credentials.yaml` and never writes or refreshes that file. |
| 4912 | - The TUI markdown parser now honors CommonMark fence-length rules: a ```` |
| 4913 | opener is not closed by a shorter ``` line, so `>` content inside a longer |
| 4914 | fence stays literal code instead of escaping into a quote. |
| 4915 | - Sub-agents finalize when the parent session id changes, so a closed |
| 4916 | session cannot block new children as a live owner (#5372). |
| 4917 | - Child spawn-route receipts stay live and usage is deduped by response |
| 4918 | (#5366). |
| 4919 | - Doctor keeps persisted setup readiness across first-run / update |
| 4920 | checkpoints (#5340). |
| 4921 | - Approval default selection is applied and explained; agents are told |
| 4922 | when approvals are disabled (#5293). |
| 4923 | - A `/models` 2xx probe is a connection check, not model readiness. |
| 4924 | - Site layout uses one container, the ticker no longer implies false |
| 4925 | provider readiness, and install links stay in the active locale. |
| 4926 | |
| 4927 | ### Contributors |
| 4928 | |
| 4929 | - EvanProgramming (@EvanProgramming) — webhook client panic fallback |
| 4930 | (#5381); session-index JSONL mutex (#5382). |
| 4931 | - Lstarsky0 (@Lstarsky0) — session peek hides internal runtime events |
| 4932 | (#5376); thinking-ladder test re-pin (#5378); provider-count follow-ups |
| 4933 | (#5383/#5384); macOS agy fixture canonicalization (#5392); zh-Hans 宪章 |
| 4934 | terminology (#5397); regenerated website facts harvested and corrected |
| 4935 | from #5398. |
| 4936 | - Matt Van Horn (@mvanhorn) — read-only models settings preview on the |
| 4937 | website (#5411, fixes #5370). |
| 4938 | - Nhat Bui (@buiducnhat) — canonical `ultra` reasoning effort mapped across |
| 4939 | provider effort tables (#5409); session titles truncated by character |
| 4940 | count, not byte offset (#5415). |
| 4941 | - Sh1Zuku (@SparkofSpike) — `/title` and the session name in the terminal |
| 4942 | tab/window title, plus the mid-turn title deadlock fix (#5419). |
| 4943 | - Kai Nacke (@redstar) — Eden AI provider registration, aliases, |
| 4944 | `EDENAI_API_KEY`, and the global/EU endpoints (#5422). |
| 4945 | - Isabel Wu (@wuisabel-gif) — background verifier test isolated from |
| 4946 | rustup and `$HOME` (#5423, slice of #5056). |
| 4947 | |
| 4948 | ## [0.9.7] - 2026-08-12 |
| 4949 | |
| 4950 | Codewhale v0.9.7 keeps the catalog ordinary. Grok 4.6 lands as a normal catalog |
| 4951 | row instead of a provider-shaped pile of special cases, OrcaRouter joins as a |
| 4952 | named provider, and a panic-safety advisory in `lru` is cleared by lifting the |
| 4953 | pin that caused it rather than living around it. |
| 4954 | |
| 4955 | ### Added |
| 4956 | |
| 4957 | - Grok 4.6 is the direct xAI default, with the `grok` alias moving onto it and |
| 4958 | `grok-4.5` still explicitly selectable. Its 500K context, text/image input, |
| 4959 | tool and structured-output support, `low`/`medium`/`high`/`xhigh` reasoning |
| 4960 | efforts (default `high`), and server-side web search all come from the |
| 4961 | Models.dev-shaped catalog rather than model-specific code. `reasoning_effort` |
| 4962 | reaches the wire only on the exact first-party `https://api.x.ai/v1` route, |
| 4963 | and the usage-aware 200K-token pricing boundary is scoped to direct xAI so |
| 4964 | aggregator routes reusing the model slug cannot inherit xAI billing. |
| 4965 | - OrcaRouter is a first-class named provider: `ORCAROUTER_API_KEY`, default base |
| 4966 | URL `https://api.orcarouter.ai/v1`, `deepseek/deepseek-v4-pro` default, |
| 4967 | `orcarouter/auto` routing, CLI `--provider` selector, and TUI picker entries |
| 4968 | (#5321). |
| 4969 | |
| 4970 | ### Changed |
| 4971 | |
| 4972 | - Reasoning-effort normalization and the model picker read a model's published |
| 4973 | `reasoning_options` list from the catalog instead of collapsing every route to |
| 4974 | the historic Low/Medium ladder. Any catalog row that publishes an effort list |
| 4975 | keeps its own vocabulary. |
| 4976 | - Docs record DeepSeek's live `DeepSeek-V4-Pro-0813` backend label while the |
| 4977 | callable API ID stays `deepseek-v4-pro`. No aliases are remapped and no |
| 4978 | `deepseek-v4-pro[1m]` selector is sent. |
| 4979 | |
| 4980 | ### Fixed |
| 4981 | |
| 4982 | - Auto-Review once again executes proven read/build/test shell commands and |
| 4983 | bounded workspace writes without opening an approval modal. Explicit policy |
| 4984 | blocks, unknown tools, publish operations, secret actions, MCP mutations, |
| 4985 | and shell commands requiring approval still fail closed (#5323; reported by |
| 4986 | USTHzhanglu and root-caused by Lstarsky0). |
| 4987 | - Copying a user or assistant message takes its canonical content instead of |
| 4988 | reserialized transcript lines, keeping role glyphs, continuation rails, and |
| 4989 | visual wrapping out of the clipboard while preserving authored Unicode, |
| 4990 | Markdown, and hard line breaks. Tool and Thinking cells stay on the existing |
| 4991 | full-transcript path (#5319). |
| 4992 | - `load_session` no longer runs crash recovery on every read. Snapshot reads go |
| 4993 | through a side-effect-free `load_session_snapshot` and recovery is explicit |
| 4994 | via `recover_session_for_resume`, so an embedding host inspecting a durable |
| 4995 | session while a tool is still running no longer gets a spurious crash repair |
| 4996 | (#5320). |
| 4997 | |
| 4998 | ### Security |
| 4999 | |
| 5000 | - `lru` moves to 0.18 to clear RUSTSEC-2026-0253, where `LruCache::pop()` was |
| 5001 | not panic-safe and could leave dangling list pointers. The `ratatui-core` |
| 5002 | `=0.1.0` pin that transitively forced `lru` ^0.16 is lifted, so |
| 5003 | `ColorCompatBackend` now answers `get_cursor_position()` from tracked cursor |
| 5004 | state — the upstream-recommended workaround for the startup CPR race |
| 5005 | (ratatui/ratatui#2483, ratatui/ratatui#2640) that the pin originally worked |
| 5006 | around. `ratatui` itself stays pinned at `=0.30.0`, so the API surface is |
| 5007 | unchanged. |
| 5008 | |
| 5009 | ### Known issues |
| 5010 | |
| 5011 | - The integration test |
| 5012 | `exec_persistent_service::failed_exec_kills_pending_service_and_exits_nonzero` |
| 5013 | is a confirmed flake under parallel load ("service pid file never appeared"). |
| 5014 | It passes in isolation and is unrelated to any v0.9.7 change. |
| 5015 | |
| 5016 | ### Contributors |
| 5017 | |
| 5018 | - XhesicaFrost (@XhesicaFrost) — canonical message copy (#5319). |
| 5019 | - h3c-hexin (@h3c-hexin) — session snapshot and crash-recovery split (#5320). |
| 5020 | - XiaoHuo888-hue (@XiaoHuo888-hue) — OrcaRouter provider registration (#5321). |
| 5021 | - USTHzhanglu (@USTHzhanglu) — Auto-Review regression report and Windows |
| 5022 | evidence (#5323). |
| 5023 | - Lstarsky0 (@Lstarsky0) — Auto-Review regression root-cause analysis (#5323). |
| 5024 | |
| 5025 | ## [0.9.6] - 2026-08-11 |
| 5026 | |
| 5027 | Codewhale v0.9.6 is a subtractive release: fewer runtime guards, one stable |
| 5028 | prompt, truthful provider endings, and a smaller compaction path that preserves |
| 5029 | the provider cache. The changes were grounded by matched Terminal-Bench 2.1 |
| 5030 | runs against Pi 0.8.41 and by dogfooding repeated manual compaction. |
| 5031 | |
| 5032 | ### Added |
| 5033 | |
| 5034 | - `web_search` defaults to Firecrawl Cloud without an API key; keyless requests |
| 5035 | are headerless and quota-bounded, while an optional user key raises limits. |
| 5036 | - Green web builds on `main` now emit an actionable manual-deploy reminder, so |
| 5037 | site changes cannot quietly appear shipped while Cloudflare still serves an |
| 5038 | older revision. |
| 5039 | - Mistral AI is a first-class provider route, including Codestral models, |
| 5040 | first-party reasoning support, authentication, picker entries, and aliases. |
| 5041 | - Headless `Bash` can transfer explicitly requested persistent Unix services |
| 5042 | out of an exec run, with ownership and cleanup receipts. |
| 5043 | - `/remote-env` opens hosted Work from the current GitHub or CNB branch tip and |
| 5044 | states exactly which unpushed, dirty, ignored, secret, and session state stays |
| 5045 | local. |
| 5046 | - Linux ARM64 release and nightly assets are static musl builds with native |
| 5047 | launch checks. |
| 5048 | - Maintainers can report observed daily active installs from the same anonymous, |
| 5049 | aggregate telemetry dataset; no additional client data is collected. |
| 5050 | - Fleet-dispatched members under a read-only evidence (no-network) ceiling now |
| 5051 | keep the `Web` tool's read-only `search` and `fetch` actions — parity with an |
| 5052 | ordinary scout — while every reaching surface (`web.run`, `fetch_url`, |
| 5053 | `github`, MCP) stays denied and the sentinel-backed capability envelope |
| 5054 | remains the fail-closed backstop. |
| 5055 | - `/fleet setup` can show an optional, deterministic, unratified role-to-model |
| 5056 | advisory built only from configured ready routes. Accept, edit, and reject |
| 5057 | all remain inside the existing human-reviewed profile save boundary; the |
| 5058 | advisory never launches a Fleet or writes a second configuration. |
| 5059 | - `/update` checks for a newer Codewhale release and installs it from inside |
| 5060 | the TUI, while `tui_help` gives agents the same command and key map users see. |
| 5061 | - Markdown file paths render as OSC 8 links where the terminal supports them, |
| 5062 | and every agent row can open that agent's transcript directly. |
| 5063 | - ACP editor sessions can execute multi-round file, search, Git, patch, and |
| 5064 | explicitly enabled shell tool calls through the shared Runtime registry. |
| 5065 | Shell access requires both the client's terminal capability and Codewhale's |
| 5066 | headless shell opt-in, and cancellation stops an in-flight tool before the |
| 5067 | turn returns (#5225 by @rafaelcavalheri). |
| 5068 | - Lowercase `read` returns bounded typed PNG, JPEG, GIF, and WebP results to |
| 5069 | image-capable Chat, Responses, Anthropic, and ACP routes. Text-only routes |
| 5070 | receive an explicit omission receipt; image bytes never spill into ordinary |
| 5071 | transcript, export, compaction, or relay text. |
| 5072 | |
| 5073 | ### Changed |
| 5074 | |
| 5075 | - Anonymous usage counting is on by default for fresh installs and disclosed in |
| 5076 | a native first-run Codewhale modal with an immediate opt-out. Prior declines |
| 5077 | remain off. Codewhale does not collect conversations, code, prompts, files, |
| 5078 | repo or branch names, credentials, model content, or per-turn activity |
| 5079 | timelines. |
| 5080 | - Wide terminals use a responsive, full-screen ocean canvas with modest |
| 5081 | gutters: prose keeps a readable measure while tools, diffs, work surfaces, |
| 5082 | the composer, and status chrome can use the available width. Turn and major |
| 5083 | activity seams breathe without padding every call inside a tool group. |
| 5084 | - Root CLI help describes product actions directly instead of exposing internal |
| 5085 | TUI/runtime layers. |
| 5086 | - `Bash action="wait"` now blocks by default when a wait is requested; callers |
| 5087 | can still ask for a nonblocking snapshot, and persistent service ownership |
| 5088 | remains explicit. |
| 5089 | - Compaction is one cache-stable summary request followed by one committed |
| 5090 | replacement summary and a bounded recent-message tail. Older saved sessions |
| 5091 | still restore. |
| 5092 | - Ask, Work, Auto-Review, and Full Access share one stable base prompt. Modes |
| 5093 | continue to differ through permissions and the live tool catalog; the former |
| 5094 | Act label is now Work throughout the product and shipped locales. |
| 5095 | - Full Access now auto-approves non-bypassable tools consistently, and the |
| 5096 | default choice shown on ordinary approval cards is configurable. |
| 5097 | - Model, context-window, dispatch-name, and nested-agent spawn receipts report |
| 5098 | the route and limits actually used rather than silently substituting a |
| 5099 | guessed identity. |
| 5100 | - Child-agent launches mint one immutable route receipt before admission and |
| 5101 | preserve it through status, interruption, completion, resume, Work Graph, |
| 5102 | and ledger projections, so provider/model attribution cannot drift (#5305). |
| 5103 | - Goal runs no longer stop because of internal continuation, repeated-gap, or |
| 5104 | unanswered-question guards. Explicit user limits and terminal goal states |
| 5105 | remain authoritative. |
| 5106 | - Account-owned `/rc` remote control now keeps exclusive ownership and a |
| 5107 | crash-recoverable delivery journal until the server acknowledges terminal, |
| 5108 | approval, failure, and snapshot state. |
| 5109 | - `todo_write` is an optional progress surface rather than required model |
| 5110 | ceremony. |
| 5111 | - New turns use one small, stable toolbox: `read`, `write`, `edit`, `bash`, |
| 5112 | `agent`, `todo_write`, and `tool_search`. The optional progress tool stays |
| 5113 | visible as familiar working memory; specialized native, Web, MCP, plugin, |
| 5114 | memory, task, and verification tools are policy-filtered and searchable; |
| 5115 | activated schemas stay in a bounded per-conversation cache. Every sub-agent |
| 5116 | keeps its own search and cache, including policy-allowed Web research, while |
| 5117 | forked context and parent activations remain warm starts rather than allowlists. |
| 5118 | - The direct file and shell schemas follow Pi's deliberately small contract: |
| 5119 | bounded complete-line reads, hash-free writes, unambiguous multi-edit with |
| 5120 | BOM/CRLF preservation and conservative fuzzy matching, and one foreground |
| 5121 | `bash` command with a bounded chronological output tail. Modes change |
| 5122 | execution authority, not those primitive names. |
| 5123 | - Codewhale no longer re-states the To-do list to the model. The model learns |
| 5124 | what is on the list from the tool result its own `todo_write` call returned, |
| 5125 | which is ordinary conversation history — the same way Pi's To-do works. The |
| 5126 | transient `<codewhale:work_state>` block that used to ride the tail of every |
| 5127 | parent turn-loop and sub-agent step request is gone, along with the stable |
| 5128 | system prefix being disturbed by list changes. A snapshot is still shown once, |
| 5129 | where a person asked for it: the `<codewhale:fork_state>` block a newly forked |
| 5130 | sub-agent is handed, `/relay` handoff instructions, and the agent card. The |
| 5131 | complete To-do stays visible in the UI. A structural test asserts real |
| 5132 | outbound provider request bodies do not carry the list. |
| 5133 | - Scout and Reviewer name the read-only investigator roles. Both expose exactly |
| 5134 | one shell entry point — canonical lowercase `bash`, bounded by the strict |
| 5135 | read-only classifier — and the legacy `Bash` alias stays denied in the catalog |
| 5136 | and at dispatch. Previously a case-insensitive name match let a call spelled |
| 5137 | `Bash` execute through that carve-out, returning raw shell to a read-only role. |
| 5138 | |
| 5139 | ### Fixed |
| 5140 | |
| 5141 | - Sending more context while a lowercase `bash` command is running now moves |
| 5142 | the command to `/jobs` and returns a successful running receipt instead of |
| 5143 | falsely reporting `Command exited with code -1`; the process keeps running |
| 5144 | and its completion still arrives through the normal runtime event. |
| 5145 | |
| 5146 | - First-run usage disclosure now opens as a native Codewhale modal instead of a |
| 5147 | shell questionnaire before application startup. Telemetry remains unarmed |
| 5148 | until the native choice is made, and an in-memory Disable choice governs the |
| 5149 | current session even when its preference cannot be saved. |
| 5150 | - `/compact` completion, failure, queued, duplicate, and mailbox outcomes are |
| 5151 | durable transcript receipts instead of short-lived toasts. A stray terminal |
| 5152 | event can no longer leave every later compaction stuck as already running. |
| 5153 | - Compaction now follows Codex's simple transcript shape: recent user context |
| 5154 | followed by one ordinary history checkpoint. It never appends the summary, |
| 5155 | the To-do list, or volatile shell/worker state to the standing system prompt; |
| 5156 | reloads migrate the persisted carrier back into exactly one history item. |
| 5157 | - Automatic compaction uses a percentage of the real context window, clamped to |
| 5158 | the route's spendable ceiling. Pressure comes from the current parent-route |
| 5159 | prompt, not cumulative billing or child-model usage. |
| 5160 | - Compaction, review, verify, routing, setup, Fleet, MCP, RLM, vision, |
| 5161 | translation, and sub-agent calls inherit the resolved route's normal output, |
| 5162 | sampling, and reasoning policy. Small internal-task token caps no longer |
| 5163 | truncate thinking routes or special-case individual providers. |
| 5164 | - Incomplete provider responses fail truthfully across ordinary turns and every |
| 5165 | internal model consumer. Partial text stays interrupted, pending tool calls do |
| 5166 | not execute, and billed usage is retained. |
| 5167 | - Transport-only `(reasoning omitted)` placeholders no longer enter new |
| 5168 | transcripts and are filtered from restored sessions. Reasoning expand/collapse |
| 5169 | actions stay attached to the exact rendered cell, including after replacement, |
| 5170 | restore, filtering, and resize (#5291). |
| 5171 | - Step-budget exhaustion is a typed failure and cannot release a pending |
| 5172 | persistent service. Cancellation after terminal usage still charges the turn. |
| 5173 | - Deferred tools now preserve a completed result when a provider reuses its |
| 5174 | tool-call ID on the retry turn, preventing successful plugin calls from |
| 5175 | entering a repeated execution loop. |
| 5176 | - Website setup, provider, diagnostics, Fleet, and single-runtime claims now |
| 5177 | match the source candidate. |
| 5178 | - Opening the sub-agent register no longer hides the to-do list: the Agents |
| 5179 | panel shows the full register and the durable checklist together, and the |
| 5180 | register header is a two-way door that returns to Tasks on a second click. |
| 5181 | - The ⌥V / Alt+V details chord opens the selected work-surface row's own |
| 5182 | inspector instead of the transcript's nearest tool cell, so a selected |
| 5183 | to-do row shows its own content rather than the latest reasoning. |
| 5184 | - The first-run usage disclosure now asks a clear question — "Help improve |
| 5185 | Codewhale?" — with unambiguous "Yes, keep anonymous counts" / "No, turn off |
| 5186 | tracking" choices in every shipped locale, and states the persistent opt-out |
| 5187 | command. Consent semantics are unchanged: telemetry stays unarmed until a |
| 5188 | choice is made. |
| 5189 | - macOS screencapture screenshots referenced in a message are copied to a |
| 5190 | stable attachments directory the moment the message is received, and the |
| 5191 | reference is rewritten to the stable path, so the image still exists when |
| 5192 | the agent reads it. Only files under a screencapture "Temporary Items" |
| 5193 | directory are touched; copies are idempotent and a failed copy keeps the |
| 5194 | original reference. |
| 5195 | - Manual `/compact` during an active turn now queues even when the engine's |
| 5196 | bounded op mailbox is saturated. The request defers client-side, retries as |
| 5197 | mailbox slots free, and cannot latch as already running after it settles. |
| 5198 | - Interactive `/load`, startup `--resume`, and `/resume` picker paths preserve |
| 5199 | the persisted provider, endpoint, and model identity; picker resume also |
| 5200 | leaves a durable transcript receipt. |
| 5201 | - Relative `mcp_config_path` values no longer depend on the launch directory or |
| 5202 | silently load an empty server pool: Codewhale warns and falls back to the |
| 5203 | user-global MCP configuration. Explicit absolute paths remain authoritative. |
| 5204 | - Alibaba Model Studio `qwen3.8-max` and `qwen3.8-max-preview` still stream |
| 5205 | their current reasoning, but no longer replay historical `reasoning_content` |
| 5206 | that those routes do not accept. Historical reasoning replay is now gated by |
| 5207 | the exact provider/API/model contract, so unknown `*-thinking` lookalikes |
| 5208 | fail closed while documented Qwen, Kimi, DeepSeek, Mistral, Anthropic, and |
| 5209 | Responses continuity rules remain intact. |
| 5210 | - Compatibility File/patch calls retain optional content-hash guards when a |
| 5211 | caller supplies them. The new direct `write` and `edit` schemas do not expose |
| 5212 | hash or prior-read ceremony. |
| 5213 | - Shell previews hold back incomplete UTF-8 sequences instead of emitting |
| 5214 | replacement characters, and compaction receipts report token deltas. |
| 5215 | - Nested agents may narrow but can never widen their inherited depth budget |
| 5216 | (#5317 by @ousamabenyounes). |
| 5217 | - Container publication now assembles AMD64 and ARM64 images in parallel on |
| 5218 | native runners from the already-verified static release binaries, then |
| 5219 | publishes and checks one multi-architecture manifest. It no longer rebuilds |
| 5220 | both targets through the single long-running QEMU job that lost its runner. |
| 5221 | |
| 5222 | - Google Gemini is its own backend (`/provider google`) on the official |
| 5223 | OpenAI-compatible route with thought-signature capture/replay and |
| 5224 | fail-closed replay for thinking models. Antigravity (`agy` 1.1.13) joins |
| 5225 | as a separate credential-plane provider: consent-gated read-only import |
| 5226 | of the official CLI's login with `ANTIGRAVITY_API_KEY`/`AGY_ADC_AUTH` |
| 5227 | precedence; requests fail closed until the cloud-code wire protocol is |
| 5228 | implemented. |
| 5229 | |
| 5230 | ### Removed |
| 5231 | |
| 5232 | - The no-progress guard, repeated-read guard, and injected tool-error strategy |
| 5233 | coaching. Productive polling, repeated inspection, and model-owned recovery |
| 5234 | are no longer interrupted by runtime heuristics. |
| 5235 | - Never-wired decision-card, keybinding, hover, shell-execution, engine-op, and |
| 5236 | release-script paths were deleted so the supported runtime has one route for |
| 5237 | each behavior. |
| 5238 | |
| 5239 | ### Contributors |
| 5240 | |
| 5241 | - Xavier Pestel (@xavierpestel-ai) — Mistral AI provider route (#5295). |
| 5242 | - Ben Younes (@ousamabenyounes) — inherited nested-agent depth cap (#5317). |
| 5243 | - Rafael Cavalheri (@rafaelcavalheri) — ACP agentic tool turns (#5225). |
| 5244 | |
| 5245 | ## [0.9.5] - 2026-08-08 |
| 5246 | |
| 5247 | Codewhale v0.9.5 consolidates the terminal application into one compiled |
| 5248 | runtime while preserving the familiar `codewhale` and `codew` commands. It |
| 5249 | also expands the managed Runtime API, makes session and Fleet work easier to |
| 5250 | inspect and resume, and removes the hidden local continuation backstop that |
| 5251 | could end productive work without a final assistant response. |
| 5252 | |
| 5253 | ### Added |
| 5254 | |
| 5255 | - **`model = "auto"` for prompt-based tier selection**: When set, the |
| 5256 | dispatcher analyses the user's prompt before delegating to the TUI and |
| 5257 | selects `deepseek-v4-pro` for complex tasks or `deepseek-v4-flash` for simple |
| 5258 | tasks (PR #5257). |
| 5259 | - Runtime API controls for persistent goals, bounded memory inspection, MCP |
| 5260 | server and skill lifecycle management, and durable Fleet receipt evidence. |
| 5261 | - Append-only session-tree history with `/tree`, `/branch`, `/fork`, and |
| 5262 | `/resume`, plus `/rc` remote control and managed login. |
| 5263 | - A unified Fleet roster for built-in dispatch postures and a pinned indicator |
| 5264 | that keeps active background work visible above the composer. |
| 5265 | - Incremental MCP registry refreshes that return the local snapshot immediately |
| 5266 | and update it in the background. |
| 5267 | - Scout and Reviewer agents can use a bounded direct-command evidence shell for |
| 5268 | read-only workspace, Git, and GitHub inspection, and can keep private working |
| 5269 | notes in their own To-do while the durable transcript retains their evidence. |
| 5270 | |
| 5271 | ### Changed |
| 5272 | |
| 5273 | - `codewhale-cli` now contains the terminal runtime directly. Release installers |
| 5274 | expose byte-identical `codewhale` and `codew` commands without a separate TUI |
| 5275 | executable. v0.9.5 introduced deprecated `codewhale-tui-*` release filenames |
| 5276 | as byte-identical compatibility copies; later releases retain those filenames |
| 5277 | while installed v0.9.4 clients remain supported upgrade sources. |
| 5278 | - Startup release checks cache successful lookups for one hour. The updater |
| 5279 | downloads and verifies the primary runtime once, then refreshes any existing |
| 5280 | `codew` or legacy `codewhale-tui` command paths from the same bytes. |
| 5281 | - Headless `codewhale exec` runs and verifier benchmark rollouts no longer |
| 5282 | impose a 100-step default. `--max-turns` remains available as an explicit |
| 5283 | opt-in ceiling; Fleet workers retain their separately configured budget. |
| 5284 | - Goal token and time budgets are telemetry rather than default stop |
| 5285 | conditions, and automatic goal continuation is unlimited unless the user |
| 5286 | explicitly configures a continuation ceiling. |
| 5287 | - Command-palette and slash-completion shadowing now share one alias-aware |
| 5288 | discovery contract. |
| 5289 | - The website install guidance, localized product copy, navigation controls, |
| 5290 | social metadata, and Cloudflare build pipeline now describe and deploy the |
| 5291 | same one-runtime release contract. |
| 5292 | |
| 5293 | ### Fixed |
| 5294 | |
| 5295 | - The hidden 20-step no-user-input backstop no longer ends productive turns. |
| 5296 | Tool results, queued steering, child completions, REPL feedback, and goal |
| 5297 | continuations can all reach the next provider step and a final assistant |
| 5298 | response; explicit user-configured limits and genuine stuck-loop guards remain. |
| 5299 | - Complete error details are directly inspectable after a failure instead of |
| 5300 | leaving the terminal with a clipped, unrecoverable error fragment. |
| 5301 | - A newly minted OAuth credential is adopted in the same provider-selection |
| 5302 | flow instead of requiring a second picker trip. |
| 5303 | - Fresh session titles can replace a stale cached `New Session` placeholder, |
| 5304 | unknown model context limits fail loudly, and release/source-install fallbacks |
| 5305 | no longer request binaries removed by the single-runtime conversion. |
| 5306 | |
| 5307 | ### Contributors |
| 5308 | |
| 5309 | - [Sh1Zuku](https://github.com/SparkofSpike) (`@SparkofSpike`) fixed stale |
| 5310 | cached session titles that could pin the `New Session` placeholder. |
| 5311 | - [Paulo Aboim Pinto](https://github.com/aboimpinto) (`@aboimpinto`) built the |
| 5312 | shared alias-aware command discovery contract and acceptance coverage. |
| 5313 | - [Sun Zhenyuan](https://github.com/bistack) (`@bistack`) contributed the |
| 5314 | background incremental MCP Registry refresh. |
| 5315 | - [SKY ZHAO](https://github.com/skyzhao1223) (`@skyzhao1223`) contributed |
| 5316 | prompt-based `model = "auto"` routing in PR #5257. |
| 5317 | |
| 5318 | ## [0.9.4] - 2026-08-07 |
| 5319 | Codewhale v0.9.4 ships the release-train harness work: the familiar Fleet |
| 5320 | roster/setup face with a clear operator-leader and user/folder scope, a |
| 5321 | work strip that keeps actionable agents instead of a permanent archive, |
| 5322 | waiting policy that forbids polling without freezing independent work, |
| 5323 | calmer tool output and session recovery, account/Workflow-search/ |
| 5324 | automation/handoff surfaces, a shorter translation-ready website, and |
| 5325 | release-blocker fixes across permissions, DeepSeek Responses, SQLite, |
| 5326 | File edits, terminal width, and Windows installation. |
| 5327 | |
| 5328 | ### Added |
| 5329 | |
| 5330 | - Memory maintenance: `remember` gains `revise` and `retire` beside the |
| 5331 | default `append`. Both name the exact note they target and both require |
| 5332 | the evidence for the change. Append-only memory decays — a correction |
| 5333 | sits behind the note it contradicts and both keep reaching the model — |
| 5334 | so the model can now keep its own durable notes true instead of only |
| 5335 | adding to them. |
| 5336 | - An audit trail for durable state the model writes about you. Every |
| 5337 | in-place memory edit is journalled to `memory/JOURNAL.md`, and every |
| 5338 | continual-harness `refine` / `remove` to a `JOURNAL.md` beside its state, |
| 5339 | each with before, after, and evidence. Harness removal previously left no |
| 5340 | record at all even though the entry leaves state entirely, so the journal |
| 5341 | is now the only place its content survives. |
| 5342 | - A first-run tip that says so: the first time Codewhale saves something |
| 5343 | durable it points at `/memory`, translated into all fifteen complete |
| 5344 | locale packs. This state shaped later sessions and nothing ever mentioned |
| 5345 | it existed. |
| 5346 | |
| 5347 | - Sub-agent checkpoint resume: `agents/followup` resumes an |
| 5348 | `interrupted_continuable` child from its checkpoint into a fresh agent loop — |
| 5349 | new agent id, original prompt plus the prior conversation tail — when a |
| 5350 | runtime is attached, and otherwise keeps queue-only semantics with the |
| 5351 | `continuation_handle` returned; a second followup on the same interrupted id |
| 5352 | returns the existing resumed target instead of spawning a duplicate (PR #5242). |
| 5353 | - MCP Registry discovery with Registry-first tool selection: `registry_sync` |
| 5354 | surfaces the eligible local stdio catalog as a complete model-side candidate |
| 5355 | set, connect-failure messages classify early-exit and usage-help output and |
| 5356 | point recovery at the next Registry candidate, and a bundled `mcp-discovery` |
| 5357 | skill documents the flow (PR #5238). |
| 5358 | - Progressive fresh-context disclosure: fresh sessions ship a minimal |
| 5359 | constitutional kernel — ground truth, user intent and scope, truthful |
| 5360 | completion, guarantees in mechanism, and precedence — with procedural |
| 5361 | playbooks disclosed on demand, an opt-in project context pack |
| 5362 | (`project_context_pack_enabled`) counted in context reports, and `load_skill` |
| 5363 | catalogue discovery via `name="list"`; the measured fresh-context budget |
| 5364 | drops by roughly 40% (PR #5077). |
| 5365 | - Named Fleet store v2: one self-contained TOML Fleet per configuration |
| 5366 | (`schema = "fleet"`), with scope-explicit selection (user-global default vs |
| 5367 | folder override), migration receipts from legacy role profiles, and atomic |
| 5368 | saves that refuse to clobber a different Fleet on the same slug. |
| 5369 | - Scout replaces the user-facing "faster" control: catalog-verified fast |
| 5370 | siblings only, never a guessed model name; pinned Scout survives operator |
| 5371 | changes. |
| 5372 | - Truthful model-picker rows: vision/tools/limits chips only when the catalog |
| 5373 | knows, with provider → family → exact model grouping. |
| 5374 | |
| 5375 | - **Opt-in product telemetry, off by default.** A first-run notice asks once, on |
| 5376 | a terminal, with declining pre-selected — Enter declines. Nothing is collected |
| 5377 | unless both `telemetry = true` and a recorded "Enable" answer are present, so |
| 5378 | a `telemetry = true` written before this release stays inert: the key has been |
| 5379 | settable and inert for a long time, and setting it was never consent. |
| 5380 | |
| 5381 | An enabled session sends its batches to the first-party ingest endpoint, |
| 5382 | `https://telemetry.codewhale.net/v1/telemetry`, which is the shipped default |
| 5383 | for `telemetry_endpoint`. That is a Cloudflare Worker whose complete source is |
| 5384 | in this repository under `telemetry-ingest/`; it writes to Workers Analytics |
| 5385 | Engine, whose row is exactly `_sample_interval`, `blob1`–`blob20`, `dataset`, |
| 5386 | `double1`–`double20`, `index1`, and `timestamp` — **there is no IP, country, |
| 5387 | or geo column**, so storing one is structurally impossible rather than merely |
| 5388 | disabled. The handler reads two request headers, never touches the request's |
| 5389 | geo properties, logs nothing, and validates against a closed field set that |
| 5390 | rejects an entire batch carrying any unpublished key. Cloudflare's retention |
| 5391 | for that data is a fixed three months. Setting `telemetry_endpoint = ""` |
| 5392 | instead writes each batch to `$CODEWHALE_HOME/telemetry/dryrun.jsonl` and |
| 5393 | constructs no HTTP client at all, so you can read exactly what would have been |
| 5394 | sent. |
| 5395 | |
| 5396 | Turning it off is an answer, not a flag: it deletes the random install id, |
| 5397 | truncates every buffered event, and leaves a permanent tombstone that a |
| 5398 | session already running re-checks before it appends and before it sends. A |
| 5399 | failed wipe fails closed. `CODEWHALE_TELEMETRY=0` is a hard floor that beats |
| 5400 | `--telemetry true` and the config key, and a value the parser cannot read |
| 5401 | also resolves to off. Fleet workers are hard-off. A repo-local |
| 5402 | `.codewhale/config.toml` can set neither key. |
| 5403 | |
| 5404 | Never collected: prompts, completions, tool arguments, diffs, file contents, |
| 5405 | filenames, paths, git remotes, repo or branch names, memory entries, chat |
| 5406 | history, credentials (not even a boolean asserting one exists), model ids, |
| 5407 | custom provider table names, MCP server names, error or panic message bodies, |
| 5408 | per-event timestamps, keystrokes, clipboard, screenshots, or location. The |
| 5409 | full schema is [`docs/TELEMETRY.md`](docs/TELEMETRY.md), and a test parses the |
| 5410 | field names out of that file and asserts set equality with the structs the |
| 5411 | serializer uses. |
| 5412 | |
| 5413 | This supersedes the roadmap's previous "no Codewhale product telemetry" entry, |
| 5414 | which moves from "Ruled out" to an opt-in framing. What stays ruled out: |
| 5415 | always-on or silent telemetry, per-keystroke or per-tool-call phone-home, and |
| 5416 | any third-party ad or analytics SDK in the runtime binary. |
| 5417 | - Registered `GLM-5.3` (direct Z.ai) and `z-ai/glm-5.3` (OpenRouter) as |
| 5418 | selectable GLM routes, with their aliases (`glm-5.3`, `glm-5-3`, |
| 5419 | `zai-glm-5.3`, `zai-glm-5-3`). Z.ai had **not released GLM-5.3 as of |
| 5420 | 2026-08-03** — the ids are registered so they resolve to the Z.ai/OpenRouter |
| 5421 | routes instead of being rewritten to another vendor's model, and they will |
| 5422 | fail upstream until Z.ai ships the model. Metadata (context, output, |
| 5423 | reasoning controls) is inherited wholesale from `GLM-5.2` pending official |
| 5424 | Z.ai release metadata; pricing is intentionally absent, and `GLM-5.2` remains |
| 5425 | the default Z.ai model. No third-party gateway roster gained the model: |
| 5426 | OpenCode Zen, OpenCode Go, Alibaba Model Studio, and TelecomJS publish no |
| 5427 | glm-5.3 entry, so Codewhale advertises none. |
| 5428 | |
| 5429 | - Managed Codewhale account commands (`account login`, `status`, `logout`, and |
| 5430 | `keys`) with browser device flow, profile- and origin-scoped secure sessions, |
| 5431 | refresh/revocation, redacted BYOK-vault management, and a token-free Runtime |
| 5432 | account receipt. Provider authentication remains separate, and `cloud` |
| 5433 | remains a compatibility alias. |
| 5434 | - `/automation` operator controls to list, inspect, pause, resume, delete, and |
| 5435 | run durable automations. Creation remains on the approval-gated |
| 5436 | model-visible `automation` tool. |
| 5437 | - A provider-neutral `WorkflowSearchSpec` authoring and freeze boundary, plus |
| 5438 | structured 2–16-candidate experimental search in the best-of-N Workflow |
| 5439 | starter. It freezes baseline, route, evidence, evaluator, gate, score, budget, |
| 5440 | and review policy before admission; it validates gate/scoring commands but |
| 5441 | does not execute or certify them itself. |
| 5442 | - The bundled generation-9 `handoff` skill for compact, decision-ready |
| 5443 | continuation across sessions. |
| 5444 | - Expanded terminal LaTeX rendering for aligned and matrix environments, |
| 5445 | cases, arrays, text/font/accent commands, brackets, symbols, and |
| 5446 | command-aware scripts (PR #4981). |
| 5447 | - Exact 40-character build provenance and secure account-session capability |
| 5448 | receipts on `/v1/runtime/info`; unknown source provenance continues to fail |
| 5449 | closed. |
| 5450 | - Acceptance-level Gherkin coverage locking the existing user-command |
| 5451 | precedence, alias shadowing, fallback, and invalid-command error contract |
| 5452 | (PR #4992). |
| 5453 | - Agent Plugins v1.0.0: consume, publish, and slugify packaged sub-agent |
| 5454 | briefs, with an install/update/uninstall on-ramp in the TUI (PR #5182). A |
| 5455 | plugin bundles a prompt, posture, and routing as one shareable artifact; |
| 5456 | on-disk migration of the older `plugin.toml` scaffold is deliberately out |
| 5457 | of scope for this train. |
| 5458 | - `send_later`: a model-callable one-shot delayed continuation tool, so the |
| 5459 | model can schedule a single future nudge without an operator-approved |
| 5460 | durable automation (PR #5138). |
| 5461 | - `/advisor`: an opt-in background advisor watcher for live turns (PR #5139). |
| 5462 | - Notification quiet mode with per-category switches and action-first copy |
| 5463 | (PR #5066). |
| 5464 | - Automation scheduling forms — one-shot `ONCE`, five-field cron, and honest |
| 5465 | watcher modes — created through the approval-gated `automation` tool |
| 5466 | (PR #5183). |
| 5467 | - Sub-agent `resume_from` continuation chains (PR #5142), child-result |
| 5468 | diff-tainting when a claimed diff is not visible to git, per-turn usage |
| 5469 | receipts on the exec stream-json stream, and spawn receipts that report |
| 5470 | the model each sub-agent actually ran on. |
| 5471 | - Transport resilience: sub-agent exec transport retries with a 600 s |
| 5472 | default (PR #5210), SSE header stalls retryable instead of fatal, and |
| 5473 | headless turn resume after mid-stream network drops with an `EX_TEMPFAIL` |
| 5474 | exit. |
| 5475 | - Session durability and control: a deterministic compaction continuation |
| 5476 | contract (PR #5064), persisting interrupted output (PR #5206), stop-word |
| 5477 | cancellation (PR #5207), token-counter refresh (PR #5204), deny-by-default |
| 5478 | approval cards (PR #5090), and the Operate completion gate (PR #5067). |
| 5479 | - zh-Hant promoted to a full shipped locale with complete `en.json` parity |
| 5480 | (PR #5143). |
| 5481 | - A persistent update-available chip in the header, with the startup update |
| 5482 | check throttled and naming the right command. |
| 5483 | - RLM static intent extraction for code blocks (`rlm_block_intent.rs`) |
| 5484 | landed as groundwork for a future code-mode approval flow; it is not yet |
| 5485 | wired into the turn pipeline and ships dormant by design. |
| 5486 | |
| 5487 | ### Changed |
| 5488 | |
| 5489 | - `/fleet` is the familiar roster/setup face again. The operator row is the |
| 5490 | Fleet leader (session model); the header names the selected saved Fleet and |
| 5491 | whether it is user-global or folder-scoped. Named-Fleet switching lives under |
| 5492 | `/fleet fleets` (Enter selects in the row's own scope). Session route changes |
| 5493 | stay temporary until `/fleet save`, `/fleet save-as`, or `/model save-default`. |
| 5494 | - Waiting-for-subagents directions forbid peek/status polling and sleep-as-wait, |
| 5495 | but allow independent work that does not depend on a child's result — the |
| 5496 | parent no longer freezes mid-turn with useful non-conflicting work available. |
| 5497 | - `workflow run` no longer requires `--fleet`; a saved Fleet is an optional pin |
| 5498 | layer over roles + the session route. |
| 5499 | - Homepage and getting-started copy is shorter and scannable across locales, |
| 5500 | with dictionary key and `{brand}` token parity preserved. |
| 5501 | |
| 5502 | - Tool results now render as ordinary bounded previews with real expansion; |
| 5503 | storage, retention-ledger, and internal evidence language no longer leak into |
| 5504 | normal transcripts. |
| 5505 | - Prose wrapping, goal state, modal questions, composer-tail behavior, and |
| 5506 | ambient motion now follow one deterministic interface contract across narrow |
| 5507 | terminals and fast streams. |
| 5508 | - Scout and reviewer Fleet roles gain network access and the bounded |
| 5509 | verification surface for real reconnaissance while retaining the no-write, |
| 5510 | no-raw-shell security floor. |
| 5511 | - Workflow runs may describe up to 1,000 tasks while admitting at most 16 live |
| 5512 | tasks at once through the host concurrency gate. Tournament ordering now |
| 5513 | supports explicit score-first selection while retaining its cost-first |
| 5514 | default. |
| 5515 | - Runtime permission compatibility inputs resolve to one live |
| 5516 | `permission_posture`. Auto-Review can proceed without approval or structured |
| 5517 | question modals, unresolved holds fail closed, and a call planned under stale |
| 5518 | authority is retried after a posture change (PR #5025). |
| 5519 | - Duplicate and drifting per-turn metadata has been removed in favor of |
| 5520 | runtime-owned authority, and large inline account and skill tests now live in |
| 5521 | owned test seams. |
| 5522 | - Pinned Ratatui to 0.30.0 and ratatui-core to 0.1.0. ratatui-core 0.1.1+ |
| 5523 | makes `Terminal::clear()` issue a blocking cursor-position report that |
| 5524 | raced the TUI input loop and could kill first launch; both pins are |
| 5525 | load-bearing, because 0.30.0 declares `ratatui-core ^0.1` and would |
| 5526 | otherwise resolve forward on its own (PR #5192 by @bistack; upstream |
| 5527 | ratatui/ratatui#2640). |
| 5528 | - Updated globset to 0.4.19, clap-complete to 4.6.8, |
| 5529 | futures-util to 0.3.33, libc to 0.2.189, actions/stale to 11.0.0, and |
| 5530 | docker/login-action to 4.5.2. The locked graph also includes the |
| 5531 | event-listener 5.4.2 fix for RUSTSEC-2026-0221. |
| 5532 | - The progress surface now speaks plainly everywhere: the last user-visible |
| 5533 | "Work update is pending" notices say "To-do list", the tool constructor and |
| 5534 | the docs name `todo_write` as the single canonical progress tool, and |
| 5535 | `work_update`, `TodoWrite`, and `todo` stay registered as hidden |
| 5536 | compatibility aliases so saved transcripts keep replaying. |
| 5537 | - Sub-agent and `agents/wait` waits stay short by default and by cap: |
| 5538 | blocking waits default to 30 s and refuse to block past 120 s, because a |
| 5539 | blocked wait deafens the session to typed input and settled children |
| 5540 | already report back as `<codewhale:subagent.done>` sentinels. |
| 5541 | - `Bash` `action=wait` honors `timeout_secs` (seconds) and bare `timeout` |
| 5542 | (milliseconds) alongside canonical `timeout_ms`, and `block` as an alias |
| 5543 | for `wait`, so a habit formed on other wait tools gets the duration it |
| 5544 | asked for instead of silently falling back to the 30 s default; the result |
| 5545 | metadata reports the real `wait_timeout_ms` applied. |
| 5546 | |
| 5547 | ### Fixed |
| 5548 | |
| 5549 | - The memory journal is no longer indexed as memory. It is Markdown in the |
| 5550 | memory tree, so the source walk collected it and every retired note |
| 5551 | re-entered the searchable set under its `before:` line — putting the |
| 5552 | exact facts a revision had just removed back into the prompt. |
| 5553 | - `memory_path` pointed at an already-native store no longer derives a |
| 5554 | second store nested inside it, which silently wrote somewhere other than |
| 5555 | the file the user named. |
| 5556 | - `muse` and `muse-spark` resolved to `muse-spark-1.1` in the agent |
| 5557 | registry while config had defaulted to `muse-spark-1.2`, so the CLI and |
| 5558 | app-server routed those aliases somewhere the configured default never |
| 5559 | pointed. The registry now carries 1.2 and the contributor variant. |
| 5560 | |
| 5561 | - An explicit `type=builder` (or its `implementer` alias) plus |
| 5562 | `write_authority=read_only` now fails closed at spawn instead of launching a |
| 5563 | labeled write role that silently had only read-only tools and then self-BLOCKED |
| 5564 | after burning a turn (#5123). The check is deliberately narrow, because two |
| 5565 | neighbouring combinations are legitimate and stay legal: |
| 5566 | - `type=worker` + `read_only` — worker is the unnamed default (it renders as |
| 5567 | `general`) and takes its capability from authority, not from its name, so a |
| 5568 | read-only worker is an ordinary general-purpose child. Worker, scout, |
| 5569 | reviewer, and verifier remain the four canonical read-only Fleet roles. |
| 5570 | - any `role` + `read_only` — `role` is an identity for roster resolution, not |
| 5571 | a capability claim, so an acceptance Workflow can still resolve |
| 5572 | `implementer` to its saved profile while scoping that child to verification. |
| 5573 | |
| 5574 | Callers that spelled a read-only narrowing as `type: "implementer"` should |
| 5575 | move it to `role: "implementer"`. |
| 5576 | - User-global credentials survive an explicit workspace `CODEWHALE_CONFIG_PATH` |
| 5577 | that selects a route with no local key — readiness probes the user-global |
| 5578 | provider table before concluding a key is missing. |
| 5579 | - Sub-agent token figures on the work bar accumulate input+output (the same |
| 5580 | total the worker budget uses) instead of completion tokens alone; elapsed |
| 5581 | time still freezes when the child settles. |
| 5582 | - Live work-bar rows for sub-agents show how many to-dos they still have |
| 5583 | left (`N left`) when the child's own list has unsettled items — never a |
| 5584 | fabricated zero when no list exists. |
| 5585 | |
| 5586 | - Surfaces no longer claim an OS sandbox on platforms that cannot enforce one. |
| 5587 | The policy resolver takes no platform input, so on default Linux (bubblewrap |
| 5588 | is opt-in) and on all Windows the header chip read `files: workspace` and |
| 5589 | `/status` read `sandbox workspace-write` while nothing was restricted. Both |
| 5590 | now resolve the real backend and say `(unenforced)`. |
| 5591 | - `tool_category` hook conditions matched only retired tool names, so a |
| 5592 | `category = "shell"` **deny** hook — the security control `docs/HOOKS.md` |
| 5593 | documents — silently never fired. Categories now use the registered names, |
| 5594 | and multi-action tools classify by action. |
| 5595 | - A `Retry-After` header of `-5`, `nan`, or `1e300` crashed the request task |
| 5596 | (`Duration::from_secs_f64` panics on a negative). Parsing is now guarded and |
| 5597 | bounded to one hour. |
| 5598 | - Bearer tokens no longer leak into operator-visible receipts. `Authorization: |
| 5599 | Bearer <jwt>` split into two tokens and the JWT matched no redaction rule; |
| 5600 | prefix matching was also case-sensitive, so `SK-live-…` survived. |
| 5601 | - `prune_older_than` destroyed the NEWEST rollback snapshots and kept the old |
| 5602 | ones — on every boot, for any workspace with snapshots spanning the retention |
| 5603 | window. Both prune paths now share one orphan-chain rebuild and preserve each |
| 5604 | survivor's real timestamp. |
| 5605 | - An absolute or relative command path no longer defeats every execpolicy deny |
| 5606 | rule (`/bin/rm -rf /` did not match a `rm -rf /` rule), and a typed `Allow` |
| 5607 | rule no longer auto-approves a chained suffix such as `git log ; curl … | sh`. |
| 5608 | - Wrong types on `File` read range params and `Bash` stdin/cwd/task_id are now |
| 5609 | errors instead of silent defaults — a `start_line:"1200"` string used to |
| 5610 | return the head of the file, and a non-string `stdin` ran the command with no |
| 5611 | stdin and reported success. |
| 5612 | - Multibyte tool ids no longer panic the context inspector, wide (CJK) text no |
| 5613 | longer overflows the decision card, and a hostname like `127.evil.example.com` |
| 5614 | is no longer treated as loopback. |
| 5615 | - Refusals name calls the model can actually make (`rlm action='open'` rather |
| 5616 | than a retired `rlm_open`; `Bash` rather than `exec_shell`). |
| 5617 | |
| 5618 | - Sub-agent dispatch no longer aborts the process. The Tokio runtime was built |
| 5619 | by `#[tokio::main]`, leaving every worker thread on the 2 MiB default while |
| 5620 | only the owner thread received the explicit 16 MiB stack — and the engine runs |
| 5621 | on a worker. A debug-build `agent` dispatch exceeded that stack and raised |
| 5622 | SIGABRT, which is not a panic and so could not be caught; the process died |
| 5623 | mid-spawn with no child request ever issued. Release builds were unaffected. |
| 5624 | - Fleet profiles that pin a provider no longer leak a bare model id onto the |
| 5625 | session route. `model_overrides` exported each role's model while dropping its |
| 5626 | provider, so a scout pinned to another provider's model was dispatched against |
| 5627 | the active client and denied at the wire — visible as an instant auth failure |
| 5628 | on the first sub-agent of a fan-out. |
| 5629 | - The rail's Pinned panel no longer spends four rows saying "No active work". |
| 5630 | An empty panel now collapses like the Tasks panel always has, and the settings |
| 5631 | migration no longer folds the default `sidebar_focus = "auto"` into a pinned |
| 5632 | always-on strip, which had silently handed that panel to every user who had a |
| 5633 | settings file at all. (An *empty* panel collapses; a panel holding settled |
| 5634 | to-dos or finished workers is not empty — see the standing-register entry |
| 5635 | below.) |
| 5636 | - The work bar keeps settled to-dos and an honest Subagents header, while |
| 5637 | completed/cancelled workers collapse out of the Top strip so fan-outs do not |
| 5638 | permanently eat the transcript. Failed or interrupted workers stay visible |
| 5639 | (they still need attention). Settled agents remain reachable through the |
| 5640 | Agents panel and catalog. To-do rows say their state in words (pending / |
| 5641 | in progress / completed / cancelled), and sub-agent rows carry type, |
| 5642 | objective, elapsed, and input+output tokens. Every work row is a door in |
| 5643 | every rail panel and placement: click and Enter open the row's world |
| 5644 | (work inspector / agent details — finished agents included) instead of |
| 5645 | doing nothing. A click after the detail pager closed itself reopens the |
| 5646 | detail rather than being swallowed by a stale toggle. |
| 5647 | - The rail strip yields its rows to the transcript when the terminal cannot |
| 5648 | seat both, so the idle ocean survives at 24 rows instead of being evicted. |
| 5649 | - `code_execution` and `js_execution` no longer describe themselves to the model |
| 5650 | as sandboxed. Both are ordinary local subprocesses with no seccomp, jail, or |
| 5651 | container (PR #5221 by @h3c-hexin and @asto18089). |
| 5652 | - Model Studio reasoning controls now fail closed on the host rather than on the |
| 5653 | provider enum, so a custom `base_url` no longer receives Alibaba-specific |
| 5654 | `enable_thinking` fields, and `qwen3.8-max` is no longer sent a thinking |
| 5655 | switch it does not accept (PR #5233 by @Inference1, closing #5203). |
| 5656 | - `config.example.toml` no longer claims Shift+Tab cycles the reasoning tier. |
| 5657 | Shift+Tab cycles the permission posture; Ctrl+T cycles reasoning |
| 5658 | (found by @vFONGv, PR #5229). |
| 5659 | |
| 5660 | - Alibaba Model Studio reasoning controls are now route- and model-scoped |
| 5661 | instead of provider-wide (#5203, harvested from #5233 by |
| 5662 | [@Inference1](https://github.com/Inference1)). Codewhale sends |
| 5663 | `enable_thinking` / `preserve_thinking` / `reasoning_effort` only when the |
| 5664 | configured `base_url` is a verified Alibaba Chat Completions host, so |
| 5665 | pointing a `modelstudio-*` provider ID at a custom gateway no longer injects |
| 5666 | DashScope's dialect into it. `qwen3.8-max` and `qwen3.8-max-preview` are |
| 5667 | thinking-only and no longer receive an `enable_thinking: false` they cannot |
| 5668 | honor; `preserve_thinking` is sent for the models documented to accept it, so |
| 5669 | their reasoning trace survives into the next turn; and `deepseek-v4*` / |
| 5670 | `glm-5.x` map the reasoning tier onto the documented `high` / `max` ladder. |
| 5671 | |
| 5672 | - xAI device login now recovers from a config that points at a missing |
| 5673 | Codewhale-owned credential generation instead of failing every attempt |
| 5674 | with a generic activation error, and finalize failures report the full |
| 5675 | error chain (#5032). |
| 5676 | - API keys saved to the secret store no longer read as unconfigured for |
| 5677 | providers that are not currently active; a configured Kimi/Moonshot key |
| 5678 | survives provider switches and restarts without re-entry (#5033). |
| 5679 | - Switching to the Codex provider with no saved model now lands on the live |
| 5680 | roster's flagship model instead of a stale static default (#5034). |
| 5681 | - Worktree-isolated Fleet builders no longer contend on the per-workspace |
| 5682 | delegated-coordination lock, and a failed lock acquisition is retried on |
| 5683 | use instead of being memoized for the life of the process (#5036). |
| 5684 | - Fleet dispatch now rebinds the child client when the resolved profile |
| 5685 | model requires a different wire protocol (DeepSeek flash on Responses), |
| 5686 | instead of failing deterministically on the worker's first request |
| 5687 | (#5042). |
| 5688 | - DeepSeek Responses now sends `reasoning.effort: "none"` for the Off tier, |
| 5689 | shows a truthful notice instead of silently discarding server-side |
| 5690 | `web_search_call` items, and parses cache-hit, cache-miss, cache-write, and |
| 5691 | pricing telemetry while retaining the OpenAI-style nested fallback. |
| 5692 | - File edits now explain no-op and missing-search failures, reject newly |
| 5693 | unbalanced C/C++ preprocessor replacements, handle the reported |
| 5694 | CRLF/non-ASCII cases, and safely relocate stale unified-diff hunks only when |
| 5695 | whole-file context is unique (PRs #5008 and #5030). |
| 5696 | - Circled digits, enclosed alphanumerics, and keycap graphemes use consistent |
| 5697 | two-column measurement in Codewhale, Ratatui, and CJK terminals, preventing |
| 5698 | missing-character and phantom-space corruption (PR #5001). |
| 5699 | - SQLite connections install their busy timeout before locking setup and avoid |
| 5700 | rewriting persistent WAL mode on every open, removing the concurrent-open |
| 5701 | release-gate failure. |
| 5702 | - The Windows installer preserves long current-user `PATH` values, their |
| 5703 | registry type, and unrelated entries across install and uninstall (PR #5006). |
| 5704 | - Provider configuration no longer contains user-reachable panic paths when |
| 5705 | metadata or prior credential state is missing. |
| 5706 | - Resuming a session restores composer text only from a same-session persisted |
| 5707 | draft; submitted prompts and internal background-runtime envelopes remain in |
| 5708 | history instead of appearing in the composer (PR #5029). |
| 5709 | - Shared CI now handles bot-authored issue-link checks, provisions cargo-deny's |
| 5710 | toolchain, and fetches the locked test graph before offline runtime-budget |
| 5711 | validation. |
| 5712 | - Re-quote each linker argument in the Windows OpenHarmony clang launcher so a |
| 5713 | spaced SDK path (e.g. the default `D:\DevEco Studio\...` install) keeps its |
| 5714 | `--sysroot` intact through the final Rust link, and extend the no-SDK release |
| 5715 | guard to keep the re-quoting contract (PR #5095). |
| 5716 | |
| 5717 | - The shell tool reports the real elapsed wait time in its result content |
| 5718 | instead of echoing the requested timeout (PR #5240). |
| 5719 | - Transcript wheel scrolling under iTerm2: xterm alternate-scroll (DECSET |
| 5720 | 1007) now stays off while mouse capture is active, so wheel events arrive as |
| 5721 | mouse events instead of being converted into arrow keys (#5223, PR #5234). |
| 5722 | - A stalled model stream no longer ends the turn as `Completed` over a |
| 5723 | frozen reasoning block: a mid-stream chunk-timeout now counts toward the |
| 5724 | stream-error budget, so a stall with nothing streamed retries the request |
| 5725 | transparently, and a stall that exhausts the retry budget fails the turn |
| 5726 | with the real reason instead of reporting success. |
| 5727 | - A finished background shell task now wakes the engine even when no goal is |
| 5728 | active: the idle loop starts an ordinary runtime turn so the completion |
| 5729 | reaches the model immediately instead of sitting unclaimed until the user |
| 5730 | types (a dead provider route claims the completion once and reports where |
| 5731 | the output lives instead of re-arming the same error every tick). |
| 5732 | - Sub-agent final reports that exceed the summary budget are now spilled to |
| 5733 | a session artifact, and the truncation footer names the |
| 5734 | `retrieve_tool_result` ref for the elided middle instead of telling the |
| 5735 | model the bytes are unrecoverable; write failures degrade to the honest |
| 5736 | no-ref footer. |
| 5737 | - An interactive mid-stream network drop after partial output no longer fails |
| 5738 | the turn: the partial reply is preserved as a committed assistant message, |
| 5739 | a runtime continuation message is appended, and the request is re-issued |
| 5740 | bounded by the stream-retry budget. |
| 5741 | - Large pasted input is no longer sent to the model twice as inline text and |
| 5742 | as a backup `.md` paste file; the submitted message now carries only the |
| 5743 | `@`-mention so the model reads the file once. |
| 5744 | - A builder sub-agent can run ordinary shell writes again. Write claims |
| 5745 | outlive the agents that register them, so a workspace accumulated one per |
| 5746 | builder that ever ran — six completed agents left four standing claims in |
| 5747 | testing — and the shared-checkout gate counted those long-finished children |
| 5748 | as live contenders. Every later builder was refused `Bash` writes with |
| 5749 | "cannot prove a bounded file target" and pushed toward worktree isolation, |
| 5750 | which puts the work in a checkout the operator never looks at. The gate now |
| 5751 | asks the question it meant to ask: is another *running* child writing in this |
| 5752 | shared checkout. Concurrent writers are still gated; a lone builder writes in |
| 5753 | the workspace you are actually watching. |
| 5754 | - Ctrl-C during the first moments of startup no longer kills Codewhale |
| 5755 | outright. The terminating-signal handlers were registered inside the task |
| 5756 | that waits on them, and a spawned task does not run until the scheduler |
| 5757 | first polls it, so a SIGINT arriving in that window hit the default |
| 5758 | disposition — the process died with no exit code, no terminal restore, and |
| 5759 | no session record. The handlers are now installed synchronously, before |
| 5760 | the telemetry notice and before arming, so the window is closed. |
| 5761 | - The documented tool list on the docs site named `update_plan` and |
| 5762 | `work_update` as coordination tools. Neither is callable by the model — |
| 5763 | `update_plan` replays older Plan artifacts and `work_update` is a hidden |
| 5764 | compatibility alias — so the page listed two tools a reader cannot use and |
| 5765 | omitted `todo_write`, the one they can. |
| 5766 | |
| 5767 | ### Security |
| 5768 | |
| 5769 | - Bumped `nanoid` past GHSA-2v37-7h3g-55p8 (a custom generator given size |
| 5770 | zero could loop indefinitely), restoring a zero-advisory `npm audit` for |
| 5771 | the website. |
| 5772 | |
| 5773 | - Google Gemini is its own backend (`/provider google`) on the official |
| 5774 | OpenAI-compatible route with thought-signature capture/replay and |
| 5775 | fail-closed replay for thinking models. Antigravity (`agy` 1.1.13) joins |
| 5776 | as a separate credential-plane provider: consent-gated read-only import |
| 5777 | of the official CLI's login with `ANTIGRAVITY_API_KEY`/`AGY_ADC_AUTH` |
| 5778 | precedence; requests fail closed until the cloud-code wire protocol is |
| 5779 | implemented. |
| 5780 | |
| 5781 | ### Removed |
| 5782 | |
| 5783 | - The default model-facing SlopLedger implementation, its storage-oriented |
| 5784 | transcript language, and the `/debt`, `/cleanup`, `/slop`, and `/canzha` |
| 5785 | command surface. |
| 5786 | |
| 5787 | ### Contributors |
| 5788 | |
| 5789 | - [Sh1Zuku](https://github.com/SparkofSpike) (`@SparkofSpike`) contributed |
| 5790 | LaTeX rendering in PR #4981, completed circled-digit/keycap width handling in |
| 5791 | PR #5001, and delivered actionable File-edit recovery in PR #5008; for this |
| 5792 | train he resumed interrupted sub-agents from checkpoints in PR #5242, |
| 5793 | surfaced real shell wait elapsed time in PR #5240, and kept alternate-scroll |
| 5794 | off while mouse capture is active in PR #5234. |
| 5795 | - [XhesicaFrost](https://github.com/XhesicaFrost) (`@XhesicaFrost`) fixed long |
| 5796 | Windows user-PATH preservation in PR #5006. |
| 5797 | - [Paulo Aboim Pinto](https://github.com/aboimpinto) (`@aboimpinto`) added the |
| 5798 | user-command dispatch acceptance contract in PR #4992. |
| 5799 | - [DracheTek](https://github.com/DracheTek) (`@DracheTek`) provided the |
| 5800 | multilingual, CRLF-heavy File-edit failure report in issue #5003. |
| 5801 | - [An Ziwu](https://github.com/MuRongMoQing) (`@MuRongMoQing`) reported the |
| 5802 | Windows PATH-overwrite defect in issue #4685. |
| 5803 | - [shenjackyuanjie](https://github.com/shenjackyuanjie) (`@shenjackyuanjie`) |
| 5804 | fixed the Windows OpenHarmony linker re-quoting for spaced SDK paths in |
| 5805 | PR #5095. |
| 5806 | - [bistack](https://github.com/bistack) (`@bistack`) contributed MCP Registry |
| 5807 | discovery with Registry-first tool selection in PR #5238. |
| 5808 | - [vFONGv](https://github.com/vFONGv) (`@vFONGv`) wrote the zh-CN Windows |
| 5809 | beginner guide with screenshots in PR #5229, harvested after its base branch |
| 5810 | was accidentally deleted during maintainer cleanup. |
| 5811 | - [mky](https://github.com/mky) (`@mky`) fixed the FreeBSD build (PR #5254, `rquickjs` `bindgen` on FreeBSD). |
| 5812 | - [cacdcaecawae](https://github.com/cacdcaecawae) (`@cacdcaecawae`) contributed embedder-owned sub-agent state roots (PR #5252). |
| 5813 | |
| 5814 | ## [0.9.3] - 2026-07-31 |
| 5815 | |
| 5816 | This is the Codewhale v0.9.3 source candidate. It is not a published release |
| 5817 | until the matching tag, packages, checksums, and release assets exist. |
| 5818 | |
| 5819 | DeepSeek V4 Flash is now a first-class Codewhale route, and the agent-facing |
| 5820 | tool surface has been reduced to the canonical action tools that current |
| 5821 | models actually need. This release also hardens credential, authorization, |
| 5822 | durability, compaction, and macOS File Provider boundaries while deleting |
| 5823 | stale runtime and dependency surface. |
| 5824 | |
| 5825 | ### Added |
| 5826 | |
| 5827 | - Native `deepseek-v4-flash` support over DeepSeek's Responses API, including |
| 5828 | stateless reasoning-item replay, semantic SSE terminal events, structured |
| 5829 | function calls and outputs, `apply_patch`, and model-aware wire-format |
| 5830 | selection. Exact current Flash IDs use Responses; future direct |
| 5831 | `deepseek-vN-*` model IDs inherit that route conservatively, while custom |
| 5832 | DeepSeek-compatible endpoints retain Chat Completions unless configured |
| 5833 | otherwise. |
| 5834 | - A pipe-only `codewhale auth print-api-key` handoff for explicitly selected |
| 5835 | providers. It shares Codewhale's home-scoped credential authority, refuses |
| 5836 | terminal output, and prevents sentinel placeholders from becoming live |
| 5837 | credentials. |
| 5838 | - Per-turn `max_tool_calls` enforcement at the engine admission gate, plus a |
| 5839 | named-file write scope with a separate read seam. The runtime now rejects |
| 5840 | over-budget calls before execution and keeps the operator's write boundary |
| 5841 | explicit (#4415). |
| 5842 | - Runtime-contract, source-structure, and persistence-backlog ratchets that |
| 5843 | name drift instead of allowing large ownership surfaces to grow silently |
| 5844 | (#3921, #4785). |
| 5845 | |
| 5846 | ### Changed |
| 5847 | |
| 5848 | - Model-visible built-ins now use the canonical `Bash`, `File`, and `Run` |
| 5849 | action schemas. `apply_patch` remains available as the one direct custom |
| 5850 | edit tool supported by DeepSeek Responses. The bundled stop-ship workflow, |
| 5851 | Fleet fixtures, shell shortcut, and engine tests use the same canonical |
| 5852 | vocabulary. |
| 5853 | - Canonical `File { action: "write" }` requests now pass through the same |
| 5854 | semantic repo-law checks as the former write path. Approval, Full Access, |
| 5855 | and workflow execution cannot bypass the repository safety floor by choosing |
| 5856 | the canonical schema. |
| 5857 | - Codewhale home resolution is shared across the CLI, TUI, state, and secret |
| 5858 | stores. `doctor` is offline by default, distinguishes credential source from |
| 5859 | availability, and reports one consistent path snapshot. |
| 5860 | - Durable runtime event writes are serialized across simultaneous processes, |
| 5861 | blocking history waits move off async workers, and provider quota exhaustion |
| 5862 | remains typed and retryable through compaction (#4522). |
| 5863 | - Skill discovery caches the merged catalog behind watched-mtime validation; |
| 5864 | large skill, engine, subagent, UI, and ambient-ocean test blocks now live in |
| 5865 | owned test seams. |
| 5866 | - Reasoning summaries stay in the user's language, complete jellyfish |
| 5867 | silhouettes relocate around transcript text, and cached ocean frames include |
| 5868 | their palette identity (#4807). |
| 5869 | - The authorization-order contract now documents and tests how modes, hooks, |
| 5870 | permission rules, safety floors, repo law, approvals, and sandboxing compose |
| 5871 | (PR #4980). |
| 5872 | |
| 5873 | ### Fixed |
| 5874 | |
| 5875 | - macOS sandbox extensions cover CloudStorage/File Provider workspaces without |
| 5876 | broadening unrelated paths; thanks @Watcher24 for the #4085 report and |
| 5877 | reproduction. |
| 5878 | - Foreground shell state detaches before steering, so an interrupted command |
| 5879 | cannot keep owning the composer (PR #4979). |
| 5880 | - MCP application-level failures and malformed error envelopes fail closed |
| 5881 | instead of looking like successful tool output. |
| 5882 | - Optional PDF failures are truthful and PDF classification no longer misses |
| 5883 | supported inputs. |
| 5884 | - Bracketed-paste contents are redacted from traces, and credential diagnostics |
| 5885 | never treat placeholder sentinels as usable keys. |
| 5886 | |
| 5887 | - Google Gemini is its own backend (`/provider google`) on the official |
| 5888 | OpenAI-compatible route with thought-signature capture/replay and |
| 5889 | fail-closed replay for thinking models. Antigravity (`agy` 1.1.13) joins |
| 5890 | as a separate credential-plane provider: consent-gated read-only import |
| 5891 | of the official CLI's login with `ANTIGRAVITY_API_KEY`/`AGY_ADC_AUTH` |
| 5892 | precedence; requests fail closed until the cloud-code wire protocol is |
| 5893 | implemented. |
| 5894 | |
| 5895 | ### Removed |
| 5896 | |
| 5897 | - The legacy callable aliases `exec_shell`, `run_shell_command`, `read_file`, |
| 5898 | `write_file`, `list_dir`, `grep_files`, `file_search`, and the duplicate |
| 5899 | Work/RLM registrations. Historical transcript and policy semantics remain |
| 5900 | readable, but new model turns receive only the canonical action surface. |
| 5901 | - The bundled PDF parser dependency chain, replacing it with the smaller |
| 5902 | optional extraction boundary tracked by #4382. |
| 5903 | |
| 5904 | ### Contributors |
| 5905 | |
| 5906 | - [Turisla](https://github.com/greyfreedom) (`@greyfreedom`) documented and |
| 5907 | locked the authorization-order contract in PR #4980. |
| 5908 | - [Nightt](https://github.com/nightt5879) (`@nightt5879`) fixed foreground |
| 5909 | shell detachment before steering in PR #4979. |
| 5910 | - [Watcher24](https://github.com/Watcher24) (`@Watcher24`) provided the macOS |
| 5911 | File Provider report and reproduction for #4085. |
| 5912 | - [Fred Leitz](https://github.com/fleitz) (`@fleitz`) retains required |
| 5913 | source-candidate credit for the canonical `Bash` workspace fix from PR #4673 |
| 5914 | and issue #4674. |
| 5915 | |
| 5916 | ## [0.9.2] - 2026-07-29 |
| 5917 | |
| 5918 | This is the Codewhale v0.9.2 source candidate. It is not a published release |
| 5919 | until the matching tag, packages, checksums, and release assets exist. |
| 5920 | |
| 5921 | ### Changed — behavior |
| 5922 | |
| 5923 | - **Legacy `model = auto` no longer elects a network classifier on its own.** |
| 5924 | Holding a DeepSeek API key used to silently select `deepseek-v4-flash` as the |
| 5925 | classifier for every Auto turn — a per-turn cost on a route nobody asked for, |
| 5926 | and one provider privileged over the rest. Auto now stays local and free |
| 5927 | unless an explicit `[auto.router]` block names a provider and model. |
| 5928 | |
| 5929 | **If you relied on the implicit default**, restore it explicitly: |
| 5930 | |
| 5931 | ```toml |
| 5932 | [auto.router] |
| 5933 | provider = "deepseek" |
| 5934 | model = "deepseek-v4-flash" |
| 5935 | ``` |
| 5936 | |
| 5937 | `[auto.router]` remains legacy `model = auto` configuration. It is unrelated |
| 5938 | to a Fleet's Adaptive Reasoning Router, which is a saved service referenced by |
| 5939 | name from a Fleet file and decides only how hard an already-frozen route |
| 5940 | thinks. |
| 5941 | |
| 5942 | Landed since v0.9.1, not yet released. A cluster of defects found by a |
| 5943 | read-through audit of the policy engine, the MCP proxy, the session index, |
| 5944 | and the app-server bridge — several of them cases where the wrong outcome |
| 5945 | was reached silently, behind a response or a log line that looked fine. The |
| 5946 | release also adds opt-in session, reasoning, localization, and inspectability |
| 5947 | surfaces; existing defaults remain stable unless an entry below explicitly |
| 5948 | says otherwise. |
| 5949 | |
| 5950 | ### Added |
| 5951 | |
| 5952 | - `/permissions` now lists the active user permission-rule source, each rule's |
| 5953 | effective matcher and global/repository scope, and whether that scope applies |
| 5954 | in the current workspace. `/permissions remove <number>` previews deletion |
| 5955 | and requires a snapshot-bound confirmation token, so a concurrent edit |
| 5956 | cannot move a different rule under the confirmed index. Appends and removals |
| 5957 | share one adjacent lock, preserve unrelated TOML formatting and comments, |
| 5958 | atomically replace `permissions.toml`, and reload the live user ruleset |
| 5959 | without clearing session-only approvals. `/config ask-rules` remains a |
| 5960 | compatibility entry; rule creation, glob/directory rules, and deny |
| 5961 | persistence remain out of scope (#1186, PR #4960 by @greyfreedom). |
| 5962 | |
| 5963 | - `/preview-request` (aliases `/dryrun` and `/preview_request`) is a human-only, |
| 5964 | provider-free inspection of the next primary turn. Production dispatch and |
| 5965 | preview share one prepared-request seam across Chat Completions, Anthropic |
| 5966 | Messages, and OpenAI Responses, so the manifest reads the final wire model, |
| 5967 | reasoning controls, tool choice, tool schemas, and body hash from the same |
| 5968 | value production sends. Route, tool, or body facts that require Auto's |
| 5969 | provider classifier, an MCP connection, mutable hooks, compaction, or queued |
| 5970 | runtime injections remain typed unavailable. The manifest reports exact |
| 5971 | primary role/lane identity, upstream route-source provenance, requested and |
| 5972 | effective reasoning, canonical JSON sizes, conservative offline estimates, |
| 5973 | and provider-reported usage as unavailable because no request ran. It never |
| 5974 | adds a model-visible tool, sends a provider call, or prints prompt, message, |
| 5975 | credential, endpoint-path, or workspace-path content. The explicit |
| 5976 | `/preview-request base-prompt` mode prints only the exact effective base |
| 5977 | prompt; effective system text remains protected behind its final hash. The |
| 5978 | exact body includes the same authoritative transient Work/To-do tail used by |
| 5979 | production, including graph-backed state newer than the legacy projection. |
| 5980 | Preflight preserves production's separately framed base-plus-Work estimate, |
| 5981 | and fails closed when the authoritative projection is unavailable. An |
| 5982 | exhausted active goal token budget also produces a typed unavailable result |
| 5983 | before any outbound request is built. |
| 5984 | (#1004, #3928; dry-run concept harvested from PR #1099 by @GTC2080 / TaoMu.) |
| 5985 | |
| 5986 | - Slash commands, hotbar actions, and CLI entrypoints for the same Lane/Fleet |
| 5987 | lifecycle operation now share one typed control-plane contract |
| 5988 | (`codewhale-lane::control`): a stable `<domain>.<verb>` id, read-vs-write |
| 5989 | authority, persistence scope, exact-identity target selection, retryability, |
| 5990 | lifecycle outcome, and one bounded, sanitized receipt. `docs/COMMAND_CONTROL_PLANE.md` |
| 5991 | documents it (#1888). |
| 5992 | |
| 5993 | - `/lane [list|status|interrupt|restart|resume]` — durable Lane control from the |
| 5994 | composer, backed by the same executor `codewhale lane …` calls. `codewhale |
| 5995 | lane interrupt|restart|resume` are the matching CLI verbs; `lane stop` stays as |
| 5996 | a compatibility spelling of `lane interrupt`. Appending `@<lifecycle-seq>` to a |
| 5997 | lane id fences a write to the exact durable generation you observed, so a |
| 5998 | concurrent transition is rejected as a conflict rather than acted on (#1888). |
| 5999 | |
| 6000 | - `codewhale fleet list` and `/fleet [list|status|interrupt|resume]` — durable |
| 6001 | Fleet run inspection and control from either surface, through shared DTOs that |
| 6002 | carry the exact provider, provider-table id, model, effective reasoning tier, |
| 6003 | and route source when the ledger records them, and a typed `not_recorded` / |
| 6004 | `not_applicable` / `redacted` reason when it does not. Requested-vs-effective |
| 6005 | reasoning is never back-filled: the ledger persists the effective tier only, so |
| 6006 | the requested tier reports `not_recorded` (#4022). |
| 6007 | |
| 6008 | - The bundled skill pack now ships a `help` skill (catalog generation 7). It is |
| 6009 | `invocation: explicit-only`, so it never enters the model's ambient catalogue |
| 6010 | and costs no prompt budget. Its body is a routing card that points at the |
| 6011 | surfaces this build actually exposes — `/help` and `/help <command>`, |
| 6012 | `/skills` and `/skills inspect`, `/config`, `doctor`, and the `docs/` tree |
| 6013 | when the workspace is a Codewhale checkout — and explicitly forbids pasting a |
| 6014 | command list or settings table into context (#4698). |
| 6015 | |
| 6016 | - `crates/tui/assets/skills-catalog-matrix.json`: an authored, provider-free |
| 6017 | expectation matrix covering every bundled skill (tier, invocation, aliases, |
| 6018 | ambient-catalogue eligibility, shadowed aliases). Contract tests in |
| 6019 | `crates/tui/src/skills/catalog_matrix.rs` assert a bijection between the |
| 6020 | fixture and the shipped bundle, so the starter pack cannot change without an |
| 6021 | explicit fixture update. The matrix covers positive eligibility and explicit |
| 6022 | load, non-activation negatives, alias resolution, explicit-only exclusion, |
| 6023 | alias-vs-canonical collision precedence, and prompt-budget invariants (no |
| 6024 | duplicate catalogue entries, no aliases as extra entries, and the shipped |
| 6025 | pack fitting inside the 12 000-char budget with no omitted-skills line). These |
| 6026 | are deterministic registry/catalog/resolver assertions and make no claim about |
| 6027 | semantic model routing (#4698). |
| 6028 | |
| 6029 | - Locale-routing coverage for the complete bundled catalog across every shipped |
| 6030 | locale (`en`, `ja`, `zh-Hans`, `zh-Hant`, `pt-BR`, `es-419`, `vi`, `ko`). No |
| 6031 | bundled skill ships a localized routing description and none was invented; |
| 6032 | the tested contract is deterministic fallback to the canonical English |
| 6033 | description, with the rendered catalogue byte-identical across locales. |
| 6034 | Exact-tag match, primary-subtag fallback, and English fallback are covered |
| 6035 | against a synthetic authored fixture, and the parity test fails if a bundled |
| 6036 | skill ever gains localized metadata without source-backed coverage (#4698). |
| 6037 | |
| 6038 | - `docs/LIVE_SMOKE.md`: copy-pasteable, opt-in live-smoke instructions for Kimi |
| 6039 | K3 and a second provider/model (DeepSeek). The runs are manual only — nothing |
| 6040 | in CI, tests, or skills invokes them. They use `env -i` plus a throwaway |
| 6041 | `CODEWHALE_HOME`; `HOME` is left unset rather than repurposed, and ambient |
| 6042 | provider variables are not forwarded. The operator names the credential |
| 6043 | variable explicitly, and the isolated child reads its value with echo off, |
| 6044 | restores the prior terminal state on exit or interruption, and never persists |
| 6045 | the value or puts it in a command argument. The page states the expected |
| 6046 | route/model/reasoning/tool receipt fields while treating provider errors as |
| 6047 | unclassified until provider configuration, authentication/entitlement, and |
| 6048 | harness behavior have been corroborated independently (#4698). |
| 6049 | |
| 6050 | - Approval cards can now remember eligible safe shell and file-write approvals |
| 6051 | as exact `allow` rules scoped to the current repository. Remembered shell |
| 6052 | commands use complete-command matching, validated file and patch paths remain |
| 6053 | workspace-relative, and dangerous, critical, or repo-law-held requests stay |
| 6054 | ineligible and continue to require review. |
| 6055 | |
| 6056 | - `tui.header_items` (array of strings, optional, default `[]`): an opt-in |
| 6057 | header chip showing cumulative session token usage as input / cache-hit / |
| 6058 | output. Set `header_items = ["tokens"]` under `[tui]` to enable it. The |
| 6059 | chip is the only elidable element of the header — the git label, context |
| 6060 | meter, and version stamp keep their space, and narrow terminals drop the |
| 6061 | chip rather than the baseline chrome. Unknown entries are warned about and |
| 6062 | skipped so configs written by newer builds stay loadable by older ones |
| 6063 | (#4520 requested by @eugenicum; PR #4610 by @XhesicaFrost, harvested with |
| 6064 | co-authorship). |
| 6065 | |
| 6066 | - `thinking_default_expanded` lets reasoning blocks start open while keeping |
| 6067 | Space as the per-block toggle. The setting is persisted, available through |
| 6068 | native and runtime configuration, and documented for SSH/tmux accessibility |
| 6069 | (issue #4925 and PR #4928 by @M-Maciej). |
| 6070 | |
| 6071 | - The transcript renders a conservative subset of LaTeX math as readable |
| 6072 | Unicode without rewriting fenced/inline code, ordinary currency, escaped |
| 6073 | dollars, or unknown commands. The contribution from PR #4973 by |
| 6074 | @SparkofSpike was hardened and landed through PR #4974; reported by |
| 6075 | @antarikshraya in #4957. |
| 6076 | |
| 6077 | - Session control now includes a sessions rail, shared archive projection, |
| 6078 | picker archive controls, and opt-in interactive auto-resume with explicit |
| 6079 | handoff behavior. The work closes the remaining session-browsing direction |
| 6080 | from #2934; thanks @cy2311 for the original report. |
| 6081 | |
| 6082 | - The bundled contributor-onboarding skill can sync contribution context, |
| 6083 | select the appropriate gate, and prepare a digest without inflating the |
| 6084 | ambient skill catalog. It follows the contributor-navigation request in |
| 6085 | #4227 by @JayBeest. |
| 6086 | |
| 6087 | - Bahasa Indonesia now has a complete repository documentation suite and a |
| 6088 | registered website dictionary alongside the shipped TUI locale (PRs #4962 |
| 6089 | and #4972 by @atmosuwiryo, closing #4789). |
| 6090 | |
| 6091 | - Reasoning content can keep its rail, italics, cursor, and expansion controls |
| 6092 | while disabling only the warm background highlight. The independent setting |
| 6093 | is persisted and localized (#4089; reported by @elijahchan2019). |
| 6094 | |
| 6095 | - StepFun setup now asks whether a key belongs to PAYG or Step Plan, keeps the |
| 6096 | two endpoint/billing routes distinct, and localizes the choice across the |
| 6097 | complete packs (#4526; reported by @whp233). |
| 6098 | |
| 6099 | - OpenCode Zen is a separate model-aware API-key provider. Its curated catalog |
| 6100 | selects Responses, Anthropic Messages, or Chat Completions per model; |
| 6101 | unsupported Gemini and unknown models fail closed, and missing Zen |
| 6102 | credentials never fall through to ChatGPT/Codex OAuth guidance. The |
| 6103 | implementation from closed PR #4467 by @snail-vs (snailoniu) is preserved in |
| 6104 | the candidate. |
| 6105 | |
| 6106 | - Markdown exports correlate prompts with stable workspace restore-point ids |
| 6107 | and say when correlation is unavailable or ambiguous, completing the |
| 6108 | remaining restoration/export direction from #2494 by @wywsoor. |
| 6109 | |
| 6110 | ### Fixed |
| 6111 | |
| 6112 | - Permission setup now consistently presents the product postures Ask, |
| 6113 | Auto-Review, and Full Access instead of leaking the internal `never` token. |
| 6114 | The same resolved sandbox policy now drives execution and UI receipts: Plan |
| 6115 | stays read-only, Ask and Auto-Review stay workspace-scoped, and Full Access |
| 6116 | is actually unsandboxed unless a stricter effective configuration wins. |
| 6117 | |
| 6118 | - Fleet setup no longer stalls when a user explicitly selects a configured |
| 6119 | Codex or Grok external-consent route. The selected route is activated and |
| 6120 | validated before saving, roster roles open directly on their Model step, |
| 6121 | Review saves on the first Enter, and new profiles default to the personal |
| 6122 | profile directory that the roster loads on the next session. |
| 6123 | |
| 6124 | - Provider credential dialogs now share one wrapping, secret-safe API-key |
| 6125 | surface across every non-OAuth provider. A key already present in durable |
| 6126 | storage is reported as configured without rendering it, typing or pasting is |
| 6127 | clearly framed as replacement, narrow help text remains visible, and Codex |
| 6128 | and Grok OAuth flows remain token-free in this modal. |
| 6129 | |
| 6130 | - Ctrl+O again opens the complete recorded reasoning detail for the selected, |
| 6131 | active, or latest reasoning block. The whole-turn Turn Inspector moved to |
| 6132 | Ctrl+Alt+O and `/turn inspect`, removing the shortcut collision while keeping |
| 6133 | raw leaf detail and post-flush reasoning discoverable. |
| 6134 | |
| 6135 | - Failed child agents now deliver a distinct high-priority failure receipt to |
| 6136 | their owning parent with a sanitized failure class, elapsed work, and a full |
| 6137 | transcript handle. Parent-to-child message, follow-up, and interrupt tools |
| 6138 | now use one hierarchy-checked mailbox path, and persisted nested completion |
| 6139 | envelopes remain safely restorable across instruction-text revisions. |
| 6140 | |
| 6141 | - Background-shell completion events now carry only bounded tails plus a |
| 6142 | retrievable exact-evidence handle. Terminal foreground Bash results are |
| 6143 | acknowledged at the direct tool-result boundary and are no longer emitted a |
| 6144 | second time as background completion artifacts. |
| 6145 | |
| 6146 | - Providerless Fleet and child-agent fixed-model routes now reject only |
| 6147 | high-confidence foreign-provider model ids before creating a worktree, while |
| 6148 | explicit provider/model pairs, custom and local endpoints, unknown ids, and |
| 6149 | aggregator wire-id resolution retain their intended behavior. |
| 6150 | |
| 6151 | - Manual compaction now preserves and reports the supplied provider failure |
| 6152 | class instead of replacing it with an opaque generic error. This does not |
| 6153 | infer quota exhaustion when the recorded failure does not prove it. |
| 6154 | |
| 6155 | - The ambient jellyfish keep complete, readable silhouettes while animating, |
| 6156 | and the website favicon now uses the Signal Current desktop tile instead of |
| 6157 | the legacy whale mark. |
| 6158 | |
| 6159 | - ACP JSON-RPC responses preserve numeric request ids for avante.nvim while |
| 6160 | retaining the negotiated string-id exception for Zed (PR #4929 by |
| 6161 | @atmosuwiryo). |
| 6162 | |
| 6163 | - Restored shell cells whose job no longer exists stop displaying live |
| 6164 | spinners and settle into a truthful stale/no-output state across transcript, |
| 6165 | phase strip, and sidebar (PR #4937 by @LI-Jialu, closing #4547). |
| 6166 | |
| 6167 | - Interrupted checkpoints and timed recovery snapshots remain checkpoints |
| 6168 | instead of being promoted into orphan session files, preventing duplicate |
| 6169 | `/resume` entries (PR #4963 by @SparkofSpike). |
| 6170 | |
| 6171 | - Every shipped locale is admitted by the typed settings schema and native |
| 6172 | chooser, with complete/partial status kept independent and tested (PR #4856 |
| 6173 | by @nightt5879, closing #4786). Context-menu hover hit-testing also accounts |
| 6174 | for its title row (PR #4897 by @XhesicaFrost; reported by @SparkofSpike in |
| 6175 | #4803). |
| 6176 | |
| 6177 | - OSC 52 and SSH/tmux clipboard transport run on one bounded background worker |
| 6178 | rather than blocking input and rendering on the TUI loop; late transport |
| 6179 | failures still surface through the status path (PR #4896 by @nightt5879, |
| 6180 | closing #4159). |
| 6181 | |
| 6182 | - Non-streaming model calls receive a generation-length response budget rather |
| 6183 | than the SSE header-open timeout, while actual SSE opens share the bounded |
| 6184 | cross-provider transport seam. The equivalent fix direction came from |
| 6185 | closed PR #4743 by @vibecoding-skills. |
| 6186 | |
| 6187 | - Resumed sessions diagnose a deleted inherited workspace before shell launch |
| 6188 | instead of failing as an opaque Windows process error (report #4100 by |
| 6189 | @redjade75723). DeepSeek native tool-call wrapper tokens are also scrubbed |
| 6190 | from visible streaming and completed output as a grounded fail-soft follow-up |
| 6191 | to report #3880 by @hardy922; that report's exact emitted marker remained |
| 6192 | unconfirmed. |
| 6193 | |
| 6194 | - Auto model routing now preserves the user's requested reasoning effort |
| 6195 | through startup, provider/model changes, session restore, the picker, |
| 6196 | Ctrl+T, and Hotbar actions. The tier is normalized only after the concrete |
| 6197 | provider route is known instead of being silently replaced by Auto |
| 6198 | (#4941, PR #4961 by @nightt5879). |
| 6199 | |
| 6200 | - Auto-compaction now defaults on for every known model context window, |
| 6201 | including Kimi K3's 1,048,576-token routes. Persisting only an |
| 6202 | `auto_compact_threshold` or `auto_compact_threshold_percent` now counts as |
| 6203 | opt-in intent, while an explicit `auto_compact = false` remains authoritative. |
| 6204 | `/config` reports the effective state, percentage, and computed token trigger. |
| 6205 | |
| 6206 | - Per-provider `context_window` overrides are now documented and visible in |
| 6207 | `/config`, provider setup help, diagnostics, and the example configuration. |
| 6208 | The effective override consistently drives preflight budgeting, the context |
| 6209 | meter, and compaction; this lets a user cap a 1M Kimi route to 256K when their |
| 6210 | Coding Plan tier has the smaller window. |
| 6211 | |
| 6212 | - Agent Details now projects status, model, elapsed time, and step counts from |
| 6213 | the same row snapshot as the primary agents list, eliminating contradictory |
| 6214 | worker state between the two surfaces. |
| 6215 | |
| 6216 | - Composer submission and its hints now share one state machine. Portable |
| 6217 | terminals use Enter to queue during a running turn and Enter again to steer; |
| 6218 | Ctrl/Cmd+Enter is accepted only when an enhanced terminal reports it and is |
| 6219 | no longer advertised as universally available. |
| 6220 | |
| 6221 | - `edit_file` now matches LF-only model search text against CRLF files, |
| 6222 | preserves the file's line-ending style for replacement text, and still |
| 6223 | rejects newline-normalized duplicate matches as non-unique (#4764). |
| 6224 | Implemented in PR #4942 by @nightt5879; reported and root-caused by |
| 6225 | @LmeSzinc. |
| 6226 | |
| 6227 | - `/fleet status` read the current TUI session's sub-agents while `codewhale |
| 6228 | fleet status` read the durable `.codewhale/fleet.jsonl` ledger — two different |
| 6229 | things wearing one name, so a run started by `codewhale fleet run` never |
| 6230 | appeared in the TUI. `/fleet status` now reads the durable ledger through the |
| 6231 | same code path as the CLI; the session view keeps its own name as |
| 6232 | `/fleet workers` (`/subagents` and `n` still work). When a workspace has no |
| 6233 | ledger, both surfaces report a typed `no_fleet_ledger` reason instead of an |
| 6234 | empty-looking "all clear", and neither creates the ledger as a side effect of |
| 6235 | reading it (#4022). |
| 6236 | |
| 6237 | - `codewhale fleet status` (and `list`/`interrupt`/`resume`) created |
| 6238 | `.codewhale/fleet.jsonl` as a side effect of opening the manager, then |
| 6239 | reported `no_fleet_ledger` for the file it had just made — so the second |
| 6240 | invocation showed an empty Fleet where none existed. The CLI now refuses |
| 6241 | those verbs before the manager is constructed, matching `/fleet` (#4022). |
| 6242 | |
| 6243 | - `fleet resume <run-id>` accepted any string. An id absent from the ledger |
| 6244 | reconciled nothing but still wrote a run-status record keyed by whatever was |
| 6245 | typed, and reported `no_change`. Unknown ids are now refused as `not_found` |
| 6246 | before any durable write (#4022). |
| 6247 | |
| 6248 | - `lane interrupt` reported `transitioned` even when it changed nothing — |
| 6249 | another process's stop looked like our own. The Runtime backend now reports |
| 6250 | whether *this* call performed the transition, and a no-op is `no_change`. |
| 6251 | The `@<lifecycle-seq>` fence is also evaluated inside the registry's per-Lane |
| 6252 | lock rather than before it, so a stale fence refuses without running Runtime |
| 6253 | teardown instead of racing between the check and the stop (#1888). |
| 6254 | |
| 6255 | - `/lane` no longer runs Runtime teardown on the TUI composer thread. Reads on |
| 6256 | the slash surface skip reconciliation (which probes tmux and takes a lock) |
| 6257 | and say so on the receipt instead of implying freshness; `lane interrupt` is |
| 6258 | CLI-only until that work runs off-thread, and reports |
| 6259 | `surface_not_supported` naming `codewhale lane interrupt` (#4022). |
| 6260 | |
| 6261 | - The hotbar is no longer modelled as a third control surface. A slot binds a |
| 6262 | slash command and fires it with no argument, so it runs *as* the slash |
| 6263 | surface; the contract now declares which verb a bare press actually reaches |
| 6264 | (`hotbar_bare_dispatch`, true only for `lane.list`) instead of advertising |
| 6265 | target-taking verbs as hotbar-reachable (#1888). |
| 6266 | |
| 6267 | - `codewhale lane list --json` and `lane status --json` keep emitting the |
| 6268 | `LaneRecord` shape they always have — the receipt did not replace it. The |
| 6269 | human `lane status` output also regained `branch`, `session`, `socket`, |
| 6270 | `attach`, and `log`, which the first cut of the shared DTO had dropped |
| 6271 | (#1888). |
| 6272 | |
| 6273 | - No surface advertises a backend it does not have. `lane restart` and |
| 6274 | `lane resume` have no implementation — a Lane is re-created by |
| 6275 | `codewhale lane start`, and a stopped Lane's Runtime session is gone — so all |
| 6276 | three surfaces refuse them with `backend_not_implemented` and say why. |
| 6277 | `fleet restart` drives the manager loop to completion, which only the CLI |
| 6278 | runs, so `/fleet restart` reports `surface_not_supported` and names the CLI |
| 6279 | command rather than quietly doing a smaller thing (#1888). |
| 6280 | |
| 6281 | - Deny rules in `permissions.toml` no longer miss a command because of an |
| 6282 | intervening flag: deny matching is token-based with flag-skipping and |
| 6283 | backtracking, so a `git push` rule still catches |
| 6284 | `git -c foo=bar push`. Path matching folds case only on platforms whose |
| 6285 | filesystems are case-insensitive, and the default approval branch no |
| 6286 | longer proposes the working directory as a network host. |
| 6287 | |
| 6288 | - MCP tool calls run once. A failed call is no longer retried as if it |
| 6289 | were a failed lookup, qualified-name resolution collects every match and |
| 6290 | reports an ambiguity instead of taking whichever the hash map yielded |
| 6291 | first, and registering a server whose name collides with an existing one |
| 6292 | after sanitization is now an error rather than a silent overwrite. |
| 6293 | The equivalent call-once fix direction came from closed PR #4756 by |
| 6294 | @adity982. |
| 6295 | |
| 6296 | - The session index survives a torn line: an unparseable entry is skipped |
| 6297 | rather than aborting the whole read, appends carry their data through to |
| 6298 | disk, and appends and compaction share a lock so a compaction can no |
| 6299 | longer race an append into a lost record. |
| 6300 | |
| 6301 | - `Edit` counts as a write tool for workflow elevation, and the TUI's |
| 6302 | write/shell classification now delegates to one shared allowlist rather |
| 6303 | than keeping a second copy that could drift. |
| 6304 | |
| 6305 | - A rejected `app/config/set` stays a no-op. Previously an invalid value |
| 6306 | still tore down the cached runtime bridge, killing the child runtime and |
| 6307 | orphaning every other in-flight stdio thread behind a response that |
| 6308 | correctly reported failure. |
| 6309 | |
| 6310 | - A malformed project `config.toml` is no longer indistinguishable from |
| 6311 | having no project config. Because a project config may only *tighten* |
| 6312 | approval and sandbox policy, silently discarding a broken one dropped a |
| 6313 | repository's restrictions back to the looser user defaults; the setup |
| 6314 | wizard now says so, naming the file but never quoting its contents. |
| 6315 | |
| 6316 | - An expired lane worktree no longer leaves its branch behind, which made |
| 6317 | reusing the same lane name fail with "branch already exists". A branch |
| 6318 | still carrying unmerged commits is kept — a TTL lapsing is not consent |
| 6319 | to delete someone's work. |
| 6320 | |
| 6321 | - An in-flight `thread/message` turn can be stopped. The stdio loop keeps |
| 6322 | reading while a turn streams, so the new `thread/interrupt` request (and |
| 6323 | `shutdown`) can reach a runaway turn instead of waiting on the very turn |
| 6324 | they were meant to stop. |
| 6325 | |
| 6326 | - Precedence is stated only in the constitution's "Whose word wins" section. |
| 6327 | Memory hygiene no longer ships an inverted Tier list that put the |
| 6328 | constitution above the user's current request; approval, compaction, and |
| 6329 | personality overlays describe behavior without rank vocabulary; and the |
| 6330 | authority recap points at the single source rather than restating a second |
| 6331 | ladder. |
| 6332 | |
| 6333 | - `<turn_meta>` carries facts (mode, posture, model, workspace), not mode |
| 6334 | doctrine or permission-question essays re-asserted every user message. |
| 6335 | |
| 6336 | - The project context pack (pretty-printed workspace tree) is off by default |
| 6337 | and opt-in via `[context] project_pack = true`. Language law is compressed |
| 6338 | while keeping the English-constitution / user-language-reply contract. |
| 6339 | |
| 6340 | - Modal lists and config pickers wrap selection at both ends (Down past the |
| 6341 | last row returns to the top). Home-directory resolution prefers |
| 6342 | `HOME`/`USERPROFILE` via `effective_home_dir` across remaining call sites so |
| 6343 | Windows tests that fake the home env vars match production paths. The |
| 6344 | equivalent home-directory sweep came from closed PR #4760 by |
| 6345 | @EvanProgramming. |
| 6346 | |
| 6347 | ### Changed |
| 6348 | |
| 6349 | - Prefix-cache tool catalog entries store only the SHA-256 digest, not the |
| 6350 | joined catalog string. Unused plan-transition validation helpers are removed. |
| 6351 | |
| 6352 | - Settings sections now hold only what they claim (#4751). Fleet keeps |
| 6353 | Fleet/member concerns; `/goal` moved to a **Session** section and Workflow |
| 6354 | orchestration to its own **Workflow** section. The inert DeepSeek-only |
| 6355 | `default_model` fallback moved out of Model settings into an explicit |
| 6356 | **Legacy** section — exact-Fleet users switch Fleets, not fallback models; |
| 6357 | the config field is retained because the runtime still reads it. This is |
| 6358 | presentation only: the persisted keys (`goal_command`, `workflow`, |
| 6359 | `default_model`), their values, scopes, and runtime behavior are unchanged. |
| 6360 | |
| 6361 | - Auto model routing is scoped to the active provider. The classifier |
| 6362 | inventory no longer discloses other providers' runnable routes (or the fact |
| 6363 | that their credentials exist), a classifier reply naming another provider is |
| 6364 | refused, the local heuristic no longer falls back to a different provider |
| 6365 | when the active one is unusable, and the implicit DeepSeek-flash classifier |
| 6366 | is skipped for non-DeepSeek sessions. Auto receipts and the model picker |
| 6367 | hint report the active-provider-only scope instead of "runnable providers". |
| 6368 | Cross-provider Auto is available only through the persisted `[auto] |
| 6369 | cross_provider = true` opt-in (an explicit `[auto.router]` route remains its |
| 6370 | own opt-in for the classifier call). Same-provider strong/fast selection and |
| 6371 | `[auto] cost_saving` are unchanged. |
| 6372 | |
| 6373 | - The QA pseudo-terminal acceptance harness now parses frames with `rio-vt` |
| 6374 | behind its existing neutral frame/color surface, retaining the assertions |
| 6375 | while removing the `vt100` dependency (PR #4931 by @raphamorim). |
| 6376 | |
| 6377 | - Anthropic Messages and OpenAI Responses stream opening now share the |
| 6378 | `client/stream_entry.rs` seam already used by Chat Completions: one bounded |
| 6379 | response-header wait, shared dual/HTTP-1.1 policy selection, at most one |
| 6380 | HTTP/1.1 fallback on a classified HTTP/2 header stall, and common idle-timeout |
| 6381 | diagnostics. Wire-specific authentication, headers, endpoints, decoding, and |
| 6382 | rate-limit behavior remain at each adapter edge. The timeout-placement |
| 6383 | diagnosis and fix direction came from closed PR #4743 by |
| 6384 | @vibecoding-skills. |
| 6385 | |
| 6386 | ### Security |
| 6387 | |
| 6388 | - Release containers now publish an SBOM attestation and pin maximum-mode |
| 6389 | provenance explicitly so supply-chain metadata cannot silently weaken with a |
| 6390 | builder-default change (PR #4958 by @kobihikri). |
| 6391 | |
| 6392 | ### Contributors |
| 6393 | |
| 6394 | Thank you to the contributors whose code, reports, and reviews shaped v0.9.2: |
| 6395 | |
| 6396 | - [@greyfreedom](https://github.com/greyfreedom) — exact repository-scoped |
| 6397 | allow grants and cross-platform path semantics (PR #4761), plus safe |
| 6398 | permission-rule listing and snapshot-bound removal (PR #4960). |
| 6399 | - [@nightt5879](https://github.com/nightt5879) — off-event-loop clipboard |
| 6400 | writes (PR #4896), complete locale exposure in settings (PR #4856), CRLF-safe |
| 6401 | edits (PR #4942), and reasoning-effort preservation across automatic model |
| 6402 | routing (PR #4961). |
| 6403 | - [@XhesicaFrost](https://github.com/XhesicaFrost) — the configurable |
| 6404 | session-token header (PR #4610) and context-menu hover alignment (PR #4897). |
| 6405 | - [@cyq1017](https://github.com/cyq1017) — the hooks configuration/executor |
| 6406 | split from PR #4087. |
| 6407 | - [@snail-vs](https://github.com/snail-vs) (snailoniu) — OpenCode Zen's |
| 6408 | model-aware routes, authentication, documentation, and test isolation from |
| 6409 | closed PR #4467, whose contributor commits are preserved in the candidate. |
| 6410 | - [@SparkofSpike](https://github.com/SparkofSpike) — the zh-Hans translation |
| 6411 | quality review harvested from PR #4908, duplicate-session fix in PR #4963, |
| 6412 | LaTeX implementation from PR #4973 landed through #4974, and the context-menu |
| 6413 | reproduction in #4803. |
| 6414 | - [@GTC2080](https://github.com/GTC2080) — the request-preview concept from |
| 6415 | PR #1099. |
| 6416 | - [@h3c-hexin](https://github.com/h3c-hexin) — non-UTF-8 `fetch_url` |
| 6417 | decoding direction from PR #4909. |
| 6418 | - [@fleitz](https://github.com/fleitz) — required source-candidate credit for |
| 6419 | the canonical `Bash` no-`cwd` workspace fix and regression in PR #4673 |
| 6420 | (issue #4674). |
| 6421 | - [@LmeSzinc](https://github.com/LmeSzinc) — the Windows CRLF `edit_file` |
| 6422 | reproduction, root-cause analysis, and affected-code anchors in issue #4764. |
| 6423 | - [@atmosuwiryo](https://github.com/atmosuwiryo) — ACP numeric-id compatibility |
| 6424 | (PR #4929) and the Indonesian documentation and website locale (PRs #4962 |
| 6425 | and #4972). |
| 6426 | - [@M-Maciej](https://github.com/M-Maciej) — the expanded-by-default reasoning |
| 6427 | setting and its original report (PR #4928, issue #4925). |
| 6428 | - [@raphamorim](https://github.com/raphamorim) — migration of the QA PTY frame |
| 6429 | parser to `rio-vt` (PR #4931). |
| 6430 | - [@LI-Jialu](https://github.com/LI-Jialu) — truthful finalization of restored |
| 6431 | stale shell cells (PR #4937). |
| 6432 | - [@kobihikri](https://github.com/kobihikri) — release-container SBOM and |
| 6433 | explicit provenance mode (PR #4958). |
| 6434 | - [@EvanProgramming](https://github.com/EvanProgramming), |
| 6435 | [@adity982](https://github.com/adity982), and |
| 6436 | [@vibecoding-skills](https://github.com/vibecoding-skills) — equivalent fix |
| 6437 | direction for the effective-home sweep (#4760), MCP call-once behavior |
| 6438 | (#4756), and streaming/non-streaming timeout split (#4743). |
| 6439 | - [@antarikshraya](https://github.com/antarikshraya) — the LaTeX transcript |
| 6440 | rendering report in #4957. |
| 6441 | - [@eugenicum](https://github.com/eugenicum) — the token-header request and |
| 6442 | output-presentation measurements in #4520 and #4468. |
| 6443 | - [@whp233](https://github.com/whp233) — the StepFun/OpenCode subscription-route |
| 6444 | request in #4526. |
| 6445 | - [@redjade75723](https://github.com/redjade75723), |
| 6446 | [@hardy922](https://github.com/hardy922), |
| 6447 | [@JayBeest](https://github.com/JayBeest), |
| 6448 | [@elijahchan2019](https://github.com/elijahchan2019), |
| 6449 | [@cy2311](https://github.com/cy2311), and |
| 6450 | [@wywsoor](https://github.com/wywsoor) — reports and product direction behind |
| 6451 | the stale-workspace diagnosis (#4100), native-tool-token filtering (#3880), |
| 6452 | contributor onboarding (#4227), optional reasoning highlight (#4089), |
| 6453 | session control (#2934), and export/restore correlation (#2494). |
| 6454 | |
| 6455 | ## [0.9.1] - 2026-07-24 |
| 6456 | |
| 6457 | ### Dogfood follow-ups (2026-07-24) |
| 6458 | |
| 6459 | ### Added |
| 6460 | |
| 6461 | - `/compact [focus]`: the manual compaction command now accepts an |
| 6462 | optional focus argument that is injected into the summary prompt, and |
| 6463 | the compaction summary itself becomes a structured nine-section |
| 6464 | successor briefing (primary intent, key concepts, files and code, |
| 6465 | errors and fixes, problem solving, user messages, pending tasks, |
| 6466 | current work, next step) that carries earlier compaction summaries |
| 6467 | forward and explicitly forbids tool use — replacing the free-form |
| 6468 | "under N words" instruction. Codewhale's pin/working-set and |
| 6469 | V4 prefix-cache-aligned machinery are unchanged. |
| 6470 | |
| 6471 | - Saved workflows become slash commands: `*.workflow.js` files under |
| 6472 | `<workspace>/.codewhale/workflows/` and `~/.codewhale/workflows/` are |
| 6473 | discovered as `/name` commands that accept custom arguments (forwarded |
| 6474 | to the run's `args`), launch through the `workflow` tool in the |
| 6475 | background, and report their run id. Hand-written `.md` commands with |
| 6476 | the same name always win. The workflow tool's `source_path` now also |
| 6477 | accepts the user-global `~/.codewhale/workflows/` store, and every |
| 6478 | settled run leaves a durable synthesized report under |
| 6479 | `.codewhale/reports/<run_id>.md` (status, goal, gates, progress, |
| 6480 | result, verification). |
| 6481 | |
| 6482 | ### Fixed |
| 6483 | |
| 6484 | - Disambiguate the two Kimi K3 model-picker rows, which read as an |
| 6485 | unexplained duplicate: bare `k3` is now labeled "Kimi Code plan route" |
| 6486 | with its default 262K window annotated as the plan-tier floor (raisable |
| 6487 | via the provider `context_window` setting for plans that include 1M), |
| 6488 | and `kimi-k3` is labeled "Moonshot direct route" with its 1M window. |
| 6489 | Both remain distinct, valid routes for the same underlying model. |
| 6490 | - Close the model-facing `agent` tool role schema: the `type` property now |
| 6491 | publishes the canonical JSON Schema enum `["worker", "scout", "planner", |
| 6492 | "reviewer", "builder", "verifier", "custom"]` instead of describing the |
| 6493 | accepted values in prose. Legacy aliases are no longer advertised to |
| 6494 | models; they remain accepted only at replay/deserialization boundaries. |
| 6495 | Provider schema sanitizers (Chat Completions, strict mode, Anthropic |
| 6496 | Messages / OpenAI Responses, Moonshot/Kimi) are pinned by test to |
| 6497 | preserve the closed enum. |
| 6498 | |
| 6499 | ### Changed |
| 6500 | |
| 6501 | - Rework the ambient idle ocean: the water now holds exactly one loose |
| 6502 | wedge school of fish, jellyfish, bubbles, and the rare whale cameo — |
| 6503 | seaweed and bio-dust are removed. Fish swim on a wrap-around path and |
| 6504 | always face the way they move (direction can only change while the |
| 6505 | school is off-screen); the lead fish carries an eye (`><o>`). |
| 6506 | Jellyfish become a pulsing bell with a lagging swaying tentacle. All |
| 6507 | ambient marks now glow via background→ink color lerp: a travelling |
| 6508 | sin² wave through the school, a floor-bounded pulse for jellyfish, |
| 6509 | and occasional raised-cosine glints on bubbles, with deliberately |
| 6510 | non-matching periods so nothing strobes in sync. |
| 6511 | |
| 6512 | - Rename the internal delegated-worker role type from `SubAgentType` to |
| 6513 | `FleetRole` with canonical variants (`Worker`, `Scout`, `Planner`, |
| 6514 | `Reviewer`, `Builder`, `Verifier`, `Custom`) matching the public Fleet |
| 6515 | vocabulary one-to-one. Wire behavior is unchanged: serialization emits |
| 6516 | canonical Fleet values only, and persisted `agent_type` fields plus |
| 6517 | documented legacy spellings (`general`, `explore`, `plan`, `review`, |
| 6518 | `implementer`, …) continue to load at deserialization/parse boundaries; |
| 6519 | unknown role tokens still fail closed with the canonical vocabulary in |
| 6520 | the error. |
| 6521 | |
| 6522 | |
| 6523 | The Codewhale v0.9.1 source candidate includes a first-class local web client over the Runtime API, |
| 6524 | first-class OpenCode Go and TelecomJS TokenHub providers and restored xAI device login, |
| 6525 | calendar-correct hourly automations, a buildable OpenHarmony workflow-js |
| 6526 | target, and hardening for Auto routing, remote-terminal clipboard transport, |
| 6527 | restart recovery, and a coherent TUI, Work, evidence, and public release |
| 6528 | surface. |
| 6529 | |
| 6530 | ### Added |
| 6531 | |
| 6532 | - Add `codewhale web [--port 7878]`, a first-class loopback-only browser |
| 6533 | client over the canonical Runtime API. The dependency-free embedded shell |
| 6534 | supports thread lifecycle, snapshot-then-SSE transcripts, turn start/steer/ |
| 6535 | interrupt, approvals, and user questions, including pending-request recovery |
| 6536 | across tab reloads, while leaving unsupported managed, |
| 6537 | files, PTY, model-selection, and Fleet controls absent. Browser auth uses a |
| 6538 | short-lived one-time loopback capability exchanged for an opaque, bounded, |
| 6539 | process-local HttpOnly, SameSite=Strict session cookie with a same-origin |
| 6540 | mutation guard; Runtime tokens never enter URLs, HTML, browser storage, logs, |
| 6541 | or browser-launch arguments (#4423). |
| 6542 | - Add OpenCode Go as a first-class, subscription-backed Chat Completions |
| 6543 | provider with `[providers.opencode_go]`, `OPENCODE_GO_API_KEY`, and the eight |
| 6544 | models currently documented on its `/v1/chat/completions` endpoint. Models |
| 6545 | served only through OpenCode Go's Anthropic `/messages` endpoint remain out |
| 6546 | of this narrow route until Codewhale supports per-model wire selection |
| 6547 | (#1481 by @seanthefuturegorilla; implementation harvested from PR #773 by |
| 6548 | @zhangweiii and PR #1050 by @sternelee). |
| 6549 | - Add TelecomJS TokenHub as a first-class Chat Completions provider with |
| 6550 | `[providers.telecomjs]`, `TELECOMJS_API_KEY`, and a key-scoped live |
| 6551 | `/v1/models` refresh. Models.dev and provider-specific catalogs remain in |
| 6552 | separate source partitions so either refresh order preserves both; refreshes |
| 6553 | do not delete the other source's rows, matching model ids from unrelated |
| 6554 | providers do not fabricate metadata, and chat requests omit unsupported |
| 6555 | reasoning fields (PR #4370 by @baendlorel; harvested with co-authorship). |
| 6556 | - Prepare native Windows ARM64 `codewhale`, `codew`, and `codewhale-tui` |
| 6557 | binaries, npm selection, updater support, and standard/portable release |
| 6558 | archives. Build and smoke them on GitHub's native Windows 11 ARM runner, |
| 6559 | and move Linux ARM64 release builds to the native Ubuntu ARM runner to |
| 6560 | remove the slower multi-arch cross-link setup (#4267 by @w1w218). |
| 6561 | - `load_skill` tool now supports listing: omit `name` or pass `"list"` to |
| 6562 | see all available skills without loading one (#4651). |
| 6563 | - Add a unified `/skills` manager with one precedence-aware root catalog, |
| 6564 | bounded duplicate/shadow/conflict auditing, package provenance, and |
| 6565 | validated install, update, remove, and trust mutations (PR #4679 by |
| 6566 | @SamhandsomeLee). |
| 6567 | - Add a safe Agent Details view and bounded, structured `current_activity` to |
| 6568 | the single Work projection, sourced from worker events instead of renderer |
| 6569 | string inference. Rows stay compact, exact evidence is opt-in, and raw child |
| 6570 | output never enters the parent transcript (#2889 and #4636; design direction |
| 6571 | by @aboimpinto, preserved from #2694). |
| 6572 | - Make exact results and delegated coordination durable: non-inline tool output |
| 6573 | becomes immutable session-owned evidence behind bounded receipts; File |
| 6574 | mutations add configurable success-only diffs; and decisions and write |
| 6575 | contention survive restart with typed neutral-fan-in records (#4619, #4636, |
| 6576 | #4647). |
| 6577 | - Runtime API provider registry and atomic provider-switch endpoints |
| 6578 | (`GET /v1/providers`, `GET /v1/providers/{id}/models`, |
| 6579 | `POST /v1/providers/{id}/switch`) so the web GUI renders a dynamic |
| 6580 | provider/model picker without the setConfig+reload clobber (#4658). |
| 6581 | - Typed filter (`/`) in the Fleet setup wizard's Model step: substring |
| 6582 | match over provider id, display label, and model id keeps |
| 6583 | OpenRouter-scale catalogs navigable (#4639). |
| 6584 | - `[auto.router]` config: explicit provider/model/thinking for the Auto |
| 6585 | mode classifier route; unset keeps the DeepSeek flash default, and |
| 6586 | missing credentials fall back to the local heuristic. |
| 6587 | |
| 6588 | ### Changed |
| 6589 | |
| 6590 | - Keep the top activity bar literal and actionable: active To-dos appear first, |
| 6591 | followed by Sub-agents, while generic operations and coordination stay in |
| 6592 | the detail surface. Completed-only bars auto-hide, and top/side layouts can |
| 6593 | be resized by dragging their divider and retain the chosen size (#4700, |
| 6594 | #4702). |
| 6595 | - Use each theme's semantic colors for composer mode and permission rails, and |
| 6596 | show a larger inline reasoning preview with clearer local/full expansion |
| 6597 | affordances (#4699, #4701). |
| 6598 | - Simplify the model-facing runtime around stable action tools (`File`, `Git`, |
| 6599 | `Run`, deferred `Web`, and durable task and automation families), with legacy |
| 6600 | spellings hidden for replay. Fresh sessions no longer reserve a Work surface |
| 6601 | before real work exists (PR #4675). |
| 6602 | - Give the terminal shell one deliberate visual language: cool Plan → Act → |
| 6603 | Operate and warm Ask → Auto-Review → Full Access ramps match between header |
| 6604 | and split composer edges; transcript rhythm groups related activity; a |
| 6605 | refined whale keeps the empty state calm; and one-cell live motion with |
| 6606 | truthful labels distinguishes reasoning, reading, tool use, and verification |
| 6607 | without exposing private reasoning text. Reduced-motion and animation-off |
| 6608 | settings freeze it, while ASCII-safe terminals retain the signal (#4676, |
| 6609 | #4677). |
| 6610 | - Unified shell tool: the model now sees a single `Bash` tool with an `action` |
| 6611 | parameter (run/wait/interact/cancel). Legacy `exec_shell*` names remain as |
| 6612 | hidden compat aliases for transcript replay, and the tool-search catalog |
| 6613 | keeps `Bash` active by default (#4625). |
| 6614 | - Tool output inline preview increased from 6 to 12 lines (4 head + 4 tail) |
| 6615 | before the fold indicator; full pager (`v` key) unchanged (#4603). |
| 6616 | - Mode changes (`/mode agent|plan|operate`) now persist to `settings.toml` |
| 6617 | and restore across sessions (#4628). |
| 6618 | - Billing provenance: every outgoing API request carries an |
| 6619 | `x-codewhale-provenance` header with client version and provider (#4324). |
| 6620 | - The `/model` picker's typed search now ranks results: provider-name |
| 6621 | matches first (drill-down), then exact id, then id-prefix, then the |
| 6622 | active provider's rows (#4639). |
| 6623 | - System prompt text consolidated into a single `prompts/text.rs` |
| 6624 | module (byte-exact constants replacing 17 layered files); |
| 6625 | composition order, constitution-first binding, and locale/personality |
| 6626 | variants unchanged. |
| 6627 | - Ask, Auto-Review, Full Access, and Never resolve through one permission |
| 6628 | contract: `resolve_tool_permission` in the engine and |
| 6629 | `resolve_approval_request_disposition` in the UI share one truth table for |
| 6630 | session grants/denials, non-bypassable policy holds, and modal prompts |
| 6631 | (#4412). |
| 6632 | - Collapsed multi-struct tool families into single action-dispatched tools |
| 6633 | (`AutomationTool`, `TasksTool`, `GithubTool`, `RlmTool`) while keeping |
| 6634 | legacy tool names as hidden compatibility aliases for transcript replay. |
| 6635 | - Operate-mode children default to leaf depth (`max_depth=0`) unless the |
| 6636 | caller explicitly grants a deeper budget (#4598). |
| 6637 | |
| 6638 | ### Fixed |
| 6639 | |
| 6640 | - Restore `uwu` theme config round-tripping and keep header permission colors |
| 6641 | and authored idle-whale geometry aligned with the selected theme (#4696). |
| 6642 | - Default canonical `Bash` runs with no explicit `cwd` to the active |
| 6643 | `ToolContext.workspace`, including an isolated sub-agent worktree, instead of |
| 6644 | falling through to the shared shell manager's parent workspace. The regression |
| 6645 | test detects the selected workspace through marker files so it remains |
| 6646 | meaningful across PowerShell path spellings (#4674, PR #4673 by @fleitz). |
| 6647 | - Generate QuickJS bindings for `aarch64-unknown-linux-ohos` with the native |
| 6648 | SDK's libclang and sysroot, carry the OHOS target and sysroot through final |
| 6649 | linking, and keep unsupported persistent PTY dependencies out of the target |
| 6650 | while retaining non-PTY `exec_shell` support (#4470 by @shenjackyuanjie; |
| 6651 | original bindgen approach in #4384 by @shenyongqing). |
| 6652 | - Honor `[auto] cost_saving = true` in provider-aware heuristic and classifier |
| 6653 | routing, using only validated same-provider fast siblings and deriving |
| 6654 | fallback candidates from their actual provider so Auto cannot invent a |
| 6655 | cross-provider model. Providers without a known fast sibling stay on the |
| 6656 | active model (#4486; partial #4405). |
| 6657 | - Make terminal-client clipboard behavior truthful over SSH: use OSC 52 |
| 6658 | outside tmux, stock `tmux load-buffer -w` inside tmux, and bracketed paste |
| 6659 | for client-to-remote text. Graphical text and image access now requires |
| 6660 | credible forwarding or an explicit override, transport failures no longer |
| 6661 | claim success, and help distinguishes terminal text paste from graphical |
| 6662 | image attachment (#4484). |
| 6663 | - Keep a fresh TUI Work surface from rendering prior-session worker snapshots |
| 6664 | or durable-task terminal receipts whose creation or completion predates the |
| 6665 | current app start. Active durable tasks remain visible, and shared history |
| 6666 | stays available through `/tasks` and archived agent views (#4488; partial |
| 6667 | #4416). |
| 6668 | - Make doctor and setup output distinguish static configuration, command |
| 6669 | availability, MCP protocol readiness, and backend health instead of |
| 6670 | presenting configured routes as live-healthy. Ordinary doctor runs no |
| 6671 | longer wake loopback/self-hosted providers unless `--probe-local` is |
| 6672 | explicitly requested (#4485; partial #4406). |
| 6673 | - Serialize test-only configuration-path readers with temporary environment |
| 6674 | redirects so the Windows provider-persistence matrix cannot observe another |
| 6675 | test's transient `CODEWHALE_HOME` or config path (#4483, closing #4463). |
| 6676 | - Restore direct Moonshot `kimi-k3` to its documented 1,048,576-token |
| 6677 | context window and 131,072-token output limit instead of treating the live |
| 6678 | model as an unknown legacy 128K route. The existing Kimi Code tiered `k3` |
| 6679 | route and credential reuse remain unchanged (#4481). |
| 6680 | - Keep read-before-edit snapshots in the engine session so a file read remains |
| 6681 | valid across turns and context compaction, while a new session still starts |
| 6682 | with an empty tracker (#4475 by @Angel-Hair). |
| 6683 | - Make `apply_patch` expose the canonical `replace` operation while continuing |
| 6684 | to accept deprecated `changes` payloads through one validation path. Mixed |
| 6685 | patch, replace, and compatibility modes now fail before any write (#4476 by |
| 6686 | @Angel-Hair). |
| 6687 | - Show the prompt-cache hit rate in the phase strip when the Cache status item |
| 6688 | is enabled, using overflow-safe rounded integer math and leaving compact or |
| 6689 | disabled status layouts unchanged (#4474 by @dmitri-0). |
| 6690 | - Preserve Solarized Light's canonical Base3 (`#fdf6e3`) shell background |
| 6691 | instead of tinting it green-grey through the default underwater Ombre |
| 6692 | treatment, while retaining foreground ambient life (#4457 by |
| 6693 | @AiurArtanis; PR #4471 by @nightt5879). |
| 6694 | - Register `/slop` and `/canzha` as compatibility aliases of `/debt`, while |
| 6695 | keeping user-command ownership truthful across dispatch, help, slash |
| 6696 | completion, alias copy, and typo suggestions (PR #4680 by @nightt5879). |
| 6697 | - Fail closed on legacy Kimi CLI credential imports: remove Codewhale's |
| 6698 | hard-coded first-party-client impersonation and refresh request, never |
| 6699 | auto-enable or rewrite imported credentials, and label the compatibility |
| 6700 | route as a read-only imported token. An explicitly configured, still-valid |
| 6701 | access token remains usable until expiry; missing, malformed, and expired |
| 6702 | imports recover through the supported Kimi Code API-key route while |
| 6703 | first-class OAuth awaits Codewhale's own vendor registration (#4417, |
| 6704 | partially addressed). |
| 6705 | - Restore xAI/Grok device-code OAuth login against the live xAI OIDC |
| 6706 | contract: discovery with issuer/endpoint validation and documented |
| 6707 | fallbacks, user-principal scope set, RFC 8628 `slow_down` backoff capped at |
| 6708 | code expiry, bounded, sanitized error reporting for denial, expiry, and |
| 6709 | malformed responses, and a shared blocking-worker boundary for both CLI and |
| 6710 | TUI login so reqwest's blocking client never creates or drops its private |
| 6711 | runtime inside Codewhale's Tokio runtime (#4410). |
| 6712 | - Anchor `FREQ=HOURLY` automations with `BYHOUR`/`BYMINUTE` to persisted |
| 6713 | local-calendar slots so intervals keep their wall-clock phase across DST, |
| 6714 | restart, resume, RRULE updates, duplicate-slot recovery, and post-run |
| 6715 | advancement. Nonexistent clock slots are skipped and ambiguous slots run at |
| 6716 | their first occurrence (#4381 by @h3c-hexin). |
| 6717 | - Give content-watch drafts canonical identities: the link and semantic-drift |
| 6718 | watchers now write and dedup through one canonical draft-storage key with |
| 6719 | deterministic hash-suffixed IDs, validate and bound model drift output |
| 6720 | before any KV writes, and show truthful admin draft labels, so unchanged |
| 6721 | findings dedup and changed findings re-draft instead of colliding (#4453). |
| 6722 | - Make model-policy JSON repair consider object and array payloads in source |
| 6723 | order, matching nested delimiters across quoted strings and escapes and |
| 6724 | returning the earliest balanced candidate that parses, instead of letting |
| 6725 | an unmatched opening delimiter or object-first preference corrupt array |
| 6726 | payloads (#4430). |
| 6727 | - Convert persisted sub-agent completion and still-running control events into |
| 6728 | concise, non-authoritative resume checkpoints, keeping their raw runtime |
| 6729 | envelopes, sentinels, and retry instructions out of restored model and TUI |
| 6730 | conversation state (#4409). |
| 6731 | - Deliver failed, stopped, and stale sub-agent outcomes exactly once to the |
| 6732 | awaiting parent, lifecycle mailbox, and TUI before closing their runtime |
| 6733 | state. Restart now reconciles orphaned queued/model/tool-wait worker records |
| 6734 | to interrupted while preserving checkpoints, and cancelled workers no |
| 6735 | longer read as completed in the TUI (#4408). |
| 6736 | - Give host applications a cancellation boundary for MCP OAuth login so a |
| 6737 | stalled or abandoned provider login no longer hangs the calling session |
| 6738 | (#4380). |
| 6739 | - Avoid blocked reader joins after Windows process kills so terminated shell |
| 6740 | sessions cannot hang their readers (#4383). |
| 6741 | - Give stdin-less observer hooks immediate EOF and contain timed-out hook |
| 6742 | process trees so descendants and pipe readers cannot leak after the parent |
| 6743 | shell exits (#4489 by @luismateusvargas). |
| 6744 | - Preserve the full unsigned Windows PTY process status instead of collapsing |
| 6745 | every high-bit exception or NTSTATUS to `2147483647`, including decimal and |
| 6746 | hexadecimal diagnostic metadata for device retests (#4100 by |
| 6747 | @redjade75723). |
| 6748 | - Keep the Hotbar Setup action list synchronized with keyboard focus when the |
| 6749 | selection moves beyond the visible rows, including Down past `/export` |
| 6750 | (#4418). |
| 6751 | - Route Windows OpenHarmony Cargo links through the repository's target-aware |
| 6752 | clang launcher so the final Rust link keeps its target, sysroot, and MUSL |
| 6753 | flags, and extend the no-SDK release guard to protect that contract. This |
| 6754 | completes [@shenjackyuanjie](https://github.com/shenjackyuanjie)'s PR #4470 |
| 6755 | setup alongside [@shenyongqing](https://github.com/shenyongqing)'s original |
| 6756 | bindgen approach in PR #4384. |
| 6757 | - Reconcile the website roadmap with reality: the retired share-link |
| 6758 | direction is now an explicit non-goal, Workrooms is the considered |
| 6759 | direction, and the local web client appears as underway, in English and |
| 6760 | Chinese (#3418). |
| 6761 | - System-prompt skills block and skill-load warnings no longer embed absolute |
| 6762 | home/workspace paths; entries render workspace-relative or `~/…` so the |
| 6763 | byte-stable prompt prefix never leaks private paths. A new invariant test |
| 6764 | guards absolute paths, API keys, and workspace paths in the prefix (#4632). |
| 6765 | - Mode/permission baseline unit tests no longer read the developer's live |
| 6766 | `settings.toml`; they isolate config I/O to a temp directory (#4628). |
| 6767 | - Enter no longer freezes the composer on send: dispatch splits into a |
| 6768 | sync prepare phase (instant history + spinner) and a spawned async |
| 6769 | phase (auto-route, preflight, engine send), with submits gated while |
| 6770 | a dispatch is in flight (#4605). |
| 6771 | - Self-hosted routes keep explicit per-model output limits for unknown |
| 6772 | wire aliases instead of the generic 4K fallback (#4655 by @h3c-hexin; |
| 6773 | PR #4656). |
| 6774 | - Chat Completions idle-timeout errors now include received-byte and |
| 6775 | timing telemetry, distinguishing prefill stalls from mid-stream |
| 6776 | stalls with truncated tool-call arguments (#4657 by @h3c-hexin). |
| 6777 | - `set_config` provider writes now keep the in-memory route in step, |
| 6778 | so a following model write lands in the new provider's table instead |
| 6779 | of clobbering the previous provider's root default_text_model (#4658 |
| 6780 | by @gaord, with a follow-up route-sync fix). |
| 6781 | |
| 6782 | ### Security |
| 6783 | |
| 6784 | - Restrict cross-origin Runtime API browser preflights to the documented |
| 6785 | authentication and content headers, explicitly allowing `Authorization` |
| 6786 | instead of relying on a wildcard (#4454). |
| 6787 | |
| 6788 | ### Contributors |
| 6789 | |
| 6790 | Thank you to the contributors whose code, reports, and reviews shaped v0.9.1: |
| 6791 | |
| 6792 | - [@h3c-hexin](https://github.com/h3c-hexin) — calendar-anchored hourly |
| 6793 | automation recurrence (PR #4381), the MCP OAuth cancellation report |
| 6794 | (#4380), explicit limits for unknown local models (PR #4656 / #4655), |
| 6795 | and idle-timeout progress telemetry (PR #4657). |
| 6796 | - [@gaord](https://github.com/gaord) — Runtime API provider registry and |
| 6797 | atomic provider-switch endpoints (PR #4658). |
| 6798 | - [@SamhandsomeLee](https://github.com/SamhandsomeLee) — the unified `/skills` |
| 6799 | root catalog, audit/provenance model, validated mutations, manager UI, and |
| 6800 | acceptance coverage (PR #4679), plus Enter-send lag diagnosis and fix |
| 6801 | direction for #4605 (PR #4654; landed via the release-lane async-dispatch |
| 6802 | split). |
| 6803 | - [@aboimpinto](https://github.com/aboimpinto) — the Layer 5.1 user-command |
| 6804 | registry boundary from PR #3278; the exact authored evidence commit from PR |
| 6805 | #4046, preserved intact in the integration graph; and the #2870 follow-up |
| 6806 | audit whose metadata and malformed-sibling gaps shaped the final corrections. |
| 6807 | Paulo also provided the structured, redacted Agent Details and |
| 6808 | `current_activity` direction preserved from #2694/#2889 and the real-PTY |
| 6809 | lifecycle acceptance direction from #2886. |
| 6810 | - [@baendlorel](https://github.com/baendlorel) — TelecomJS TokenHub provider |
| 6811 | support and key-scoped live-catalog direction from PR #4370, harvested into |
| 6812 | the current provider architecture with co-authorship preserved. |
| 6813 | - [@zhangweiii](https://github.com/zhangweiii) and |
| 6814 | [@sternelee](https://github.com/sternelee) — the original first-class |
| 6815 | OpenCode Go implementations (PRs #773 and #1050), harvested into the |
| 6816 | current provider architecture. |
| 6817 | - [@seanthefuturegorilla](https://github.com/seanthefuturegorilla) — the |
| 6818 | canonical OpenCode Go/Zen provider request and acceptance direction |
| 6819 | (#1481). |
| 6820 | - [@nightt5879](https://github.com/nightt5879) — `/debt` compatibility aliases |
| 6821 | with dispatch-consistent user-command shadowing across discovery surfaces |
| 6822 | (PR #4680), plus the Solarized Light background preservation fix (PR #4471). |
| 6823 | - [@AiurArtanis](https://github.com/AiurArtanis) — the Solarized Light |
| 6824 | regression report and reproduction (#4457). |
| 6825 | - [@shenjackyuanjie](https://github.com/shenjackyuanjie) — the HarmonyOS |
| 6826 | workflow-js bindgen, portable-pty gating, and SDK environment work |
| 6827 | (PR #4470). |
| 6828 | - [@shenyongqing](https://github.com/shenyongqing) — the original HarmonyOS |
| 6829 | bindgen approach (PR #4384), carried into the landed implementation. |
| 6830 | - [@luismateusvargas](https://github.com/luismateusvargas) — the Windows hook |
| 6831 | process-leak reproduction, process-tree analysis, and EOF fix direction |
| 6832 | (#4489). |
| 6833 | - [@redjade75723](https://github.com/redjade75723) — the persistent Windows PTY |
| 6834 | report that exposed lossy high-bit process-status handling (#4100). |
| 6835 | - [@w1w218](https://github.com/w1w218) — the Windows ARM64 release request and |
| 6836 | real-device motivation (#4267). |
| 6837 | - [@stream2stream](https://github.com/stream2stream) — the legacy-session |
| 6838 | recovery report that led to the read-only doctor diagnostic (#4032, #4539). |
| 6839 | - [@Angel-Hair](https://github.com/Angel-Hair) — session-owned read-before-edit |
| 6840 | tracking and the explicit, backwards-compatible `apply_patch` replacement |
| 6841 | contract (PRs #4475 and #4476). |
| 6842 | - [@dmitri-0](https://github.com/dmitri-0) — configurable cache-hit visibility |
| 6843 | in the phase strip (PR #4474). |
| 6844 | - [@fleitz](https://github.com/fleitz) — the canonical `Bash` no-`cwd` |
| 6845 | workspace fix and regression test that keep isolated sub-agent commands in |
| 6846 | their own worktree (PR #4673, closing #4674). |
| 6847 | - [@SparkofSpike](https://github.com/SparkofSpike) — the Windows Ctrl+O |
| 6848 | reproduction that exposed pre-pager result truncation and conflicting composer |
| 6849 | shortcut routing (#4482), and the exact Vim-space regression reproduction |
| 6850 | verifying the v0.9.1 input path already contains the needed global binding |
| 6851 | (PR #4477). |
| 6852 | |
| 6853 | ### Security |
| 6854 | |
| 6855 | - Harden the public community-site boundary: scheduled review drafts now use |
| 6856 | one canonical freshness namespace, admin discard is restricted to validated |
| 6857 | draft objects, public feed requests cannot spend the server-held GitHub |
| 6858 | token, and maintainer login bodies are type- and size-bounded before parsing. |
| 6859 | |
| 6860 | --- |
| 6861 | |
| 6862 | Older releases: [CHANGELOG.md](https://github.com/codewhale-hq/CodeWhale/blob/main/CHANGELOG.md) and [docs/CHANGELOG_ARCHIVE.md](https://github.com/codewhale-hq/CodeWhale/blob/main/docs/CHANGELOG_ARCHIVE.md). |
| 6863 |