| 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.0] - Unreleased candidate |
| 11 | |
| 12 | The v0.10.0 source candidate brings a redesigned terminal workbench, clearer |
| 13 | settings, and more reliable session and runtime behavior. It supersedes the |
| 14 | unpublished v0.9.14 candidate. Nothing below is published until the matching |
| 15 | tag, packages, checksums and release assets exist. |
| 16 | |
| 17 | ### Contributors |
| 18 | |
| 19 | - **[@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/Hmbown/Codewhale/pull/6369), [#6363](https://github.com/Hmbown/Codewhale/pull/6363), [#6365](https://github.com/Hmbown/Codewhale/pull/6365)). |
| 20 | - **[@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/Hmbown/Codewhale/pull/6096)). |
| 21 | - **[@BX166](https://github.com/BX166)** — contributed the AICraft provider template and its documentation ([#6171](https://github.com/Hmbown/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/Hmbown/Codewhale/issues/6289)). |
| 22 | - **[@7jrxt42BxFZo4iAnN4CX](https://github.com/7jrxt42BxFZo4iAnN4CX)** — reported the session-retention defects behind archive-past-the-cap and empty-session cap occupancy ([#6136](https://github.com/Hmbown/Codewhale/issues/6136), [#6137](https://github.com/Hmbown/Codewhale/issues/6137)), the resume-failure design behind durable transcript errors ([#6138](https://github.com/Hmbown/Codewhale/issues/6138)), and the gaps behind the opt-in approval timeout ([#6101](https://github.com/Hmbown/Codewhale/issues/6101)), `codewhale exec --hooks` ([#6099](https://github.com/Hmbown/Codewhale/issues/6099)), Markdown drag-copy ([#6156](https://github.com/Hmbown/Codewhale/issues/6156)), and the browsable, current-aware session picker ([#6014](https://github.com/Hmbown/Codewhale/issues/6014)); the goal token-budget hard stop ([#6013](https://github.com/Hmbown/Codewhale/issues/6013)) and the fleet no-progress guard shared with child workers ([#6015](https://github.com/Hmbown/Codewhale/issues/6015)) landed as first slices of two larger proposals, and the runtime-store session refusal ([#6207](https://github.com/Hmbown/Codewhale/issues/6207)). |
| 23 | - **[@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/Hmbown/Codewhale/issues/5359)). |
| 24 | - **[@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/Hmbown/Codewhale/issues/6165)). |
| 25 | - **[@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/Hmbown/Codewhale/issues/6173)). |
| 26 | - **[@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/Hmbown/Codewhale/issues/6174)). |
| 27 | - **[@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/Hmbown/Codewhale/issues/6184), [#6185](https://github.com/Hmbown/Codewhale/issues/6185)). |
| 28 | |
| 29 | ### Security |
| 30 | |
| 31 | - Approving an `apply_patch` "for the session" is now scoped to the file you |
| 32 | approved. The grouping key that scopes a session grant was built by a second, |
| 33 | weaker patch parser that read only `+++ b/` headers and the `replace` array: |
| 34 | it saw no target at all for the documented `apply_patch{path, patch}` |
| 35 | override, for `--no-prefix` diffs, or for delete-only diffs, and collapsed |
| 36 | every one of them to a single shared key. One approval therefore pre-approved |
| 37 | every later patch of that shape, to any file, with no card and no notice. The |
| 38 | key now comes from the same resolver the executor and the permission path |
| 39 | already use, and an input that cannot be resolved gets its own key rather |
| 40 | than a shared one (#6247). |
| 41 | |
| 42 | ### Added |
| 43 | |
| 44 | - TTFT and average output rate stay visible in the compact working footer when |
| 45 | space allows. `/statusline` now controls them separately; existing |
| 46 | `session_metrics` settings still work. |
| 47 | - StepFun’s current coding catalog includes Step 5 Preview, Step 3.7 Flash, |
| 48 | Step 3.5 Flash and its 2603 version, with published reasoning controls and |
| 49 | PAYG rates. Existing Step Plan routing remains subscription-based. |
| 50 | |
| 51 | - `read` responses now always report the file's byte size, line count, and |
| 52 | whether output was truncated, and truncation footers name the total size |
| 53 | alongside the continuation offset — so paging through a large file is |
| 54 | deliberate instead of a surprise (#6283). |
| 55 | - File edits are parse-gated before the write lands: Rust goes through |
| 56 | `syn::parse_file` for a grammar-exact `line:column`, and `.toml` / `.json` |
| 57 | through the parsers already vendored. An edit is refused only when the file |
| 58 | parsed *before* and would not parse *after* — repairing an already-broken |
| 59 | file is the commonest reason to edit source at all, so pre-existing breakage |
| 60 | and new files fail open. The check precedes the write, so a rejection leaves |
| 61 | the file untouched and `apply_patch` cannot half-apply (#6204, #6206, #6151). |
| 62 | - Rust files that were already `rustfmt`-clean are re-normalized after an edit, |
| 63 | so the next patch's anchors still match. Hand-formatted files are never |
| 64 | rewritten, and every failure path skips and lets the edit land (#6205, #6151). |
| 65 | - Native clients can finish provider setup without dropping to the CLI: |
| 66 | `DELETE /v1/providers/{id}/key` clears a Codewhale-owned credential through |
| 67 | the same shared owner as `codewhale auth clear`, and `GET /v1/providers` |
| 68 | now carries `credentialSource` / `credentialWritable` (plus a reason) so a |
| 69 | client disables its control with a truthful explanation instead of letting |
| 70 | a write fail late. A credential Codewhale does not own — a literal key in a |
| 71 | config file, or an active external consent — refuses both verbs with `409` |
| 72 | rather than appearing to succeed against a source that still wins at |
| 73 | request time (#6179). |
| 74 | - The interactive approval card can be bounded: `[approval] timeout_seconds` |
| 75 | resolves an unanswered card to **deny** when the window elapses — the same |
| 76 | fail-closed decision the external approval path takes — and the transcript |
| 77 | says the bound denied the call, not the operator. Omitted or `0` keeps |
| 78 | today's unbounded wait, so nothing changes unless you opt in (#6101). |
| 79 | - Transcript drag selection copies Markdown source by default: every cell the |
| 80 | selection touches serializes through the same canonical path `Ctrl-Y` and |
| 81 | `/copy` use, partial intersections round out to whole cells joined with |
| 82 | blank lines, and the toast names the copied cell count. |
| 83 | `tui.selection_copy_markdown = false` keeps the rendered-text payload |
| 84 | (#6156). |
| 85 | - The Runtime API serves the workspace files a native client browses and edits: |
| 86 | `GET /v1/workspace/files` lists one directory, `GET /v1/workspace/files/read` |
| 87 | returns a bounded byte window with a whole-file SHA-256 revision, and |
| 88 | `PUT /v1/workspace/files` writes atomically through the confined opener with |
| 89 | revision-checked overwrites (409 on drift). `.git` is never served and |
| 90 | symlinks are never followed. A saved session's oversized tool outputs are |
| 91 | served as artifacts at `GET /v1/sessions/{id}/artifacts` and |
| 92 | `GET /v1/sessions/{id}/artifacts/{artifact_id}`. (#6163) |
| 93 | - A session that ended mid-turn is no longer invisible to the model. The newest |
| 94 | workspace-scoped session still holding a crash-recovery checkpoint is |
| 95 | surfaced as a one-line `## Prior Session` notice in the session-pinned prompt |
| 96 | prefix — metadata reads only, excluding the live session and any session this |
| 97 | process instance created. Clean sessions get no block, so their prefix bytes |
| 98 | are unchanged. Two bounded read-only tools, `session_search` and |
| 99 | `session_get`, give the model workspace-scoped recall over the same store |
| 100 | (one-line summaries and an 8-message tail, labeled untrusted user data, read |
| 101 | on the blocking pool). Resuming stays the user's decision: the hint tells the |
| 102 | model to offer a continuation, never to silently take one (#5715). |
| 103 | - `codewhale exec --hooks` opts a headless run into the same `HookExecutor` the |
| 104 | TUI builds — global config, reviewed plugin snapshots, and trusted project |
| 105 | `hooks.toml`. Headless runs previously fired no hooks at all. `tool_call_before` |
| 106 | can still deny and `shell_env` still applies; a hook `ask` resolves |
| 107 | fail-closed without a terminal. Fleet worker subprocesses never opt in, and |
| 108 | `permissions.toml` typed rules are unchanged (#6099). |
| 109 | - `codewhale doctor` flags fleet and profile model pins that the provider's own |
| 110 | roster no longer offers. A pin is reported only when a *fresh* cached live |
| 111 | roster for that exact route exists and omits it — stale, failed, or absent |
| 112 | rosters prove nothing and are counted as `unverifiable` rather than raising a |
| 113 | false warning. Each row names the route and every owner of the pin; the pin |
| 114 | is surfaced, never rewritten (#6035). |
| 115 | - Background-capable clients can enumerate owned work and watch TUI-visible |
| 116 | conditions: `GET /v1/threads/running` lists threads with queued or |
| 117 | in-progress turns in one call (one turns scan grouped by thread), and |
| 118 | `GET /v1/threads/{id}/notices` serves active `subagent-terminal`, |
| 119 | `elevation-needed`, and `model-notify` notices with thread/turn identity, |
| 120 | cleared by ack or — for elevation — when the tool call completes (#6180, |
| 121 | #3757). |
| 122 | - Sub-agent launches adapt to provider throttling: a `DynamicGate` replaces |
| 123 | the fixed semaphore so launch capacity adjusts at runtime, and a |
| 124 | `RateLimitGovernor` halves capacity on 429 pressure, pauses admissions |
| 125 | past the threshold, and recovers additively; 429 retries honor |
| 126 | `Retry-After` with jittered backoff, and quota exhaustion keeps the |
| 127 | failure path (#6055). |
| 128 | - Turns record the mode they ran in, so mixed-mode sessions stay legible |
| 129 | after the fact (#6321). |
| 130 | - Shell spawning refuses NUL bytes in command and cwd before spawn, and |
| 131 | sub-agent runs fall back loudly past credentialless profile provider |
| 132 | pins instead of misrouting silently (#5529, #6318, #6320). |
| 133 | - Children land past a per-step context bound instead of burning |
| 134 | quadratically, and status rows surface live declared-vs-observed writes |
| 135 | (#6189, #6194). |
| 136 | - Queued Agent Mail can be cancelled before delivery, and the TUI |
| 137 | suspend/resume handshake restores on stop and rebuilds on continue |
| 138 | (#6176, #6169). |
| 139 | - MCP connections are supervised: dead servers are probed and reconnected |
| 140 | with transitions reported, and a failed reconnect keeps the last-good |
| 141 | catalog instead of dropping tools (#6187, #6142). |
| 142 | - Web search autodetects Tavily from `TAVILY_API_KEY` (Firecrawl stays the |
| 143 | default), fleet refusals name the alternative, and verification runs on |
| 144 | a bounded Git fetch plus a `merge_tree` verify surface (#6298, #6296). |
| 145 | - Fleet authority projects through one `ChildGrant`, and ModelScope joins |
| 146 | the built-in providers (#5633, #6299). |
| 147 | - Child tool results are capped at capture time, and run |
| 148 | tests/verifiers accept a bounded cwd (#6282, #6294, #6296). |
| 149 | |
| 150 | ### Changed |
| 151 | |
| 152 | - The launcher keeps the Codewhale mark while balancing its layout above the |
| 153 | composer. A single cursor identifies the selected action; MCP faults retain |
| 154 | their warning color even in compact terminals. Recent-session counts now |
| 155 | read correctly for a single message. |
| 156 | - Model and provider settings use quieter selection surfaces, one focused |
| 157 | cursor, clearer missing-key warnings, compact output limits, and less |
| 158 | repetitive credential detail. Plugin actions use plain labels. |
| 159 | |
| 160 | - The terminal opens on **Shoreline**, the same palette the GPUI client already |
| 161 | uses: warm charcoal field `#211F23`, a raised plate for panels and the |
| 162 | composer, one blue for action and selection `#90B9FF`, and the whale's ivory |
| 163 | `#F2ECE5` for body text, with 4.5:1 floors on every muted step. The old |
| 164 | saturated navy gradient is not gone — `underwater` is a named theme now |
| 165 | rather than the ground the product opens on. Existing installs keep whatever |
| 166 | theme they have saved; `/theme` switches (#6222). |
| 167 | |
| 168 | - Menu navigation is starting to mean the same thing everywhere. `menu_style` |
| 169 | already single-sourced how a selected row *looks*; what a key *does* was still |
| 170 | reinvented per surface — `h`/`l` in the provider picker against `Left`/`Right` |
| 171 | in the model picker one screen later, `Home`/`End` in one of seven pickers, and |
| 172 | no paging at all in Fleet's detail view. `list_nav`, which already owned the |
| 173 | wrap arithmetic, now owns the vocabulary too: one vertical axis, one |
| 174 | horizontal axis, and two entry points so a picker with a live filter never has |
| 175 | a letter stolen out of its query. Fleet's detail view adopts it first and |
| 176 | gains PageUp/PageDown and Home/End in both its lists (#6290). |
| 177 | |
| 178 | - Reviewed plugin bundles are no longer re-hashed four times per MCP dispatch. |
| 179 | `verify_plugin_authority` walks and hashes both the reviewed source and the |
| 180 | runtime snapshot, and four separate authority checks ran per `tools/call` — |
| 181 | eight tree walks. Three of them sat one statement after a |
| 182 | `validate_before_use` on the same source, so `is_ready` re-verified what had |
| 183 | just been verified; readiness and authority are now separate, and only the |
| 184 | callers with no preceding check still pay for both. The tool catalog is built |
| 185 | once per turn instead of twice, which also removes a case where the two |
| 186 | assemblies could disagree if authority drifted between them. The digest is |
| 187 | deliberately **not** cached on `(path, mtime, len)`: the reviewed tree is |
| 188 | user-writable and `utimensat(2)` lets a same-uid process restore an mtime |
| 189 | after an equal-length rewrite, so a stat-keyed cache would serve a pre-tamper |
| 190 | digest (#6209). |
| 191 | - A sub-agent's completion is read from the manager once instead of polled. The |
| 192 | workflow pump re-read it up to fifty times, sleeping 20ms between attempts, |
| 193 | waiting for a terminal status that was already committed — every publisher |
| 194 | commits the status inside the same `&mut self` call that wakes the pump, so |
| 195 | the write guard spans both and the first read always sees it. A child the |
| 196 | manager had no record of cost a full second of head-of-line blocking before |
| 197 | failing; it now fails immediately, and says what actually happened instead of |
| 198 | claiming the child "did not report a terminal status within 1s" (#6211). |
| 199 | |
| 200 | - MCP protocol negotiation: every surface advertised the original 2024-11-05 |
| 201 | revision and the stdio client required an exact match, so newer servers |
| 202 | could not connect. The server and both clients now advertise 2025-06-18 |
| 203 | and negotiate over the supported set (2025-06-18, 2025-03-26, 2024-11-05) |
| 204 | — the server echoes the client's revision when it is supported and answers |
| 205 | with the latest otherwise, the stdio client accepts any supported revision, |
| 206 | and streamable HTTP sends the required `MCP-Protocol-Version` header on |
| 207 | every post-initialize request (#6280, first half). |
| 208 | - Configured MCP servers now connect lazily instead of all at session boot. The |
| 209 | pool owns a `connecting` set marked at spawn and cleared on resolution or |
| 210 | abort, so "connecting" is no longer inferred as enabled-minus-connected. The |
| 211 | boot pass scopes to the eager set — `required` servers plus those covered by |
| 212 | `tools.always_load` / `allowed_tools` — and a turn naming an unstarted server |
| 213 | spawns its connects alongside, under the existing five-second deadline. A |
| 214 | configured-but-unstarted server now reads as configured on every surface |
| 215 | (session-boot rows, Extensions tab, launch card), never as connecting. |
| 216 | `docs/MCP.md` documents the lifecycle (#6033). |
| 217 | - The launch card's MCP problems row runs its own remedy. It already printed |
| 218 | `/mcp login <name>` or `/mcp`; it now joins the shared paint/click/keyboard |
| 219 | ordering, so Up/Down lands on it and Enter or a click types the printed |
| 220 | command into the composer for you to send. Typing beats copying: no clipboard |
| 221 | dependency over SSH, and you see the command before a second Enter runs it |
| 222 | (#6085). |
| 223 | |
| 224 | - Computer Use is the only computer-use product in Extensions and |
| 225 | `/mcp recommendations`. Cua is no longer suggested as a parallel |
| 226 | desktop-control MCP; enable the first-party `computer-use` plugin |
| 227 | instead. The bundled plugin is 0.4.0: Return/Enter from `type`, |
| 228 | filtered and paginated `get_app_state`, `focus`/`get_value`, and |
| 229 | `strategy:"app"` window-scoped clicks. Shared-desktop pointer |
| 230 | gestures stay gated. |
| 231 | - The bundled first-party catalog pins marketplace revision `ca6be22`, so |
| 232 | installing Computer Use from the Extensions listing fetches the same 0.4.0 |
| 233 | source and the published notarized 0.4.0 Mac app. |
| 234 | |
| 235 | ### Fixed |
| 236 | |
| 237 | - Stopping a turn revokes its pending approvals. A late approval cannot resume |
| 238 | the cancelled action or save an automatic approval for later turns. |
| 239 | - Expanding and collapsing selected reasoning now matches its rendered state |
| 240 | when verbose mode and the default-expansion preference are both enabled. |
| 241 | |
| 242 | - Branch navigation preserves sibling histories, stable entry IDs and timestamps |
| 243 | through autosave, resume and forks, and synchronizes the selected branch into |
| 244 | the live engine. Thanks to @7jrxt42BxFZo4iAnN4CX for the report (#6367). |
| 245 | - Compaction now writes local diagnostic records for completed passes and |
| 246 | automatic refusals. `codewhale metrics` reports them with summarizer token |
| 247 | usage; text-mode exec retains its session after attempting compaction. |
| 248 | Historical artifacts are not backfilled. Thanks to @7jrxt42BxFZo4iAnN4CX |
| 249 | for identifying the missing producer (#6368). |
| 250 | - The opening workbench retains the canonical Codewhale mark in a responsive |
| 251 | header while keeping recent-session titles full-width and actions clickable. |
| 252 | - `serve --acp` no longer ignores the approval posture. The ACP adapter |
| 253 | hardcoded `ApprovalMode::Suggest`, so `--yolo` (and any configured |
| 254 | `approval_policy`) never reached admission: every mutating tool parked |
| 255 | behind a permission request no unattended client answers, and sessions |
| 256 | executed zero tools. Posture now derives from server config — `--yolo` |
| 257 | pre-approves prompts and flows into the sandbox policy — while hard blocks |
| 258 | (safety floor, repo law, reviewer consult) and the Plan read-only guardrail |
| 259 | stay intact (#6337). |
| 260 | - Plain agent spawns could not resolve. `built_in_members()` seeded both |
| 261 | `general` and `worker`, and the role parse boundary migrates `worker` to |
| 262 | `general`, so both canonicalized to the same role — and `role:general`, the |
| 263 | selector the roster advertises for the default posture, matched two members |
| 264 | and raised `Ambiguous` every time, permanently. The duplicate built-in is |
| 265 | gone. The legacy name still resolves: `general`, `member:general`, |
| 266 | `role:general` and `default` all land on the `worker` posture through the |
| 267 | identity selector rather than through a second member, which is what allowed |
| 268 | the duplicate to be removed (#6244). |
| 269 | - Clicking a `path:line` in tool output no longer spawns `$EDITOR` detached |
| 270 | while the TUI still owns the terminal, and no longer spawns one editor per |
| 271 | matching line. The launch goes through the single terminal-handoff path, and |
| 272 | a click is one request to open one file (#6235). |
| 273 | - A write-scope contention refusal now names a remedy that works. The `agent` |
| 274 | tool's description claimed `release` was "the remediation a write-scope |
| 275 | contention refusal names"; the refusal did not name it, and pointing back at |
| 276 | it would have been worse, because `release` only clears claims whose owner is |
| 277 | no longer running while a contention refusal names a live one. The refusal |
| 278 | itself now says to wait for that owner to settle or cancel it (#6272). |
| 279 | - The session picker no longer refuses a saved session whose Runtime store |
| 280 | exists but holds nothing. A force-quit leaves the store on disk, ownerless |
| 281 | and empty, and the switch path refused it because recovery only covered a |
| 282 | *missing* store. A switch now also adopts a store that is provably empty |
| 283 | (every work directory, plus the event sequence that remembers pruned |
| 284 | appends) *and* provably unheld (the process-owner lock, which a live |
| 285 | manager holds from open to close), with no automation pinned to its |
| 286 | execution scope — and the save gate treats that shape as abandonable too, |
| 287 | so the repaired binding persists. The first fix was reverted on a race |
| 288 | (emptiness without liveness); this reland checks the lock first (#6207). |
| 289 | - Double-tap Enter now sends every queued follow-up into the running turn, |
| 290 | oldest first. The second Enter used to steer only the most recent message |
| 291 | and leave older ones queued; a failed steer restores the failed message |
| 292 | plus everything unattempted in original order, so nothing is lost or |
| 293 | reordered. |
| 294 | - Only the most recently sent prompt carries the elevated-surface background |
| 295 | now; every older prompt renders on the bare ground. The fill used to sit |
| 296 | behind every user row (striping), then behind none; newest-only keeps the |
| 297 | eye on the turn in play. Sending a new prompt moves the highlight and |
| 298 | un-highlights its predecessor. |
| 299 | - Diff rows tint whole: added/deleted line numbers now share the row's green |
| 300 | / red background instead of sitting bare next to a painted body. Context |
| 301 | rows stay on the bare ground. |
| 302 | - MCP connections are supervised now: a background task notices a dead |
| 303 | server within one sweep, reconnects on the existing backoff ladder, and |
| 304 | reports each transition, so Extensions rows flip with liveness instead |
| 305 | of parking on stale-ready or a silent [reconnect]. Five consecutive |
| 306 | failures park the server with a notice naming `/mcp retry`; an explicit |
| 307 | retry or a fresh connection resumes watching. Tool calls also retry |
| 308 | once across a dead pipe/socket (not just stale sessions), and a |
| 309 | reconnect that fails reports both errors instead of swallowing the |
| 310 | original (#6187; `list_changed` catalog refresh stays open). |
| 311 | |
| 312 | - A steer the engine never delivered is no longer reported as sent. The runtime |
| 313 | API persisted the steer item as already-`Completed` and emitted |
| 314 | `turn.steered` + `item.completed` the moment the text entered the engine's |
| 315 | mailbox — before the engine decided anything. The engine discards a steer |
| 316 | whose turn has moved on, and an interrupted or failed turn drops whatever it |
| 317 | had queued, so a GUI could show "Guidance sent", clear the composer, and lose |
| 318 | the user's words. The engine now returns a verdict for every steer on every |
| 319 | exit path, the item settles `completed` or `canceled` to match, a dropped |
| 320 | steer emits `turn.steer_dropped` and answers `409` so a client can resend, |
| 321 | and `steer_count` counts steers the model actually received (#6276). |
| 322 | - `<recommended_plugins>` suggestions stop nagging: a plugin id is now |
| 323 | injected at most once per engine lifetime, and a plugin whose name a |
| 324 | loaded skill already covers is never suggested — the local skill owns |
| 325 | the domain, so the nudge was noise. Dismissals still apply, and the |
| 326 | fragment stays append-only on the user turn (#6274). |
| 327 | - A canceled automation run now settles with a transcript receipt that names |
| 328 | the cancellation (by request, cancel timeout, or shutdown) instead of |
| 329 | vanishing from the live band silently. The receipt wears attention ink and |
| 330 | never lights the failure demand; the run record keeps the cancellation |
| 331 | reason as its error detail. (#6162) |
| 332 | - A failed workflow run no longer settles silently: its terminal failure |
| 333 | raises a sticky error toast naming the cause (dispatch, schema, or script |
| 334 | errors), alongside the existing panel state (#5528). |
| 335 | - MCP OAuth re-login now forces the provider's consent screen: logout only |
| 336 | clears the local token, so without a prompt the provider silently |
| 337 | re-granted the same account/workspace and a re-login could never change |
| 338 | it. `/mcp logout` and `codewhale mcp logout` also say plainly that they |
| 339 | clear local credentials only (#6040). |
| 340 | - Session retention no longer deletes transcripts once the store reaches the |
| 341 | cap: the oldest active session is archived — still openable from the |
| 342 | picker's archived view — instead of being unlinked, and archived records |
| 343 | sit outside the cap until they are pruned (#6136). |
| 344 | - Empty auto-created "New Session" stubs are capped separately (the ten |
| 345 | newest are kept) and can no longer occupy a real transcript's slot in the |
| 346 | session cap (#6137). |
| 347 | - A failed resume or session load is now a durable transcript error instead |
| 348 | of a status line the next footer update replaces, so a resume that cannot |
| 349 | restore its target no longer looks like a silent new session (#6138). |
| 350 | - Compaction no longer retains a tool result whose tool call was summarized |
| 351 | away: an older turn that mixes text with a tool result keeps its text and |
| 352 | drops the orphaned result blocks, which providers reject outright (#6119). |
| 353 | - Automation runs that need a tool approval no longer die as silent |
| 354 | idle-timeout cancels: a pending approval suspends the idle watchdog for its |
| 355 | decision window, and an unanswered window settles the run Failed with the |
| 356 | recorded reason instead of a silent Canceled (#6118). |
| 357 | - `/mcp` no longer freezes the console while a turn is running: the panel |
| 358 | opens immediately from the last known MCP snapshot with a receipt naming |
| 359 | the wait, and live-pool mutations say their refresh is deferred instead of |
| 360 | parking the UI event loop behind the running turn (#6159). |
| 361 | - MCP OAuth login no longer fails with "Authorization server response missing |
| 362 | required issuer" against servers that implement RFC 9207, such as |
| 363 | Cloudflare's `mcp.cloudflare.com`. The local callback listener now keeps the |
| 364 | `iss` parameter from the redirect and hands it to the token exchange so the |
| 365 | callback binds to the discovered issuer; servers that do not send `iss` |
| 366 | keep working unchanged. (#6157) |
| 367 | |
| 368 | ## [0.9.13] - 2026-09-13 |
| 369 | |
| 370 | Codewhale v0.9.13 addresses integrity issues in 0.9.12: |
| 371 | multiline paste is one paste again, truncated tool arguments can no longer execute, strict |
| 372 | ACP clients connect again, concurrent instances stop destroying each |
| 373 | other's queued text, and the Computer Use bundle includes plugin 0.3.1 |
| 374 | with an accessibility-first pointer that no longer steals focus. DeepSeek V4.1 Flash |
| 375 | (`deepseek-flash`) is the default DeepSeek model, reasoning-capable routes |
| 376 | keep reasoning out of the answer even when a model id carries no version |
| 377 | number, and `/mcp reload` no longer freezes the interface while servers |
| 378 | reconnect. The Codewhale pet arrives with `/pet`: a full-screen habitat that |
| 379 | shows what the Engine is doing and reveals the answer when it is done. |
| 380 | |
| 381 | ### Added |
| 382 | |
| 383 | - `/pet` turns the terminal over to the Codewhale pet. `/pet on` (or bare |
| 384 | `/pet`) gives the habitat the whole content viewport now and on every |
| 385 | accepted turn, reveals the actual answer or error when the turn completes, |
| 386 | and Escape returns to the composer without cancelling anything. `/pet off` |
| 387 | closes the view and stops automatic entry while the durable companion keeps |
| 388 | the pet alive; `/pet appearance|window|source|sound|export|status` address |
| 389 | the shared companion. The pet no longer lives in the workbar: the Watch |
| 390 | panel and `/workbar watch …` are gone (#6109, #6110). |
| 391 | - Codewhale Computer Use 0.3.1 ships as its own notarized Mac app. Download |
| 392 | the disk image from [codewhale.net/computer-use](https://codewhale.net/computer-use) |
| 393 | or the [v0.3.1 release](https://github.com/Hmbown/codewhale-cu-plugin/releases/tag/v0.3.1) |
| 394 | (`Codewhale-Computer-Use-0.3.1-macos-universal.dmg`, drag into |
| 395 | Applications; the ZIP stays for the in-app updater). The bundled plugin and |
| 396 | the first-party marketplace pin the same 0.3.1 sources, so the app, the |
| 397 | `computer-use` plugin and `/mcp` see one implementation. |
| 398 | |
| 399 | ### Fixed |
| 400 | |
| 401 | - The website's Computer Use download page resolves its state without the |
| 402 | GitHub API (using `GITHUB_TOKEN` only when bound), and every page regenerates |
| 403 | on the Worker again: the Open Graph image route read brand SVGs at import |
| 404 | time, which the Workers runtime cannot do, so codewhale.net had been serving |
| 405 | its build-time snapshot. |
| 406 | - Operate can run structured workflows directly, with named phases, model |
| 407 | assignments from Fleet, prerequisite results and shared budgets. Independent |
| 408 | steps run together; dependent work waits for its required results and gates. |
| 409 | Detached runs return their outcome to the owning conversation, and headless |
| 410 | sessions stay alive between phases until the final handback is consumed. |
| 411 | - Computer Use 0.3.1: mouse actions no longer steal focus or reclaim the |
| 412 | foreground when the user switches apps mid-action; background typing, |
| 413 | scrolling and selection use semantic input, and screenshots stay scoped to |
| 414 | the targeted app. The bundled plugin and the first-party marketplace pin |
| 415 | carry the same 0.3.1 sources. A registered macOS helper stays in charge of |
| 416 | input through its Pause and Stop controls; an unavailable registered helper |
| 417 | produces an error instead of silently bypassing those controls. |
| 418 | - The Fleet editor uses the standard model picker to manage sub-agent model |
| 419 | and thinking assignments. Enter edits the selected row without changing the |
| 420 | running session's model. Unconfigured providers are refused, failed saves |
| 421 | retain the previous assignment, and a changed or removed team file must be |
| 422 | reopened before a pick can overwrite it. |
| 423 | - The provider catalog includes Baseten and the other compatible-provider |
| 424 | templates as selectable rows, opening their existing prefilled setup forms. |
| 425 | DeepSeek routes with clock-based pricing show the current peak or off-peak |
| 426 | tier beside session cost, with translated labels. |
| 427 | - Extensions, teams, workflows and automations support mouse-wheel scrolling. |
| 428 | Plugin and MCP rows have keyboard enable/disable controls and two-step |
| 429 | removal; MCP OAuth can retry with narrower scopes after a scope rejection. |
| 430 | - Healthy sub-agents continue after an ordinary parent reply. Headless runs |
| 431 | keep the existing Engine alive for child results within the run deadline. |
| 432 | Explicit cancellation remains authoritative when result queues are full or |
| 433 | a completion starts a followup turn. |
| 434 | - Sub-agent followup supports multiple targets and all parked children, keeps |
| 435 | old IDs connected to their current continuation, and saves continuation |
| 436 | identity before starting work. Repeated followup does not fork duplicates. |
| 437 | - Sub-agents validate declared output files and distinguish real edit claims |
| 438 | from file citations and unrelated workspace changes. Disjoint file claims |
| 439 | can run together; overlapping writers receive the actual conflict and remedies. |
| 440 | Explicit read-only shell analysis requires an enforcing native sandbox and |
| 441 | refuses execution when that protection is unavailable. |
| 442 | - Delegation depth stays absolute through saved profiles, nested workers and |
| 443 | continuations. Per-call token, step and time limits narrow inherited limits; |
| 444 | continuation retains ancestor usage and deadlines. Workers reserve room for |
| 445 | one tools-disabled partial report inside those limits, then run the declared- |
| 446 | output checks. Missing usage or unavailable reporting room produces an |
| 447 | explicit fallback; partial work is never marked complete. |
| 448 | - Agent rosters and detail pages have bounded output, visible continuation and |
| 449 | descendant relationships, and usable handles for full diagnostic evidence. |
| 450 | Completion receipts include measured worker and descendant token usage, |
| 451 | count each continuation once, and distinguish unreported usage from zero. |
| 452 | - Localization and native helper builds resolve the active checkout when the |
| 453 | build script runs, so a shared Cargo target keeps working after a worktree |
| 454 | moves or is removed. |
| 455 | - Selecting a saved agent profile that is malformed, unreadable or duplicated |
| 456 | now fails before any child request, including when its name matches a |
| 457 | built-in role; the parent's default route is never substituted silently. |
| 458 | `agent(action: "roster")` lists affected profile identities and paths, Fleet |
| 459 | run creation performs the same check, and `docs/SUBAGENTS.md` documents the |
| 460 | valid personal profile format with `[permissions]` (#6117, thanks |
| 461 | @Gabriel-Degret). |
| 462 | - Interactive startup no longer mistakes worker scheduling delays for an |
| 463 | unresponsive terminal. Terminal ownership checks and shutdown cleanup remain |
| 464 | enforced (#5929). |
| 465 | - Interrupted conversations whose saved runtime store is missing recover into a |
| 466 | fresh scope without restoring old tasks or approvals. Stale session saves |
| 467 | cannot resurrect the broken binding (#6102). |
| 468 | - Permission checks distinguish literal heredoc data from executable commands, |
| 469 | including substitutions and shell stdin (#6098). |
| 470 | - Automatic compaction runs quietly from live context pressure, preserving the |
| 471 | current task and recent tool exchanges while keeping the system/tool prefix |
| 472 | stable. Original history and the handoff are saved before context replacement; |
| 473 | failed or canceled compaction retains the conversation (#5620, #6047). |
| 474 | - Custom and gateway providers can override context limits for each exact model, |
| 475 | so switching models also switches the meter and compaction budget (#6108). |
| 476 | - Plugin suggestions explain their matching term and remember explicit dismissals |
| 477 | across restarts. Generic words and repository-host domains no longer trigger |
| 478 | unrelated installation prompts (#6031). |
| 479 | - Plugin trust and automation deletion have keyboard and mouse confirmation |
| 480 | controls bound to the exact reviewed content; users can still copy the command |
| 481 | and changed content requires a fresh review (#6039). |
| 482 | - The model-facing MCP start tool can reconnect an existing configured name after |
| 483 | login without changing its credential key or restarting healthy siblings (#6030). |
| 484 | A decreasing token-expiry countdown no longer makes a revoked credential look |
| 485 | like a new login from another session. |
| 486 | - Gemini setup uses the official endpoint's supported reasoning-effort field, |
| 487 | avoiding the rejected top-level Google thinking object. Gemini 2.5 and 3 keep |
| 488 | their supported effort ranges; signed tool history still survives reasoning |
| 489 | changes and restart (#6018, thanks @vmakarov-uk). |
| 490 | - Missed automation occurrences coalesce without overlapping a running job; |
| 491 | restart reconciles durable receipts without replaying accepted work. Damaged |
| 492 | neighboring records are isolated while preserving their original bytes. |
| 493 | - The bundled first-party marketplace lists the actual plugin bundles and uses |
| 494 | the existing install, review, trust and update paths. A read-only connection |
| 495 | check verifies catalog and skill mirrors on changes and weekly. Already present |
| 496 | bundles lead to their local review and management controls; catalog installs |
| 497 | refuse name collisions before downloading, without overwriting or granting trust. |
| 498 | - Windows deny checks preserve native path separators while retaining the |
| 499 | conservative POSIX scan for shell wrappers and substitutions. |
| 500 | - The config example agrees with the telemetry disclosure: usage analytics are |
| 501 | optional and enabled by default; local diagnostics do not require telemetry (#6011). |
| 502 | |
| 503 | - Sub-agents enforce the session's typed shell and file deny rules, including |
| 504 | Full Access, delegated edits, and policy updates after a child starts (#6097). |
| 505 | - Live permission edits reach running engine clones atomically. Deny rules |
| 506 | support token wildcards and Windows command spellings while keeping POSIX |
| 507 | arguments literal (#6054, thanks @h3c-hexin and @asto18089). |
| 508 | - Tool-result images use the existing typed inline path and are fully decoded |
| 509 | under size and allocation limits before admission or provider projection. |
| 510 | Invalid images keep a visible omission receipt alongside the text result |
| 511 | (adapted from #6053, thanks @h3c-hexin and @asto18089). |
| 512 | |
| 513 | - A lone `y`, `Y`, or `r` remains composer input after selecting transcript |
| 514 | text. Clicking the composer releases transcript and dock focus. |
| 515 | - The Agents register updates from live worker events while the parent is |
| 516 | busy, including when the register opened before the workers spawned. |
| 517 | - Ghostty no longer shows a second graphical whale over the launch mark. |
| 518 | The selected model stays visible before the first message; unused session |
| 519 | metrics stay quiet. Scheduled counts open `/automation` directly. |
| 520 | - Marketplace installation accepts compatible Claude plugin bundles and roots |
| 521 | their relative sources outside `.claude-plugin`; unsupported components fail |
| 522 | explicitly. Native trust and enablement review still applies. |
| 523 | - Config table and nested reads work consistently and redact credentials. |
| 524 | Unsupported dotted writes fail without changing the file, and `config doctor` |
| 525 | no longer labels runtime settings as never applied (#6083). |
| 526 | |
| 527 | - Esc during a worker fanout keeps the parent stopped when cancelled workers |
| 528 | finish. Their receipts remain available for the next explicit user turn. |
| 529 | - Undo preserves messages even when older state lacks a timestamp. Session |
| 530 | journal entries retain their append-time stamps when saved again. |
| 531 | - Extension actions refresh in place, and inspection output uses the text |
| 532 | pager. The empty launch shell hides unused metrics and keeps recovery hints |
| 533 | readable when several MCP servers need attention. |
| 534 | - The large-output router defaults to bounded spillover; adaptive routing |
| 535 | remains opt-in through `CODEWHALE_ADAPTIVE_OUTPUT_ROUTING=1`. |
| 536 | - Direct composer paste (`Ctrl-V`) preserves rich clipboard headings, lists, |
| 537 | links, tables and code as Markdown, with plain-text fallback. Whole-answer |
| 538 | copy preserves authored Markdown without terminal wrapping; settings fields |
| 539 | still paste literal text. |
| 540 | - The embedded Computer Use bundle includes the marketplace's JPEG capture |
| 541 | and bounded-payload fixes, so new built-in installations receive them too. |
| 542 | - A provider's missing-`thought_signature` HTTP 400 now explains how to recover: |
| 543 | use the built-in Google provider and start a new session, or verify the |
| 544 | gateway's signature handling. Working gateways are not blocked by a broader |
| 545 | preflight check (#6048, #6081, thanks @nightt5879). |
| 546 | - Chinese documentation links resolve to the contributor guide and Windows |
| 547 | screenshots from their translated paths (#6080, thanks @c020627). |
| 548 | - GLM-5.3 reasoning controls follow the forced-thinking contract on Z.ai and |
| 549 | BigModel routes, including low effort when a prior configuration requested |
| 550 | thinking off (#6051, thanks @h3c-hexin and @asto18089). |
| 551 | - Finance calls respect the session network policy, and model-facing shell, |
| 552 | verifier, notification and Fleet guidance matches executable contracts |
| 553 | (#6052, thanks @h3c-hexin and @asto18089). |
| 554 | - The sandbox-elevation prompt shows every option, `Abort` included. The card |
| 555 | was a fixed 22 rows centred on the frame; inside its border and padding that |
| 556 | left at most 18 usable rows against 20 to 23 rows of content, with no scroll |
| 557 | rail and no truncation hint. The safe exit — the one choice that grants |
| 558 | nothing — was painted past the bottom edge at every terminal size. The card |
| 559 | is measured from its content now and reserves the option rows before the |
| 560 | denial detail, which is what shortens; below roughly 60x24 the per-option |
| 561 | descriptions shed and every choice keeps its row. Option hitboxes were also |
| 562 | counted in unwrapped source lines, so a description that wrapped put every |
| 563 | hitbox below it out of step and a click committed a different choice than the |
| 564 | one under the pointer. |
| 565 | - `d` in the Hotbar setup modal asks before it clears every slot. It persisted |
| 566 | `hotbar = []` on the first keystroke, in a view that takes bare letters as its |
| 567 | filter — the destructive key and the search key were the same press. It arms a |
| 568 | confirmation that owns every key until answered, and the prompt takes the |
| 569 | intro's place in the header so it cannot be the line that falls off a |
| 570 | five-row budget. |
| 571 | - Failure red means failure again. The metrics line painted the context reading |
| 572 | in the error colour from 80 %, while the posture bar one row above called the |
| 573 | identical threshold Attention; the workflow panel painted a `Waiting` row like |
| 574 | a crashed one, though its own `is_running` counts Waiting as healthy; and the |
| 575 | work surface spent `error_fg` on to-dos that were merely waiting, blocked or |
| 576 | stale, and on the routine approach to auto-compaction. `WorkTone` has a real |
| 577 | `Failure` variant now, and a guard test holds the reservation across every |
| 578 | selectable theme rather than the default alone. |
| 579 | - The command palette runs the row you highlighted. `refilter` clamped the |
| 580 | selection index but never re-anchored it, and every keystroke re-sorts the |
| 581 | list, so refining a query could move the highlight to an unrelated entry that |
| 582 | Enter then ran. Long labels also overran their column and pushed the |
| 583 | description off the card, because the padding never truncated and the capacity |
| 584 | was measured against the popup rather than the content area. |
| 585 | - The work surface's first `Down` reaches the first row. Nothing is selected |
| 586 | when the dock opens, and that resolved to "row 0 is selected", so the first |
| 587 | press moved to row 1 and row 0 could not be reached by pressing Down at all. |
| 588 | - Auto-compact could not fire mid-turn. The gate read `max(last billed |
| 589 | prompt, /4 estimate of the whole list)`, so as soon as the estimator |
| 590 | undercounted the full list below the last bill, every tool result appended |
| 591 | after that prompt was invisible to it, and a long turn could exhaust the |
| 592 | context window with nothing compacted. It now reads live tokens — the |
| 593 | billed prompt plus the growth since it, watermarked when the parent usage |
| 594 | is recorded — and is still evaluated at the pre-request boundary after |
| 595 | tools complete, never mid-tool-call. |
| 596 | - Esc or Ctrl+C during a compaction that is serving an in-flight turn now |
| 597 | stops the turn. It previously cancelled only the compaction pass, so the |
| 598 | turn resumed against the context that had just failed to shrink. A manual |
| 599 | `/compact` with no request in flight still cancels only the pass. |
| 600 | - The `request_user_input` dialog is a bottom-anchored sheet instead of a |
| 601 | centered 22-row overlay. It leaves the transcript visible above it, grows |
| 602 | with its content, and scrolls internally so the highlighted option and the |
| 603 | custom response being typed stay on screen at 141x38 and 80x24. Left arrow |
| 604 | or `h` goes back to the previous question; Esc still cancels the whole |
| 605 | request. PageUp/PageDown, Home/End and modified arrows now review the |
| 606 | transcript while the sheet stays open; the mouse wheel scrolls the surface |
| 607 | under the pointer. Wheel browsing preserves the answer, and option navigation |
| 608 | or typing restores the focused content to view. The transcript viewport ends |
| 609 | above question and approval prompts, so End keeps the newest rows visible. |
| 610 | Documented in GUIDE.md and KEYBINDINGS.md (#6045). |
| 611 | - `/mcp reload` no longer freezes the interface. The reload was awaiting the |
| 612 | whole reconnect batch on the TUI event loop; it now joins the same |
| 613 | supervised background pass the session boot uses, the status chip counts |
| 614 | the batch down live, and the finished receipt arrives as an event. With |
| 615 | 23 configured servers (11 live, 10 awaiting auth, 2 failing) the first |
| 616 | echoed keystroke after a reload lands in ~5 s instead of ~42 s (#5974). |
| 617 | - The posture bar no longer states the same duration twice on a first turn |
| 618 | (#6041). |
| 619 | - Reasoning-capable models whose id carries no version substring |
| 620 | (`deepseek-flash`) keep `reasoning_content` in the thinking block instead |
| 621 | of the answer text. The gate only ever matched the literal `deepseek-v4` |
| 622 | version string, so it now consults the model catalog as well; the older |
| 623 | literal arms remain for the V4 aliases they were written for (#6044). |
| 624 | - `codewhale model resolve` accepts a provider's declared default even when |
| 625 | its registry row is missing — `deepseek-flash` failed resolution against |
| 626 | the provider that declares it as default — and a test now resolves every |
| 627 | provider's `DEFAULT_*_MODEL` for its own provider (#6043). |
| 628 | - A configured `default_text_model` is honored when a new thread's route is |
| 629 | resolved. That path consulted only the provider's catalog default, so a |
| 630 | config naming one model silently created threads on another, and the |
| 631 | unset default disagreed with the shipped one; the active provider's |
| 632 | configured default now wins, matching `provider_default_model`, and both |
| 633 | unset defaults name `deepseek-flash` (#6043). |
| 634 | - Markdown `_italic_` requires both delimiters to be flanking per CommonMark, |
| 635 | so math subscripts no longer italicize the prose between them |
| 636 | (`[t_, b_p]. Actually — hold on, do we even tile all the way from t_?` |
| 637 | rendered 60 characters italic) (#6042). |
| 638 | - An MCP server configured for OAuth that answers 401 before its first login |
| 639 | now points at `/mcp login <name>` in the failure hint instead of a bearer |
| 640 | token that does not exist (#6030). |
| 641 | - Cancelling a foreground shell wait stops its owned process group even when |
| 642 | the tool future is dropped. Explicitly backgrounded jobs retain their |
| 643 | ownership. Interrupted tool receipts distinguish work that started from |
| 644 | calls skipped before execution, and returned tool failures remain errors in |
| 645 | the next model request. |
| 646 | - Saved Fleet model identifiers retain exact spelling through selection, |
| 647 | role pins, and roster changes, so changing one saved model does not modify |
| 648 | another identifier that differs only in letter case. |
| 649 | - Chat wrapping reserves its scrollbar gutter consistently, keeping long |
| 650 | identifiers readable when the viewport changes. |
| 651 | - The Engine keeps large send-message futures off the event loop's stack, |
| 652 | preventing stack exhaustion when a restored session starts a provider turn. |
| 653 | - New, imported, and live session titles skip runtime handoffs and use the |
| 654 | first real user prompt. Explicitly renamed titles retain priority |
| 655 | (#6012, thanks @SparkofSpike). |
| 656 | - UI dispatch acceptance now precedes Engine execution, so a delayed acceptance |
| 657 | callback cannot overwrite a turn that has already started or completed. |
| 658 | Cancelling before acceptance preserves the prompt and leaves the next |
| 659 | dispatch usable. |
| 660 | - Bottom-chrome effort is omitted when the route cannot prove an effective |
| 661 | tier; `/status` retains the full explanation. Cost remains visible when |
| 662 | known, and `cost: unknown` remains on metered routes lacking a reading (#5950). |
| 663 | |
| 664 | - Pasting multiline text is one paste again. 0.9.12 gated the |
| 665 | paste-burst heuristic off whenever bracketed paste was *requested*, but |
| 666 | a terminal can accept `EnableBracketedPaste` and still deliver a paste |
| 667 | as individual keystrokes — on those terminals (observed on Windows 11) |
| 668 | every pasted line was submitted as its own message. The heuristic is |
| 669 | again armed whenever `tui.paste_burst_detection` is on, and the |
| 670 | existing `bracketed_paste_seen` guard still disarms it for the rest of |
| 671 | the session once a real `Event::Paste` arrives, so fast typing on |
| 672 | terminals with working bracketed paste is unaffected (#5981, thanks |
| 673 | @nsfoxer). |
| 674 | - `serve --acp` no longer breaks strict JetBrains clients: the |
| 675 | `initialize` response advertised `sessionCapabilities.list` as a |
| 676 | boolean and carried an undefined nested `load` capability; it now |
| 677 | sends `{"list": {}}` with no `load` key, per the ACP schema (#5969, |
| 678 | reported by @Lujc0523). |
| 679 | - Concurrent Codewhale instances no longer destroy each other's queued, |
| 680 | unsent text. The offline input queue was one global file that boot |
| 681 | cleared on session-id mismatch, so a second instance deleted the |
| 682 | first's parked messages. Queues are now keyed per session (mirroring |
| 683 | per-session checkpoints), an existing global file is adopted by its |
| 684 | owning session rather than discarded, and the adoption race between |
| 685 | two instances of the same session tolerates the loser's cleanup. |
| 686 | - A tool call truncated at the provider's output limit can no longer be |
| 687 | repaired into valid JSON and executed: repairs that had to synthesize |
| 688 | structure (append or discard closers) are routed to the existing |
| 689 | malformed-arguments path so the model is asked to re-issue — including |
| 690 | when the stream is cut before the closing content-block event (#5986). |
| 691 | - `codewhale metrics` reads Codewhale's own receipts again: the |
| 692 | deepseek-home fallback resolved `$HOME/.deepseek` unconditionally, so |
| 693 | the rollup reported all zeros from a directory nothing has written |
| 694 | since 2024. The Codewhale audit log is primary, with a checked legacy |
| 695 | fallback. |
| 696 | - The goal-continuation loop's promised stall bound actually bounds |
| 697 | stalls now, and undeclared fleet role names fail closed to read-only |
| 698 | `explore` in both fleet drivers instead of resolving to write-capable |
| 699 | customs in one and not the other. |
| 700 | - `allow_insecure_http = true` under a `[providers.<name>]` table works |
| 701 | again. 0.9.12 tightened plain-HTTP base URL handling in a way that |
| 702 | silently dropped the per-provider key, leaving the process-wide env |
| 703 | var as the only opt-in — LAN llama.cpp and internal-gateway users |
| 704 | had to export `CODEWHALE_ALLOW_INSECURE_HTTP=1` to connect at all. |
| 705 | The key is honored again (parsed, settable and unsettable through |
| 706 | `codewhale config set providers.<name>.allow_insecure_http`, and |
| 707 | listed in the custom-provider field hint), it stays distinct from |
| 708 | `insecure_skip_tls_verify`, and the refusal message now leads with |
| 709 | the config key. Loopback hosts remain auto-allowed and telemetry |
| 710 | endpoint validation deliberately still consults neither switch |
| 711 | (#5991, thanks @Gabriel-Degret). |
| 712 | - A Fleet task that selects a roster member with `worker.agent_profile` now |
| 713 | runs with that member's posture. The launch-time resolver only consulted the |
| 714 | resolved member when the legacy `worker.role` label was absent, so a task |
| 715 | labelled `manager` that selected `member:reviewer` ran as a write-capable |
| 716 | manager instead of a reviewer and was never leased. The member's canonical |
| 717 | slot now wins whenever one resolved; the label remains the posture only when |
| 718 | no member resolved at all. To keep the fix from widening authority in the |
| 719 | mirror case (a read-only label on a write-capable member), a spec whose |
| 720 | `worker.role` names a different posture than the selected member's role is |
| 721 | rejected at run creation with a message naming both postures; casing and |
| 722 | legacy aliases of the member's own role are still accepted (#5945, thanks |
| 723 | @gaord). |
| 724 | - A queued message keeps one transcript entry from queue through steer to |
| 725 | dispatch. It no longer reads as delivered while it is still pending, and the |
| 726 | second Enter the strip prompts for no longer paints a duplicate bubble. |
| 727 | - The Tasks rail panel no longer swallows the first keystroke of typed input: |
| 728 | bare `y`/`Y` yank only when the work surface holds keyboard focus, so a |
| 729 | message that starts with "yes" stays intact (#2000). |
| 730 | - `wait` results reach the parent intact. The parent-context summarizer |
| 731 | projected every `agent` tool result through the sub-agent snapshot renderer, |
| 732 | which replaced a wait envelope's `settled`, `still_running`, `timed_out`, |
| 733 | `waited_ms`, and `note` with `unknown (agent) status=unknown`. Only |
| 734 | snapshot-shaped results are summarized now. |
| 735 | - A sub-agent's final summary uses the same adaptive tool-result budget as |
| 736 | every other tool result (`tool_result_max_bytes`, 12k floor, 2 MiB ceiling) |
| 737 | instead of a hardcoded 12k/4k/4k copy that cut a 12,001-character report to |
| 738 | 8,000. |
| 739 | - The metrics line no longer carries a permanent `/help` hint. The route still |
| 740 | appears until its binding has been used and then retires with the other |
| 741 | footer hints, so the row stays quiet once help is learned. |
| 742 | - `request_user_input`'s description names when asking is the right move |
| 743 | (ambiguous scope, an irreversible or expensive choice, a missing preference) |
| 744 | and when it is not, so the model stops guessing at discoverable facts. |
| 745 | - `config.example.toml` states the real search default (keyless Firecrawl, not |
| 746 | DuckDuckGo) and the preferred `CODEWHALE_SEARCH_*` environment names. |
| 747 | - Startup type-ahead is preserved whole, and a slash command interrupted by |
| 748 | startup keystrokes is no longer re-read as prose and sent to the model |
| 749 | (#5925). |
| 750 | - The model picker renders a large catalog without lag and supports per-column |
| 751 | sort and mouse selection (#5975). |
| 752 | - Session metrics report effective request throughput from provider receipts |
| 753 | instead of a live estimate divided by the whole turn, and cost stays honest |
| 754 | when a route has no price reading (#5976, #5977). |
| 755 | - An offline-queue submit delivered as late raw keystrokes no longer wedges the |
| 756 | composer behind stacked session notices (#5999). |
| 757 | - Fleet setup with a model filter that matches nothing renders a hint instead |
| 758 | of panicking (#5953), and shortlist enrollment plus authoritative role pins |
| 759 | are honored on dispatch (#5915). |
| 760 | - A mid-turn MCP catalog refresh keeps the tool pool deferred and the active |
| 761 | set narrow (#5939). |
| 762 | - Computer Use on macOS verifies application activation before sending |
| 763 | keystrokes and guards input by the frontmost app (#5927). |
| 764 | - Onboarding tests isolate `CODEWHALE_HOME`, so a fixture provider can no |
| 765 | longer leak into the real setup state (#5932). |
| 766 | - Snapshot availability is retained with one warning per session, and a |
| 767 | diverged engine session id is a visible notice rather than a log line |
| 768 | (#5930). |
| 769 | |
| 770 | ### Changed |
| 771 | |
| 772 | - How long Codewhale waits for a human is configurable. `[tools] |
| 773 | user_input_timeout_seconds` governs the wait for an approval decision or a |
| 774 | `request_user_input` answer; it was a hardcoded 300 seconds, which silently |
| 775 | cancelled the work of anyone who stepped away mid-task. An explicit `0` |
| 776 | waits indefinitely, the value is clamped to 24 hours, and omitting the key |
| 777 | keeps the previous 300-second default. Documented in |
| 778 | `docs/CONFIGURATION.md` ([#6003](https://github.com/Hmbown/Codewhale/issues/6003)). |
| 779 | - `docs/PROVIDERS.md` lists every beginner setup template, not the four it |
| 780 | happened to mention when the page was written. Baseten, Groq, Cerebras and |
| 781 | Command Code have shipped as supported OpenAI-compatible hosts for a while |
| 782 | and appeared nowhere in the provider documentation, which reads from outside |
| 783 | exactly like not supporting them. The page now carries the full table — |
| 784 | host, default model and key env for each — and states the rule it follows: |
| 785 | a plain Chat Completions backend is a template row, while `ProviderKind` is |
| 786 | reserved for distinct wires. A test now fails if a shipped template is |
| 787 | missing from that page. |
| 788 | - Reasoning capability for the Kimi coding routes and the qwen3.x Model Studio |
| 789 | deep-thinking ids is catalog data now rather than hardcoded match arms, and |
| 790 | `model_reasoning_capability` reports a model nothing knows about as unknown |
| 791 | instead of silently not reasoning-capable. `model_supports_reasoning` keeps |
| 792 | its `bool` shape for existing callers, where unknown still reads as false. |
| 793 | The ids that have no cited source yet keep their literal arms (#6032). |
| 794 | - The website uses Shannon Sans with versioned local font assets and retained |
| 795 | serif, monospace, and language fallbacks. Terminal fonts are unchanged. |
| 796 | - `codewhale metrics` reports recorded model requests and stream recovery |
| 797 | separately from provider-reported token usage, with coverage for missing |
| 798 | and duplicate receipts. Status messages and cumulative snapshots do not |
| 799 | add requests or count tokens again. |
| 800 | - Runtime turn receipts retain the Engine's terminal model-request, stream-retry, |
| 801 | and resume counters separately from displayed status and provider-reported |
| 802 | usage. These counters do not count HTTP retries inside a provider client or |
| 803 | establish provider billing. |
| 804 | - Initial tool definitions no longer repeat shell interpreter guidance and |
| 805 | agent lifecycle/scope instructions in multiple description fields. Parameter |
| 806 | schemas, approval rules and dispatch behavior are preserved. This reduces |
| 807 | prompt schema size; it does not establish a provider billing regression. |
| 808 | |
| 809 | - The built-in Computer Use plugin bundle is refreshed to the standalone |
| 810 | plugin's 0.2.1 runtime (vendored from `Hmbown/codewhale-cu-plugin` |
| 811 | at `724ad258`): the native macOS accessibility backend with an |
| 812 | a11y-first pointer strategy (covered points are refused, previews are |
| 813 | drawn), the permission-owning desktop-app socket transport, remote |
| 814 | computers over ssh and HarmonyOS HDC with contained temp handling, |
| 815 | truthful win32 PowerShell failure reporting, and the shared |
| 816 | allow-listed request handler for the app socket and ssh agent. |
| 817 | The bundle retains the hardening port from |
| 818 | [standalone plugin PR #12](https://github.com/Hmbown/codewhale-cu-plugin/pull/12). |
| 819 | Single left clicks on macOS element targets now revalidate and press |
| 820 | the observed element directly, without substituting a point hit-test |
| 821 | or raw-pointer fallback. Explicit event clicks retain the app-ownership |
| 822 | guard; a sent press still requires visual verification. Background mode |
| 823 | permits application-bound keys and accessibility actions while refusing |
| 824 | shared-pointer gestures; it does not provide an isolated desktop. The |
| 825 | embed list gained the five new runtime files, and a consistency test |
| 826 | now pins the embed list to the vendored tree so the bundle cannot rot |
| 827 | silently again. Because the bundle's content hash changes, Computer |
| 828 | Use deactivates and asks for a fresh review after upgrading — that is |
| 829 | the designed fail-closed path for a desktop-driving plugin. The |
| 830 | current macOS source candidate also embeds the compiled native helper, |
| 831 | so its bundled server can run directly without a separate Computer Use |
| 832 | app or a compiler on the user's machine. Accessibility and Screen |
| 833 | Recording permissions belong to the hosting app or terminal and remain |
| 834 | user-controlled. The CLI's Computer Use server requires Node.js 20 or newer. These are source |
| 835 | candidate changes; they do not establish published-package or platform |
| 836 | qualification. See the [included plugin guide](crates/tui/plugins/computer-use/README.md) |
| 837 | for platform requirements and limitations. |
| 838 | - `/statusline` drives the bottom chrome again. Since the 0.9.12 shell |
| 839 | redesign the posture bar and the metrics line were built independently of |
| 840 | `tui.status_items`, so every toggle in the picker except the balance fetch |
| 841 | was decoration. Each remaining item now shows or hides exactly one thing: |
| 842 | `model`, `context_percent`, `cost`, `balance`, `cache`, `tokens` and |
| 843 | `session_metrics` are metrics-line segments, and `mode` is the posture |
| 844 | bar's plan/act/operate chip. The `status`, `agents`, `reasoning_replay`, |
| 845 | `prefix_stability`, `git_branch`, `last_tool_elapsed` and `rate_limit` |
| 846 | items drove nothing and are retired; an existing `config.toml` still loads |
| 847 | and those keys are ignored (#5950, #5962). |
| 848 | - The context reading is back on screen at every fullness. 0.9.12 painted |
| 849 | `ctx NN%` only from 50% up, which left most of a session with no context |
| 850 | signal at all; it now paints from 0% and keeps its warning colour from 80% |
| 851 | up (#5950). |
| 852 | - A child agent parked because its parent's turn ended is shown as `parked` |
| 853 | in the Agents panel, the sidebar and Agent Details, with `resume_from` / |
| 854 | `cancel` as the recovery, instead of wearing the same "waiting for input" |
| 855 | label as a child that asked a question. Parked work sorts below live and |
| 856 | answerable work and no longer inflates the `blocked` chip; the receipts |
| 857 | roster and the wire `state` gain `parked` (#5906, #5921). |
| 858 | |
| 859 | - `codewhale account keys set|remove|list` no longer carry a hardcoded |
| 860 | eight-provider list. Provider ids come from the control plane's public |
| 861 | catalog (`GET /api/model-providers`), are validated locally against |
| 862 | `^[a-z0-9][a-z0-9-]{0,63}$` before they reach a URL path, and `list` shows |
| 863 | every catalog provider with its label and stored-key state. `--from-local` |
| 864 | maps a catalog row onto the local runtime provider through the catalog's own |
| 865 | `runtimeProvider` field, so a newly supported provider needs no CLI release. |
| 866 | |
| 867 | - `/mcp` lists the servers that need a login first, as their own |
| 868 | `Needs login` group above `Needs attention`, and opens with the cursor |
| 869 | already on the first such row so the Enter the screen advertises runs |
| 870 | `/mcp login <server>` straight away; translated in all 15 packs. A |
| 871 | snapshot test pins the footer shape the chip landed with (`MCP · N |
| 872 | connected · N ◆ auth required · N failed`) so an expired login never |
| 873 | regresses into the failed count (#5926). |
| 874 | |
| 875 | ### Fixed |
| 876 | |
| 877 | - Five of the load-flaky tests tracked in #5929 no longer depend on shared |
| 878 | state or live local daemons. Background-hook capture tests wait for the |
| 879 | capture file to hold bytes instead of merely existing (the shell's `>` |
| 880 | redirection creates the file empty before `cat` writes, which read as |
| 881 | `valid JSON: EOF` under load); the session-picker acceptance test drives |
| 882 | the real picker over a private store instead of a process-global |
| 883 | `CODEWHALE_HOME` redirect that concurrent tests could observe mid-flight; |
| 884 | the DeepSeek-Anthropic translate test holds the test env barrier so its |
| 885 | request-time and assertion-time `max_tokens` reads cannot straddle another |
| 886 | test's `CODEWHALE_MAX_OUTPUT_TOKENS` override; the unit-test binary no |
| 887 | longer probes a real local Ollama daemon (`127.0.0.1:11434`) from the |
| 888 | fire-and-forget provider catalog refresh, whose merged tags could flip |
| 889 | another test's live-snapshot assertions; and the tmux clipboard test's |
| 890 | attach/OSC 52 wait bounds tolerate a fully loaded machine (3s -> 30s) |
| 891 | without changing what they verify (#5929). |
| 892 | - The posture bar states how long the session has been working and how long |
| 893 | the current turn has run, distinguishing actively working from waiting on |
| 894 | a tool, a sub-agent or the operator; the 0.9.12 shell had dropped the overall |
| 895 | working-time indicator from the place a glancing user checks (#5914). |
| 896 | - A background runtime turn whose own store record could not be read, parsed |
| 897 | or written (`Failed to read turn …`, `Failed to read item …`) was only a log |
| 898 | line. The runtime now publishes a `runtime.store_failure` event naming the |
| 899 | file, the root cause and the next action (move the file aside, or check free |
| 900 | space and permissions); the TUI shows it as a warning toast and a transcript |
| 901 | line, the task timeline records it, and the runtime API streams it. A turn |
| 902 | whose own record is unreadable or unwritable is reported as terminal, so its |
| 903 | task fails at once instead of idling out (#5931). |
| 904 | |
| 905 | - An MCP token refresh that fails to parse the provider's answer keeps the |
| 906 | endpoint's receipt — status line, content type, and a 200-byte excerpt |
| 907 | with every credential-shaped value (`access_token`, `refresh_token`, |
| 908 | `client_secret`, `id_token`, bearer schemes) masked before the cut — |
| 909 | instead of rmcp's bare `Failed to parse server response`, so a provider |
| 910 | outage answering an HTML 502 reads differently from a parser defect, and |
| 911 | the login remedy stays named (#5926; remedy wording landed in #5959). |
| 912 | |
| 913 | ### Added |
| 914 | |
| 915 | - `POST /v1/threads/{id}/file-revert` restores exactly one file from the |
| 916 | exact `tool:`/`pre-turn:` snapshot the client selected, checking the |
| 917 | reviewed file hash before and after the mandatory safety snapshot. Literal |
| 918 | file names, regular files only, thread trust and active-turn admission are |
| 919 | enforced, and `patch-undo` no longer forks a conversation whose file |
| 920 | rollback failed (#6111, thanks @gaord; engine half of |
| 921 | HengQuWorld/CodeWhale-VSCode#3). |
| 922 | - Authenticated Runtime API workspace file suggestions reuse TUI `@file` |
| 923 | matching and discovery, with bounded queries/results and workspace-contained |
| 924 | relative paths only (`GET /v1/workspace/files/search`, #6095, #6120, thanks @wuisabel-gif; reported by @LmeSzinc). Shared discovery |
| 925 | now honors disabled symlink following for AI-tool directory scan roots too. |
| 926 | - Serply is available as an opt-in `[search]` provider for the Web tool |
| 927 | (`provider = "serply"`, key from `[search] api_key` or `SERPLY_API_KEY`). |
| 928 | Preflight fails closed without a key; Firecrawl remains the default and |
| 929 | existing configurations are unchanged (#6100, thanks @googio). |
| 930 | - Linux terminals: finishing a transcript or composer mouse selection copies |
| 931 | the text to the PRIMARY selection without touching the regular clipboard, and |
| 932 | middle-click inside the composer pastes PRIMARY at the pointer without |
| 933 | submitting. Native X11 and Wayland data control are used through one bounded |
| 934 | background worker; SSH sessions without a forwarded display keep their |
| 935 | terminal's own selection behavior (#6116, thanks @dmt4). |
| 936 | - `codewhale sessions export <id-or-unique-prefix>` saves a `.tar.xz` archive |
| 937 | with the durable record, portable session container, manifest and artifacts. |
| 938 | Prefix exports preserve unfinished tool calls; confined reads reject linked |
| 939 | artifact roots, and existing outputs require `--force`. Archives retain |
| 940 | unredacted content; `/load` opens the extracted record without installing |
| 941 | extracted artifacts (#6056, thanks @h3c-hexin and @asto18089). |
| 942 | |
| 943 | - `deepseek-flash` (DeepSeek V4.1 Flash: 1M-token context, |
| 944 | reasoning and tool calls) joins the catalog as DeepSeek's declared default, |
| 945 | and the offline catalog seed matches it; the DeepSeek Pro listing no longer |
| 946 | overstates the published price (#6025). |
| 947 | - DeepSeek's September 11 reversal is reflected in provider notices and cost |
| 948 | estimates: V4 Pro remains available after September 14 at Pro rates. Explicit |
| 949 | Pro selections remain unchanged; Flash remains the default (#6025, thanks @ronohara). |
| 950 | - Native plugin authoring guides now cover English and Chinese. The explicit |
| 951 | offline converter supports selected portable Skills and static Streamable |
| 952 | HTTP MCP declarations from OpenCode and DSH. Unsupported executable hooks, |
| 953 | automatic OAuth and policy-bearing configurations are refused; generated |
| 954 | bundles still require native installation, review and trust. Legacy SSE |
| 955 | fallback is not reproduced (#5827, requested by @giancarlocp). |
| 956 | |
| 957 | - Signed cloud model facts can refresh provider capabilities and prices while |
| 958 | preserving verified cached data when a refresh fails. A dispatched request |
| 959 | keeps its selected price snapshot so later catalog updates cannot change its |
| 960 | recorded cost (#5752). |
| 961 | - Saved sessions preserve exact provider routes. Auxiliary model calls settle |
| 962 | their usage once against the route and price snapshot that executed them, |
| 963 | including recovery, rather than resolving a new price at completion |
| 964 | (#5726, #5848). |
| 965 | - `[tui].posture_bar` and `[tui].metrics_line` accept `full`, `compact`, or |
| 966 | `hidden`, also available through `/config`. Compact preserves the existing |
| 967 | rows' essential fields; hidden returns their space to the transcript (#5973). |
| 968 | - Optional model-bound tool-output redaction opt-out, with two explicit startup |
| 969 | confirmations and a receipt bound to the readable config contents and |
| 970 | modification time. Unconfirmed requests keep masking enabled; routing and |
| 971 | stored goal summaries remain redacted (#5982, thanks @SparkofSpike). |
| 972 | |
| 973 | - The `rusty-alloc` cargo feature on `codewhale-tui` and `codewhale-cli` |
| 974 | opts the binaries into the `rusty_alloc` global allocator (the mimalloc |
| 975 | v2.4.5 architecture remade in pure Rust — no C compiler or build script |
| 976 | on that path) instead of the default mimalloc. It is off by default and |
| 977 | the default build is unchanged; build with |
| 978 | `cargo build -p codewhale-tui --features rusty-alloc` (#5872). |
| 979 | - The `/theme` picker now discovers valid user-authored `custom:<name>` |
| 980 | overlays, previews their colors, highlights the active overlay, and preserves |
| 981 | it when the picker is opened and committed without navigation (#5901). |
| 982 | - Compaction has two standing knobs next to `[context]` in config.toml: |
| 983 | `[compaction] summary_instructions` (appended to the summarizer prompt on |
| 984 | every manual and automatic pass; `/compact <focus>` still composes after |
| 985 | it) and `[compaction] retained_user_message_tokens` (default 20 000, |
| 986 | clamped 2 000..=200 000) for the verbatim user-message budget. Both are |
| 987 | absent by default and absent means the pre-existing behavior. The |
| 988 | `/compact` receipt names the effective budget and whether operator |
| 989 | instructions applied (#5956). |
| 990 | - `[tools] user_input_max_questions` (default 6, 1..=10) and |
| 991 | `[tools] user_input_max_options` (default 4, 2..=10) replace the hard-coded |
| 992 | `request_user_input` limits; the validator, the tool schema and its |
| 993 | description read one value, spawned children inherit the parent's ceilings, |
| 994 | and a rejected payload names the ceiling it hit and the key to raise (#5949). |
| 995 | - The slash menu shows a command's usage line and its subcommands as soon as |
| 996 | a space is typed after the verb, filtered by what follows, so Tab completes |
| 997 | `/workspace wor` to `/workspace worktrees`; `/help` states the focused |
| 998 | command's usage in its detail slot (#5952). |
| 999 | - The three `/fleet` views (roster, live workers, saved teams) are one |
| 1000 | back-navigable stack: `Esc` in workers or saved teams returns to the roster |
| 1001 | with its cursor intact and still closes the window at the root or on direct |
| 1002 | entry; the `Esc` footer hint says `back` or `close` accordingly (#5954). |
| 1003 | - `/fleet` presents its prioritized core (`members`, `setup`, `teams`, |
| 1004 | `workers`, `help`); every other verb stays dispatchable and is documented |
| 1005 | under explicit groups in `/fleet help`. The roster no longer shows the |
| 1006 | untouched built-in `general` alias next to `worker` (#5888). |
| 1007 | - `codewhale` provider: account-backed model access over the provider keys a |
| 1008 | customer connected to their Codewhale account. One base URL |
| 1009 | (`https://api.codewhale.net/v1`, overridable with `CODEWHALE_API_BASE`; |
| 1010 | HTTPS required except on loopback), one `cwc_key_…` account API key with the |
| 1011 | `models:infer` scope (`CODEWHALE_API_KEY`), and a per-model wire chosen from |
| 1012 | the account's authenticated `GET /v1/models`: ids are `provider/model` and |
| 1013 | each row states `chat-completions` (`/v1/chat/completions`) or |
| 1014 | `anthropic-messages` (`/v1/messages`). Both protocols authenticate with |
| 1015 | `Authorization: Bearer`, never `x-api-key`. The key is read from |
| 1016 | `CODEWHALE_API_KEY`, the `codewhale` secret-store slot, or |
| 1017 | `[providers.codewhale] api_key` / `api_key_env`, and a missing key fails |
| 1018 | before any request instead of dispatching unauthenticated. If the catalog |
| 1019 | cannot be fetched the route falls back to three bootstrap ids and says so. |
| 1020 | - `codewhale account api-keys create --scope` now accepts `models:infer` |
| 1021 | alongside `account:read` and `agent:run`, and an omitted `--scope` sends all |
| 1022 | three explicitly. `--use` saves the new secret as this machine's local |
| 1023 | `codewhale` provider credential in the same secret store `codewhale auth` |
| 1024 | uses; nothing is uploaded. |
| 1025 | - `Git` grows a `commit_plan` action: a propose-only planner that splits the |
| 1026 | working tree into ordered atomic commits (#3999). It groups whole files — |
| 1027 | lock files ride with their manifest, tests ride with the source they name — |
| 1028 | orders the groups so a commit that defines a symbol lands before the commit |
| 1029 | that uses it, and refuses the whole plan when that dependency graph has a |
| 1030 | cycle. It reads `git diff HEAD` plus the untracked-file list and writes |
| 1031 | nothing: no `git add -N`, no `git apply --cached`, no `git commit`, so |
| 1032 | staging and committing stay with the ordinary `git add` / `git commit` shell |
| 1033 | path where the approval gate already applies. Thanks |
| 1034 | [@goransh-walia](https://github.com/goransh-walia) for the original |
| 1035 | implementation (PR #5870, fixes #3999). |
| 1036 | |
| 1037 | ### Contributors |
| 1038 | |
| 1039 | - **[@LmeSzinc](https://github.com/LmeSzinc)** — requested Runtime API access to the TUI's fuzzy file search ([#6095](https://github.com/Hmbown/Codewhale/issues/6095)). |
| 1040 | - **[@googio](https://github.com/googio)** — added the Serply web-search provider ([#6100](https://github.com/Hmbown/Codewhale/pull/6100)). |
| 1041 | - **[@dmt4](https://github.com/dmt4)** — requested Linux copy-on-select and middle-click paste ([#6116](https://github.com/Hmbown/Codewhale/issues/6116)). |
| 1042 | - **[@Gabriel-Degret](https://github.com/Gabriel-Degret)** — reported that saved agent profiles were silently ignored when spawning sub-agents ([#6117](https://github.com/Hmbown/Codewhale/issues/6117)). |
| 1043 | - @nightt5879 — Gemini signature recovery guidance and transport regressions (#6081). |
| 1044 | - @c020627 — Chinese documentation link repairs (#6080). |
| 1045 | - @h3c-hexin and @asto18089 — GLM-5.3 reasoning controls and tool-gating/documentation fixes (#6051, #6052). |
| 1046 | - @Hmbown — dependency updates (#6057) and the Gemini signature recovery report (#6048). |
| 1047 | - **[@gaord](https://github.com/gaord)** — contributed the file-scoped restore endpoint and the trust-gated whole-tree rollback ([#6111](https://github.com/Hmbown/Codewhale/pull/6111)), Fleet schema inspection, role precedence and worker deliverable receipts, and linked the community VS Code frontend ([#5944](https://github.com/Hmbown/Codewhale/pull/5944), [#5945](https://github.com/Hmbown/Codewhale/pull/5945), [#5946](https://github.com/Hmbown/Codewhale/pull/5946), [#5992](https://github.com/Hmbown/Codewhale/pull/5992)). |
| 1048 | - **[@goransh-walia](https://github.com/goransh-walia)** — contributed the propose-only commit-planning rework ([#5870](https://github.com/Hmbown/Codewhale/pull/5870)). |
| 1049 | - **[@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/Hmbown/Codewhale/pull/5996), [#5952](https://github.com/Hmbown/Codewhale/issues/5952), [#5954](https://github.com/Hmbown/Codewhale/issues/5954), [#6003](https://github.com/Hmbown/Codewhale/issues/6003), [#6004](https://github.com/Hmbown/Codewhale/issues/6004), [#6006](https://github.com/Hmbown/Codewhale/issues/6006), [#6007](https://github.com/Hmbown/Codewhale/issues/6007)). |
| 1050 | - **[@SparkofSpike](https://github.com/SparkofSpike)** — contributed two-stage consent for opting out of model-bound credential redaction ([#5982](https://github.com/Hmbown/Codewhale/pull/5982)). |
| 1051 | - **[@aboimpinto](https://github.com/aboimpinto)** — moved session lifecycle and session-control commands onto shared command contracts ([#5902](https://github.com/Hmbown/Codewhale/pull/5902), [#5951](https://github.com/Hmbown/Codewhale/pull/5951)). |
| 1052 | - **[@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/Hmbown/Codewhale/issues/5908), [#5909](https://github.com/Hmbown/Codewhale/issues/5909), [#5910](https://github.com/Hmbown/Codewhale/pull/5910), [#5911](https://github.com/Hmbown/Codewhale/pull/5911), [#5912](https://github.com/Hmbown/Codewhale/pull/5912)). |
| 1053 | - **[@wuisabel-gif](https://github.com/wuisabel-gif)** — exposed workspace file suggestions through the Runtime API ([#6120](https://github.com/Hmbown/Codewhale/pull/6120)) and added custom-theme discovery, preview and selection in the theme picker ([#5907](https://github.com/Hmbown/Codewhale/pull/5907)). |
| 1054 | - **[@zhuowp](https://github.com/zhuowp)** — matched model-visible shell guidance to the interpreter selected for execution ([#5900](https://github.com/Hmbown/Codewhale/pull/5900)). |
| 1055 | - **[@nsfoxer](https://github.com/nsfoxer)** — reported the multiline-paste regression and incomplete provider model lists ([#5981](https://github.com/Hmbown/Codewhale/issues/5981), [#6009](https://github.com/Hmbown/Codewhale/issues/6009)). |
| 1056 | - **[@Nefelibata1024](https://github.com/Nefelibata1024)** — confirmed the multiline-paste regression's impact ([#5981](https://github.com/Hmbown/Codewhale/issues/5981)). |
| 1057 | - **[@Gabriel-Degret](https://github.com/Gabriel-Degret)** — reported the loss of the allow_insecure_http provider setting ([#5991](https://github.com/Hmbown/Codewhale/issues/5991)). |
| 1058 | - **[@Lujc0523](https://github.com/Lujc0523)** — reported the ACP initialize schema violation affecting strict IDE clients ([#5969](https://github.com/Hmbown/Codewhale/issues/5969)). |
| 1059 | - **[@mo-vic](https://github.com/mo-vic)** — proposed storing evicted context on disk so it can be retrieved later ([#6008](https://github.com/Hmbown/Codewhale/issues/6008)). |
| 1060 | - **[@giancarlocp](https://github.com/giancarlocp)** — requested a plugin authoring guide and OpenCode plugin conversion ([#5827](https://github.com/Hmbown/Codewhale/discussions/5827)). |
| 1061 | - **[@hxfhd](https://github.com/hxfhd)** — supplied a Windows reproduction of a turn stopping before its stated next tool action ([#6010](https://github.com/Hmbown/Codewhale/discussions/6010)). |
| 1062 | |
| 1063 | ### Notes |
| 1064 | |
| 1065 | - **DeepSeek V4 Pro continues after September 14.** The vendor reversed its |
| 1066 | earlier retirement notice. Codewhale preserves Pro selections and Pro pricing; |
| 1067 | `deepseek-flash` remains the default for new direct DeepSeek configurations. |
| 1068 | - Upgrading from 0.9.12 with Computer Use trusted and enabled: the |
| 1069 | bundle's content hash changes with the 0.2.1 refresh, so the plugin |
| 1070 | deactivates and asks for a fresh review — that is the designed |
| 1071 | fail-closed path for a desktop-driving plugin. Re-trust it from the |
| 1072 | Plugins page. |
| 1073 | - The multiline-paste fix restores v9.11 behavior on terminals that |
| 1074 | accept `EnableBracketedPaste` but deliver pastes as keystrokes |
| 1075 | (reported on Windows 11 / PowerShell). Verified at the input-contract |
| 1076 | level and in CI; a manual paste check on a real Windows terminal is |
| 1077 | still welcome — please comment on #5981 with your terminal if anything |
| 1078 | still misbehaves. |
| 1079 | |
| 1080 | ## [0.9.12] - 2026-09-03 |
| 1081 | |
| 1082 | Codewhale v0.9.12 puts computer use in the binary, opens two new routes — |
| 1083 | Alibaba Model Studio through the data-driven provider table and Concentrate |
| 1084 | as an opt-in BYOK Responses gateway — and adds cloud dispatch plus a |
| 1085 | config-gated per-session control socket. The shell is the other half of the |
| 1086 | release: a new launch card, the work surface docked under the composer, one |
| 1087 | focus owner for Tab, tool cells that carry their own state, and `fleet` as |
| 1088 | the public word for the live collective. The complete item-level change |
| 1089 | record is retained below the categorized release highlights. |
| 1090 | |
| 1091 | ### Added |
| 1092 | |
| 1093 | - Computer use ships with the binary. The `computer-use` plugin — 38 tools |
| 1094 | across macOS, Windows, Linux and HarmonyOS, accessibility-first observation |
| 1095 | with pixel fallback, screenshots, zoom, screen recording, and registered |
| 1096 | remote computers over ssh and hdc — is embedded in Codewhale and written to |
| 1097 | `$CODEWHALE_HOME/builtin-plugins` on first run, so every install channel |
| 1098 | carries it. It lists as `builtin · not-reviewed` and stays disabled until |
| 1099 | you review and enable it: shipping it is not consenting to it. The |
| 1100 | stdlib-Python computer-use server it replaces is gone. |
| 1101 | - Alibaba Model Studio joins the data-driven provider table as an |
| 1102 | `openai-compatible` descriptor: international compatible-mode endpoint, |
| 1103 | `DASHSCOPE_API_KEY` credential, live `/v1/models` discovery. Qwen 3.8 |
| 1104 | Flash and Qwen 3.8 Max arrive through the catalog authority — never a |
| 1105 | hard-coded id. |
| 1106 | - Concentrate: first-class opt-in BYOK Responses gateway with live models |
| 1107 | discovery and typed SSE streaming (#5725). |
| 1108 | - Cloud dispatch: remote runner offloads coding agent tasks to isolated |
| 1109 | cloud sandboxes with machine token auth and structured job tracking |
| 1110 | (#5701, #5712). |
| 1111 | - Per-session control socket: config-gated `[control_socket]` table binds |
| 1112 | `<sessions-dir>/<session-id>/control.sock` per running session, exposing |
| 1113 | message, interrupt, relaunch, and status JSON-RPC verbs (#5533, #5831). |
| 1114 | |
| 1115 | ### Changed |
| 1116 | |
| 1117 | - **Anonymous usage counting is on by default.** The 0.9.11 release asked |
| 1118 | first; 0.9.12 counts the same aggregate version/platform, session, feature |
| 1119 | and error totals unless you turn it off, and says so once at first launch |
| 1120 | (policy notice version 5, schema 3, `notice_version` replacing |
| 1121 | `consent_version`). Every recorded opt-out stays off: a durable |
| 1122 | `telemetry = false`, a decline recorded under the old opt-in notice, |
| 1123 | unreadable privacy state, and the `CODEWHALE_TELEMETRY=0` / `--telemetry |
| 1124 | false` kill switches. Showing the disclosure records only that it was |
| 1125 | shown, never an acceptance. `codewhale config set telemetry false` turns |
| 1126 | it off and wipes queued counts; `codewhale config set telemetry true` |
| 1127 | deliberately re-enables it. Nothing new is collected: no conversations, |
| 1128 | code, prompts, files, names, model content, credentials, or IP. |
| 1129 | |
| 1130 | - The launch screen is our own card take: a thin top line |
| 1131 | `⑂ branch path`; a centred bordered card with the whale mark, |
| 1132 | `Codewhale` + version, one announcement line only when it is true (the |
| 1133 | no-model warning, or MCP news), and the menu New worktree / Resume |
| 1134 | session / Changelog / Quit with their real chords right-aligned. Enter |
| 1135 | runs the highlighted entry, Up/Down move it, and typing goes straight to |
| 1136 | the composer. The card dissolves on the first keystroke or command |
| 1137 | (≤240 ms, instant under reduced motion) (#5826, #5801, #5815, #5286). |
| 1138 | - The work surface sits under the composer by default, keeping history |
| 1139 | readable and leaving the stage unencumbered (#5809). |
| 1140 | - Skills command shapes: FEAT-022 command shapes and retained-host |
| 1141 | validation (#5825, #5829). |
| 1142 | - After the card dissolves, the working screen shows `⑂ branch path` with |
| 1143 | `⋮ MCP n/m` on the right, the transcript starts with the |
| 1144 | `◆ session_start` receipt (naming the configured session-start hooks), |
| 1145 | and the composer's bottom rule carries `model (effort) · permission` — |
| 1146 | the route's one launch reading. The posture bar and metrics line appear |
| 1147 | only once a session exists. |
| 1148 | - Vocabulary: `fleet` is the public term and `Pod` is retired from copy — |
| 1149 | roster, setup, detail, worker-runtime and managed-API messages now say |
| 1150 | Fleet (`/fleet` canonical, `/pod` alias). The workflow wire accepts the |
| 1151 | canonical role spellings (general/explore/planner/reviewer/implement/ |
| 1152 | test/advisor) with the pre-rename ones kept as load-time aliases, and |
| 1153 | serializes canonical names. |
| 1154 | - The Operate mode-picker hint is shortened to fit 80 columns. |
| 1155 | |
| 1156 | - The footer always shows the permission posture; when only one chip |
| 1157 | fits, the permission chip outranks the mode word (#5796). |
| 1158 | - Local Ollama: the header names a model only when the local catalog can |
| 1159 | serve it, and says `unknown` until it knows. The startup mark, web and |
| 1160 | app icon carry the new side-view prompt-eye whale (#5795). |
| 1161 | - One focus owner: Tab and Shift+Tab work regardless of what is in the |
| 1162 | composer; Alt shortcuts survive mid-draft; Ctrl+Tab no longer cycles the |
| 1163 | mode by accident (#5798). |
| 1164 | - Tool cells carry their own state: a running, failed or warned tool |
| 1165 | reads as such in the transcript itself, with per-entry rail dots and |
| 1166 | family-coloured glyphs (#5799). |
| 1167 | - Web: docs hub with task search, shared empty/loading/error states, an |
| 1168 | offline-to-back-online banner, `/changelog` in every locale, and real |
| 1169 | 404s with correct metadata (#5743). |
| 1170 | - Web: the app's colours come from one file generated from the TUI whale |
| 1171 | palette; re-typing a colour by hand fails web CI (#5797). |
| 1172 | - Web: a one-way ceiling on `isZh` branching outside the i18n spine — |
| 1173 | the count may only go down (#5805). |
| 1174 | - An internal agent handoff doc was removed from the public tree and |
| 1175 | `.playwright-mcp/` is now ignored (#5800). |
| 1176 | - First run paints the composer immediately: the Welcome/language/provider/ |
| 1177 | trust gates no longer precede the first keystroke. Missing-key and |
| 1178 | workspace-trust recovery stay for returning users; language and provider |
| 1179 | remain in `/setup`. |
| 1180 | - The canonical whale-tile mark propagates beyond web to the exact-raster |
| 1181 | surfaces that can carry it (#5738). |
| 1182 | - Dead-code sweep: delete proven-unreferenced helpers (unused builders, |
| 1183 | wrappers, and leftover identifiers) and drop stale `#[allow(dead_code)]` |
| 1184 | where the item is production-called or test-exercised. No runtime behavior |
| 1185 | change (#5791, #5587). |
| 1186 | - Remote-control recovery gives every fresh pre-dispatch attempt a new lease |
| 1187 | generation while preserving that generation across its typed start (#5605). |
| 1188 | |
| 1189 | - Public roster language is Pod. `/pod` is the customer surface; fleet remains |
| 1190 | the internal wire, storage, and migration name (#5776). |
| 1191 | |
| 1192 | - Compaction replacement history keeps a bounded last user round (assistant + |
| 1193 | tool results) instead of dropping them behind a summary. `/context` names |
| 1194 | the compaction path and `/anchor` survival. Failed compact still does not |
| 1195 | replace live history (#4394). |
| 1196 | - Provider catalogs: compatible hosts (Baseten, Groq, Cerebras, SenseNova, |
| 1197 | Command Code) no longer compile a frozen model roster. Descriptors name the |
| 1198 | wire, URL, and env; live `GET /v1/models` and a Codewhale-owned catalog |
| 1199 | layer are the offering list. Command Code is a catalog/descriptor row, not |
| 1200 | a `ProviderKind`. Catalog presence is not an availability, entitlement, or |
| 1201 | provider-acceptance claim (#5783). |
| 1202 | |
| 1203 | - Provider selection no longer probes or adopts an external CLI credential on |
| 1204 | ordinary picker use. Reuse requires an explicit "Use external CLI credentials" |
| 1205 | choice, exact-path confirmation, and Codewhale-owned revoke (#5772). |
| 1206 | |
| 1207 | - TUI: startup no longer presents an approximate ASCII or block-glyph whale as |
| 1208 | the product mark. It keeps the direct Tideline prompt while exact-raster |
| 1209 | surfaces remain responsible for the canonical asset. |
| 1210 | |
| 1211 | - TUI: the active-session composer paints the same three-cell `[↑]` send |
| 1212 | target as Startup and clicks it through the existing Enter submit |
| 1213 | dispatcher (#5771). Compact/quiet composers still omit the control. |
| 1214 | |
| 1215 | - TUI/CLI: Pod is the public roster surface. User-facing Fleet wording |
| 1216 | moves to Pod; durable receipt keys stay compatible (#5776). |
| 1217 | |
| 1218 | ### Contributors |
| 1219 | |
| 1220 | - **hexin ([@h3c-hexin](https://github.com/h3c-hexin))** — provider-native web |
| 1221 | search across four routes (#5682, #5683, #5685, #5687), authoritative |
| 1222 | edit-last-turn boundaries (#5621), Kimi Code k3-256k (#5622), |
| 1223 | post-compaction input-token reporting (#5623), and preserving the scheduled |
| 1224 | model selection in automations (#5650). |
| 1225 | - **秋月凉梦 ([@qiuYliangM](https://github.com/qiuYliangM))** — co-authored the |
| 1226 | edit-last-turn boundary fix (#5621), Kimi Code k3-256k support (#5622), and |
| 1227 | post-compaction input-token reporting (#5623). |
| 1228 | - **Isabel Wu ([@wuisabel-gif](https://github.com/wuisabel-gif))** — live |
| 1229 | session token totals (#5624), persisted context-pressure warnings (#5629), |
| 1230 | discoverable Fleet roster editing (#5604), the capability-gated cursor |
| 1231 | accent (#5599), and `/copy` for the latest completed response (#5692). |
| 1232 | - **Paulo Aboim Pinto ([@aboimpinto](https://github.com/aboimpinto))** — |
| 1233 | Windows verbatim-path operands preserved through POSIX word splitting |
| 1234 | (#5610), the plugins group moved onto the command shapes (#5657), FEAT-022 |
| 1235 | skills command shapes with retained-host validation (#5825), and FEAT-020 |
| 1236 | plugin command shapes re-landed on main (#5865). |
| 1237 | - **Alex Musichen ([@musichen](https://github.com/musichen))** — a stable |
| 1238 | DeepSeek heading in the configured-view model picker, keeping every official |
| 1239 | catalog model for the active provider visible (#5689). |
| 1240 | - **[@gaord](https://github.com/gaord)** — the `GET /v1/fleet/profiles` |
| 1241 | runtime API endpoint, reusing the FleetManager validation path (#5688). |
| 1242 | - **Sh1Zuku ([@SparkofSpike](https://github.com/SparkofSpike))** — corrected |
| 1243 | English documentation inaccuracies and the first zh_hans translations for |
| 1244 | the Tier-2 docs (#5613). |
| 1245 | - **[@M-Maciej](https://github.com/M-Maciej)** — goal continuation cadence |
| 1246 | (#5591) and the per-session control socket (#5533, #5831). |
| 1247 | - **Serephus ([@serephus](https://github.com/serephus))** — nixpkgs update |
| 1248 | (#5669). |
| 1249 | - **[@whp233](https://github.com/whp233)** — `wire = responses|anthropic` for |
| 1250 | openai-compatible custom routes and opencode-zen muse-spark (#5716, landed |
| 1251 | as #5719). |
| 1252 | - **Gabriel Degret ([@Gabriel-Degret](https://github.com/Gabriel-Degret))** — |
| 1253 | found the reasoning-only retry gap and built the first fix; landed as the |
| 1254 | `[reasoning_only]` retry ceiling with a request-scoped nudge (#5867). |
| 1255 | - **[@huangxianzhan](https://github.com/huangxianzhan)** — the |
| 1256 | `x-opencode-session` header for OpenCode Go and Zen gateways (#5868). |
| 1257 | - **[@zhuowp](https://github.com/zhuowp)** — task origin preserved in job |
| 1258 | snapshots (#5869). |
| 1259 | - **AdityaG ([@AdityaVG13](https://github.com/AdityaVG13))** — a ten-commit |
| 1260 | performance pass: a zero-copy LaTeX fast path for streaming render, |
| 1261 | single-pass token accounting on the per-turn pressure paths, memoized |
| 1262 | provider resolution in the catalog cutline, parsing the bundled and |
| 1263 | on-disk models.dev catalogs once per process (interactive boot -70%), |
| 1264 | adaptive poll cadence for foreground shell completion, and worker caps |
| 1265 | across the read-only diagnostic family. |
| 1266 | - **Nightt ([@nightt5879](https://github.com/nightt5879))** — isolated remote |
| 1267 | recovery lease generations (#5790). |
| 1268 | - **[@yiheng-kkk](https://github.com/yiheng-kkk)** — replaced stale todo |
| 1269 | transcript snapshots so a rewritten todo list renders its current tasks |
| 1270 | (#5871, #5873). |
| 1271 | - **[@Lfanxing](https://github.com/Lfanxing)** — Moonshot routes now degrade |
| 1272 | incompatible tool definitions per request instead of failing the turn. |
| 1273 | - **WissssleyL ([@Lstarsky0](https://github.com/Lstarsky0))** — moved |
| 1274 | `docs/subagents` and `docs/mcp` onto the dictionary spine (#5337), with the |
| 1275 | metaTitle probe that keeps them there. |
| 1276 | |
| 1277 | Reports and reproductions that shaped this release: |
| 1278 | |
| 1279 | - **[@slowly247](https://github.com/slowly247)** — reported the Ollama input |
| 1280 | budget collapsing to 1,024 tokens on 32K local models (#5820). |
| 1281 | - **[@ronohara](https://github.com/ronohara)** — reported the engine stopping |
| 1282 | after recoverable network errors, with the reproduction that pinned the |
| 1283 | discarded approval (#5769), and surfaced DeepSeek's model-service notices and the subsequent reversal |
| 1284 | retaining V4 Pro (#6025). |
| 1285 | - **[@Lujc0523](https://github.com/Lujc0523)** — asked for ACP session |
| 1286 | configuration of mode and model (#5863). |
| 1287 | - **[@senka9h](https://github.com/senka9h)** — reported that `serve --acp` |
| 1288 | lacked `session/list` and `session/load` (#5864). |
| 1289 | |
| 1290 | ### Added |
| 1291 | |
| 1292 | - Native ChatGPT sign-in for the `openai-codex` route: `codewhale auth |
| 1293 | chatgpt` opens a browser PKCE flow and stores refreshable tokens in |
| 1294 | Codewhale-owned credentials — no Codex CLI install required. |
| 1295 | `/auth chatgpt-revoke` clears them off the event loop (#5784, #5778). |
| 1296 | - MCP servers and plugins can be connected self-serve from the session: a |
| 1297 | unified auth flow with rotation-safe token handling, a spoken authorization |
| 1298 | URL, and catalog refresh when stored credentials stop working (#5747). |
| 1299 | - `/operate` reads match the landed CWC `OperateRecord` contract: fetching an |
| 1300 | absent record returns a truthful not-found view instead of a fabricated |
| 1301 | operation, and an empty evidence path is rejected rather than resolving to |
| 1302 | the workspace directory (#5703). |
| 1303 | - TUI: scheduled automations project into the top strip |
| 1304 | (`⏱ N scheduled · M running`, compact `⏱ N·M`) with typed |
| 1305 | `HistoryCell::Automation` receipts when a run this session watched settle. |
| 1306 | `/automation` acknowledges failures. The merged footer does not carry the |
| 1307 | work fact (#5748). |
| 1308 | - The app-server can listen on a unix domain socket and advertise a |
| 1309 | `daemon/attach` handshake, so a local client can attach to an already-running |
| 1310 | engine instead of spawning its own. The socket is created with |
| 1311 | owner-only permissions and stale sockets are reclaimed on start. Non-unix |
| 1312 | hosts return a typed unsupported-platform refusal; the Windows named-pipe |
| 1313 | endpoint is named but not yet implemented (#5749). |
| 1314 | - The engine's internal `Op`/`Event` types and the wire protocol's `Op`/ |
| 1315 | `EventMsg` now carry a compile-enforced twin for every variant: adding an |
| 1316 | engine variant without a protocol counterpart fails the build instead of |
| 1317 | drifting silently. Internal durability work — no user-visible surface |
| 1318 | change yet (#5751). |
| 1319 | - Machine tokens: with `CODEWHALE_API_KEY` set, the CLI authenticates as the |
| 1320 | Codewhale account with no local session file and no browser — the CI |
| 1321 | authentication path, with a typed token shape and redaction (#5721). |
| 1322 | - Compaction publishes a structured survival contract for session-tree |
| 1323 | journal entry types (`crates/tui/src/compaction/SURVIVAL_CONTRACT.md`) and |
| 1324 | fails closed when the last user round, tool results, `/anchor` text, or |
| 1325 | checkpoint receipt would vanish (#4394, #5782). |
| 1326 | - Internal: `codewhale-config` gains `RouteAuthoritySnapshot`, one immutable |
| 1327 | authority that owns a compiled provider catalog together with the route |
| 1328 | resolver projected from it, so a picker, a readiness view, and an execution |
| 1329 | path can no longer resolve against different catalog snapshots without a |
| 1330 | type-level signal. Resolution still goes through the sole resolver; the |
| 1331 | returned receipt distinguishes an exact catalog row, a custom-endpoint route |
| 1332 | whose provider facts are deliberately not reused, and an allowed |
| 1333 | pass-through route with no catalog row. All state is secret-free. No call |
| 1334 | site changed and no user-visible behaviour changed yet (#5766). |
| 1335 | |
| 1336 | - Computer session records now count only time a provider actually accepted the |
| 1337 | session as active, at per-second granularity. Idle, queued, stopped, and |
| 1338 | teardown time are excluded, and a session whose allocation does not match a |
| 1339 | standard profile is refused rather than recorded approximately. Covered by |
| 1340 | hermetic fixtures; no live provider call and no deploy (#5781). |
| 1341 | |
| 1342 | - Website: the public site moves to the Tideline deep-ocean design language |
| 1343 | (dark by default with an opt-in light documentation sheet, palette grounded |
| 1344 | in the TUI's WHALE_* tokens) and the new whale brand mark across the favicon, |
| 1345 | app icons, web manifest, nav wordmark, and social card (#5573). |
| 1346 | |
| 1347 | - Add `codewhale dispatch` / `/dispatch` so a local session can propose a |
| 1348 | Codewhale cloud agent against an explicit `github`, `cnb`, or `gitee` remote. |
| 1349 | Confirmation is required; missing credentials fail closed; cloud jobs share |
| 1350 | the existing `/jobs` surface as `kind=cloud`. See |
| 1351 | [DAYTONA_CLOUD_DISPATCH.md](docs/DAYTONA_CLOUD_DISPATCH.md). |
| 1352 | - `/login` reports the Codewhale account session and provider-key next |
| 1353 | steps. The internal cloud-agent credential is not user surface: there is |
| 1354 | no `auth set-slot`/`auth clear-slot` command, no hint, and no completion |
| 1355 | entry for it — signing in with `codewhale login` is the only door. |
| 1356 | - Add the Tideline component family from the ratatui translation spec |
| 1357 | (#5698's screens, riding the #5699 work-strip layout): hero startup |
| 1358 | surface with quick actions and option strip, notifications inbox, merged |
| 1359 | footer band, pod ledger, receipt |
| 1360 | stream, theme list with motion toggles, live preview, settings rail, |
| 1361 | and the left rail — each a standalone render module pinned by 28 new |
| 1362 | byte-exact golden buffers. Frame wiring follows the Tideline acceptance |
| 1363 | gate; `NO_COLOR` is now honored by palette depth detection. |
| 1364 | - Route Contract Phase 1: `RouteResolver` is the runtime path for |
| 1365 | `resolve_runtime_options`; `codewhale providers export --json` ships the |
| 1366 | owned descriptor catalog; CLI `--provider` accepts any catalog route id |
| 1367 | (the closed `ProviderArg` enum is deleted). Catalog layers are |
| 1368 | bundled → models.dev → provider `/v1/models` → config.toml → user, with |
| 1369 | policy DENY last and never overridden. |
| 1370 | - Add provider-native web search for documented Xiaomi MiMo 2.5 Pro and 2.5 |
| 1371 | chat routes while keeping neighboring models and custom gateways fail-closed. |
| 1372 | - Add structured provider-native web search for exact Z.AI global and Zhipu |
| 1373 | China general API routes, using each site's documented search engine value. |
| 1374 | Existing `open.bigmodel.cn` configurations now share Z.AI's official model |
| 1375 | namespace and credential scope; unknown model IDs still pass through. |
| 1376 | - Add provider-native web search for documented Qwen models on ModelStudio |
| 1377 | Token Plan's Responses Harness, without enabling Coding Plan or Anthropic |
| 1378 | routes. |
| 1379 | - Added `/copy` to place the latest completed assistant response on the |
| 1380 | clipboard without copying tools, system messages, hidden reasoning, or |
| 1381 | active partial output (#5668). |
| 1382 | - Add provider-native web search for documented DeepSeek V4 routes through the |
| 1383 | Responses API, with fail-closed capability gating for compatible custom |
| 1384 | endpoints. |
| 1385 | - Add provider-native search for exact Moonshot K3 Formula, legacy K2.6 |
| 1386 | built-in search, and Kimi Code membership `/search` routes. Treat the exact |
| 1387 | Moonshot China endpoint as a first-party direct route. |
| 1388 | - Z.ai `GLM-5.3-Flash` and OpenRouter `z-ai/glm-5.3-flash` are first-class |
| 1389 | picker rows (`/model GLM-5.3-Flash`). Flash is the faster/explore sibling |
| 1390 | of `GLM-5.3`; the Z.ai default stays `GLM-5.3`. List price is $0.15/$0.50 |
| 1391 | per 1M (durable; the 50% promo through 2026-09-09 is not the catalog row). |
| 1392 | - Baseten, Groq, and Cerebras are bundled OpenAI-compatible setup templates |
| 1393 | (`[providers.<id>] kind = "openai-compatible"`), not new `ProviderKind` |
| 1394 | variants. `/provider` fills URL, model, and env from one catalog row. |
| 1395 | - MCP manager copy now names the server, the failure, and one recovery |
| 1396 | command (`The X MCP server requires OAuth reauthentication. Run /mcp login X`). |
| 1397 | - Settings Advanced exposes clickable MCP Connect, Reconnect, and Diagnose |
| 1398 | actions, while Extensions and Problems route recovery through the existing |
| 1399 | `/mcp login`, `/mcp reload`, `/mcp validate`, and `/plugin validate` commands |
| 1400 | (#5643, #5655). |
| 1401 | - Plugin prompt matching (#5579): sending a task can toast the next review |
| 1402 | step when the prompt strongly matches an installed-but-idle plugin or a |
| 1403 | marketplace catalog you added (for example a Supabase prompt suggesting |
| 1404 | `/plugin trust supabase`). A live composer CTA offers the same review |
| 1405 | command while you type, matching turns append a bounded |
| 1406 | `<recommended_plugins>` user block, and `request_plugin_install` surfaces |
| 1407 | review without installing. `/plugin suggest` now ranks manifest keywords and |
| 1408 | catalog candidates, never auto-installs, and on-disk plugin changes also |
| 1409 | nudge `/plugin reload` between turns. |
| 1410 | |
| 1411 | |
| 1412 | - Added `/import-claude` (#5557): reads `~/.claude.json` and |
| 1413 | `~/.claude/settings.json` read-only and renders an explicit, reviewable |
| 1414 | migration plan plus a written report. MCP servers route through the |
| 1415 | existing `/mcp import <name> --approve` consent flow, allowlisted env keys |
| 1416 | become an unapplied portable bundle for `codewhale config import`, and |
| 1417 | permissions/hooks map to manual follow-ups; secret-shaped values are named |
| 1418 | but never echoed or imported. |
| 1419 | - Added the managed Chat relay: account-owned Chat commands now execute on the |
| 1420 | native runtime thread engine through a new `runtime_chat_relay` module |
| 1421 | instead of a second execution path. Each Chat thread is a dedicated, |
| 1422 | isolated runtime thread with an empty model-visible tool allowlist, a |
| 1423 | chat-only system prompt, and no workspace, memory, skill, credential, or |
| 1424 | local-path context; the active interactive TUI thread is never reused. The |
| 1425 | relay keeps one durable state file per scope behind a session-wide owner |
| 1426 | lock, binds a saved session permanently to its first remote target, replays |
| 1427 | exact duplicate commands from retained results instead of starting a second |
| 1428 | inference turn, terminalizes orphaned reservations on restart, and rejects |
| 1429 | (never queues into) a busy local Work turn with an immediate retryable |
| 1430 | result. Stop commands require the exact run and turn identity, and a worker |
| 1431 | aborts on any account or target mismatch during token refresh. |
| 1432 | |
| 1433 | - Added a verified Omarchy/AUR packaging path: `packaging/aur` now carries a |
| 1434 | `PKGBUILD` template, `.SRCINFO` renderer and tests, release-candidate |
| 1435 | render step, and docs; the live AUR compatibility alias `codewhale-tui -> |
| 1436 | codewhale` is preserved, AUR dependencies match the live package, and the |
| 1437 | self-updater refuses to fight an Omarchy/package-manager installation. |
| 1438 | - Added a Fleet run-wide cost/token usage ceiling (R6, #5567): an accumulator |
| 1439 | plus admission gate and alert bound a whole run's spend across workers. |
| 1440 | - Added the real provider cache hit rate to `/context` (C3, DSH #3): the |
| 1441 | token-weighted provider-reported rate from the same telemetry `/cache` |
| 1442 | aggregates, plus an honest "no cache telemetry yet" state when nothing is |
| 1443 | recorded. |
| 1444 | - Added per-step cost movement: `TurnUsage` receipts are priced as they land |
| 1445 | so the live cost surface moves during long agentic turns instead of only at |
| 1446 | `TurnComplete` (#5578), and the footer now honestly shows `cost: unknown` |
| 1447 | when nothing can be priced instead of hiding the line. |
| 1448 | - Added the underwater session surface: the ambient water reads session state |
| 1449 | from across the room, its animation shape follows live agent activity, and |
| 1450 | attention tints are steady (no breathing) with a distinct reading treatment |
| 1451 | and no mid-water seam on tall windows. |
| 1452 | - Added `@path:START-END` ranged line mentions (#5550, picker half to follow), |
| 1453 | a predictable last-copy backup file for clipboard exports with the path |
| 1454 | named when the clipboard fails (#5555), `wait` on multiple background shell |
| 1455 | tasks with `until=any|all` (#5549, named-kill half to follow), and composer |
| 1456 | double-click word / triple-click line selection. |
| 1457 | - Added workflow parallel-`schema` slot partial success (#5583): a slot that |
| 1458 | produces a schema-valid partial result no longer fails the whole parallel |
| 1459 | branch. |
| 1460 | - Added plugin load-failure startup hints (#5579) and OpenRouter app |
| 1461 | attribution headers on outbound requests. |
| 1462 | - Added `codewhale doctor --fix` (with `--yes` for non-interactive consent): |
| 1463 | the doctor now computes a concrete repair plan — delete stale `.tmp*` |
| 1464 | leftovers from interrupted atomic writes, tighten secret-store file |
| 1465 | permissions to `0600`, disable structurally broken (Error-status) MCP |
| 1466 | entries through the atomic MCP save path, and scaffold missing user-global |
| 1467 | `skills`/`tools`/`plugins` directories — shows it, and applies it only after |
| 1468 | explicit consent. Every action is narrowly scoped and idempotent; JSON and |
| 1469 | context-JSON modes stay read-only and conflict with `--fix` (#5552, v1). |
| 1470 | - Added `/context` reporting of the real provider prompt-cache hit rate (C3) |
| 1471 | alongside token pressure. |
| 1472 | |
| 1473 | ### Changed |
| 1474 | |
| 1475 | - Provider-native web search now applies domain constraints before accepting an |
| 1476 | attempt, discards generated answers when returned citations violate those |
| 1477 | constraints, and preserves the caller's configured/local timeout as an |
| 1478 | independent fallback budget (#5681). |
| 1479 | - Idle session metrics omit zero facts (`0 turns`, `LLM 0s`) until the |
| 1480 | runtime has evidence. Working chrome says `in the current` instead of a |
| 1481 | generic `working`. |
| 1482 | - Deleted nine uncompiled `runtime_contract/` staging files. Live contracts |
| 1483 | remain `model.rs` and `termination.rs`. |
| 1484 | |
| 1485 | - The first #5587 dead-code sweep converts audited test-only helpers to |
| 1486 | `#[cfg(test)]`, keeping production builds free of test-only APIs without |
| 1487 | changing runtime behavior. |
| 1488 | - `/plugin reload` is now discoverable when on-disk plugin bundles change: the |
| 1489 | next send and `/plugin list` nudge once with `Run /plugin reload to apply` |
| 1490 | instead of silently keeping the stale catalog (#5579). Trust is unchanged; |
| 1491 | this does not auto-reload. |
| 1492 | - Context-pressure warnings and critical alerts now remain visible in sticky UI |
| 1493 | status until compaction or explicit dismissal, instead of disappearing into |
| 1494 | scrolling turn metadata (#5620). |
| 1495 | - The Runtime thread store defaults to a per-session root |
| 1496 | (`$CODEWHALE_HOME/sessions/<id>/runtime`) so multiple Codewhale processes on |
| 1497 | one machine no longer share one owner lock (#5630). The exclusive lock is |
| 1498 | unchanged; `CODEWHALE_RUNTIME_DIR` still selects a shared root when that is |
| 1499 | intended. |
| 1500 | - Session token totals now include display-only per-model-call deltas while a |
| 1501 | turn is running, including input/output and cache-class counters; the |
| 1502 | authoritative `TurnComplete` totals still reconcile exactly once (#5581). |
| 1503 | - Transcript focus now exposes per-block actions: `y` copies content, `Y` |
| 1504 | copies the rendered metadata view, Enter opens a fullscreen block pager, and |
| 1505 | `r` opens raw detail; the existing Tasks rail shortcuts remain unchanged |
| 1506 | (#5551). |
| 1507 | - Provider neutrality (#5588): model resolution of omitted/aliased models is |
| 1508 | now provider-relative, OpenAI-native defaults no longer route through |
| 1509 | another provider's table, CLI credentials stay provider-scoped, and NVIDIA |
| 1510 | credentials no longer leak into the DeepSeek keychain. Neutrality test |
| 1511 | matrices exercise several providers instead of standing in with one. |
| 1512 | - The workflow engine module was decomposed out of its 3k-line mega-file into |
| 1513 | `journal`, `usage`, and `report` modules plus a module directory (#5586 |
| 1514 | slices 1a/B/C/D), a semantic-free move verified by normalized-content hash. |
| 1515 | - Compaction refusals are now always named (#5577): silent holds under context |
| 1516 | pressure are gone, the context meter honors the same provider-billed prompt |
| 1517 | the trigger uses (T1), and prune outcomes are projected without cloning the |
| 1518 | transcript. |
| 1519 | - Step budgets now end honestly: an ~80% soft landing nudges the model to |
| 1520 | write its final report, and exhaustion grants exactly one bounded |
| 1521 | report-on-exhaustion turn instead of dying silently (A1/A2). |
| 1522 | - Contributor credit: recognized agent contributors (e.g. `Codewhale Agent`) |
| 1523 | may now carry `Co-authored-by` trailers; unknown bot/tool trailers are |
| 1524 | still rejected by the credit gate. |
| 1525 | |
| 1526 | ### Fixed |
| 1527 | |
| 1528 | - Read-only Fleet workers no longer send `"action": {"enum": null}` in their |
| 1529 | projected `bash` schema. The read-only projection probed the action enum |
| 1530 | with a mutating index, which auto-vivified the key on schemas that have no |
| 1531 | action property, and strict OpenAI-compatible validators then rejected the |
| 1532 | whole request (`null is not of type "array"`). The probe is non-mutating |
| 1533 | now, in both the read-only projection and the `Run` arm next to it, and a |
| 1534 | regression test walks the whole projected catalog for nulls |
| 1535 | (#5944, thanks @gaord). |
| 1536 | - Fast typing no longer corrupts the composer. The paste-burst heuristic ran |
| 1537 | on every session until a real bracketed paste arrived, holding, buffering, |
| 1538 | retro-grabbing, and absorbing Enter on timing guesses; it is now |
| 1539 | fallback-only (gated off when the terminal provides bracketed paste), the |
| 1540 | retro-grab is deleted, and Enter on held command text flushes and submits. |
| 1541 | - Ctrl+C works on the pre-session launch menu and speaks everywhere: the |
| 1542 | first press arms the two-second exit window with a visible localized |
| 1543 | "Press Ctrl+C again to quit" hint (previously silent), the second exits. |
| 1544 | The worktree name input keeps Ctrl+C as cancel-input. |
| 1545 | - Fresh interactive sessions no longer leave a phantom one-message duplicate |
| 1546 | behind. The TUI claimed one session id (Runtime store lock, turn-start crash |
| 1547 | checkpoint) while the engine minted a second one; the first `SessionUpdated` |
| 1548 | re-keyed the App, the completion commit cleared only the engine id's |
| 1549 | checkpoint, and `codewhale --continue` later "recovered" the orphaned |
| 1550 | checkpoint as a duplicate session instead of the real one. The engine now |
| 1551 | adopts the host-owned id at spawn (`EngineConfig::session_id`) and `/clear` |
| 1552 | mints the next id in the App like `/new`. A non-TTY `--continue` no longer |
| 1553 | promotes and consumes the crash checkpoint before failing the terminal |
| 1554 | check, and the root `codewhale --resume <id>` / `--session-id <id>` flags |
| 1555 | documented in the operations runbook now parse instead of being swallowed |
| 1556 | as a prompt. |
| 1557 | - Website: `/signin`, `/signup`, and `/auth/callback` are locale-aware public |
| 1558 | routes instead of localized 404s. Sign-in and create-account send the person |
| 1559 | to the CWC app; OAuth callbacks hop to `app.codewhale.net` with the query |
| 1560 | intact; `/login` and `/register` are aliases. Local CLI use is not presented |
| 1561 | as requiring an account (#5767). |
| 1562 | - The sandbox read deny-list matches a rule's resolved path as well as its |
| 1563 | literal spelling. On macOS `/etc` and `/var` are symlinks into `/private`, |
| 1564 | so a read of `/private/etc/sudoers` walked around the `/etc/sudoers` rule, |
| 1565 | and a rule written against a symlinked directory never fired for the real |
| 1566 | path that `canonicalize` and the process cwd hand back. |
| 1567 | - Background shells are first-class work-strip rows (`▾ Shells N`) you can |
| 1568 | open, watch, and cancel by the `shell_*` id on the row. `/jobs cancel all` |
| 1569 | cancels running shells; it no longer looks up a task named `all`. The |
| 1570 | composer hourglass crumb no longer stands in for a shell surface. |
| 1571 | - `codewhale logout` and `/logout` now clear the Codewhale account session |
| 1572 | and the Daytona secret slot, not only provider API keys. The TUI crate's |
| 1573 | leftover `login --api-key` path no longer claims to save a key. |
| 1574 | - Account sessions no longer read the macOS Keychain. Unsigned or rebuilt |
| 1575 | `codewhale` binaries were a new Keychain ACL principal every time, so |
| 1576 | `codewhale web` and the TUI popped a password dialog on start. Sessions |
| 1577 | now use `~/.codewhale/secrets/secrets.json` (mode 0600), the same store |
| 1578 | as provider keys. Extracted from the Keychain-retirement half of #5632. |
| 1579 | - Hardened the dispatcher-side config parse the same way: `ConfigStore` |
| 1580 | loads and project-config parsing now deserialize `ConfigToml` on a |
| 1581 | dedicated 16 MiB-stack thread (the guided-setup save path could overflow |
| 1582 | a 2 MiB worker stack the same way the TUI's `ConfigFile` parse did), and |
| 1583 | the #5585 setup-confirm toast test runs its runtime on an equally sized |
| 1584 | thread instead of overflowing the default libtest stack. |
| 1585 | - Fixed detached interactive agents reporting worker usage after the parent |
| 1586 | turn ends with the usage missing from the session/live `/cost` total |
| 1587 | (#5597): interactive turns acquire an owner-scoped runtime usage lease, |
| 1588 | late usage enters the session cost pool without reopening the sealed |
| 1589 | mailbox, and worker/session/reload accounting share one hashed response |
| 1590 | identity so retried deliveries stay exactly-once. |
| 1591 | - Fixed the sub-agent fiasco class: in-workspace absolute `git -C` no longer |
| 1592 | trips the read-only child shell gate with a coherent bounded gate (#5595), |
| 1593 | turn end parks turn-owned children resumably instead of silently cancelling |
| 1594 | them (#5596), stale write-claims are released by liveness with coordinate |
| 1595 | release (#5562), and the verifier role description matches its real |
| 1596 | surface (#5562). |
| 1597 | - Fixed workflow responseSchema failure handling (#5583): bounded repair with |
| 1598 | typed receipts (kind + attempt), raw-output receipts persisted as artifacts |
| 1599 | that survive reload, and failures surfaced instead of null success (#5528). |
| 1600 | Degraded owner snapshots no longer project as ordinary Completed runs |
| 1601 | (#5582), typed task error kinds enable fail-fast parallel/pipeline (R9), and |
| 1602 | `/workflow confirm` finds the draft despite interleaved messages. |
| 1603 | - Fixed the DeepSeek session that never auto-compacted at 842k/1M (#5577): the |
| 1604 | exact `billed_842k_on_a_1m_window_compacts_despite_a_small_estimate` |
| 1605 | regression pins the trigger. |
| 1606 | - Fixed sandbox escapes and authority gaps: workspace-write tools resolve |
| 1607 | hard-linked files before writing (S2, #5569), an opt-in read deny-list |
| 1608 | bounds full-disk reads in any posture (S1, #5568), and session grants match |
| 1609 | the command family instead of widening the whole tool (R2). |
| 1610 | - Fixed provider-transport robustness: non-streaming HTTP requests are bounded |
| 1611 | by a read timeout (R4), and Chat-Completions mid-stream error frames surface |
| 1612 | instead of hanging (R3). MCP OAuth expiry now reacts to 401/403 with a named |
| 1613 | recovery path and login hint instead of looking like a broken server (T4, |
| 1614 | #5572). |
| 1615 | - Fixed Fleet lifecycle gaps: detached workers are reaped when their manager |
| 1616 | dies (R7) and the per-task wall-clock timeout is enforced (R5); the local |
| 1617 | Fleet host compiles on non-Unix targets; detached schema repair stays within |
| 1618 | the runtime budget. |
| 1619 | - Fixed prompt-cache correctness: the tool catalog is fingerprinted in |
| 1620 | provider wire order (C1), prefix changes between requests are always |
| 1621 | declared (C5) — including the newly named mid-turn `change:tool_surface` |
| 1622 | reasons for deferred-tool admission, tool-search activation, and runtime MCP |
| 1623 | tool arrival — and a reasoning-only response stopped at the output limit now |
| 1624 | fails the turn honestly instead of re-issuing a request that can only |
| 1625 | reproduce the stop. |
| 1626 | - Fixed docs/public-surface drift: REBRAND.md no longer presents |
| 1627 | `api.deepseeki.com` as a China fallback (#5564), and the web facts/tool |
| 1628 | counts match the repository. |
| 1629 | |
| 1630 | - Heavy pull requests now run the real Linux workspace nextest, doctest, and |
| 1631 | lockfile lanes directly on GitHub Actions instead of reporting a green |
| 1632 | placeholder while waiting for a branch-specific CNB mirror (#5547). |
| 1633 | - Fleet roster members in a selected Fleet now expose a visible edit affordance |
| 1634 | and a direct `m` model-picker shortcut, while the coordinator row remains |
| 1635 | read-only (#5604, covers #5589). |
| 1636 | - The context inspector now attributes bounded tool-schema cost to the built-in |
| 1637 | catalog and each discovered MCP server without changing prompt assembly or |
| 1638 | cache behavior (#5553). |
| 1639 | - The goal-continuation quiet period (`[goal] continuation_delay_seconds`, |
| 1640 | added in #5508) now applies on every dispatch path. Previously the |
| 1641 | within-turn dispatch hook fired the next continuation prompt immediately |
| 1642 | whenever a model step ended with the goal still active, so CLI-resumed and |
| 1643 | host-managed sessions never observed the configured delay (measured |
| 1644 | end-to-start gaps of ~9 s with a 300 s delay configured). The wait now |
| 1645 | runs unconditionally inside `goal_continuation_message_if_needed`, |
| 1646 | remains cancellable, and pause/clear/terminal `update_goal` calls still |
| 1647 | cancel a pending pass (#5534). |
| 1648 | - Two unit tests no longer depend on process-global environment state that |
| 1649 | sibling tests mutate concurrently. |
| 1650 | `route_budget::tests::v4_trigger_uses_window_percent_when_it_fits_spendable_input` |
| 1651 | asserted no-override output-budget values while reading |
| 1652 | `CODEWHALE_MAX_OUTPUT_TOKENS` / `DEEPSEEK_MAX_OUTPUT_TOKENS` without |
| 1653 | holding `lock_test_env()`, so a concurrent writer could flip the value |
| 1654 | mid-assertion (the order-dependent full-suite flake). |
| 1655 | `prompts::tests::system_prompt_prefix_never_leaks_private_content` read the |
| 1656 | real home via `HOME`/`USERPROFILE`, so a machine with |
| 1657 | `~/.codewhale/instructions.md` leaked its absolute path into the prompt and |
| 1658 | failed the no-private-paths assertion unless a sibling's temporary `HOME` |
| 1659 | guard happened to be live. Both tests now hold the env barrier and pin the |
| 1660 | variables (the route-budget test removes the overrides; the prompts test |
| 1661 | points `HOME`/`USERPROFILE` at a scratch dir). Assertions unchanged. |
| 1662 | |
| 1663 | - TUI sessions now apply a subtle OSC 12 cursor accent only on explicitly |
| 1664 | supported terminals and restore the terminal default through normal, panic, |
| 1665 | and signal cleanup paths (#5554). |
| 1666 | |
| 1667 | ## [0.9.11] - 2026-08-22 |
| 1668 | |
| 1669 | Codewhale v0.9.11 tightens the long-running agent loop, makes workflow |
| 1670 | failures visible instead of successful-looking, adds an experimental |
| 1671 | vision-capable DeepSeek route, and prepares reproducible Codewhale-versus-Pi |
| 1672 | evaluation without publishing a result before a real run. The complete |
| 1673 | item-level change record is retained below the categorized release highlights. |
| 1674 | |
| 1675 | ### Added |
| 1676 | |
| 1677 | - Added first-party `deepseek-v4-flash-vision-exp` discovery and selection for |
| 1678 | DeepSeek, including the `flash-vision` alias, bundled offline metadata, |
| 1679 | registry and picker entries, and image-input capability on the chat route. |
| 1680 | Context and output limits inherit from V4 Flash until DeepSeek publishes |
| 1681 | distinct values; pricing remains unknown rather than guessed. |
| 1682 | - Added a provider-controlled Codewhale-versus-Pi parity harness with three |
| 1683 | hermetic coding tasks, route and reasoning-effort receipts, doctor/dry-run |
| 1684 | modes, and bounded result artifacts. The repository ships the harness, not a |
| 1685 | benchmark verdict; comparable real runs remain an acceptance gate. |
| 1686 | - Added portable, secret-free config export/import with a reviewable plan, |
| 1687 | explicit headless consent, backup and rollback, and idempotent re-import. |
| 1688 | - Added bounded multi-file diagnostics through the existing model-facing `lsp` |
| 1689 | tool without increasing the tool-catalog count. Thanks to **Isabel Wu |
| 1690 | ([@wuisabel-gif](https://github.com/wuisabel-gif))** for PR #5524. |
| 1691 | - Added portable presentation, media-attachment, and operation-digest facets to |
| 1692 | the command contract, then moved all seven utility handlers onto the |
| 1693 | contract-backed dispatch path. Thanks to **Paulo Aboim Pinto |
| 1694 | ([@aboimpinto](https://github.com/aboimpinto))** for PR #5525. |
| 1695 | |
| 1696 | ### Changed |
| 1697 | |
| 1698 | - Sub-agent, Fleet-worker, workflow-task, and thread-runtime model turns no |
| 1699 | longer inherit a hidden role-based step ceiling. An omitted or zero |
| 1700 | `max_steps` is unbounded; a positive user/config value remains an explicit |
| 1701 | cap and is still clamped to the runtime safety ceiling. Wall-clock, provider, |
| 1702 | heartbeat, cancellation, and admission safeguards are unchanged. |
| 1703 | - `/rc` now mirrors one shared session rather than transferring terminal |
| 1704 | ownership: local and web prompts remain available while idle, approvals use |
| 1705 | first-decision-wins semantics, and transport/integrity failures remain |
| 1706 | fail-closed. |
| 1707 | - The terminal status rows around the composer are now two stable bands: |
| 1708 | `provider · model · thinking level` is the persistent identity row below |
| 1709 | the composer in every phase, and a separate activity row above the |
| 1710 | composer carries the live phase, notices, and cost/metrics. Sending a |
| 1711 | prompt no longer relocates the route identity above the composer, and |
| 1712 | neither row ever duplicates it. |
| 1713 | - The embedded local Web client now uses the current CWC Ocean hierarchy and |
| 1714 | readable control sizing, follows the shared Enter/Shift+Enter composer |
| 1715 | grammar, and chooses a provider plus model per new thread without mutating |
| 1716 | Runtime defaults. Exact image-input capability is labelled honestly; a |
| 1717 | vision-capable route does not imply that browser attachments exist. |
| 1718 | - The runtime now has one authoritative model-turn loop. The placeholder |
| 1719 | `crates/core` engine tree is gone, while the active TUI loop and its extracted |
| 1720 | tool-call stages retain existing policy, hook, cancellation, and budget |
| 1721 | behavior. Thanks to **Sun Zhenyuan |
| 1722 | ([@bistack](https://github.com/bistack))** for PR #5523. |
| 1723 | |
| 1724 | ### Fixed |
| 1725 | |
| 1726 | - Chat Completions streams now require terminal proof from `[DONE]` or a |
| 1727 | non-empty `finish_reason`. Protocol-only frames no longer count as answer |
| 1728 | content or time-to-first-token, and a provider continuation that ends after |
| 1729 | tool results with no answer or tool call fails durably instead of producing |
| 1730 | a false `Completed` receipt. |
| 1731 | - A selected v2 Fleet now drives one bounded, deterministic Agent roster across |
| 1732 | terminal and runtime surfaces. Fleet operator/member/explicit-route |
| 1733 | precedence, resolved member identity, and exact `vision` requirement |
| 1734 | admission now fail visibly instead of silently falling back, first-matching, |
| 1735 | or rerouting. |
| 1736 | - A workflow whose `task()` dispatch was rejected no longer loses that failure |
| 1737 | inside a `parallel()` null slot or presents a successful-looking run. Rejected |
| 1738 | dispatches now fail the run, persist as typed bounded receipts with an exact |
| 1739 | count, and appear in transcript, activity detail, and workflow-panel views. |
| 1740 | - Provider readiness, credential-source explanations, focused-agent scrolling, |
| 1741 | compact `/status` and `/help` rendering, shell/web output bounds, MCP |
| 1742 | lifecycle reporting, and narrow-terminal onboarding received the detailed |
| 1743 | fixes recorded below. |
| 1744 | - Portable config import/export now preserves typed tables, arrays, numbers, |
| 1745 | booleans, and datetimes without stringifying them, while refusing |
| 1746 | machine-bound trust overlays, credential readers, automatically executable |
| 1747 | hooks/LSP definitions, local-path authority, machine-local network proxy |
| 1748 | routes, cookies, redaction placeholders, and nested or camel/dotted |
| 1749 | credential keys. Project and global bundle operations now load and validate |
| 1750 | the document for their actual scope in both directions, including a |
| 1751 | workspace whose document still lives under the legacy app directory. |
| 1752 | - `codewhale login` now means Codewhale account sign-in (the same browser |
| 1753 | device flow as `codewhale account login`, with `--no-open` and |
| 1754 | `--timeout-seconds`); provider API keys are configured exclusively through |
| 1755 | `codewhale auth set --provider <provider>`, and the hidden legacy |
| 1756 | `--api-key`/`--provider` flags redirect loudly instead of silently writing |
| 1757 | a key. |
| 1758 | - Account sessions prefer the OS credential manager and now fall back |
| 1759 | automatically to the private `0600` Codewhale secrets file on headless |
| 1760 | hosts, SSH boxes, and containers; the `CODEWHALE_CLOUD_ALLOW_FILE_SESSION_STORE` |
| 1761 | opt-in is deprecated and ignored. |
| 1762 | - `/update` gained a `Ctrl+Shift+U` install chord (catalogued in |
| 1763 | `docs/KEYBINDINGS.md`, localized in all 15 packs) and a startup hint that |
| 1764 | names the previous and current version on the first launch of a newer |
| 1765 | build, pointing at `/change`. |
| 1766 | - Fleet product-model copy pass: the TUI, docs, and locale packs now use |
| 1767 | Fleet / Member / Role / Model / Access / Saved consistently so a user can |
| 1768 | say "scout", "DeepSeek V4 Flash", or the member name and mean the same |
| 1769 | thing. |
| 1770 | - A reasoning model that returns only hidden reasoning and a clean stop (no |
| 1771 | answer, no tool call) is now re-requested automatically up to twice before |
| 1772 | the turn fails, instead of dead-ending with "the provider response was |
| 1773 | incomplete." The retry reuses the cached prefix so it is cheap; an |
| 1774 | output-length stop (`length`/`max_tokens`) is never retried, and a |
| 1775 | persistently answerless model still fails honestly after the bound. |
| 1776 | - Model-bound tool results now use a credential-shaped redaction policy: |
| 1777 | only values that look like secrets (known prefixes, JWTs, bearer tokens, |
| 1778 | PEM private-key blocks, long opaque strings) are masked before a `read` or |
| 1779 | shell result reaches the model, so code such as `password: |
| 1780 | credentials?.password` or `"password-validator": "^5.3.0"` stays byte-exact |
| 1781 | for edits and read-back. Exact configured credential values are still always |
| 1782 | replaced, and logs/previews/exports keep the broad key-based scrubber. (#5546, |
| 1783 | reported by @ronohara) |
| 1784 | - Terminal input shutdown no longer waits forever on a wedged TTY read, |
| 1785 | Windows launch receipts can atomically replace an existing record, and the |
| 1786 | complete `/status` report now follows the active locale without rewriting |
| 1787 | exact custom-provider identities that contain brace-like text. |
| 1788 | - Localized READMEs again match the English install and third-party-notice |
| 1789 | surface, including shell-completion guidance in all 18 translations. |
| 1790 | |
| 1791 | ### Security |
| 1792 | |
| 1793 | - Unified OAuth device-code polling now validates verification URLs before |
| 1794 | opening them, redacts token-bearing types, honors server slowdown intervals, |
| 1795 | and keeps credential save/logout mutations serialized. |
| 1796 | - Project instructions, rules-directory traversal, secret-shaped config data, |
| 1797 | URL fingerprints, and shell network authority now retain the explicit bounds |
| 1798 | and fail-closed behavior described in the detailed record. |
| 1799 | |
| 1800 | ### Contributors |
| 1801 | |
| 1802 | - **Sun Zhenyuan ([@bistack](https://github.com/bistack))** — tool-call stage |
| 1803 | extraction with the existing execution and policy contracts preserved |
| 1804 | (#5523). |
| 1805 | - **Isabel Wu ([@wuisabel-gif](https://github.com/wuisabel-gif))** — bounded |
| 1806 | multi-file `read_lints` support (#5524), plus independently reviewed |
| 1807 | completion-routing overlap in #5530. |
| 1808 | - **Lstarsky0 ([@Lstarsky0](https://github.com/Lstarsky0))** — maintainer review |
| 1809 | hardening for truthful per-file states and truncation metadata in #5524. |
| 1810 | - **Paulo Aboim Pinto ([@aboimpinto](https://github.com/aboimpinto))** — portable |
| 1811 | presentation/media/digest facets and the seven utility-handler migrations |
| 1812 | (#5525). |
| 1813 | - **RepentStar ([@RepentStar](https://github.com/RepentStar))** — reported and |
| 1814 | reproduced the stale completion-generator path and missing `codew` |
| 1815 | registration fixed for #5526. |
| 1816 | |
| 1817 | ### Detailed change record |
| 1818 | |
| 1819 | The notes below are preserved in full so the categorized highlights do not |
| 1820 | erase behavior, migration, security, compatibility, or verification details. |
| 1821 | |
| 1822 | - Provider completion is now evidence-based. A Chat Completions stream reaches |
| 1823 | `MessageStop` only after `[DONE]` or a non-empty `finish_reason`; raw EOF |
| 1824 | without either is a typed failure. Message-start, ping, usage/terminal |
| 1825 | deltas, block-stop, and message-stop frames do not count as productive |
| 1826 | content or mint time-to-first-token. After tool results, a terminal provider |
| 1827 | step with no answer or tool call now emits a durable failed turn and never |
| 1828 | fabricates an empty assistant message. |
| 1829 | |
| 1830 | - A selected v2 Fleet is the single effective Agent roster across terminal, |
| 1831 | Runtime threads, direct Workflow, Fleet execution, doctor, and |
| 1832 | setup/readiness; legacy profile layers are consulted only when no Fleet is |
| 1833 | selected, and invalid selections fail visibly with bounded, redacted errors. |
| 1834 | Member references resolve exact id first and otherwise require a unique |
| 1835 | display name, role, pinned model, offline model name, or provider/model route; |
| 1836 | `agent action=roster` exposes that same bounded roster. The Fleet operator |
| 1837 | supplies fresh-root and inherited-member routing unless an explicit launch |
| 1838 | route or member pin wins, the resolved member is shown separately from the |
| 1839 | requested alias, and `requires = ["vision"]` is admitted only on an exact |
| 1840 | route with verified offline `image_input` support—never by silent rerouting |
| 1841 | or custom-proxy inference. Fleet selection remains an explicit user/folder |
| 1842 | contract independent of legacy project-profile loading. |
| 1843 | |
| 1844 | - **Breaking (app-server):** `/prompt`, `prompt/request` and `prompt/run` now |
| 1845 | execute a real model turn instead of reporting success for work they never |
| 1846 | did. `Runtime::handle_prompt` called no model: it resolved config, ran a |
| 1847 | local `ModelRegistry` lookup, emitted three canned hook events |
| 1848 | (`ResponseDelta` was literally the string `model-selected`), and returned |
| 1849 | HTTP 200 with `output` set to a stringified JSON echo of the caller's own |
| 1850 | routing metadata — the prompt included. Worse, when a `thread_id` was |
| 1851 | supplied it appended a real user row, flipped the thread to `Running`, and |
| 1852 | then wrote that echo into durable history as an **assistant message** plus a |
| 1853 | `prompt_response` checkpoint. Nothing marked the row synthetic and nothing |
| 1854 | ever moved the thread out of `Running`. All three endpoints now route |
| 1855 | through the same `RuntimeBridge` that stdio `thread/message` has always |
| 1856 | used, so `output` is the model's streamed text, `model` is what the runtime |
| 1857 | reports for the thread that ran the turn, and `events` are the real |
| 1858 | streaming frames. `Runtime::handle_prompt` and its synthetic history write |
| 1859 | are gone. |
| 1860 | |
| 1861 | - **Breaking (app-server):** a failed prompt is now a typed failure rather |
| 1862 | than a success-shaped body. `POST /prompt` returns |
| 1863 | `{"error":{"code":...,"message":...}}` with `400` (invalid request), `404` |
| 1864 | (thread not found), `503` (`runtime_unavailable`) or `500`, instead of HTTP |
| 1865 | 500 carrying a `PromptResponse` with the error text stuffed into `output` |
| 1866 | where model text belongs. The stdio surface gained JSON-RPC `-32005` |
| 1867 | `runtime_unavailable` for "the turn engine could not be reached, so nothing |
| 1868 | ran" — distinct from `-32603`, and retryable. There is no configuration in |
| 1869 | which a prompt silently echoes instead of running. |
| 1870 | |
| 1871 | - **Breaking (app-server):** `POST /thread` with a `Message` body runs the |
| 1872 | turn. It previously replied `status: "accepted"` with a |
| 1873 | `ResponseDelta("queued")` frame while starting no worker and calling no |
| 1874 | bridge — the stdio path for the same request has always done real work, so |
| 1875 | the two transports disagreed about what `accepted` meant. HTTP now replies |
| 1876 | `status: "completed"` once the turn reaches a terminal state, with the |
| 1877 | streamed frames in `events` and the turn id in `data`. `Runtime::handle_thread` |
| 1878 | no longer accepts `ThreadRequest::Message` at all: it owns thread |
| 1879 | bookkeeping, not the turn engine, and returns an error naming |
| 1880 | `POST /v1/threads/{id}/turns` rather than a canned acceptance. |
| 1881 | |
| 1882 | - **Breaking (app-server):** `AppRequest::SubmitUserInput` now refuses |
| 1883 | explicitly (`ok: false`, `error: "user_input_reply_unsupported"`) instead of |
| 1884 | returning `resolved: true` and filing the answers in a map that had no |
| 1885 | reader anywhere in the crate — every answer submitted was silently |
| 1886 | discarded. It cannot be made to work on this transport: while a turn |
| 1887 | streams, the stdio loop executes only `thread/interrupt` and queues |
| 1888 | everything else, so an answer sent there would wait on the very turn |
| 1889 | waiting for it. The refusal names the surface that does accept it, |
| 1890 | `POST /v1/user-input/{thread_id}/{request_id}` on the runtime API. The |
| 1891 | client-visible refusal is whitespace-clean, and the `/tool` path that mints |
| 1892 | the `UserInputRequest` is unchanged and still genuine. |
| 1893 | - Split the coordination ledger out of `tools/subagent/coord.rs` into |
| 1894 | `tools/subagent/coord/ledger.rs`. The file held two unrelated things: the |
| 1895 | model-facing `agents/*` tool wrappers, and the durable decision/claim/ |
| 1896 | contention records those wrappers happen to write — records whose consumers |
| 1897 | are mostly *not* in the tool layer (`tui::coordination_detail`, |
| 1898 | `tui::work_surface`, `tui::ui::tests`, `core::engine::tests` all name these |
| 1899 | types). At 3.8k lines, reading either one started by scrolling past the |
| 1900 | other. A pure move with a glob re-export from `coord`, so every |
| 1901 | `crate::tools::subagent::coord::{…}` path still resolves and no consumer file |
| 1902 | was edited; the only content change the move required is one constant going |
| 1903 | from private to `pub(super)` because its caller stayed behind. `coord.rs` is |
| 1904 | now 2.3k lines and `ledger.rs` 1.6k. |
| 1905 | |
| 1906 | - `agent` is now the only sub-agent tool the model can see. `AGENTS.md` has |
| 1907 | said "the model-facing sub-agent surface is `agent` only" since the lifecycle |
| 1908 | tools were removed, but six more were reachable: `agents/list`, |
| 1909 | `agents/message`, `agents/followup`, `agents/interrupt`, `agents/coordinate`, |
| 1910 | and `agents/wait` all defaulted to model-visible, so they shipped in the |
| 1911 | catalog and `tool_search` could load any of them — and the `agent` |
| 1912 | description told the model they existed. They now declare |
| 1913 | `model_visible() -> false`, the same shape `rlm` and `exec_shell` use: still |
| 1914 | registered, still executable by name so a persisted transcript replays |
| 1915 | against the same implementation, never advertised and never returned by |
| 1916 | either `tool_search` matcher. |
| 1917 | |
| 1918 | Five of the six were already duplicates of an `agent` action. The sixth was |
| 1919 | not: `agents/coordinate action=claim` was the *only* way to widen a write |
| 1920 | claim, and write enforcement fails closed, so hiding it would have left a |
| 1921 | refusal ("expand it first with…") pointing at a tool the model could no |
| 1922 | longer call. `agent` gains one action, `claim`, taking the write scope |
| 1923 | vocabulary `action=start` already uses (`write_roots`, plus parse-accepted |
| 1924 | `exact_files` and `coordination_contracts`). It keeps `agents/coordinate`'s |
| 1925 | `Auto` approval — gating it deadlocks autonomous fan-in — and it can only |
| 1926 | widen the caller's own scope; peer contention still fails. A scopeless claim |
| 1927 | is refused rather than reported as granted, because `expand_write_claim` |
| 1928 | returns the unchanged claim with `Ok` when every list is empty. |
| 1929 | |
| 1930 | Collapsing six tools into one action set also collapses the gating: `agent` |
| 1931 | is deliberately exempt from both name-keyed gates (`posture_permits_tool` |
| 1932 | short-circuits it so delegation depth governs spawning, and |
| 1933 | `execution_envelope` classifies it `Bounded` so a read-only member can fan |
| 1934 | out read-only work), so a capability folded into it inherits no gate. `claim` |
| 1935 | is therefore gated per action, reproducing the envelope check that kept |
| 1936 | `agents/coordinate` off a read-only role's catalog — in the catalog and again |
| 1937 | at dispatch, since catalog shaping is not an authority boundary. The other |
| 1938 | actions keep exactly the visibility they had. |
| 1939 | - One placement table now decides which wire channel a message role belongs |
| 1940 | in, and unrepresentable role/dialect pairs are refused at the outbound seam |
| 1941 | (`DeepSeekClient::prepare_outbound_request`) instead of at the provider. |
| 1942 | Chat Completions and OpenAI Responses used to drop an unfamiliar role |
| 1943 | silently, Anthropic Messages forwarded `message.role` verbatim and took an |
| 1944 | opaque provider 400 for it, and Google cloud-code was alone in failing |
| 1945 | closed. Positioned `system` and `developer` history — including compaction |
| 1946 | and branch summaries — is carried natively by Chat Completions and Responses |
| 1947 | and projected, in place, onto Anthropic's user channel. It is neither |
| 1948 | hoisted nor dropped. Genuinely unknown roles keep the previous |
| 1949 | dialect-specific fail-closed/omit behavior, now decided in one table. The |
| 1950 | dead `"tool"` arm in the Responses adapter is gone — nothing constructs that |
| 1951 | role. |
| 1952 | |
| 1953 | - Message roles are a closed `Role` enum (`crates/core/src/role.rs`) instead of |
| 1954 | a free-form `String` on `Message`. Four wire adapters each decided |
| 1955 | independently what an unfamiliar role meant, and a typo in a role string was |
| 1956 | a silent transcript edit rather than a compile error. `Role` keeps an |
| 1957 | `Unrecognized(String)` variant and serializes via `as_str()`, so a saved |
| 1958 | session's bytes are unchanged, a transcript written by a newer build still |
| 1959 | loads here, and `assistant_interrupted` stays a distinct session item — no |
| 1960 | session schema bump and no migration ladder. |
| 1961 | |
| 1962 | - Portable config bundles: `codewhale config export --portable` writes a |
| 1963 | deterministic, secret-free bundle (credential and machine-specific keys |
| 1964 | dropped), and `codewhale config import <FILE|URL|->` applies one with a |
| 1965 | strict versioned envelope, a printed added/changed/skipped/conflicting/ |
| 1966 | rejected plan, consent gating (`--yes` required headless), a timestamped |
| 1967 | backup with rollback, and idempotent re-import. Credential-shaped entries |
| 1968 | are rejected by key name and value shape — rejections name the field, |
| 1969 | never the value. Remote imports revalidate the HTTPS-or-loopback-HTTP policy |
| 1970 | on every same-scheme redirect hop, and duplicate keys across applicable |
| 1971 | section labels fail before any backup or write instead of silently resolving |
| 1972 | by section order. Structured TOML values round-trip with their original |
| 1973 | types and exact named-provider identity; recursive sanitization covers |
| 1974 | arrays/tables and camel-case, dotted, cookie, and access-key spellings while |
| 1975 | retaining ordinary token-count metrics. Machine-bound project trust, |
| 1976 | credential-source consent, automatic hook/LSP execution, and local-path |
| 1977 | authority are non-portable and fail before mutation. A missing target is |
| 1978 | created transactionally and removed again on rollback, and project/global |
| 1979 | scope validation rejects the wrong document before import or export. |
| 1980 | Imported tables deep-merge portable fields into the target, so omitted |
| 1981 | machine-local provider credentials, endpoints, and executable definitions |
| 1982 | remain intact instead of being erased by a sanitized bundle. |
| 1983 | |
| 1984 | - `/rc` is now a shared-session mirror instead of a terminal takeover. |
| 1985 | Attaching the web app no longer locks the local composer or hides |
| 1986 | approvals: both surfaces can prompt while idle (one turn runs at a |
| 1987 | time), approval cards stay visible in the terminal and are shared with |
| 1988 | the web with first-decision-wins semantics (the losing side is told, a |
| 1989 | web decision dismisses the local card), and structured questions are |
| 1990 | answered locally instead of cancelled. Fail-closed behavior survives — |
| 1991 | the post-failure reconnect lockout, integrity-gated `/rc stop`, and the |
| 1992 | fail-closed shared-approval channel on transport loss are unchanged. |
| 1993 | The takeover vocabulary ("web owns prompts and approvals") is gone from |
| 1994 | every surface. |
| 1995 | |
| 1996 | - Auto-mode provider readiness no longer reports "key saved · not checked" |
| 1997 | forever. Readiness checks are recorded against the concrete model the |
| 1998 | router ran, but auto-mode reads resolved against the literal `auto` |
| 1999 | identity, which never matched any recorded check — so the setup receipt, |
| 2000 | model picker, and fleet setup view showed an eternal unchecked badge |
| 2001 | even after hundreds of successful turns. The read now falls back to the |
| 2002 | most recent check on the same route (provider + endpoint + auth class); |
| 2003 | concrete-model reads keep exact per-model scoping. |
| 2004 | |
| 2005 | - The focused sub-agent transcript now scrolls like the main transcript. |
| 2006 | The frame renderer sampled the ocean column through a `ChatWidget` whose |
| 2007 | constructor consumed `pending_scroll_delta` — every PageUp/PageDown and |
| 2008 | wheel event was swallowed by an invisible widget before the focused pane |
| 2009 | could read it. The delta is now parked across the sample; the pane pins |
| 2010 | on user scroll-up, follows new child activity at tail, and |
| 2011 | jump-to-bottom releases the pin. |
| 2012 | |
| 2013 | - Every Codex OAuth Responses request carried `max_output_tokens`, a parameter |
| 2014 | that endpoint rejects outright ("Unsupported parameter: max_output_tokens"), |
| 2015 | so every gpt-5.6-sol turn — including every sub-agent on that route — failed |
| 2016 | at the first request. Codex Responses bodies now ship without a client-side |
| 2017 | output cap; the backend applies its own. Every other Responses route keeps |
| 2018 | the central cap on the wire, exactly as before. |
| 2019 | |
| 2020 | - The model-facing `lsp` tool now supports a bounded `read_lints` operation |
| 2021 | for multi-file, workspace-relative LSP diagnostics without adding another |
| 2022 | tool catalog entry (#4070). |
| 2023 | |
| 2024 | - HTTP 400 classification no longer calls an unsupported-parameter error a |
| 2025 | context-window overflow. Responses shape errors such as "Unsupported |
| 2026 | parameter: max_output_tokens" name a token-shaped field, which the generic |
| 2027 | keyword rules read as prompt-size exhaustion and pointed users at compaction |
| 2028 | that could never help. Such responses now classify as invalid requests. |
| 2029 | |
| 2030 | - xAI device login validated nothing about the URL it opened. The |
| 2031 | `verification_uri` from the device-code response went straight to |
| 2032 | `webbrowser::open` with no parse, no scheme check and no credential check, so a |
| 2033 | spoofed or compromised issuer could hand the platform's "open this" call a |
| 2034 | `file:` path, a custom application scheme (`vscode://`, `slack://`), or a |
| 2035 | credential-bearing URL. The shared primitive now refuses anything that is not a |
| 2036 | web page before the URI is printed or opened. **Behaviour change:** a |
| 2037 | non-loopback plain-`http:` verification URI now aborts login where it |
| 2038 | previously opened; `http:` on a loopback host is still allowed, because local |
| 2039 | runtimes legitimately use it. |
| 2040 | - The xAI OAuth types no longer print bearer material through `Debug`. Five types |
| 2041 | holding tokens (`GrokAuthEntry`, `TokenResponse`, `DeviceCodeResponse`, |
| 2042 | `DeviceCodeGrant` and the poll outcome) either redact or no longer derive |
| 2043 | `Debug` at all, so a token has no printable path through a `{:?}` on any |
| 2044 | surrounding struct. The shared `DevicePollOutcome` derives nothing, which the |
| 2045 | compiler enforces. |
| 2046 | - **Behaviour change:** an `interval` of `0` from the authorization server now |
| 2047 | falls back to RFC 8628's five-second default rather than a one-second floor, |
| 2048 | in both the xAI and account device flows. |
| 2049 | |
| 2050 | - OAuth device-code login is now one implementation. xAI/Grok device login and |
| 2051 | Codewhale account login each carried their own hand-rolled RFC 8628 polling |
| 2052 | loop with nothing shared between them; both now call a single primitive |
| 2053 | (`codewhale-config`'s `device_code`), ported from pi. Three fixes come with |
| 2054 | it. `slow_down` now honours a server-supplied `interval` instead of always |
| 2055 | adding five seconds, which is what stops polling from running early forever |
| 2056 | under WSL and VM clock drift. Timing out after a `slow_down` now says so and |
| 2057 | names clock drift, rather than reading as a plain timeout. And the xAI |
| 2058 | verification URI is validated before it is handed to the browser opener — |
| 2059 | Codewhale previously opened whatever the device-code response said, so a |
| 2060 | spoofed or compromised issuer could point the platform "open this" call at a |
| 2061 | `file:` path or a custom application scheme. It must now be `https:`, or |
| 2062 | `http:` on a loopback host for self-hosted issuers. Stored credential files |
| 2063 | are unchanged and existing logins keep working. MCP OAuth is untouched: it |
| 2064 | delegates to `rmcp`/`oauth2` and was never hand-rolled. |
| 2065 | - Shell output truncation now stays inside its own budget. A truncated shell |
| 2066 | result keeps a 6 KB head, a 24 KB tail, and any high-signal lines rescued |
| 2067 | from the omitted middle — but that rescued block was bounded only by a line |
| 2068 | count. One rustc `error:` line carrying a long inferred type or a minified |
| 2069 | bundler frame is routinely hundreds of kilobytes, so a "30 KB" result could |
| 2070 | arrive at 430 KB with the omitted line pasted back in whole. Each rescued |
| 2071 | line is now clipped and the block has a 4 KiB ceiling; the signal survives, |
| 2072 | the payload does not. |
| 2073 | |
| 2074 | - Fetched web pages in non-Latin scripts no longer arrive half-read. Page text |
| 2075 | was reflowed against a column budget measured in bytes, so Cyrillic and Greek |
| 2076 | wrapped at roughly half the intended width and CJK at two thirds — and since |
| 2077 | the page view is delivered by line count, the surplus lines pushed real |
| 2078 | content off the end of the window. A Russian or Japanese URL returned a |
| 2079 | fraction of the text an English one did, for the same call. Wrapping now |
| 2080 | measures display width. |
| 2081 | |
| 2082 | - The `bash` tool no longer tells the model it has no default timeout when it |
| 2083 | does. An omitted timeout has always been bounded at 120 seconds and the |
| 2084 | command killed there, but the tool description and its `timeout` field both |
| 2085 | claimed otherwise — steering the model away from the one parameter that |
| 2086 | would have saved a longer build. Both now name the real bound. |
| 2087 | - MCP servers no longer restart because an unrelated setting was saved. The |
| 2088 | lazy config reload re-reads every watched source whenever one of their |
| 2089 | mtimes moves and keeps the live connections only when the content hash |
| 2090 | matches — but the hash was taken over `serde_json` bytes produced straight |
| 2091 | from the config's `HashMap`s, and two `HashMap`s with identical contents do |
| 2092 | not iterate in the same order. Any touch of any watched file therefore hashed |
| 2093 | differently, tore down every connection, and SIGTERMed and respawned every |
| 2094 | stdio child. Keys are now sorted before hashing. |
| 2095 | |
| 2096 | - An MCP server marked `required` now still tells you *why* it failed to start. |
| 2097 | `connect_all` appended a generic "required MCP server failed to initialize" |
| 2098 | entry after the real per-server error, and the snapshot folds those pairs into |
| 2099 | a map keyed by server name — so the contentless entry replaced the diagnosis |
| 2100 | and /mcp showed the marker instead of "No such file or directory". The marker |
| 2101 | is now only synthesized when nothing else reported a cause. |
| 2102 | |
| 2103 | - A crashed stdio MCP server is now rebuilt instead of being handed back dead. |
| 2104 | A failed transport *read* disconnected the connection; a failed *write* did |
| 2105 | not, so after the child exited the connection stayed `Ready`, the pool reused |
| 2106 | it on every later tool call, and /mcp kept listing the server as connected. |
| 2107 | |
| 2108 | - An MCP response carrying neither `result` nor `error` is now an error rather |
| 2109 | than an empty success. It previously reached the model as a successful tool |
| 2110 | call with a `null` payload, indistinguishable from a tool that did nothing. |
| 2111 | An explicit `"result": null` is still a valid empty success. |
| 2112 | - Stdio MCP server requests are answered while the client is idle instead of |
| 2113 | blocking behind the zero-capacity response rendezvous until an unrelated |
| 2114 | client call. `ping` receives its prompt empty result, unsupported methods |
| 2115 | receive JSON-RPC `-32601`, and the reader keeps only a weak stdin handle so |
| 2116 | dropping the client still delivers graceful EOF. |
| 2117 | - `base_url_fingerprint` is a persisted-key change for two input shapes. |
| 2118 | The digest is serde-serialized into `ProviderCatalogCache` and |
| 2119 | `LiveOffering`, pricing defect receipts, and |
| 2120 | `TurnRecord.routed_usage_source_ids` — it is not an in-memory-only cache |
| 2121 | label. Empty or whitespace-only values (and scheme-less query-only strings |
| 2122 | that strip to an empty authority) now hash the invalid-or-secret-bearing |
| 2123 | sentinel instead of SHA-256 of the empty string. Scheme-less URLs that |
| 2124 | contain `@` now strip `userinfo` before hashing, matching the |
| 2125 | scheme-bearing branch, so a typed `user:pass@host/v1` no longer embeds the |
| 2126 | password in a stored digest. `routed_usage_source_fingerprint` feeds |
| 2127 | arbitrary scheme-less source ids into the same function, so a turn |
| 2128 | rehydrated from an older build can fail to dedupe one routed-usage row. |
| 2129 | Recovery is a cache miss and a re-fetch, not corruption. Empty input was |
| 2130 | not restored to the old digest: an empty authority is not a usable |
| 2131 | endpoint, and mapping it to the same sentinel the scheme branch already |
| 2132 | uses for an empty host keeps invalid inputs from minting a unique cache |
| 2133 | scope. |
| 2134 | |
| 2135 | - Diagnostic lines that mention token *counts* are no longer swallowed by |
| 2136 | secret redaction. A stream error such as `max tokens = 8192 but budget = |
| 2137 | 4096` was matching the `token` hint as a substring of the English word |
| 2138 | `tokens`, and the spaced-assignment pass then dropped the rest of the |
| 2139 | line, leaving `max tokens = [redacted]`. Token counts are not credentials; |
| 2140 | the hint now matches a credential identifier (`token`, `api_token`) rather |
| 2141 | than an English word, so the numbers survive while `token = Bearer …` is |
| 2142 | still redacted. |
| 2143 | - Dashboard thread search no longer loads every thread's transcript to decide |
| 2144 | whether the row matches. `GET /v1/threads/summary?search=` walked the full |
| 2145 | thread list and called `get_thread_detail` on each row before matching, and |
| 2146 | that detail read is itself a whole-store walk of every turn JSON and every |
| 2147 | item JSON. A non-matching keystroke was therefore |
| 2148 | O(threads × (all_turns + all_items)) file reads — on the order of 10^8 JSON |
| 2149 | parses at a few thousand threads. Search now matches `id`, title, and model |
| 2150 | from the thread record (and, when the title is unset, the single latest-turn |
| 2151 | file that supplies the displayed title) and loads detail only for matches, so |
| 2152 | preview stays a display field rather than a search key. Session summary |
| 2153 | already refused to search last-message text for the same reason. |
| 2154 | |
| 2155 | - Silent `#[allow(dead_code)]` suppressions on the modules AGENTS.md warns |
| 2156 | auditors not to delete — prompt zones, context budget, the route seam — |
| 2157 | and on the next-largest holders (palette tokens, hotbar actions, core |
| 2158 | events) are now `#[expect(dead_code)]`, or gone where the lint was already |
| 2159 | stale. A suppression that stops matching the lint fails the `-Dwarnings` |
| 2160 | gate instead of sitting quiet. The same gate is recorded in |
| 2161 | `[workspace.lints]` so member crates inherit it from the manifest rather |
| 2162 | than only from CI `RUSTFLAGS`. |
| 2163 | - "missing key" now says where it looked. The provider picker reported |
| 2164 | credential readiness as the bare strings `missing key` / `key:not-set`, |
| 2165 | which named no source at all — so a home whose secret store held a working |
| 2166 | DeepSeek key could show `DeepSeek missing key` in the picker while a real |
| 2167 | turn from that same home completed, and nothing on screen said which layer |
| 2168 | disagreed. Every row now resolves through one sourced resolver and states |
| 2169 | the place its credential came from ("OPENROUTER_API_KEY", `secret store |
| 2170 | "deepseek"`, `[providers.x] api_key`, "xAI OAuth", a consented external CLI |
| 2171 | file); a row without a credential lists the places that were probed, in |
| 2172 | precedence order, and the command that fixes the first of them. Where a |
| 2173 | durable slot is deliberately *not* read — an inactive provider whose config |
| 2174 | table carries no api-key marker — the row says so rather than implying an |
| 2175 | empty slot. |
| 2176 | |
| 2177 | - Provider credential precedence is now stated once, in a doc comment beside |
| 2178 | the single resolver that enforces it, instead of being implied by a |
| 2179 | 150-line cascade of provider special cases. No precedence decision changed: |
| 2180 | `has_api_key_for` is now a wrapper over that resolver, and a test asserts |
| 2181 | the two agree for every provider. |
| 2182 | |
| 2183 | - Credential saves and logouts no longer interleave. Both took a snapshot of |
| 2184 | the durable slot, wrote it, mutated the config document, and rolled back on |
| 2185 | failure, with no lock held across the sequence — so a save racing a logout |
| 2186 | on the same slot could leave the secret store and the config file |
| 2187 | disagreeing. Both now hold that provider's credential write lock for the |
| 2188 | whole read-modify-write. |
| 2189 | |
| 2190 | Design ported from pi-mono (MIT, Copyright (c) 2025 Mario Zechner); see |
| 2191 | `docs/THIRD_PARTY_NOTICES.md`. |
| 2192 | |
| 2193 | - Enumerating stored credentials no longer fails closed on one bad slot. |
| 2194 | Listing used to propagate a backend read error, so a single unreadable |
| 2195 | secret-store entry made `/provider` and logout treat every other stored |
| 2196 | credential as missing. Enumeration now skips the unreadable slot and |
| 2197 | continues, matching the probe loop it replaced. |
| 2198 | |
| 2199 | - The first screen of first run no longer cuts its own headline. The welcome |
| 2200 | and ready titles, and the provider-step heading, were emitted as single |
| 2201 | unwrapped lines while the sentence beneath them wrapped, so at 40 columns |
| 2202 | German read "Codewhale arbeitet mit dir in diesem O", Russian lost its final |
| 2203 | stop, and Japanese lost "します。". Headings are prose and now wrap like it, |
| 2204 | in every shipped locale. |
| 2205 | |
| 2206 | - The workspace-trust screen no longer cuts its own question in half on a small |
| 2207 | terminal. The question, the prompt-injection risk hint, and the trust-effect |
| 2208 | hint were each pushed as one unwrapped line, so at 40 columns the screen read |
| 2209 | "Should Codewhale work with the instruc" — severed mid-word with nothing |
| 2210 | marking the cut, while the workspace path directly beneath it wrapped |
| 2211 | correctly. Asking someone to grant filesystem trust while the question itself |
| 2212 | is truncated is the worst place in the product for that to happen. All three |
| 2213 | now wrap through the same helper the rest of onboarding uses, which also |
| 2214 | means they wrap correctly in Japanese and Chinese. Verified across all |
| 2215 | fifteen shipped locales at 40, 60, 80 and 120 columns. |
| 2216 | - `codewhale completions <shell>` generated a script for the wrong program. |
| 2217 | The subcommand forwarded to the in-tree `codewhale-tui` binary, which |
| 2218 | rendered completions from *its own* clap tree under *its own* name, so the |
| 2219 | output ended in `complete -F _codewhale__tui ... codewhale-tui` (bash), |
| 2220 | `#compdef codewhale-tui` (zsh), and |
| 2221 | `Register-ArgumentCompleter -Native -CommandName 'codewhale-tui'` |
| 2222 | (PowerShell). Sourcing it registered nothing for `codewhale` or `codew` — |
| 2223 | the two commands current installers expose — so tab completion appeared to |
| 2224 | do nothing. The forwarded tree was also stale against the real CLI: it offered |
| 2225 | `pr`, `scorecard`, and `session-diagnostics`, which `codewhale` does not |
| 2226 | have, and omitted `run`, `rc`, `config`, `model`, `thread`, `lane`, |
| 2227 | `workflow`, `web`, `account`, `app-server`, `mcp-server`, `metrics`, |
| 2228 | `update`, `cloud`, `completion`, and `lane-log-proxy`, which it does. |
| 2229 | Completions are now rendered in-process from the CLI's own command tree, |
| 2230 | and `completions` is an alias of the existing |
| 2231 | `completion` subcommand rather than a second, divergent path. Regenerate any |
| 2232 | script you installed from an earlier release. Reported by **RepentStar** |
| 2233 | (#5526); part of the `deepseek-tui`-era identifier retirement in #5443. |
| 2234 | |
| 2235 | - Completion scripts now fire for the `codew` shorthand as well as |
| 2236 | `codewhale`. Releases publish `codew` as a byte-identical copy of the |
| 2237 | `codewhale` binary, so a script bound to only one of the two names was half |
| 2238 | installed for anyone who types the short one. Each shell gets its own |
| 2239 | idiomatic hook rather than a second copy of the script: bash re-binds the |
| 2240 | generated function, zsh widens the `#compdef` tag line to |
| 2241 | `#compdef codewhale codew`, fish adds `complete -c codew -w codewhale`, |
| 2242 | PowerShell registers `-CommandName 'codewhale','codew'`, and Elvish aliases |
| 2243 | the completer with |
| 2244 | `set edit:completion:arg-completer[codew] = $edit:completion:arg-completer[codewhale]`. |
| 2245 | |
| 2246 | - Documented shell completions. `docs/INSTALL.md` § 8 now gives the generate |
| 2247 | and install commands for bash, zsh, fish, PowerShell, and Elvish, with a |
| 2248 | note to regenerate after upgrading and to delete scripts produced by |
| 2249 | v0.9.10 or earlier. There was previously no completion documentation |
| 2250 | anywhere in the repository, which is how #5526 was reported as three |
| 2251 | problems instead of one. |
| 2252 | - `/status` was 31 rows. On an 80x24 terminal the transcript viewport is 18, so |
| 2253 | typing `/status` landed you on the *tail* of the report: the version, route, |
| 2254 | directory, mode and sandbox rows had already scrolled past, and what stayed on |
| 2255 | screen was five `not reported` rows and a `$0.0000`. The report is 18 rows on a |
| 2256 | fresh session — `Window override:` is present unless the value is already |
| 2257 | configured. That is the viewport's height, so once `/status` itself occupies a |
| 2258 | history cell the title row still scrolls off; it does not fit that terminal |
| 2259 | whole. Provider, model and reasoning effort are one `Route:` lockup, the way |
| 2260 | the header rail already writes them. Mode and its permissions are one statement |
| 2261 | of posture. `Rate limits:` is gone — it was a `push_row` of a string literal |
| 2262 | and could never say anything but "not available from provider telemetry". The |
| 2263 | per-turn token ledger is gone too, because `/tokens` is that ledger's whole |
| 2264 | subject and `/status` was printing six rows of it at the same weight as the |
| 2265 | sandbox policy; the two facts that lived nowhere else, the cumulative in/out |
| 2266 | split and the cumulative cache totals, survive on one `Session tokens:` row. |
| 2267 | `Footer items:` no longer prints ten internal config keys across the full |
| 2268 | width — `/statusline` owns them, and the report now points there in the same |
| 2269 | row that points at `/tokens`. Two blank gutters do the grouping; the |
| 2270 | `===================` rule under the title is gone. |
| 2271 | |
| 2272 | - The `/status` window-override key has its own labelled row. It used to be |
| 2273 | parenthesised onto the end of the provenance row, which pushed |
| 2274 | `context_window in config.toml` past the right edge at 80 columns and wrapped |
| 2275 | the sentence. `Window source:` states the provenance and `Window override:` |
| 2276 | names the exact key — and the override row is omitted entirely when the value |
| 2277 | is already configured, rather than advising you to set what you have set. |
| 2278 | |
| 2279 | - `/help` no longer truncates anything. Every label and description used to run |
| 2280 | through a `truncate_to_width` that appended `…`, which in a two-hundred-row |
| 2281 | list promises text no keystroke can reveal and lands mid-token: |
| 2282 | `(aliases: /qin…` left the parenthesis hanging open. Descriptions now shed |
| 2283 | whole fields — the alias parenthetical first, then trailing clauses at their |
| 2284 | own joints, and only where there is no joint at all, the sentence's short form |
| 2285 | on a whole word with no mark, keeping the head noun of a simple verb + |
| 2286 | modifier + noun phrase rather than the adjectives that qualified it. The |
| 2287 | focused row's description is restated under the filter at the panel's full |
| 2288 | width, *only when the row itself could not hold it*, so a wide terminal does |
| 2289 | not say the same sentence twice. At 60 columns that restatement is itself |
| 2290 | shed — the `/advisor` detail stops before `session` — so the detail is longer |
| 2291 | than the row, not a copy of the original sentence. |
| 2292 | |
| 2293 | - The `/help` label column is measured instead of assumed. It was a flat 28 |
| 2294 | columns at every terminal size, so at 60 columns twenty blank cells sat |
| 2295 | between `/advisor` and a description cut down to 21. Each group now sizes its |
| 2296 | column to the labels it actually holds, which nearly doubles the description |
| 2297 | column on a narrow terminal, and the label — the string you have to type — |
| 2298 | reads one step brighter than the description that qualifies it. |
| 2299 | |
| 2300 | - `/help` stopped spending rows on itself. The match count moved onto the filter |
| 2301 | row it describes, the blank spacer under it is gone, and the footer no longer |
| 2302 | repeats `type to filter` while the filter box says `Type to filter` two lines |
| 2303 | above — at 60 columns that duplicate was what pushed the footer onto a second |
| 2304 | row. A group header also stopped printing `▸ ▾`: the selection cursor and the |
| 2305 | collapsed chevron are the same glyph, and a focused collapsed group was |
| 2306 | showing it twice for two different facts. Help now opens focused on the first |
| 2307 | entry rather than the header above it. |
| 2308 | |
| 2309 | - The bottom status rail is no longer one run-on sentence. At 120 columns it |
| 2310 | read `▌· idle · Ollama · deepseek-v4-flash · max · Anonymous usage counts are |
| 2311 | on. … ⌥V:output · /context:context · fn+F1:keys` — live state, route |
| 2312 | identity, a telemetry consent notice, and keyboard hints all strung together |
| 2313 | by the same middle dot in the same ink, so nothing was grouped and the eye |
| 2314 | had nothing to skim by. At 80 columns it simply stopped mid-notice, and at 60 |
| 2315 | the row overflowed and was clipped by the terminal mid-word. The rail now |
| 2316 | divides its groups with a blank gutter instead of another dot (the dot is |
| 2317 | kept for peers *inside* a group), the model name reads one step brighter than |
| 2318 | the qualifiers that narrow it, and `Esc to interrupt` reads in the same hint |
| 2319 | weight as the right-hand chords rather than in the separator weight. |
| 2320 | |
| 2321 | - Nothing on the status rail is ever truncated now. A notice sheds whole |
| 2322 | sentences to fit, and if one sentence is still too long it sheds at the inner |
| 2323 | joints — a colon, a semicolon — with the trailing mark cut so the phrase that |
| 2324 | survives does not itself advertise that more was coming. Route identity sheds |
| 2325 | the provider, then the reasoning effort, rather than rendering |
| 2326 | `deepseek-v4-flash-prev…`; a clipped model name is worse than no model name |
| 2327 | because routes share prefixes. Clauses rejoin without a Latin space after a |
| 2328 | full-width stop, so the Japanese receipt reads as Japanese. |
| 2329 | |
| 2330 | - A notice now stands the standing facts down instead of queueing behind them. |
| 2331 | Route identity and the ledger chips are still there in ten seconds; the |
| 2332 | notice is not, so it takes the row and the key hints yield last. This is what |
| 2333 | makes the telemetry receipt readable at 80 columns, where it used to be |
| 2334 | simultaneously always present and never legible. |
| 2335 | |
| 2336 | - The status rail no longer advertises `/context:context`. It was spending |
| 2337 | eighteen columns of a 24-row screen to name a slash command that announces |
| 2338 | itself the moment you type `/`; the rail advertises chords you cannot |
| 2339 | discover any other way. The rail now reads the same at 80 columns as at 200. |
| 2340 | |
| 2341 | - The idle screen no longer has an absolute path stretched across it. The |
| 2342 | workspace caption between the wordmark and "What do you want to accomplish?" |
| 2343 | was composed at full length and then truncated to the lane width, which made |
| 2344 | the centering inset `(width - caption.width()) / 2` evaluate to zero — so a |
| 2345 | line that was written to be centered rendered flush-left and full-bleed, |
| 2346 | cutting the centered whale/wordmark/prompt composition in half. The clipping |
| 2347 | also destroyed the information it was supposed to carry: at 80 columns the |
| 2348 | line read `/private/tmp/claude-501/-Volumes-.../34267917-11f4-4d15-911a-…`, |
| 2349 | which tells the reader nothing about where they are. The caption now sheds |
| 2350 | detail instead of being cut — MCP count first, then branch, then leading path |
| 2351 | components — so it always fits with room to center, and the folder you are |
| 2352 | standing in is the last thing to go. Elisions land on a path separator rather |
| 2353 | than mid-directory. |
| 2354 | |
| 2355 | - Removed the placeholder engine tree in `crates/core/src/engine/`. Its |
| 2356 | `Engine::run` accepted `Op::SendMessage`, appended to a journal, and emitted |
| 2357 | `TurnComplete { status: "completed" }` without ever contacting a model, and |
| 2358 | `TurnExecutor` was a struct with a field-copy constructor and a |
| 2359 | `step < max_steps` comparison. Nothing in the workspace referenced any of it — |
| 2360 | the only mention of `codewhale_core::engine` anywhere was a doc comment inside |
| 2361 | the tree itself — but its comments ("the real turn loop is wired here in the |
| 2362 | next slice") were what `docs/ARCHITECTURE.md` leaned on to claim that |
| 2363 | `crates/core` owns the agent loop. There is now exactly one turn loop in the |
| 2364 | workspace, `Engine::run_turn`, and a guard test fails if a second one appears. |
| 2365 | `docs/ARCHITECTURE.md` and `AGENTS.md` now say where it actually lives. |
| 2366 | |
| 2367 | - First-run onboarding no longer silently truncates its explanation in |
| 2368 | languages that do not put spaces between words. `wrap_words` split on |
| 2369 | whitespace, so a Japanese sentence arrived as a single token, the |
| 2370 | line-break check (which only fires once a line is non-empty) never |
| 2371 | triggered, and the over-wide line was clipped by the terminal. At 80 |
| 2372 | columns the provider screen read |
| 2373 | "Hosted providers need a key, but loca" and stopped — losing exactly the |
| 2374 | half that tells the reader local runtimes need no key, on the screen where |
| 2375 | they choose a provider. Space-less scripts now break by display width on |
| 2376 | grapheme clusters, and a line may not begin with closing punctuation |
| 2377 | (`。`, `、`, `」`, `)` and friends). Wrapping for languages that do use |
| 2378 | spaces is unchanged. |
| 2379 | |
| 2380 | - Project instructions are bounded by one budget and no longer treat other |
| 2381 | agents' files as law by default. Previously `.claude/instructions.md` and |
| 2382 | `CLAUDE.md` sat at ranks 2 and 3 of the canonical instruction list — *above* |
| 2383 | Codewhale's own `.codewhale/instructions.md` — `.claude/rules/` was an |
| 2384 | auto-discovered rules directory, and `.cursorrules`, `.cursor/rules`, |
| 2385 | `.clinerules`, `.windsurf/rules`, `.gemini`, `.github/copilot-instructions.md` |
| 2386 | and `.github/muse-instructions.md` were all imported into the system prompt |
| 2387 | with no opt-in. Dropping a `CLAUDE.md` written for a different tool into a |
| 2388 | repository silently made it standing authority here, which is an injection |
| 2389 | surface rather than a convenience. Codewhale now reads `AGENTS.md`, the |
| 2390 | cross-agent `.agents/AGENTS.md`, and its own instruction files by default; |
| 2391 | every other agent's format is opt-in by name through |
| 2392 | `project_instruction_imports` (env `CODEWHALE_PROJECT_INSTRUCTION_IMPORTS`), |
| 2393 | imported files rank *below* Codewhale's own, and a workspace that contains an |
| 2394 | un-imported format says so in a warning naming the exact setting. |
| 2395 | - Separately, a symlinked candidate rules directory — `.cursor/rules`, |
| 2396 | `.windsurf/rules`, or `.gemini` pointing outside the workspace — was |
| 2397 | traversed and its contents imported as instruction authority, because the |
| 2398 | directory check followed the link while only the files inside it were |
| 2399 | checked. The two instruction loaders now apply the same no-follow rule that |
| 2400 | `.codewhale/rules/` already had. |
| 2401 | - The three separate ceilings on standing instructions (200 KiB for the |
| 2402 | root->workspace chain, 500 KiB for the rules block, 40 KiB for imported |
| 2403 | fragments, and a global layer that was merged in after the chain budget had |
| 2404 | already closed and so counted against nothing) are replaced by a single |
| 2405 | 48 KiB aggregate budget covering all of them together. Instructions claim it |
| 2406 | before rules, and are trimmed from the broadest scope inward so the |
| 2407 | nearest-scope file is the last thing dropped rather than the first thing |
| 2408 | stranded. Truncation still leaves an explicit marker. |
| 2409 | |
| 2410 | - Editing the workspace no longer grants the shell outbound network access. |
| 2411 | `workspace-write` sandboxes are created network-restricted; `curl`, package |
| 2412 | installs, and `git fetch` inside a sandboxed shell are denied by the OS |
| 2413 | sandbox unless network is granted explicitly. This closes a real gap rather |
| 2414 | than tightening a working boundary: the elevation added in #273 was justified |
| 2415 | by the application-level `NetworkPolicy` remaining "the only outbound |
| 2416 | boundary", but that policy governs `fetch_url`, `web_search`, and MCP HTTP |
| 2417 | and never constrained shell subprocesses, so workspace-write turns had |
| 2418 | unrestricted egress with nothing enforcing anything. Network now comes from |
| 2419 | one of three explicit places: the new `sandbox_network_access` config key |
| 2420 | (also `CODEWHALE_SANDBOX_NETWORK_ACCESS`), a `danger-full-access` posture, or |
| 2421 | the existing post-denial elevation prompt that grants network for a single |
| 2422 | call. Yolo and `--yolo`/Bypass are unchanged — they resolve to |
| 2423 | `danger-full-access`, which applies no sandbox at all. `external-sandbox` |
| 2424 | reports the network it was actually granted instead of hardcoding `true`, and |
| 2425 | `/status` reads the flag instead of printing "network on" for every |
| 2426 | workspace-write policy. Platforms with no sandbox backend (default Linux |
| 2427 | without bubblewrap, and Windows) still enforce nothing, and both `/status` |
| 2428 | and `doctor` continue to say so. |
| 2429 | |
| 2430 | - The nightly Windows ARM64 artifact build works again. Every nightly from |
| 2431 | 2026-08-16 failed while compiling `codewhale-tui`, deterministically on the |
| 2432 | same codegen unit across all three build attempts, with |
| 2433 | `thread 'optimize module codewhale_tui...-cgu.13' has overflowed its stack`. |
| 2434 | The trigger is stack depth in the LLVM worker threads that run per-codegen-unit |
| 2435 | optimization, not the workflow's `lto=off` override: holding the crate and |
| 2436 | every flag fixed and varying only `RUST_MIN_STACK` on aarch64 shows 1 MiB |
| 2437 | crashes rustc while 2 MiB and 4 MiB succeed. Unix std defaults to 2 MiB and |
| 2438 | passed; the Windows ARM64 runner sat under the requirement. Nightly now sets |
| 2439 | `RUST_MIN_STACK` explicitly for every target, because the requirement follows |
| 2440 | from the size of `crates/tui` rather than from the platform. The redundant |
| 2441 | `codegen-units` override is gone -- `[profile.release]` already sets 16, so |
| 2442 | restating it never changed anything. Shipped binaries were never affected; |
| 2443 | `release-artifacts.yml` builds `--profile dist` with fat LTO and |
| 2444 | `codegen-units = 1`. |
| 2445 | |
| 2446 | - Test debt: the transcript history-cell suite has been rebuilt. It was 123 |
| 2447 | tests across 3,964 lines, and about a third of it pinned the current skin |
| 2448 | rather than any behavior -- `assert_eq!(spans[1], "⣤")` for the |
| 2449 | reduced-motion marker, `title_span.style.fg == theme.tool_title_color`, |
| 2450 | `visible[1] == "▏ done: scan repo"`, four separate tests each asserting one |
| 2451 | shape of fenced code never takes the transcript rail, and one test whose |
| 2452 | only assertion was `!text.is_empty()` under a name promising it checked the |
| 2453 | rendered tool id. Assertions like those break on every legitimate visual |
| 2454 | change and catch nothing a reader of the transcript would notice, which is |
| 2455 | the liability `d64b9429b` named. The replacement is 40 tests, each named |
| 2456 | for the property it protects and asserting the property instead of the |
| 2457 | token: reduced motion is checked by rendering the same running card at two |
| 2458 | different elapsed times and requiring the frames to match -- which also |
| 2459 | catches an animation leak the glyph constant missed -- and a frozen marker |
| 2460 | must stay visible rather than landing on the spinner's invisible blank |
| 2461 | (U+2800). Severity colors are checked by requiring warning not to read as |
| 2462 | error rather than by naming a palette entry. A streaming assistant glyph |
| 2463 | must actually pulse when motion is allowed, checked against |
| 2464 | `pulse_brightness` rather than by sleeping on the 2s sine. Each of the |
| 2465 | invariants claimed was verified to fail the new suite when deliberately |
| 2466 | broken in the renderer. |
| 2467 | ## [0.9.10] - 2026-08-19 |
| 2468 | |
| 2469 | - 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/Hmbown/CodeWhale/issues/998). Thanks [@AiurArtanis](https://github.com/AiurArtanis) and [@formp3](https://github.com/formp3) for identifying the affected surfaces. |
| 2470 | - `registry_sync` no longer ships the full MCP Registry catalog into the |
| 2471 | conversation. It takes a required query, scores the local snapshot |
| 2472 | host-side, and returns at most eight matches; the complete catalog stays on |
| 2473 | disk, and the compaction and spillover exemptions that let a multi-hundred- |
| 2474 | kilobyte dump reach the model unchanged are gone. |
| 2475 | - Providers that mirror the outgoing `(reasoning omitted)` replay placeholder |
| 2476 | back as a reasoning delta no longer have that echo ingested as real |
| 2477 | thinking: the exact transport placeholder is dropped on arrival, so live |
| 2478 | sessions stop showing a stream of placeholder reasoning blocks and saved |
| 2479 | transcripts stay free of them. |
| 2480 | - Mid-stream connection drops during an interactive turn no longer persist a |
| 2481 | synthetic `[runtime]` user message. Retry state is a typed engine-internal |
| 2482 | descriptor; a thinking-only drop re-issues the request without claiming a |
| 2483 | partial reply was preserved, the retry budget is enforced in mechanism, and |
| 2484 | recovery produces exactly one authoritative final answer. |
| 2485 | |
| 2486 | Codewhale v0.9.10 is a retention, identity, and product-clarity release: the shell and |
| 2487 | transcript can no longer retain unbounded tool output in memory or on disk, |
| 2488 | mid-turn history inserts no longer strand in-flight tool rows, every agent |
| 2489 | that ran this session is visible from `/agents list`, the PTY acceptance |
| 2490 | lane has a stall watchdog and bounded CI steps, approval outcomes are |
| 2491 | durable and fail closed (cyq1017, #5360), and three $HOME disk leaks are |
| 2492 | reclaimed. Extension surfaces now name their real state and act only |
| 2493 | through the reviewed install and trust flows, and sub-agent, shell, task, |
| 2494 | and workflow state is owned by the session that created it (#5518). Test |
| 2495 | threads get an 8 MiB stack so the lib suite can no longer |
| 2496 | abort under load. |
| 2497 | |
| 2498 | ### Fixed |
| 2499 | |
| 2500 | - First run starts on the welcome screen again. A missing key no longer |
| 2501 | skips Welcome and auto-opens the local-provider list: Enter walks to the |
| 2502 | calm provider explanation, then Enter opens the picker so a first API key |
| 2503 | can be set. Returning missing-key recovery still opens the picker on |
| 2504 | launch. |
| 2505 | - A foreground `bash` command that named no timeout is bounded again. The |
| 2506 | model-facing `bash` tool left an omitted `timeout_ms` at the internal |
| 2507 | ceiling (~24.8 days) instead of the 120 s default its own schema |
| 2508 | advertises, so a CLI that blocked on an interactive prompt or a hung |
| 2509 | network call held the turn open indefinitely — one report sat on a single |
| 2510 | unauthenticated CLI call for over two hours with the tool row simply |
| 2511 | counting seconds. The advertised default now applies, which arms the |
| 2512 | existing recovery: the process is killed and the model is told to rerun |
| 2513 | with `background=true` and poll with `action="wait"`. An explicit |
| 2514 | `timeout_ms` is still honored for genuinely long foreground work, and |
| 2515 | background and interactive runs keep their own lifetimes. |
| 2516 | - The Extensions (`/plugin`) Marketplace is no longer a read-only list. |
| 2517 | Every recommendation and stored candidate names its truthful state and |
| 2518 | primary action — Add, Enable, Configured, or Unavailable — and Enter or a |
| 2519 | mouse click runs that action through the existing reviewed `/mcp add |
| 2520 | recommended`, `/mcp enable`, and `/plugin` install/trust controllers, so |
| 2521 | no second trust path exists. Browser Use and Sandbox Runtime stay |
| 2522 | honestly Unavailable with their real setup routing instead of implying an |
| 2523 | install Codewhale cannot perform. |
| 2524 | - The Extensions MCP tab now renders one honest inventory: the header count |
| 2525 | and the visible rows derive from the same configured-server set, so |
| 2526 | `MCP (6)` can no longer sit above two rendered rows. Disabled servers |
| 2527 | stay visible and labeled disabled instead of silently disappearing, and |
| 2528 | configured servers absent from the live snapshot list as not-yet-inspected |
| 2529 | with their own explicit reload affordance through the MCP command |
| 2530 | controller. |
| 2531 | - Installed plugin rows now act on their real state: Enter opens an active |
| 2532 | bundle (`/plugin show`), offers Enable for a trusted-but-disabled bundle, |
| 2533 | or routes an untrusted bundle to the existing trust review — through the |
| 2534 | same confirmation and persistence controllers as the slash commands. |
| 2535 | - Sub-agent handoffs and rosters, background shell jobs, durable tasks, |
| 2536 | delayed continuations, and workflow controls are now scoped to the |
| 2537 | session that owns them. Records carry immutable root-session ownership, |
| 2538 | stale completion-channel payloads are rejected before deduplication, |
| 2539 | background work drains and reports only to its owning session, and |
| 2540 | legacy ownerless jobs fail closed (#5518 failure class reported by |
| 2541 | @hxfhd; the report's exact JavaScript provenance was not claimed as |
| 2542 | reproduced). |
| 2543 | - The resolved route envelope now reaches every outbound model call: all |
| 2544 | wire dialects and auxiliary calls clamp at the shared transport seam |
| 2545 | under one wire/reservation budget, provider input limits are honored, and |
| 2546 | switching models on the same protocol no longer inherits the previous |
| 2547 | model's limits (#5516, #5518). |
| 2548 | - First-run continuity: the chosen onboarding provider persists across |
| 2549 | restarts, a missing first-run config no longer interrupts the flow, and |
| 2550 | the automatic working-agreement checkpoint renders as a standalone setup |
| 2551 | handoff instead of regressing the onboarding rail to the full wizard's |
| 2552 | 4/10 progress. |
| 2553 | - Explicitly worded natural-language `/goal` declarations now create a |
| 2554 | durable goal in the provider-neutral engine before model dispatch, while |
| 2555 | ordinary tasks and quoted transcripts stay out of goal mode and prose |
| 2556 | acknowledgement alone can no longer stand in for goal creation. |
| 2557 | - `/model` now keeps the current Z.ai default (`GLM-5.3`) visible when an |
| 2558 | older installation has an explicit `GLM-5.2` route saved. The saved 5.2 |
| 2559 | route remains exact; choosing 5.3 sends and remembers the distinct 5.3 ID. |
| 2560 | - The constitution checkpoint now leads with the bundled balanced agreement; |
| 2561 | the default path writes no custom constitution. The startup launch surface |
| 2562 | distinguishes read-only Chat from folder-bound, approval-gated Work. |
| 2563 | - Tabby and other IME bridges no longer observe a stale visible caret while a |
| 2564 | frame diff is being painted; Codewhale hides the cursor during the diff, |
| 2565 | restores the canonical composer cell, and only then reveals it again |
| 2566 | (BrathonBai, #5023). |
| 2567 | - Pre-header HTTP/2/SSE transport failures get one bounded HTTP/1.1 retry; |
| 2568 | authentication, provider-semantic, response-body, and already-pinned HTTP/1 |
| 2569 | failures remain fail-closed (demian-welt, #4683). |
| 2570 | - MCP `tools/call` images now travel as bounded typed content instead of |
| 2571 | leaking base64 through model-visible JSON. Direct and parallel calls share |
| 2572 | the same MIME, size, validation, and one-image boundary (PR #5515 by |
| 2573 | @cacdcaecawae). |
| 2574 | - Linux npm installs and updates race GitHub Releases against the CNB mirror |
| 2575 | at the checksum-manifest layer, then download from the first verified source |
| 2576 | without making users wait through a doomed slow-source timeout. |
| 2577 | - `CODEWHALE_PREFER_BWRAP` now applies the documented Linux sandbox override, |
| 2578 | and Codewhale-era names own build metadata, hook session/tool-call IDs, and |
| 2579 | sandbox child markers. The corresponding `DEEPSEEK_*` names remain as 0.9.x |
| 2580 | compatibility aliases (#5443). |
| 2581 | - Windows default launch prefers Windows Terminal: zip archives ship |
| 2582 | `codewhale.bat` (CRLF, `wt.exe` then the exe), `install.bat` copies that |
| 2583 | launcher, and the NSIS Start Menu shortcut opens it instead of the raw |
| 2584 | binary (#1854). |
| 2585 | - `fix(tui): make the header status mark honour its setting` — `status_indicator` |
| 2586 | did nothing for three of its four documented values. The header hardcoded a |
| 2587 | leading `cw` span *and* asked for a second mark beside the effort chip, then |
| 2588 | filtered the second one against the literal `"cw"`; because `cw`, the legacy |
| 2589 | `whale` opt-in, and every unknown value all normalize onto that same mark, |
| 2590 | the filter discarded them and left `off` with nothing to turn off. `cw`, |
| 2591 | `whale`, `off`, and a typo all rendered byte-identical headers. There is one |
| 2592 | mark now and the setting owns it: `cw`/`whale` draw the typographic mark, |
| 2593 | `dots` draws the activity frames, `off` removes it (thejayjetson, #5512). |
| 2594 | - `fix(tui): rebase active-cell tool bindings on every mid-turn history |
| 2595 | insert` — `/rename` mid-turn left the running tool row spinning forever |
| 2596 | (#5478). |
| 2597 | - `fix(tui): bound what the shell and transcript retain from tool output` — |
| 2598 | a 1.1 MB Bash call kept over a megabyte resident for up to an hour; raw |
| 2599 | streams now cap at 16 MiB in flight and release delivered output, and |
| 2600 | retained tool outputs cap at 64 KiB per record / 8 MiB per transcript |
| 2601 | (#5472). |
| 2602 | - `fix(tui): reclaim the three $HOME disk leaks` — orphaned session dirs, |
| 2603 | the unbounded audit.log, and stranded writer temp files. |
| 2604 | - `fix(tui): persist approval outcomes before execution` (cyq1017) — |
| 2605 | approval receipts are committed to a session-owned log before execution |
| 2606 | proceeds; unpersistable evidence blocks the tool; resume reconstructs |
| 2607 | closed and interrupted approvals (#5360). |
| 2608 | - `test(tui): break the LazyLock/env-barrier deadlock in the test harness`. |
| 2609 | - `ci: give test threads the 8 MiB stack they need` — the lib suite aborted |
| 2610 | with SIGABRT under load on the default 2 MiB stack. |
| 2611 | - YOLO entry points honor a locked approval policy: `--yolo`, `/mode yolo`, |
| 2612 | `/zidong`, and Alt+Y can no longer set Full Access + trust + shell when |
| 2613 | config or managed requirements own the posture. |
| 2614 | - Terminal PTY tools fail closed without a sandbox backend under a narrowed |
| 2615 | filesystem posture, and otherwise start `$SHELL -i` through |
| 2616 | `SandboxManager::prepare` like `bash`. |
| 2617 | - Skill update refuses to replace a directory that has no `.installed-from` |
| 2618 | marker — same ownership gate plugins already used. |
| 2619 | - `cp`/`mv` are workspace-safe only when every path operand stays inside |
| 2620 | the workspace — Auto-Review no longer auto-allows `cp /etc/passwd .`. |
| 2621 | - Main CI no longer shares one concurrency group per branch: each SHA |
| 2622 | gets a verdict instead of a cancelled pending run. A hermetic Safety |
| 2623 | gate job runs authorization tests in under 15 minutes (test bankruptcy |
| 2624 | restructuring — no tests deleted). |
| 2625 | - Config-fixture tests no longer honor `lock_test_env` as a license to |
| 2626 | read a populated `~/.codewhale/config.toml`; they need an `EnvVarGuard` |
| 2627 | like settings already did. Safety-gate and CNB workspace tests pin a |
| 2628 | hermetic `CODEWHALE_HOME`. `exec_persistent_service` is serialized in |
| 2629 | nextest and inside the cargo-test binary instead of dropped (#5355). |
| 2630 | - Short CLI no longer waits up to three seconds for a telemetry POST on |
| 2631 | exit; `session_end` is recorded and the buffer ships on the next |
| 2632 | interactive session. |
| 2633 | - Bare `/` now opens a deliberately small starter set: `/help`, `/setup`, |
| 2634 | `/model`, `/settings`, `/resume`, and `/rc`. The full command inventory |
| 2635 | remains searchable through `/help`, the command palette, and direct prefix |
| 2636 | typing, without front-loading the entire control surface (#5442, #5439). |
| 2637 | - First run now asks only for decisions needed to become usable, keeps the |
| 2638 | offline route explicit, and leaves optional provider, tools, policy, and |
| 2639 | appearance work in the progressive `/setup` repair guide. The idle aquarium |
| 2640 | asks one task-oriented question instead of advertising a tutorial or command |
| 2641 | billboard, and the localized telemetry choice appears after the workspace is |
| 2642 | ready without blocking the composer. |
| 2643 | - Provider, active model, and reasoning effort moved out of the crowded header |
| 2644 | into a quiet, width-aware footer identity. Compact layouts keep model and |
| 2645 | effort before provider detail and shed whole low-priority groups instead of |
| 2646 | clipping the composer or control hints. |
| 2647 | - The model picker no longer re-parses `~/.codewhale/config.toml` once per |
| 2648 | provider when deciding who has a saved key. |
| 2649 | |
| 2650 | ### Added |
| 2651 | |
| 2652 | - `/workflows` opens a live run dashboard over this workspace's durable |
| 2653 | workflow journal: every retained run with status, phases, child roster, |
| 2654 | progress, and host-side cancel — observation only, it never launches a run. |
| 2655 | - Repository instructions now assemble from the actual containing checkout: |
| 2656 | applicable `AGENTS.md` files resolve repository-root to current-directory in |
| 2657 | order under one aggregate budget, a linked worktree is its own root, and |
| 2658 | scope is never inferred from path mentions or whichever branch is named |
| 2659 | `main`. |
| 2660 | - `/goal` is a codex-style control plane: setting an objective dispatches it |
| 2661 | to the engine, which owns the goal and starts the first goal turn itself — |
| 2662 | the objective is never echoed back as the user's own message, pause/resume |
| 2663 | are real control ops, and the hunt-era vocabulary and trophy cards are |
| 2664 | gone. |
| 2665 | - `/extensions` and `/plugins` open one localized inventory for Hooks, |
| 2666 | Plugins, local Marketplace catalogs, Skills, and MCP. Reviewed suggestions |
| 2667 | include Playwright, Chrome DevTools, Cua Computer Use, Browser Use, and the |
| 2668 | sandbox runtime without granting trust or installing anything on open. |
| 2669 | - Turn Inspector now opens the newest turn and pages across complete recorded |
| 2670 | user, reasoning, tool/subagent, and assistant output with page-scoped search, |
| 2671 | copy, and export (sky-sun-moon, #1682). |
| 2672 | - Background tasks have bounded incremental persistence, durable terminal |
| 2673 | reasons, truthful timeout/cancellation receipts, restart recovery, and |
| 2674 | interruptible continuous-goal delays (#5497, #5508). |
| 2675 | - `/title` once again controls the terminal window title independently from |
| 2676 | `/rename`, survives session save/load, and sanitizes control, bidi, and |
| 2677 | zero-width characters (PR #5509 by @SparkofSpike). |
| 2678 | - MCP snapshots preserve whether capabilities were advertised by the server, |
| 2679 | discovered through the bounded legacy fallback, or not observed (#4170). |
| 2680 | - `codewhale auth status --diagnostic` reports canonical paths, isolation |
| 2681 | source, backend class, and value-free provider-source presence without |
| 2682 | opening credential stores or creating/migrating state (#2369). |
| 2683 | - `codewhale doctor --probe-search` performs an explicit credential-free, |
| 2684 | policy-checked transport probe for the selected search provider; ordinary |
| 2685 | doctor and JSON output remain offline (#5442). |
| 2686 | - The safe deferred `read_media` tool is available to supported read-only |
| 2687 | roles, and history receipts distinguish localized tool execution outcomes |
| 2688 | without exposing raw payloads (#5102). |
| 2689 | - **npm Linux x64 first-party source selection.** The wrapper concurrently |
| 2690 | fetches the GitHub Releases and CNB checksum manifests for the exact |
| 2691 | package version, locks the first source whose HTTP response and manifest |
| 2692 | validate, and downloads binaries only from that source. Explicit |
| 2693 | `CODEWHALE_RELEASE_BASE_URL` / `CODEWHALE_USE_CNB_MIRROR=1` still skip the |
| 2694 | race; other targets stay on GitHub. |
| 2695 | - `/workflow <objective>` and `/workflow run <path>` now produce a bounded, |
| 2696 | tool-less proposal for review. Only `/workflow confirm` can launch that |
| 2697 | reviewed draft; status, cancel, settings, and the `/workflows` dashboard stay |
| 2698 | host-owned and do not spend a model turn (#5439). |
| 2699 | - `feat(tui): add cancellable cadence to continuous goals` (M-Maciej) — |
| 2700 | `[goal] continuation_delay_seconds` gives coordinator goals a visible quiet |
| 2701 | period between successful turns while reusing the existing coalesced goal |
| 2702 | continuation token; Esc, Ctrl+C, pause/done/blocked/clear cancel before the |
| 2703 | next provider request, and failures never continue (#5508). |
| 2704 | - `feat(tui): add command context adapters and migration gate (FEAT-015)` |
| 2705 | (aboimpinto) — TUI-owned capability facets, a dual-path dispatch seam, and |
| 2706 | source-aware CI enforcement so a command slice cannot claim to be migrated |
| 2707 | while it still accepts concrete `App`. Zero production commands migrate in |
| 2708 | this slice (#5316). |
| 2709 | - `feat(web): move docs/hooks and docs/troubleshooting onto the dictionary |
| 2710 | spine` (Lstarsky0) — both pages now read copy from the locale dictionaries |
| 2711 | instead of inline bilingual literals (#5337). |
| 2712 | - `feat(web): move docs/constitution and docs/runtime-api onto the dictionary |
| 2713 | spine` (Lstarsky0) — both pages now read copy from the locale dictionaries |
| 2714 | instead of inline bilingual literals; another incremental phase of #5337, |
| 2715 | not completion of the full epic (#5517). |
| 2716 | - `docs(i18n): complete Tier 1 of Chinese docs localization` (SparkofSpike) — |
| 2717 | Chinese and Indonesian docs move to `docs/zh_hans/` and `docs/id/`, with |
| 2718 | redirect stubs at the old paths for one release cycle (#5482). |
| 2719 | - `feat(tui): show repository context in git chrome` (wuisabel-gif) — the TUI |
| 2720 | header now identifies the active repository or linked worktree before the |
| 2721 | branch and dirty marker, so operators can see where the agent is working |
| 2722 | without opening the worktree manager (#5437). |
| 2723 | - `feat(tui): formalize the status-bar color grammar` — seven semantic |
| 2724 | families live in `docs/design/STATUS_BAR_COLOR_GRAMMAR.md` and |
| 2725 | `palette::grammar`; header and phase-strip ink resolve through named |
| 2726 | `ChromeInk` slots so chrome cannot invent an eighth meaning or spend |
| 2727 | Failure red on a dirty worktree or selected mode. The footer's session |
| 2728 | metrics strip resolves through the same inks, and the red reservation is |
| 2729 | checked against every selectable theme, not just the whale default; |
| 2730 | typed footer toasts resolve through the grammar too. |
| 2731 | Repo/worktree chrome stays metadata and still renders when Git names a |
| 2732 | location but not a ref (#5437). |
| 2733 | - `feat(tui): first slice of the agents roster` — every agent that ran this |
| 2734 | session, receipts-only, via `/agents list` and the sidebar fan-out rows |
| 2735 | (#5479 spec items 1 and 5). |
| 2736 | - `ci: bound PTY acceptance and add a stall watchdog to the harness` — |
| 2737 | QA_PTY_STALL_TIMEOUT_SECS aborts a wedged PTY run with a diagnostic; |
| 2738 | the isolated PTY step is capped at 15 minutes; Windows NSIS provisioning |
| 2739 | gets a bounded retry (#5496). |
| 2740 | - `chore(scripts): dev-cache warns before it fills a disk` (#5465 class). |
| 2741 | |
| 2742 | ### Contributors |
| 2743 | |
| 2744 | - [Sh1Zuku](https://github.com/SparkofSpike) (`@SparkofSpike`) — restored |
| 2745 | `/title` as an independent, persistent terminal-window title in PR #5509, |
| 2746 | in addition to the Tier 1 Chinese and Indonesian documentation work below. |
| 2747 | - [Sun Zhenyuan](https://github.com/bistack) (`@bistack`) — extracted the |
| 2748 | turn-loop stream processor in PR #5514 while preserving retry, cancellation, |
| 2749 | usage, TTFT, steering, and partial-response behavior. |
| 2750 | - [OctoBored](https://github.com/OctoBored) (`@OctoBored`) — supplied the |
| 2751 | working no-token Star History mirror used across the localized README set |
| 2752 | after the canonical chart endpoint began returning a restricted placeholder |
| 2753 | (#5510). |
| 2754 | - [cacdcaecawae](https://github.com/cacdcaecawae) (`@cacdcaecawae`) — added |
| 2755 | provider-neutral typed MCP image forwarding in PR #5515; the harvested |
| 2756 | version also makes malformed image fields produce a visible omission receipt. |
| 2757 | - [DingYong4223](https://github.com/DingYong4223) (`@DingYong4223`) — reported |
| 2758 | the narrow-terminal completion truncation closed by the bounded hover reveal |
| 2759 | (#998). Thanks also to @AiurArtanis and @formp3 for identifying the affected |
| 2760 | completion surfaces. |
| 2761 | - [sky-sun-moon](https://github.com/sky-sun-moon) (`@sky-sun-moon`) — reported |
| 2762 | the missing full per-turn input, reasoning, tool, and assistant pages that |
| 2763 | shaped Turn Inspector navigation (#1682). |
| 2764 | - [cy2311](https://github.com/cy2311) (`@cy2311`) — reported the Windows launch |
| 2765 | path that now ships and installs a Windows Terminal-aware batch launcher |
| 2766 | (#1854). |
| 2767 | - [demian-welt](https://github.com/demian-welt) (`@demian-welt`) — provided the |
| 2768 | reproducible pre-header SSE transport failure behind the bounded HTTP/1.1 |
| 2769 | retry (#4683). |
| 2770 | - [BrathonBai](https://github.com/BrathonBai) (`@BrathonBai`) — reported the |
| 2771 | Tabby/CJK IME candidate-window jump that led to the hide-diff-position-show |
| 2772 | cursor transaction (#5023). |
| 2773 | - M-Maciej (@M-Maciej) — the real-world organization-coordinator use case and |
| 2774 | 5–30 minute cadence requirement behind cancellable cross-turn goal delays |
| 2775 | (#5508). |
| 2776 | - cyq1017 (@cyq1017) — approval outcomes are persisted before execution can |
| 2777 | proceed: receipts commit to a session-owned log first, unpersistable |
| 2778 | evidence blocks the tool, stale decisions are rejected, and resume |
| 2779 | reconstructs closed and interrupted approvals (#5491, closes #5360). |
| 2780 | - aboimpinto (@aboimpinto) — the TUI-owned dependency-injection and migration |
| 2781 | infrastructure that makes slash-command extraction safe: seven capability |
| 2782 | facets, a dual-path dispatch seam, and source-aware CI enforcement so a |
| 2783 | command slice cannot claim migration while it still accepts concrete `App` |
| 2784 | (#5506, EPIC-005/FEAT-015 under #5316, which they also filed). |
| 2785 | - wuisabel-gif (@wuisabel-gif) — the TUI header now names the active |
| 2786 | repository or linked worktree before the branch and dirty marker, derived |
| 2787 | from Git's common directory and capped by shell density tier (#5511, the |
| 2788 | repo/worktree slice of #5437). |
| 2789 | - SparkofSpike (@SparkofSpike) — Tier 1 of the Chinese docs localization: |
| 2790 | Chinese and Indonesian documentation moves to `docs/zh_hans/` and |
| 2791 | `docs/id/` with redirect stubs held at the old paths for one release cycle |
| 2792 | (#5507, epic #5482, which they also filed). |
| 2793 | - Lstarsky0 (@Lstarsky0) — `docs/hooks` and `docs/troubleshooting` move onto |
| 2794 | the dictionary spine, retiring their inline bilingual literals in favor of |
| 2795 | locale dictionaries with token-aware code spans (#5504, closes #5337, which |
| 2796 | they also filed). |
| 2797 | - Lstarsky0 (@Lstarsky0) — `docs/constitution` and `docs/runtime-api` follow |
| 2798 | the same dictionary spine: 28 inline `isZh` branches become typed English |
| 2799 | and Chinese dictionaries held to key and token parity, while the other |
| 2800 | sixteen locales keep the English fallback (#5517, a further phase of #5337). |
| 2801 | - @thejayjetson — the header status-indicator report that pinned the |
| 2802 | regression to a specific setting, with every value, theme, and |
| 2803 | `fancy_animations` combination already ruled out (#5512). |
| 2804 | - hxfhd (@hxfhd) — reported the deterministic cross-session contamination |
| 2805 | class behind this release's session-ownership boundary, plus route |
| 2806 | budgeting evidence (#5518). |
| 2807 | - sfdzhmr (@sfdzhmr) — reported the route budgeting root causes that exact |
| 2808 | route-limit propagation now closes (#5516). |
| 2809 | |
| 2810 | ## [0.9.9] - 2026-08-18 |
| 2811 | |
| 2812 | Codewhale v0.9.9 is a truth-and-resilience release: the shell tool can no |
| 2813 | longer wedge a session when the host runs out of disk or descriptors, |
| 2814 | unverified context windows and output ceilings are labeled honestly at every |
| 2815 | surface, DeepSeek V4 is priced on the published peak/off-peak tiers, SSE |
| 2816 | UTF-8 fails closed in every dialect, Fleet shadowing is visible, bwrap gets |
| 2817 | container essentials and extra roots, the `dsh` skin rides the bundle |
| 2818 | profile, the `agent` tool schema is down to 12 fields, and README/website |
| 2819 | locales grow to 18 and 8. |
| 2820 | |
| 2821 | ### Fixed |
| 2822 | |
| 2823 | - The lowercase `bash` tool no longer wedges when its complete-output spill |
| 2824 | file cannot be created: a full temp volume or exhausted descriptor table |
| 2825 | used to fail *every* call — `echo ok` included — with the harness-internal |
| 2826 | "Failed to create streaming shell output" and never recover until the |
| 2827 | host was cleaned up. The spill is now best-effort (the bounded tail is |
| 2828 | still returned and the truncation notice says why the full-output path is |
| 2829 | missing), and any remaining spawn/stream failure names the exhausted |
| 2830 | resource — disk, file descriptors, memory — and says the next call is safe |
| 2831 | to retry (#5465; the wedge that took out the owner's own 0.9.9 session). |
| 2832 | - A concrete route/offering output limit now outranks the conservative |
| 2833 | 8,192-token compatibility guess for an uncatalogued model. Routes that |
| 2834 | publish no output limit remain fail-closed, documented model ceilings stay |
| 2835 | authoritative, and a route limit can never raise the requested cap (#5460). |
| 2836 | - Context-window honesty at every surface (#5239, #5441): the |
| 2837 | `model-name hint` and `fallback` rungs of the context-window ladder are |
| 2838 | guesses, and every surface that renders one now says so — the status line, |
| 2839 | `/status`, `/config`, the context-pressure message, the model picker chips, |
| 2840 | and the auto-router inventory. Unverified windows still drive real budgets |
| 2841 | (compaction trigger, context meter, output reservation); they just stop |
| 2842 | reading as capabilities anyone checked. A window parsed from an `_Nk` |
| 2843 | model-name suffix (`qwen3-32b-256k` → 256K) is now its own |
| 2844 | `model-name hint` rung below `catalog`, because it is optimistic rather |
| 2845 | than conservative — a catalog or provider-reported value beats it. The |
| 2846 | `[providers.<name>] context_window` override remains the hard fix and |
| 2847 | renders as `configured` with no marker. |
| 2848 | - Output-ceiling honesty (#5440): an Anthropic-family model the catalog does |
| 2849 | not describe keeps the 64K Messages floor as its clamp and the ChatGPT/ |
| 2850 | Codex OAuth route keeps its 4K policy, but `OutputCeilingSource` gained an |
| 2851 | `unverified` rung for both, so exec-stream receipts and the model picker |
| 2852 | label them `unverified`/"assumed floor" instead of `documented`. Clamp |
| 2853 | values are unchanged. |
| 2854 | - Telemetry default-on is visible (#5441): `codewhale doctor`'s |
| 2855 | runtime-posture section gained a `telemetry=on (default)`-style row with |
| 2856 | the source that decided it (cli | env | config | default), and |
| 2857 | `codewhale config get telemetry` reports the resolved consent with its |
| 2858 | source instead of `key not found` on a machine whose batches ship. Truth |
| 2859 | change only; resolution and behavior are untouched. |
| 2860 | - Fleet: a scout's read-only shell carve-out (#5428) is now honored by both |
| 2861 | the posture gate and the execution envelope, so `git log`, `find | head`, |
| 2862 | `npm view` and the other bounded read-only commands run in-place instead |
| 2863 | of being refused as "Executes" (#5426). Delegation still never widens |
| 2864 | authority: the role-isolation test and docs/SUBAGENTS.md pin that a child |
| 2865 | cannot exceed its parent's posture (#5426, #5435). |
| 2866 | - `/rename` and `/title` now apply mid-first-turn: the session file does |
| 2867 | not exist until the first autosave, so the rename fell through with |
| 2868 | NotFound; the shared path now prefers the per-session checkpoint and |
| 2869 | rebuilds from App state, with a PTY regression test through the live |
| 2870 | event loop (#5430). |
| 2871 | - `integrations dsh plan` no longer refuses DeepSeek's default |
| 2872 | Responses-dialect route (`deepseek-v4-flash`); Responses and |
| 2873 | Anthropic-Messages routes are carried through pi-ai |
| 2874 | `openai-responses` / `anthropic-messages` instead of being approximated |
| 2875 | or refused; only credentialed base URLs are still refused, with an error |
| 2876 | that names provider and model (#5434). |
| 2877 | - Session cost no longer sits at `unverified_live_pricing` when live pricing |
| 2878 | cannot be verified (control-plane 503, Models.dev capabilities-only |
| 2879 | overlays): provider-docs bundled fallback rates for the DeepSeek V4 |
| 2880 | family on Fireworks / OpenCode Zen restore a usable figure, live |
| 2881 | per-provider rows still win, and `kimi-k3` stays unpriced until a |
| 2882 | published rate exists (#5241; harvested from #5402). |
| 2883 | - Release assets: `release.yml` asset-freshness checks compare against the |
| 2884 | release job's own `started_at`, so job-level reruns of the npm step are no |
| 2885 | longer poisoned by earlier uploads (#5429). |
| 2886 | - macOS CI: the `agent_focus_pty` auto-review receipt test waited on a |
| 2887 | worker that had already completed and raced the rail's focus; it now holds |
| 2888 | the child's wrap-up and waits for a settled live row (refs #5056, #5403). |
| 2889 | - DeepSeek V4 pricing follows the published peak/off-peak tiers (peak |
| 2890 | 01:00–04:00 and 06:00–10:00 UTC; off-peak is half of peak) for |
| 2891 | `deepseek-v4-flash` and `deepseek-v4-pro` in USD and CNY, resolved from |
| 2892 | each turn's recorded time; the stale single-tier rows understated cost up |
| 2893 | to ~4×. Because every direct DeepSeek first-party rate is now |
| 2894 | time-windowed, the scorecard fails closed (`missing_recorded_time`) on an |
| 2895 | undated DeepSeek turn instead of guessing a tier (#5470; #5241 follow-up, |
| 2896 | verified against api-docs.deepseek.com on 2026-08-17). |
| 2897 | - SSE UTF-8 split across HTTP/2 DATA frames now fails closed in every |
| 2898 | streaming dialect: a shared strict decoder, tail flush, and |
| 2899 | `decode_failed` propagation (`InvalidSseUtf8`) replace the per-dialect |
| 2900 | approximations, with byte-chunk decoder tests (#5374; supersedes draft |
| 2901 | #5404). |
| 2902 | - CI: `release_four_read_only_fleet_roles_launch_with_canonical_prompts` |
| 2903 | answered Fleet children with SSE while they call the blocking JSON path; |
| 2904 | the parse failure was retried and double-counted the worker on slow macOS |
| 2905 | runners (#5471; refs #5056). |
| 2906 | - Context: every web tool surface (`Web`, `web_search`, `web.run`, |
| 2907 | `fetch_url`) now uses the noisy-result soft limit, so large fetches are |
| 2908 | compacted like shell output instead of consuming the ordinary hard limit |
| 2909 | (#5474, thanks @h3c-hexin). |
| 2910 | - Routing: a lowercase saved selector such as `glm-5.2` resolves against the |
| 2911 | owning Z.ai / DeepSeek catalog row (case-fold fallback, only when exactly |
| 2912 | one provider-owned wire id matches) instead of being classified as another |
| 2913 | provider's bare model (#5475, thanks @h3c-hexin; diagnosis by @asto18089 |
| 2914 | in Pinvou/CodeWhale#14). |
| 2915 | - Model catalog brought current as of 2026-08-17 against the official |
| 2916 | pricing pages: gpt-5.6-terra / gpt-5.6-luna rates, `claude-sonnet-5` keeps |
| 2917 | $2/$10 (the announced September increase was withdrawn), `claude-opus-5` |
| 2918 | added, `kimi-k3` and `kimi-k2.7-code-highspeed`, `MiniMax-M2.7-highspeed`, |
| 2919 | Mistral first-party rows, xAI `grok-4.5` / `grok-4.3` with long-context |
| 2920 | tiers, Gemini and Qwen limits, and RedNote's `dots3-note` preview as an |
| 2921 | OpenRouter row (no first-party API exists yet) — every number carries its |
| 2922 | source and a pinned test (#5485). |
| 2923 | - Website: copy on codewhale.net rewritten in plain declarative sentences — |
| 2924 | one idea per sentence, numbers from the generated facts, no self-narration |
| 2925 | — with a voice sheet at docs/design/WEB_VOICE.md (#5483). |
| 2926 | - CI: the release workflows no longer restore npm/cargo caches after |
| 2927 | checking out a caller-supplied SHA — the CodeQL cache-poisoning Highs |
| 2928 | #88–#107 are closed with a contract test over the workflow files (#5463). |
| 2929 | - Compact TUI rows below 60 columns no longer reserve a hidden session-metrics |
| 2930 | strip, so narrow terminals reclaim the row instead of clipping the |
| 2931 | transcript (#5486). |
| 2932 | - Ghostty's truecolor underwater field now uses a dedicated synchronized |
| 2933 | 60 FPS lane instead of the legacy 30 FPS compatibility cap, with continuous |
| 2934 | caustic fades replacing visibly stepped color changes. |
| 2935 | - Live reasoning's advertised `Space:expand` action now runs before the |
| 2936 | composer's first-character paste-burst hold, while spaces in an active paste |
| 2937 | remain payload. The newest reasoning preview also spends only genuinely free |
| 2938 | viewport rows before truncating instead of stopping at the fixed 10/12-row |
| 2939 | fallback on roomy terminals. |
| 2940 | - Strict `cargo doc` builds no longer fail on bare URLs in rustdoc comments; |
| 2941 | the remaining links are explicit Markdown targets (#5489). |
| 2942 | |
| 2943 | ### Changed |
| 2944 | |
| 2945 | |
| 2946 | - The model-facing `agent` tool advertises exactly 12 fields — `action`, |
| 2947 | `prompt`, `type`, `profile`, `name`, `agent_id`, `message`, `until`, |
| 2948 | `detached`, `worktree`, `write_roots`, `resume_from` — down from 33 |
| 2949 | (#5324, refs #5123). Budgets (`max_steps`, `wall_time_secs`, `max_depth`), |
| 2950 | routing overrides (`model`, `model_strength`, `thinking`), worktree-path |
| 2951 | knobs, the deliberate/spawn-contract fields and the wait/status/interrupt |
| 2952 | extras moved off the advertised schema. Every removed field stays |
| 2953 | parse-accepted and honored unchanged (same contract as `token_budget`), so |
| 2954 | saved transcripts, ACP/MCP clients and Fleet configs replay as-is; the |
| 2955 | #5426/#5435 containment clamps are untouched. Child budgets now resolve |
| 2956 | from role defaults (60/120 turns, 1800 s wall time, unchanged clamps) and |
| 2957 | new `[subagents]` keys `default_max_steps` / `default_wall_time_secs`. |
| 2958 | Because the tool catalog is part of the session-pinned prompt prefix |
| 2959 | (docs/CACHE.md), upgrading re-fills the KV prefix once per session. |
| 2960 | - TUI prose — user messages, assistant answers, and reasoning/thinking — |
| 2961 | now wraps at the full content width on wide terminals, matching |
| 2962 | tool/status cells, instead of stopping at a 105-column rail that left a |
| 2963 | dead right margin on ultrawide displays (#5436). |
| 2964 | - Configured skill prompts are stable across session roots and operating |
| 2965 | systems: only custom configured roots hide their physical path, ordinary |
| 2966 | workspace/global skills keep a discoverable privacy-safe path, warning |
| 2967 | replacements are boundary-aware (including non-UTF-8 Unix paths), and |
| 2968 | Windows separators render as `/`. The skills prompt is also 50 bytes |
| 2969 | leaner without raising a runtime-contract ceiling (#5492, #5473). |
| 2970 | - Auto-router classifier requests accept `[auto.router] timeout_secs`, while |
| 2971 | preserving the existing default when the key is absent (#5494). |
| 2972 | - Every `ci.yml` job now has an explicit 10–90 minute timeout appropriate to |
| 2973 | its workload, bounding stale assigned runners instead of inheriting |
| 2974 | GitHub's six-hour default (#5495). |
| 2975 | - The docs shell and shared web components now route localized copy through |
| 2976 | the typed dictionary spine; these are two incremental phases of #5337, |
| 2977 | not completion of the full epic (#5488, #5490). |
| 2978 | - Dependency: rusqlite 0.40.2 (#5391). |
| 2979 | - Documentation: stale A/B/C-tier references, provider defaults, module |
| 2980 | descriptions, and line anchors now match the current code (#5481). |
| 2981 | |
| 2982 | ### Added |
| 2983 | |
| 2984 | - `[transcript] prose_measure` (positive integer, optional): caps prose |
| 2985 | wrap at N columns for owners who want a bounded reading measure on |
| 2986 | ultrawide terminals. `0` or absent keeps the full width; negative or |
| 2987 | non-integer values are rejected with a clear config error. Tool, diff, |
| 2988 | and status cells never inherit the cap (#5436). |
| 2989 | - Localization: README translations for Français, Deutsch, 繁體中文, हिन्दी, |
| 2990 | Türkçe, Italiano, Polski, العربية and Català join the existing nine |
| 2991 | (#5451); codewhale.net routes fr, de, ca, hi, tr, it, pl and ar (with |
| 2992 | `dir="rtl"` plumbing) as partial locales (#5453). |
| 2993 | - Docs: README Integrations section (incl. the DeepSeek Harness `dsh` plugin |
| 2994 | path, docs/INTEGRATIONS_DSH.md) localized across all READMEs; RFC keeping |
| 2995 | the deterministic-first auto-review hybrid (#5427); Claude Code parity |
| 2996 | reference for agents/workflows/plugins/skills |
| 2997 | (docs/design/CLAUDE_CODE_PARITY.md); config.example.toml / SUBAGENTS.md / |
| 2998 | TOOL_LIFECYCLE.md brought back in line with the code (#5447). |
| 2999 | - `dsh` integration: the Codewhale palette is applied through the bundle |
| 3000 | profile via dsh's documented `overrideTokens` (on by default; |
| 3001 | `codewhale integrations dsh update --skin false` turns it off), replacing |
| 3002 | the 0.9.8 exported-CSS skin that dsh's inline body variables overrode |
| 3003 | (docs/design/DSH_BUNDLE_SKIN.md, docs/INTEGRATIONS_DSH.md) (#5469). |
| 3004 | - `dsh` integration: an ambient ocean scene behind the DSH web UI — slow |
| 3005 | whale silhouettes, a school of `><>` glyph fish, bubbles — drawn on a |
| 3006 | canvas under a translucent veil of the Codewhale palette, plus an explicit |
| 3007 | responsive `WHALE BROTHERS / CODEWHALE × DEEPSEEK HARNESS` lockup; light |
| 3008 | and dark, ~30 fps capped, paused when hidden, a static frame under |
| 3009 | `prefers-reduced-motion`; on by default with the skin, |
| 3010 | `codewhale integrations dsh update --ocean false` turns it off (#5484). |
| 3011 | - Fleet: agent shadowing is visible — a roster-row badge, a Layers block in |
| 3012 | agent detail, and a `doctor` "Fleet roster layers" section (JSON |
| 3013 | `operate_fleet.roster.multi_layer`), in all 15 TUI locales. Layer collapse |
| 3014 | and `[fleet.profiles]` migration stay for 0.9.10 (#5098). |
| 3015 | - Sandbox: bwrap containers get the `--dev/--proc/--tmpfs` essentials plus |
| 3016 | configurable extra roots (`bwrap_ro_roots` / `bwrap_dev_roots`) so |
| 3017 | toolchains that live outside the workspace stay reachable read-only |
| 3018 | (#5410). |
| 3019 | - Tests: `crates/tui/tests/README.md` states the keyless assembled-journey |
| 3020 | rule and maps the Auto-Review guardian acceptance items to the engine |
| 3021 | journeys that exercise them (#5361). |
| 3022 | - OrcaRouter's default endpoint is classified as an aggregator billing |
| 3023 | surface, so pricing and session-cost reporting use the correct billing |
| 3024 | posture instead of treating it as a first-party provider (#5493). |
| 3025 | - Dependencies: ratatui 0.30.2, thiserror 2.0.20. |
| 3026 | |
| 3027 | ### Removed |
| 3028 | |
| 3029 | - `dsh` integration: the exported-CSS skin file and its "skin export" status |
| 3030 | line (superseded by the bundle-applied `overrideTokens` skin, #5469). |
| 3031 | |
| 3032 | ### Contributors |
| 3033 | |
| 3034 | - hexin (@h3c-hexin) — a concrete route/offering output limit outranks the |
| 3035 | 8,192-token compatibility guess for an uncatalogued model (#5461, closes |
| 3036 | #5460); web tool results use the noisy soft limit (#5474); owned direct |
| 3037 | model casing resolves safely (#5475); and configured-skill prompts stay |
| 3038 | stable across ephemeral roots and operating systems (#5492, #5473). |
| 3039 | - Gabriel-Degret (@Gabriel-Degret) — configurable auto-router classifier |
| 3040 | timeout (#5494; first contribution). |
| 3041 | - @asto18089 — diagnosed the Z.ai `glm-5.2` casing collision and wrote the |
| 3042 | first provider-scoped fix in Pinvou/CodeWhale#14 (carried upstream in |
| 3043 | #5475). |
| 3044 | - Reports and reproductions that shaped this release: @hardy922 (context- |
| 3045 | window honesty, #5239), @redstar (bwrap extra roots, #5410), @all-lopezg |
| 3046 | (SSE UTF-8 garbling on DeepSeek Flash, #5374), @alitvak69 (unverified live |
| 3047 | pricing, #5241), and @wuisabel-gif (the macOS filtered-suite hang |
| 3048 | investigation on #5056). |
| 3049 | |
| 3050 | ## [0.9.8] - 2026-08-16 |
| 3051 | |
| 3052 | Codewhale v0.9.8 ships the remaining assigned finish. Remaining web |
| 3053 | settings polish moves to v0.9.9. Prefab third-party templates that have |
| 3054 | a published OpenAI-compatible host ship here (#5350). |
| 3055 | |
| 3056 | ### Fixed |
| 3057 | |
| 3058 | - `sudo` (and `su`/setuid helpers) work again for wheel-group administrators |
| 3059 | who want Codewhale to be able to escalate: the Linux startup hardening's |
| 3060 | irreversible `PR_SET_NO_NEW_PRIVS` flag — inherited by every child process — |
| 3061 | is now skippable with `CODEWHALE_NO_NEW_PRIVS=0` (#5413). The flag stays on |
| 3062 | by default; the no-ptrace and no-core-dump measures are never skipped. |
| 3063 | |
| 3064 | - Abort-class process deaths no longer poison the terminal (#5424). A |
| 3065 | stack overflow, allocation failure, or double panic skips the panic hook |
| 3066 | and every cleanup guard, which is how a v0.9.7 user's mid-turn exit left |
| 3067 | mouse capture leaking SGR sequences into their shell. An |
| 3068 | async-signal-safe handler now restores the terminal modes and appends a |
| 3069 | one-line cause marker to `~/.codewhale/crashes/last-fatal-signal.log` |
| 3070 | before re-raising, keeping the honest 128+signal wait status. A SIGKILL |
| 3071 | (OOM killer) remains uninterceptable by design. |
| 3072 | |
| 3073 | ### Changed |
| 3074 | |
| 3075 | - Prompt-cache prefix is pinned for the session. The tool loop no longer |
| 3076 | recomposes the system prompt from disk on every model step, so an agent |
| 3077 | writing a file no longer busts the provider KV prefix cache mid-turn. The |
| 3078 | system prompt and tool catalog are re-composed only on a declared header |
| 3079 | change (`/model`, mode, goal, session resume), which re-pins under a logged |
| 3080 | reason; an undeclared change is reported as drift and the original pin is |
| 3081 | kept instead of silently becoming the new baseline. Workspace, AGENTS.md, |
| 3082 | skills, memory, and goal drift now reaches the model as one bounded |
| 3083 | `<context_update>` user message at the next user turn — a history append, |
| 3084 | not a header rewrite. `/cache stats` shows the pin reason, the last-miss |
| 3085 | reason, the undeclared-drift count, and the context-update count. See |
| 3086 | [docs/CACHE.md](docs/CACHE.md). |
| 3087 | |
| 3088 | - Plugin compatibility is now per-component. A reviewed, trusted, enabled |
| 3089 | bundle that mixes Skills or MCP with unsupported commands, agents, hooks, |
| 3090 | LSP, native, filesystem-roots, or lifecycle-mutation declarations keeps the |
| 3091 | supported adapters active and reports the rest as inactive (`full` / |
| 3092 | `partial` / `unsupported`). All-unsupported bundles still cannot be enabled. |
| 3093 | The capability hash is now v2 and binds this build's activation policy, so |
| 3094 | older v1 receipts and any later adapter-enablement change fail closed as |
| 3095 | needs-review. Skills and each MCP transport re-request their own capability |
| 3096 | at the consumption boundary. |
| 3097 | |
| 3098 | ### Added |
| 3099 | |
| 3100 | - Opt-in multiline composer mode (`composer_multiline_mode = true`) makes |
| 3101 | Enter insert a newline and Shift+Enter send. Alt+Enter, Ctrl+J, and supported |
| 3102 | Ctrl+Enter/Cmd+Enter behavior stays unchanged (#5345, @AiurArtanis). |
| 3103 | |
| 3104 | - `/plugin marketplace add|list|show|remove|install` completes the |
| 3105 | federated marketplace journey (#5311). `add` reads one LOCAL catalog |
| 3106 | document in the real published schemas (Kimi, Claude, Codex, or |
| 3107 | Codewhale native) — no network, regular files only — and persists it |
| 3108 | beside the plugin state with the same hardened, fail-closed store. |
| 3109 | `list`/`show` render every candidate with per-entry diagnostics, |
| 3110 | display-only tiers, and honest install plans that say when Codewhale |
| 3111 | cannot fetch a source; `install` routes through the existing reviewed |
| 3112 | installer, so installed bundles still enter disabled and untrusted. |
| 3113 | Foreign auto-install policy (Codex `INSTALLED_BY_DEFAULT`) is visibly |
| 3114 | ignored; nothing is auto-installed, auto-trusted, or granted vendor |
| 3115 | trust. |
| 3116 | |
| 3117 | - `/rc` attach now includes an observed `owner/name` git remote when the |
| 3118 | folder has a GitHub, CNB, or Gitee origin, so CWC can label the paired |
| 3119 | session. Paths stay off the wire. Reconnect after both this client and |
| 3120 | CWC #202 land to backfill existing empty rows. |
| 3121 | |
| 3122 | - The local Runtime web client keeps the thread rail clipped so **New |
| 3123 | thread** cannot paint over the session fact chips. Chips wrap instead |
| 3124 | of sliding under the rail. |
| 3125 | |
| 3126 | - Z.ai `GLM-5.3` is live on the Coding Plan and is now the default direct |
| 3127 | Z.ai model: `DEFAULT_ZAI_MODEL` resolves to `GLM-5.3` in both |
| 3128 | `codewhale-tui` and `codewhale-config`, and it is the first `/model` row |
| 3129 | after `/provider zai`. Explicit `GLM-5.2` selections (`model = "GLM-5.2"` |
| 3130 | and its `glm-5.2` aliases) keep their own id — only the default moved. |
| 3131 | Limits and reasoning options still inherit from `GLM-5.2` until Z.ai |
| 3132 | publishes distinct 5.3 numbers. No USD price is claimed. A live call |
| 3133 | can still 429 with entitlement code 1311 on accounts that are not |
| 3134 | provisioned for 5.3. |
| 3135 | |
| 3136 | - The TUI transcript renders Markdown blockquotes (`>` lines) with a quote |
| 3137 | rail — nested quotes, inline bold/code/links, wrapped continuation rows, and |
| 3138 | selection copy that keeps the quote text and skips the rail chrome. |
| 3139 | |
| 3140 | - Sub-agent details show the resolved model, fleet role, and type. Labels |
| 3141 | use the session/role name instead of a generic Agent N (#5371, #5287). |
| 3142 | |
| 3143 | - Documented catalogue output ceilings (including DeepSeek V4's 384K maximum) |
| 3144 | remain authoritative bounds, while ordinary requests start at a safe 64K |
| 3145 | cap and explicit overrides can raise it within the resolved route window. A |
| 3146 | clean output-limit stop continues the turn instead of killing it (#5373, |
| 3147 | #5516, #5518). Thanks @sfdzhmr and @hxfhd for the route evidence. |
| 3148 | |
| 3149 | - Ollama Cloud is a first-class hosted provider (`/provider ollama-cloud`) |
| 3150 | on the official OpenAI-compatible `https://ollama.com/v1` route. Local |
| 3151 | Ollama stays keyless. The exact released `ollama` + Cloud URL tuple keeps |
| 3152 | a bounded compatibility path across saved sessions, Fleet, and nested |
| 3153 | subagents; neighboring remotes stay custom and fail closed against |
| 3154 | inherited official credentials. |
| 3155 | |
| 3156 | - Homebrew ships a `codewhale` formula. `brew tap Hmbown/deepseek-tui && |
| 3157 | brew install codewhale` is the install path; `brew upgrade codewhale` |
| 3158 | updates it. The legacy `deepseek-tui` formula remains a deprecated alias |
| 3159 | for one overlap release. |
| 3160 | |
| 3161 | - `/title [name|off]` sets a per-session tab/window title, shown as |
| 3162 | `[title] …` in front of the terminal window title (`Codewhale` / |
| 3163 | `reasoning…` / `using tool…` / `done`). The `title` config key supplies |
| 3164 | the default (`/config title … --save` persists it); multi-window |
| 3165 | workflows can tell parallel sessions apart at a glance. `/title` is |
| 3166 | independent of `/rename`, which keeps naming the session in the picker |
| 3167 | and composer. Control, bidi, and zero-width format characters are |
| 3168 | stripped from both the saved session name and the window title, so the |
| 3169 | picker, the Runtime API, `codewhale sessions`, and the OSC 0 tab title |
| 3170 | all carry the same escape-free text (#5419, #5430). |
| 3171 | - Eden AI is a named OpenAI-compatible Chat Completions provider (`edenai`, |
| 3172 | aliases `eden-ai` / `eden_ai`) with `EDENAI_API_KEY`, global and EU base-URL |
| 3173 | overrides, a live provider-scoped model catalog, and |
| 3174 | `deepseek/deepseek-v4-pro` as the verified default. Generic reasoning fields |
| 3175 | stay omitted because Eden AI routes multiple upstream model families |
| 3176 | (#5422, Kai Nacke). |
| 3177 | - Children (sub-agents and Fleet workers) inherit the session's permission |
| 3178 | posture faithfully: Auto-Review's deterministic floor and model guardian |
| 3179 | decide a worker's held calls (fail closed when unavailable, never a |
| 3180 | prompt); under Ask a held call is raised in the parent's approval UI and |
| 3181 | the worker waits visibly; Full Access still fails closed on the safety |
| 3182 | floor. Each prompt-less decision is a one-line note in that worker's |
| 3183 | transcript (focus mode) and an audit-log record. |
| 3184 | - Worker role defaults keep what the role does not intend to withhold: |
| 3185 | every built-in role keeps network reads; `planner` may run read-only |
| 3186 | shell probes; `custom` inherits the parent's write/network/shell posture |
| 3187 | and is narrowed only by its explicit tool list or the spawning call. |
| 3188 | Read-only roles (`scout`, `reviewer`, `planner`, `verifier`, |
| 3189 | `consultant`) still never write the workspace. The focused worker's |
| 3190 | header states its effective posture from the runtime snapshot. |
| 3191 | - `/workflow status`, `/workflow cancel [run_id]`, `/workflow settings`, and |
| 3192 | `/workflow help` are answered by Codewhale itself from the run journal and |
| 3193 | live run state — no model turn — and `/workflow run <path>` launches a |
| 3194 | checked-in workflow as-is. `/config workflow` and `/config goal` explain |
| 3195 | the effective tables. The workflow tool now honors the session `[workflow]` |
| 3196 | table (`automatic`, `auto_start_read_only`, `require_approval_for_writes`, |
| 3197 | limits) instead of product defaults. |
| 3198 | - Goal mode enters as readily as DeepSeek Harness: the agent may create the |
| 3199 | session goal when a direct request describes a verifiable multi-turn end |
| 3200 | state, and Codewhale shows a one-line `Goal set` receipt with how to pause |
| 3201 | or clear it. Bare `/goal` shows plain progress (and how to continue when no |
| 3202 | turn is running), prints usage on an empty session instead of asking the |
| 3203 | model, and `/goal help|status` are reserved words. |
| 3204 | |
| 3205 | - Whale Teams in the terminal: the six Signal Cut whale identities (Scout, |
| 3206 | Patch, Harbor, Echo, Keel, Lantern) appear as species badges on `/fleet` |
| 3207 | roster rows and worker rows, with an identity portrait in the roster detail |
| 3208 | pane and a six-state word (Resting, Thinking, Working, Waiting for you, |
| 3209 | Blocked, Offline) derived only from the child's real runtime status. Colors |
| 3210 | come from the theme tokens, every glyph has an ASCII fallback, and the |
| 3211 | working wake animates only under full motion. See |
| 3212 | `docs/design/WHALE_TEAMS_TUI.md`. |
| 3213 | - A session metrics strip on the phase row (`4 turns · 108 steps │ LLM |
| 3214 | 11m46s · Tool call 1m52s │ TTFT avg 1.5s · 120 tok/s │ Cache hit 99% │ |
| 3215 | Input 9.3M`), on by default as the `session_metrics` footer item |
| 3216 | (`/statusline`, `[tui].status_items`). Every value comes from engine |
| 3217 | receipts — turn starts, per-model-call usage with stream time, |
| 3218 | time-to-first-token and whole-call time, tool start/complete edges, and |
| 3219 | provider-reported cache and input tokens. Cells without evidence are |
| 3220 | omitted, never estimated. `/status` prints the untrimmed line; the phase |
| 3221 | row sheds its lowest-value groups to fit the columns it actually has. |
| 3222 | - Auto-Review decisions nobody was prompted for are now visible in the |
| 3223 | transcript as one-line notes: model-guardian allow/deny verdicts with |
| 3224 | their risk tier and stated reason, guardian failures (denied, fail |
| 3225 | closed), deterministic policy blocks, and holds Auto-Review denied |
| 3226 | without pausing. The audit log keeps the full record. `/permissions` |
| 3227 | ends with the active posture, what it decides on its own versus never, |
| 3228 | and the audit-log path. The footer's `Esc to interrupt` hint is |
| 3229 | localized. See `docs/design/AUTO_MODE_PARITY.md` for the Claude Code / |
| 3230 | Kimi Code parity ledger and follow-ups. |
| 3231 | - `codewhale integrations dsh status|plan|connect|update|launch|disable|enable|remove` |
| 3232 | connects an existing official DeepSeek Harness (`dsh` 0.1.0-rc.6, verified) |
| 3233 | through Codewhale using only its documented seams: a `--patch` overlay that |
| 3234 | pins the exact Codewhale provider/model/endpoint identity (native |
| 3235 | `deepseek-official` route, or a hand-declared `openai-completions` route |
| 3236 | named `codewhale-<provider>` for OpenAI-compatible providers), the |
| 3237 | Codewhale permission posture exported as `DSH_PERMISSION_MODE`, and an |
| 3238 | append-only receipt. Codewhale writes only under |
| 3239 | `$CODEWHALE_HOME/integrations/dsh/`, never copies API keys or edits DSH |
| 3240 | files, never broadens permissions (`--allow-full-access` only mirrors an |
| 3241 | existing Codewhale full-access posture), and reports not-installed / |
| 3242 | offline / incompatible / detected / connected / stale-config / |
| 3243 | stale-version / disabled honestly. Anthropic Messages and OpenAI Responses |
| 3244 | routes are refused as not carriable. The documented DSH plugin path is an |
| 3245 | explicit opt-in: `install-bundle` materializes a Codewhale bundle package |
| 3246 | (`codewhale-dsh-bundle`, MIT notice retained) and installs it with |
| 3247 | `dsh plugin --profile codewhale add <path>` into a dedicated `codewhale` |
| 3248 | profile (pnpm required, reported truthfully when missing; `web`/`headless` |
| 3249 | untouched), so `dsh --profile codewhale` alone carries the identity; |
| 3250 | `update` regenerates the bundle patch and `remove-bundle` reverses it, |
| 3251 | leaving the DSH-owned profile directory in place. `/setup tools` and `codewhale doctor` |
| 3252 | show the read-only detection state; `doctor` also lists the DSH read-only |
| 3253 | credential consent alongside Codex and Grok. The optional `--skin` export |
| 3254 | writes a Codewhale token stylesheet generated from the TUI palette |
| 3255 | (Blue Stage dark/light, ombre water column, mode/permission/state colors, |
| 3256 | reduced-motion fallbacks); DSH exposes no custom-theme API, so the sheet is |
| 3257 | labeled an unsupported overlay and is never injected. See |
| 3258 | `docs/INTEGRATIONS_DSH.md`. |
| 3259 | |
| 3260 | ### Fixed |
| 3261 | |
| 3262 | - Selecting the `google` provider kind resolved to the `antigravity` |
| 3263 | TUI identity (and vice versa): the agy provider entry was inserted at |
| 3264 | different positions in the config-level enum and the TUI's |
| 3265 | discriminant-indexed lookup table. The table now matches the enum, so |
| 3266 | provider pickers, sorted display, and kind round-trips are correct. |
| 3267 | |
| 3268 | - The provider picker's key-entry stage accepted typed input and pastes |
| 3269 | for OAuth-only providers after `antigravity` declared OAuth |
| 3270 | acquisition; those gates now key off the OAuth acquisition class |
| 3271 | instead of a hard-coded provider identity. |
| 3272 | |
| 3273 | - The webhook hook sink no longer panics when its HTTP client fails to |
| 3274 | build; it falls back to a default client (#5381, EvanProgramming). |
| 3275 | |
| 3276 | - Session-index JSONL writes are serialized behind a process-wide mutex |
| 3277 | so concurrent state stores cannot drop an append during compaction |
| 3278 | (#5382, EvanProgramming; complements the cross-process file lock). |
| 3279 | |
| 3280 | - A billed `max_tokens` stop followed by a transport error fails the turn |
| 3281 | instead of continuing into a second request. A clean output-limit stop |
| 3282 | still continues. Mid-size context windows keep the ordinary 65K internal |
| 3283 | reservation so compaction does not collapse to the 1K headroom floor |
| 3284 | when the catalogue documents a matching output ceiling. |
| 3285 | |
| 3286 | - Thinking cycle, `/effort`, and Settings now walk each model's real ladder |
| 3287 | instead of the DeepSeek off/high/max shortcut. Grok 4.6 is |
| 3288 | auto/low/medium/high/xhigh (cannot disable); Grok 4.5 is |
| 3289 | auto/low/medium/high; first-party DeepSeek keeps a documented `low` tier. |
| 3290 | `/effort` persists and receipts through the same path as Ctrl+T. |
| 3291 | |
| 3292 | - Google Gemini is its own backend (`/provider google`) on the official |
| 3293 | OpenAI-compatible route with thought-signature capture/replay and |
| 3294 | fail-closed replay for thinking models. Antigravity (`agy` 1.1.13) is |
| 3295 | a separate provider: consent-gated read-only import of the official |
| 3296 | CLI's login, then a text-only cloud-code stream |
| 3297 | (`/v1internal:streamGenerateContent`). Tools, images, and unknown SSE |
| 3298 | shapes fail closed. Gemini 3.7 Flash is not advertised until a live |
| 3299 | turn succeeds on this wire. The website 44-count still excludes |
| 3300 | Antigravity. |
| 3301 | |
| 3302 | - DeepSeek Flash SSE on macOS no longer turns mid-character HTTP/2 |
| 3303 | flushes into U+FFFD replacement characters (#5374). Invalid UTF-8 |
| 3304 | fails the line instead of using lossy decode. |
| 3305 | |
| 3306 | - `[workshop] read_result_max_bytes` and `tool_result_max_bytes` raise |
| 3307 | the model-visible read/tool-result floor; they never lower the |
| 3308 | compile-time defaults and cap at 2MiB (#5367). |
| 3309 | |
| 3310 | - Fireworks and OpenCode Zen DeepSeek V4 Flash/Pro keep a bundled |
| 3311 | family rate when the live control plane is down, so session cost is |
| 3312 | not stuck on `unverified_live_pricing` (#5241). `kimi-k3` stays |
| 3313 | unpriced until a published rate exists. |
| 3314 | |
| 3315 | - Provider setup ships a typed beginner template catalog (#5350). OpenCode |
| 3316 | Zen/Go stay first-class key-only rows with their documented hosts and |
| 3317 | curated models. SenseNova fills a named OpenAI-compatible table on the |
| 3318 | published `https://token.sensenova.cn/v1` host (`S` or `/provider setup |
| 3319 | sensenova`). Agnes is listed as unpublished because this repository has |
| 3320 | no published URL. `/provider` `P` and Settings → beginner templates open |
| 3321 | the list; `T` tests `/models` and refreshes status without treating 2xx |
| 3322 | as model-ready. `/model` names a failed Models.dev refresh as |
| 3323 | `refresh failed; catalog available` instead of `cache failed`. |
| 3324 | |
| 3325 | - Privileged release workflows no longer restore rust-cache, sccache, |
| 3326 | or npm caches after checking out a caller-supplied SHA (CodeQL |
| 3327 | cache-poisoning #88–#106). Catalog drift no longer prints raw |
| 3328 | bundled/upstream blobs (#107). |
| 3329 | |
| 3330 | - Cancelling a turn now cancels its foreground child agents with it. |
| 3331 | |
| 3332 | - Empty compaction no longer wipes conversation history. |
| 3333 | |
| 3334 | - Wide terminals and tmux panes fill the full available width again for the |
| 3335 | transcript and composer (#5322). The brief v0.9 session-shell side gutter |
| 3336 | is gone so expanding a pane rematerializes layout the same way shrinking |
| 3337 | does. |
| 3338 | |
| 3339 | - The agent tool schema rejects empty calls. |
| 3340 | |
| 3341 | - The local web client keeps recovered stream gaps closed, user questions |
| 3342 | answerable, manual bootstrap access intact, and streamed prose quiet for |
| 3343 | assistive tech. |
| 3344 | |
| 3345 | - Website zh-Hans copy now says 宪章, matching the TUI pack (#5397, |
| 3346 | Lstarsky0). |
| 3347 | |
| 3348 | - Public website provider facts include Google Gemini and Ollama Cloud |
| 3349 | (44 runnable routes). Antigravity stays credential-plane-only. |
| 3350 | Harvested from #5398 (Lstarsky0) with that correction. |
| 3351 | |
| 3352 | - The website models page carries a truthful read-only settings preview |
| 3353 | built from repository facts; it never implies the site can change local |
| 3354 | configuration (#5370, #5411, mvanhorn). |
| 3355 | |
| 3356 | - The canonical `ultra` reasoning effort now maps to each provider's |
| 3357 | maximum tier alongside the legacy `ultracode` alias, instead of being |
| 3358 | silently dropped (#5303, #5409, buiducnhat). |
| 3359 | |
| 3360 | - Session titles truncate by character count, not byte offset, so |
| 3361 | multi-byte titles (CJK, emoji) cut at the intended width and word |
| 3362 | boundary instead of past the limit (#5415). |
| 3363 | - Wide terminals and tmux panes fill the full available width again for the |
| 3364 | transcript and composer (#5322). The brief v0.9 session-shell side gutter is |
| 3365 | gone so expanding a pane rematerializes layout the same way shrinking does. |
| 3366 | - The background verifier test drives the current libtest executable |
| 3367 | instead of the rustup `rustc` shim, so the TUI suite no longer depends |
| 3368 | on `$HOME` or holds the process-wide test environment lock across an |
| 3369 | async wait (#5056, #5423, Isabel Wu). |
| 3370 | |
| 3371 | ### Removed |
| 3372 | |
| 3373 | - The source-structure budget ratchet (CI step, checker, baseline JSON). |
| 3374 | It measured line counts, not quality: every legitimate feature required |
| 3375 | a hand-edited ceiling and the accompanying "review" was self-review, so |
| 3376 | it bought ceremony, not protection. Behavior-measuring gates (dead-code, |
| 3377 | runtime-contract, persistence-backlog) stay enforced. |
| 3378 | - DeepSeek can reuse a key already stored by official DeepSeek Harness |
| 3379 | (`dsh`) after |
| 3380 | `codewhale auth external-consent --provider deepseek --mode read-only`. |
| 3381 | Codewhale reads only `DEEPSEEK_API_KEY` from the exact granted |
| 3382 | `$DSH_HOME/.credentials.yaml` and never writes or refreshes that file. |
| 3383 | - The TUI markdown parser now honors CommonMark fence-length rules: a ```` |
| 3384 | opener is not closed by a shorter ``` line, so `>` content inside a longer |
| 3385 | fence stays literal code instead of escaping into a quote. |
| 3386 | - Sub-agents finalize when the parent session id changes, so a closed |
| 3387 | session cannot block new children as a live owner (#5372). |
| 3388 | - Child spawn-route receipts stay live and usage is deduped by response |
| 3389 | (#5366). |
| 3390 | - Doctor keeps persisted setup readiness across first-run / update |
| 3391 | checkpoints (#5340). |
| 3392 | - Approval default selection is applied and explained; agents are told |
| 3393 | when approvals are disabled (#5293). |
| 3394 | - A `/models` 2xx probe is a connection check, not model readiness. |
| 3395 | - Site layout uses one container, the ticker no longer implies false |
| 3396 | provider readiness, and install links stay in the active locale. |
| 3397 | |
| 3398 | ### Contributors |
| 3399 | |
| 3400 | - EvanProgramming (@EvanProgramming) — webhook client panic fallback |
| 3401 | (#5381); session-index JSONL mutex (#5382). |
| 3402 | - Lstarsky0 (@Lstarsky0) — session peek hides internal runtime events |
| 3403 | (#5376); thinking-ladder test re-pin (#5378); provider-count follow-ups |
| 3404 | (#5383/#5384); macOS agy fixture canonicalization (#5392); zh-Hans 宪章 |
| 3405 | terminology (#5397); regenerated website facts harvested and corrected |
| 3406 | from #5398. |
| 3407 | - Matt Van Horn (@mvanhorn) — read-only models settings preview on the |
| 3408 | website (#5411, fixes #5370). |
| 3409 | - Nhat Bui (@buiducnhat) — canonical `ultra` reasoning effort mapped across |
| 3410 | provider effort tables (#5409); session titles truncated by character |
| 3411 | count, not byte offset (#5415). |
| 3412 | - Sh1Zuku (@SparkofSpike) — `/title` and the session name in the terminal |
| 3413 | tab/window title, plus the mid-turn title deadlock fix (#5419). |
| 3414 | - Kai Nacke (@redstar) — Eden AI provider registration, aliases, |
| 3415 | `EDENAI_API_KEY`, and the global/EU endpoints (#5422). |
| 3416 | - Isabel Wu (@wuisabel-gif) — background verifier test isolated from |
| 3417 | rustup and `$HOME` (#5423, slice of #5056). |
| 3418 | |
| 3419 | ## [0.9.7] - 2026-08-12 |
| 3420 | |
| 3421 | Codewhale v0.9.7 keeps the catalog ordinary. Grok 4.6 lands as a normal catalog |
| 3422 | row instead of a provider-shaped pile of special cases, OrcaRouter joins as a |
| 3423 | named provider, and a panic-safety advisory in `lru` is cleared by lifting the |
| 3424 | pin that caused it rather than living around it. |
| 3425 | |
| 3426 | ### Added |
| 3427 | |
| 3428 | - Grok 4.6 is the direct xAI default, with the `grok` alias moving onto it and |
| 3429 | `grok-4.5` still explicitly selectable. Its 500K context, text/image input, |
| 3430 | tool and structured-output support, `low`/`medium`/`high`/`xhigh` reasoning |
| 3431 | efforts (default `high`), and server-side web search all come from the |
| 3432 | Models.dev-shaped catalog rather than model-specific code. `reasoning_effort` |
| 3433 | reaches the wire only on the exact first-party `https://api.x.ai/v1` route, |
| 3434 | and the usage-aware 200K-token pricing boundary is scoped to direct xAI so |
| 3435 | aggregator routes reusing the model slug cannot inherit xAI billing. |
| 3436 | - OrcaRouter is a first-class named provider: `ORCAROUTER_API_KEY`, default base |
| 3437 | URL `https://api.orcarouter.ai/v1`, `deepseek/deepseek-v4-pro` default, |
| 3438 | `orcarouter/auto` routing, CLI `--provider` selector, and TUI picker entries |
| 3439 | (#5321). |
| 3440 | |
| 3441 | ### Changed |
| 3442 | |
| 3443 | - Reasoning-effort normalization and the model picker read a model's published |
| 3444 | `reasoning_options` list from the catalog instead of collapsing every route to |
| 3445 | the historic Low/Medium ladder. Any catalog row that publishes an effort list |
| 3446 | keeps its own vocabulary. |
| 3447 | - Docs record DeepSeek's live `DeepSeek-V4-Pro-0813` backend label while the |
| 3448 | callable API ID stays `deepseek-v4-pro`. No aliases are remapped and no |
| 3449 | `deepseek-v4-pro[1m]` selector is sent. |
| 3450 | |
| 3451 | ### Fixed |
| 3452 | |
| 3453 | - Auto-Review once again executes proven read/build/test shell commands and |
| 3454 | bounded workspace writes without opening an approval modal. Explicit policy |
| 3455 | blocks, unknown tools, publish operations, secret actions, MCP mutations, |
| 3456 | and shell commands requiring approval still fail closed (#5323; reported by |
| 3457 | USTHzhanglu and root-caused by Lstarsky0). |
| 3458 | - Copying a user or assistant message takes its canonical content instead of |
| 3459 | reserialized transcript lines, keeping role glyphs, continuation rails, and |
| 3460 | visual wrapping out of the clipboard while preserving authored Unicode, |
| 3461 | Markdown, and hard line breaks. Tool and Thinking cells stay on the existing |
| 3462 | full-transcript path (#5319). |
| 3463 | - `load_session` no longer runs crash recovery on every read. Snapshot reads go |
| 3464 | through a side-effect-free `load_session_snapshot` and recovery is explicit |
| 3465 | via `recover_session_for_resume`, so an embedding host inspecting a durable |
| 3466 | session while a tool is still running no longer gets a spurious crash repair |
| 3467 | (#5320). |
| 3468 | |
| 3469 | ### Security |
| 3470 | |
| 3471 | - `lru` moves to 0.18 to clear RUSTSEC-2026-0253, where `LruCache::pop()` was |
| 3472 | not panic-safe and could leave dangling list pointers. The `ratatui-core` |
| 3473 | `=0.1.0` pin that transitively forced `lru` ^0.16 is lifted, so |
| 3474 | `ColorCompatBackend` now answers `get_cursor_position()` from tracked cursor |
| 3475 | state — the upstream-recommended workaround for the startup CPR race |
| 3476 | (ratatui/ratatui#2483, ratatui/ratatui#2640) that the pin originally worked |
| 3477 | around. `ratatui` itself stays pinned at `=0.30.0`, so the API surface is |
| 3478 | unchanged. |
| 3479 | |
| 3480 | ### Known issues |
| 3481 | |
| 3482 | - The integration test |
| 3483 | `exec_persistent_service::failed_exec_kills_pending_service_and_exits_nonzero` |
| 3484 | is a confirmed flake under parallel load ("service pid file never appeared"). |
| 3485 | It passes in isolation and is unrelated to any v0.9.7 change. |
| 3486 | |
| 3487 | ### Contributors |
| 3488 | |
| 3489 | - XhesicaFrost (@XhesicaFrost) — canonical message copy (#5319). |
| 3490 | - h3c-hexin (@h3c-hexin) — session snapshot and crash-recovery split (#5320). |
| 3491 | - XiaoHuo888-hue (@XiaoHuo888-hue) — OrcaRouter provider registration (#5321). |
| 3492 | - USTHzhanglu (@USTHzhanglu) — Auto-Review regression report and Windows |
| 3493 | evidence (#5323). |
| 3494 | - Lstarsky0 (@Lstarsky0) — Auto-Review regression root-cause analysis (#5323). |
| 3495 | |
| 3496 | ## [0.9.6] - 2026-08-11 |
| 3497 | |
| 3498 | Codewhale v0.9.6 is a subtractive release: fewer runtime guards, one stable |
| 3499 | prompt, truthful provider endings, and a smaller compaction path that preserves |
| 3500 | the provider cache. The changes were grounded by matched Terminal-Bench 2.1 |
| 3501 | runs against Pi 0.8.41 and by dogfooding repeated manual compaction. |
| 3502 | |
| 3503 | ### Added |
| 3504 | |
| 3505 | - `web_search` defaults to Firecrawl Cloud without an API key; keyless requests |
| 3506 | are headerless and quota-bounded, while an optional user key raises limits. |
| 3507 | - Green web builds on `main` now emit an actionable manual-deploy reminder, so |
| 3508 | site changes cannot quietly appear shipped while Cloudflare still serves an |
| 3509 | older revision. |
| 3510 | - Mistral AI is a first-class provider route, including Codestral models, |
| 3511 | first-party reasoning support, authentication, picker entries, and aliases. |
| 3512 | - Headless `Bash` can transfer explicitly requested persistent Unix services |
| 3513 | out of an exec run, with ownership and cleanup receipts. |
| 3514 | - `/remote-env` opens hosted Work from the current GitHub or CNB branch tip and |
| 3515 | states exactly which unpushed, dirty, ignored, secret, and session state stays |
| 3516 | local. |
| 3517 | - Linux ARM64 release and nightly assets are static musl builds with native |
| 3518 | launch checks. |
| 3519 | - Maintainers can report observed daily active installs from the same anonymous, |
| 3520 | aggregate telemetry dataset; no additional client data is collected. |
| 3521 | - Fleet-dispatched members under a read-only evidence (no-network) ceiling now |
| 3522 | keep the `Web` tool's read-only `search` and `fetch` actions — parity with an |
| 3523 | ordinary scout — while every reaching surface (`web.run`, `fetch_url`, |
| 3524 | `github`, MCP) stays denied and the sentinel-backed capability envelope |
| 3525 | remains the fail-closed backstop. |
| 3526 | - `/fleet setup` can show an optional, deterministic, unratified role-to-model |
| 3527 | advisory built only from configured ready routes. Accept, edit, and reject |
| 3528 | all remain inside the existing human-reviewed profile save boundary; the |
| 3529 | advisory never launches a Fleet or writes a second configuration. |
| 3530 | - `/update` checks for a newer Codewhale release and installs it from inside |
| 3531 | the TUI, while `tui_help` gives agents the same command and key map users see. |
| 3532 | - Markdown file paths render as OSC 8 links where the terminal supports them, |
| 3533 | and every agent row can open that agent's transcript directly. |
| 3534 | - ACP editor sessions can execute multi-round file, search, Git, patch, and |
| 3535 | explicitly enabled shell tool calls through the shared Runtime registry. |
| 3536 | Shell access requires both the client's terminal capability and Codewhale's |
| 3537 | headless shell opt-in, and cancellation stops an in-flight tool before the |
| 3538 | turn returns (#5225 by @rafaelcavalheri). |
| 3539 | - Lowercase `read` returns bounded typed PNG, JPEG, GIF, and WebP results to |
| 3540 | image-capable Chat, Responses, Anthropic, and ACP routes. Text-only routes |
| 3541 | receive an explicit omission receipt; image bytes never spill into ordinary |
| 3542 | transcript, export, compaction, or relay text. |
| 3543 | |
| 3544 | ### Changed |
| 3545 | |
| 3546 | - Anonymous usage counting is on by default for fresh installs and disclosed in |
| 3547 | a native first-run Codewhale modal with an immediate opt-out. Prior declines |
| 3548 | remain off. Codewhale does not collect conversations, code, prompts, files, |
| 3549 | repo or branch names, credentials, model content, or per-turn activity |
| 3550 | timelines. |
| 3551 | - Wide terminals use a responsive, full-screen ocean canvas with modest |
| 3552 | gutters: prose keeps a readable measure while tools, diffs, work surfaces, |
| 3553 | the composer, and status chrome can use the available width. Turn and major |
| 3554 | activity seams breathe without padding every call inside a tool group. |
| 3555 | - Root CLI help describes product actions directly instead of exposing internal |
| 3556 | TUI/runtime layers. |
| 3557 | - `Bash action="wait"` now blocks by default when a wait is requested; callers |
| 3558 | can still ask for a nonblocking snapshot, and persistent service ownership |
| 3559 | remains explicit. |
| 3560 | - Compaction is one cache-stable summary request followed by one committed |
| 3561 | replacement summary and a bounded recent-message tail. Older saved sessions |
| 3562 | still restore. |
| 3563 | - Ask, Work, Auto-Review, and Full Access share one stable base prompt. Modes |
| 3564 | continue to differ through permissions and the live tool catalog; the former |
| 3565 | Act label is now Work throughout the product and shipped locales. |
| 3566 | - Full Access now auto-approves non-bypassable tools consistently, and the |
| 3567 | default choice shown on ordinary approval cards is configurable. |
| 3568 | - Model, context-window, dispatch-name, and nested-agent spawn receipts report |
| 3569 | the route and limits actually used rather than silently substituting a |
| 3570 | guessed identity. |
| 3571 | - Child-agent launches mint one immutable route receipt before admission and |
| 3572 | preserve it through status, interruption, completion, resume, Work Graph, |
| 3573 | and ledger projections, so provider/model attribution cannot drift (#5305). |
| 3574 | - Goal runs no longer stop because of internal continuation, repeated-gap, or |
| 3575 | unanswered-question guards. Explicit user limits and terminal goal states |
| 3576 | remain authoritative. |
| 3577 | - Account-owned `/rc` remote control now keeps exclusive ownership and a |
| 3578 | crash-recoverable delivery journal until the server acknowledges terminal, |
| 3579 | approval, failure, and snapshot state. |
| 3580 | - `todo_write` is an optional progress surface rather than required model |
| 3581 | ceremony. |
| 3582 | - New turns use one small, stable toolbox: `read`, `write`, `edit`, `bash`, |
| 3583 | `agent`, `todo_write`, and `tool_search`. The optional progress tool stays |
| 3584 | visible as familiar working memory; specialized native, Web, MCP, plugin, |
| 3585 | memory, task, and verification tools are policy-filtered and searchable; |
| 3586 | activated schemas stay in a bounded per-conversation cache. Every sub-agent |
| 3587 | keeps its own search and cache, including policy-allowed Web research, while |
| 3588 | forked context and parent activations remain warm starts rather than allowlists. |
| 3589 | - The direct file and shell schemas follow Pi's deliberately small contract: |
| 3590 | bounded complete-line reads, hash-free writes, unambiguous multi-edit with |
| 3591 | BOM/CRLF preservation and conservative fuzzy matching, and one foreground |
| 3592 | `bash` command with a bounded chronological output tail. Modes change |
| 3593 | execution authority, not those primitive names. |
| 3594 | - Codewhale no longer re-states the To-do list to the model. The model learns |
| 3595 | what is on the list from the tool result its own `todo_write` call returned, |
| 3596 | which is ordinary conversation history — the same way Pi's To-do works. The |
| 3597 | transient `<codewhale:work_state>` block that used to ride the tail of every |
| 3598 | parent turn-loop and sub-agent step request is gone, along with the stable |
| 3599 | system prefix being disturbed by list changes. A snapshot is still shown once, |
| 3600 | where a person asked for it: the `<codewhale:fork_state>` block a newly forked |
| 3601 | sub-agent is handed, `/relay` handoff instructions, and the agent card. The |
| 3602 | complete To-do stays visible in the UI. A structural test asserts real |
| 3603 | outbound provider request bodies do not carry the list. |
| 3604 | - Scout and Reviewer name the read-only investigator roles. Both expose exactly |
| 3605 | one shell entry point — canonical lowercase `bash`, bounded by the strict |
| 3606 | read-only classifier — and the legacy `Bash` alias stays denied in the catalog |
| 3607 | and at dispatch. Previously a case-insensitive name match let a call spelled |
| 3608 | `Bash` execute through that carve-out, returning raw shell to a read-only role. |
| 3609 | |
| 3610 | ### Fixed |
| 3611 | |
| 3612 | - Sending more context while a lowercase `bash` command is running now moves |
| 3613 | the command to `/jobs` and returns a successful running receipt instead of |
| 3614 | falsely reporting `Command exited with code -1`; the process keeps running |
| 3615 | and its completion still arrives through the normal runtime event. |
| 3616 | |
| 3617 | - First-run usage disclosure now opens as a native Codewhale modal instead of a |
| 3618 | shell questionnaire before application startup. Telemetry remains unarmed |
| 3619 | until the native choice is made, and an in-memory Disable choice governs the |
| 3620 | current session even when its preference cannot be saved. |
| 3621 | - `/compact` completion, failure, queued, duplicate, and mailbox outcomes are |
| 3622 | durable transcript receipts instead of short-lived toasts. A stray terminal |
| 3623 | event can no longer leave every later compaction stuck as already running. |
| 3624 | - Compaction now follows Codex's simple transcript shape: recent user context |
| 3625 | followed by one ordinary history checkpoint. It never appends the summary, |
| 3626 | the To-do list, or volatile shell/worker state to the standing system prompt; |
| 3627 | reloads migrate the persisted carrier back into exactly one history item. |
| 3628 | - Automatic compaction uses a percentage of the real context window, clamped to |
| 3629 | the route's spendable ceiling. Pressure comes from the current parent-route |
| 3630 | prompt, not cumulative billing or child-model usage. |
| 3631 | - Compaction, review, verify, routing, setup, Fleet, MCP, RLM, vision, |
| 3632 | translation, and sub-agent calls inherit the resolved route's normal output, |
| 3633 | sampling, and reasoning policy. Small internal-task token caps no longer |
| 3634 | truncate thinking routes or special-case individual providers. |
| 3635 | - Incomplete provider responses fail truthfully across ordinary turns and every |
| 3636 | internal model consumer. Partial text stays interrupted, pending tool calls do |
| 3637 | not execute, and billed usage is retained. |
| 3638 | - Transport-only `(reasoning omitted)` placeholders no longer enter new |
| 3639 | transcripts and are filtered from restored sessions. Reasoning expand/collapse |
| 3640 | actions stay attached to the exact rendered cell, including after replacement, |
| 3641 | restore, filtering, and resize (#5291). |
| 3642 | - Step-budget exhaustion is a typed failure and cannot release a pending |
| 3643 | persistent service. Cancellation after terminal usage still charges the turn. |
| 3644 | - Deferred tools now preserve a completed result when a provider reuses its |
| 3645 | tool-call ID on the retry turn, preventing successful plugin calls from |
| 3646 | entering a repeated execution loop. |
| 3647 | - Website setup, provider, diagnostics, Fleet, and single-runtime claims now |
| 3648 | match the source candidate. |
| 3649 | - Opening the sub-agent register no longer hides the to-do list: the Agents |
| 3650 | panel shows the full register and the durable checklist together, and the |
| 3651 | register header is a two-way door that returns to Tasks on a second click. |
| 3652 | - The ⌥V / Alt+V details chord opens the selected work-surface row's own |
| 3653 | inspector instead of the transcript's nearest tool cell, so a selected |
| 3654 | to-do row shows its own content rather than the latest reasoning. |
| 3655 | - The first-run usage disclosure now asks a clear question — "Help improve |
| 3656 | Codewhale?" — with unambiguous "Yes, keep anonymous counts" / "No, turn off |
| 3657 | tracking" choices in every shipped locale, and states the persistent opt-out |
| 3658 | command. Consent semantics are unchanged: telemetry stays unarmed until a |
| 3659 | choice is made. |
| 3660 | - macOS screencapture screenshots referenced in a message are copied to a |
| 3661 | stable attachments directory the moment the message is received, and the |
| 3662 | reference is rewritten to the stable path, so the image still exists when |
| 3663 | the agent reads it. Only files under a screencapture "Temporary Items" |
| 3664 | directory are touched; copies are idempotent and a failed copy keeps the |
| 3665 | original reference. |
| 3666 | - Manual `/compact` during an active turn now queues even when the engine's |
| 3667 | bounded op mailbox is saturated. The request defers client-side, retries as |
| 3668 | mailbox slots free, and cannot latch as already running after it settles. |
| 3669 | - Interactive `/load`, startup `--resume`, and `/resume` picker paths preserve |
| 3670 | the persisted provider, endpoint, and model identity; picker resume also |
| 3671 | leaves a durable transcript receipt. |
| 3672 | - Relative `mcp_config_path` values no longer depend on the launch directory or |
| 3673 | silently load an empty server pool: Codewhale warns and falls back to the |
| 3674 | user-global MCP configuration. Explicit absolute paths remain authoritative. |
| 3675 | - Alibaba Model Studio `qwen3.8-max` and `qwen3.8-max-preview` still stream |
| 3676 | their current reasoning, but no longer replay historical `reasoning_content` |
| 3677 | that those routes do not accept. Historical reasoning replay is now gated by |
| 3678 | the exact provider/API/model contract, so unknown `*-thinking` lookalikes |
| 3679 | fail closed while documented Qwen, Kimi, DeepSeek, Mistral, Anthropic, and |
| 3680 | Responses continuity rules remain intact. |
| 3681 | - Compatibility File/patch calls retain optional content-hash guards when a |
| 3682 | caller supplies them. The new direct `write` and `edit` schemas do not expose |
| 3683 | hash or prior-read ceremony. |
| 3684 | - Shell previews hold back incomplete UTF-8 sequences instead of emitting |
| 3685 | replacement characters, and compaction receipts report token deltas. |
| 3686 | - Nested agents may narrow but can never widen their inherited depth budget |
| 3687 | (#5317 by @ousamabenyounes). |
| 3688 | - Container publication now assembles AMD64 and ARM64 images in parallel on |
| 3689 | native runners from the already-verified static release binaries, then |
| 3690 | publishes and checks one multi-architecture manifest. It no longer rebuilds |
| 3691 | both targets through the single long-running QEMU job that lost its runner. |
| 3692 | |
| 3693 | - Google Gemini is its own backend (`/provider google`) on the official |
| 3694 | OpenAI-compatible route with thought-signature capture/replay and |
| 3695 | fail-closed replay for thinking models. Antigravity (`agy` 1.1.13) joins |
| 3696 | as a separate credential-plane provider: consent-gated read-only import |
| 3697 | of the official CLI's login with `ANTIGRAVITY_API_KEY`/`AGY_ADC_AUTH` |
| 3698 | precedence; requests fail closed until the cloud-code wire protocol is |
| 3699 | implemented. |
| 3700 | |
| 3701 | ### Removed |
| 3702 | |
| 3703 | - The no-progress guard, repeated-read guard, and injected tool-error strategy |
| 3704 | coaching. Productive polling, repeated inspection, and model-owned recovery |
| 3705 | are no longer interrupted by runtime heuristics. |
| 3706 | - Never-wired decision-card, keybinding, hover, shell-execution, engine-op, and |
| 3707 | release-script paths were deleted so the supported runtime has one route for |
| 3708 | each behavior. |
| 3709 | |
| 3710 | ### Contributors |
| 3711 | |
| 3712 | - Xavier Pestel (@xavierpestel-ai) — Mistral AI provider route (#5295). |
| 3713 | - Ben Younes (@ousamabenyounes) — inherited nested-agent depth cap (#5317). |
| 3714 | - Rafael Cavalheri (@rafaelcavalheri) — ACP agentic tool turns (#5225). |
| 3715 | |
| 3716 | ## [0.9.5] - 2026-08-08 |
| 3717 | |
| 3718 | Codewhale v0.9.5 consolidates the terminal application into one compiled |
| 3719 | runtime while preserving the familiar `codewhale` and `codew` commands. It |
| 3720 | also expands the managed Runtime API, makes session and Fleet work easier to |
| 3721 | inspect and resume, and removes the hidden local continuation backstop that |
| 3722 | could end productive work without a final assistant response. |
| 3723 | |
| 3724 | ### Added |
| 3725 | |
| 3726 | - **`model = "auto"` for prompt-based tier selection**: When set, the |
| 3727 | dispatcher analyses the user's prompt before delegating to the TUI and |
| 3728 | selects `deepseek-v4-pro` for complex tasks or `deepseek-v4-flash` for simple |
| 3729 | tasks (PR #5257). |
| 3730 | - Runtime API controls for persistent goals, bounded memory inspection, MCP |
| 3731 | server and skill lifecycle management, and durable Fleet receipt evidence. |
| 3732 | - Append-only session-tree history with `/tree`, `/branch`, `/fork`, and |
| 3733 | `/resume`, plus `/rc` remote control and managed login. |
| 3734 | - A unified Fleet roster for built-in dispatch postures and a pinned indicator |
| 3735 | that keeps active background work visible above the composer. |
| 3736 | - Incremental MCP registry refreshes that return the local snapshot immediately |
| 3737 | and update it in the background. |
| 3738 | - Scout and Reviewer agents can use a bounded direct-command evidence shell for |
| 3739 | read-only workspace, Git, and GitHub inspection, and can keep private working |
| 3740 | notes in their own To-do while the durable transcript retains their evidence. |
| 3741 | |
| 3742 | ### Changed |
| 3743 | |
| 3744 | - `codewhale-cli` now contains the terminal runtime directly. Release installers |
| 3745 | expose byte-identical `codewhale` and `codew` commands without a separate TUI |
| 3746 | executable. v0.9.5 introduced deprecated `codewhale-tui-*` release filenames |
| 3747 | as byte-identical compatibility copies; later releases retain those filenames |
| 3748 | while installed v0.9.4 clients remain supported upgrade sources. |
| 3749 | - Startup release checks cache successful lookups for one hour. The updater |
| 3750 | downloads and verifies the primary runtime once, then refreshes any existing |
| 3751 | `codew` or legacy `codewhale-tui` command paths from the same bytes. |
| 3752 | - Headless `codewhale exec` runs and verifier benchmark rollouts no longer |
| 3753 | impose a 100-step default. `--max-turns` remains available as an explicit |
| 3754 | opt-in ceiling; Fleet workers retain their separately configured budget. |
| 3755 | - Goal token and time budgets are telemetry rather than default stop |
| 3756 | conditions, and automatic goal continuation is unlimited unless the user |
| 3757 | explicitly configures a continuation ceiling. |
| 3758 | - Command-palette and slash-completion shadowing now share one alias-aware |
| 3759 | discovery contract. |
| 3760 | - The website install guidance, localized product copy, navigation controls, |
| 3761 | social metadata, and Cloudflare build pipeline now describe and deploy the |
| 3762 | same one-runtime release contract. |
| 3763 | |
| 3764 | ### Fixed |
| 3765 | |
| 3766 | - The hidden 20-step no-user-input backstop no longer ends productive turns. |
| 3767 | Tool results, queued steering, child completions, REPL feedback, and goal |
| 3768 | continuations can all reach the next provider step and a final assistant |
| 3769 | response; explicit user-configured limits and genuine stuck-loop guards remain. |
| 3770 | - Complete error details are directly inspectable after a failure instead of |
| 3771 | leaving the terminal with a clipped, unrecoverable error fragment. |
| 3772 | - A newly minted OAuth credential is adopted in the same provider-selection |
| 3773 | flow instead of requiring a second picker trip. |
| 3774 | - Fresh session titles can replace a stale cached `New Session` placeholder, |
| 3775 | unknown model context limits fail loudly, and release/source-install fallbacks |
| 3776 | no longer request binaries removed by the single-runtime conversion. |
| 3777 | |
| 3778 | ### Contributors |
| 3779 | |
| 3780 | - [Sh1Zuku](https://github.com/SparkofSpike) (`@SparkofSpike`) fixed stale |
| 3781 | cached session titles that could pin the `New Session` placeholder. |
| 3782 | - [Paulo Aboim Pinto](https://github.com/aboimpinto) (`@aboimpinto`) built the |
| 3783 | shared alias-aware command discovery contract and acceptance coverage. |
| 3784 | - [Sun Zhenyuan](https://github.com/bistack) (`@bistack`) contributed the |
| 3785 | background incremental MCP Registry refresh. |
| 3786 | - [SKY ZHAO](https://github.com/skyzhao1223) (`@skyzhao1223`) contributed |
| 3787 | prompt-based `model = "auto"` routing in PR #5257. |
| 3788 | |
| 3789 | ## [0.9.4] - 2026-08-07 |
| 3790 | Codewhale v0.9.4 ships the release-train harness work: the familiar Fleet |
| 3791 | roster/setup face with a clear operator-leader and user/folder scope, a |
| 3792 | work strip that keeps actionable agents instead of a permanent archive, |
| 3793 | waiting policy that forbids polling without freezing independent work, |
| 3794 | calmer tool output and session recovery, account/Workflow-search/ |
| 3795 | automation/handoff surfaces, a shorter translation-ready website, and |
| 3796 | release-blocker fixes across permissions, DeepSeek Responses, SQLite, |
| 3797 | File edits, terminal width, and Windows installation. |
| 3798 | |
| 3799 | ### Added |
| 3800 | |
| 3801 | - Memory maintenance: `remember` gains `revise` and `retire` beside the |
| 3802 | default `append`. Both name the exact note they target and both require |
| 3803 | the evidence for the change. Append-only memory decays — a correction |
| 3804 | sits behind the note it contradicts and both keep reaching the model — |
| 3805 | so the model can now keep its own durable notes true instead of only |
| 3806 | adding to them. |
| 3807 | - An audit trail for durable state the model writes about you. Every |
| 3808 | in-place memory edit is journalled to `memory/JOURNAL.md`, and every |
| 3809 | continual-harness `refine` / `remove` to a `JOURNAL.md` beside its state, |
| 3810 | each with before, after, and evidence. Harness removal previously left no |
| 3811 | record at all even though the entry leaves state entirely, so the journal |
| 3812 | is now the only place its content survives. |
| 3813 | - A first-run tip that says so: the first time Codewhale saves something |
| 3814 | durable it points at `/memory`, translated into all fifteen complete |
| 3815 | locale packs. This state shaped later sessions and nothing ever mentioned |
| 3816 | it existed. |
| 3817 | |
| 3818 | - Sub-agent checkpoint resume: `agents/followup` resumes an |
| 3819 | `interrupted_continuable` child from its checkpoint into a fresh agent loop — |
| 3820 | new agent id, original prompt plus the prior conversation tail — when a |
| 3821 | runtime is attached, and otherwise keeps queue-only semantics with the |
| 3822 | `continuation_handle` returned; a second followup on the same interrupted id |
| 3823 | returns the existing resumed target instead of spawning a duplicate (PR #5242). |
| 3824 | - MCP Registry discovery with Registry-first tool selection: `registry_sync` |
| 3825 | surfaces the eligible local stdio catalog as a complete model-side candidate |
| 3826 | set, connect-failure messages classify early-exit and usage-help output and |
| 3827 | point recovery at the next Registry candidate, and a bundled `mcp-discovery` |
| 3828 | skill documents the flow (PR #5238). |
| 3829 | - Progressive fresh-context disclosure: fresh sessions ship a minimal |
| 3830 | constitutional kernel — ground truth, user intent and scope, truthful |
| 3831 | completion, guarantees in mechanism, and precedence — with procedural |
| 3832 | playbooks disclosed on demand, an opt-in project context pack |
| 3833 | (`project_context_pack_enabled`) counted in context reports, and `load_skill` |
| 3834 | catalogue discovery via `name="list"`; the measured fresh-context budget |
| 3835 | drops by roughly 40% (PR #5077). |
| 3836 | - Named Fleet store v2: one self-contained TOML Fleet per configuration |
| 3837 | (`schema = "fleet"`), with scope-explicit selection (user-global default vs |
| 3838 | folder override), migration receipts from legacy role profiles, and atomic |
| 3839 | saves that refuse to clobber a different Fleet on the same slug. |
| 3840 | - Scout replaces the user-facing "faster" control: catalog-verified fast |
| 3841 | siblings only, never a guessed model name; pinned Scout survives operator |
| 3842 | changes. |
| 3843 | - Truthful model-picker rows: vision/tools/limits chips only when the catalog |
| 3844 | knows, with provider → family → exact model grouping. |
| 3845 | |
| 3846 | - **Opt-in product telemetry, off by default.** A first-run notice asks once, on |
| 3847 | a terminal, with declining pre-selected — Enter declines. Nothing is collected |
| 3848 | unless both `telemetry = true` and a recorded "Enable" answer are present, so |
| 3849 | a `telemetry = true` written before this release stays inert: the key has been |
| 3850 | settable and inert for a long time, and setting it was never consent. |
| 3851 | |
| 3852 | An enabled session sends its batches to the first-party ingest endpoint, |
| 3853 | `https://telemetry.codewhale.net/v1/telemetry`, which is the shipped default |
| 3854 | for `telemetry_endpoint`. That is a Cloudflare Worker whose complete source is |
| 3855 | in this repository under `telemetry-ingest/`; it writes to Workers Analytics |
| 3856 | Engine, whose row is exactly `_sample_interval`, `blob1`–`blob20`, `dataset`, |
| 3857 | `double1`–`double20`, `index1`, and `timestamp` — **there is no IP, country, |
| 3858 | or geo column**, so storing one is structurally impossible rather than merely |
| 3859 | disabled. The handler reads two request headers, never touches the request's |
| 3860 | geo properties, logs nothing, and validates against a closed field set that |
| 3861 | rejects an entire batch carrying any unpublished key. Cloudflare's retention |
| 3862 | for that data is a fixed three months. Setting `telemetry_endpoint = ""` |
| 3863 | instead writes each batch to `$CODEWHALE_HOME/telemetry/dryrun.jsonl` and |
| 3864 | constructs no HTTP client at all, so you can read exactly what would have been |
| 3865 | sent. |
| 3866 | |
| 3867 | Turning it off is an answer, not a flag: it deletes the random install id, |
| 3868 | truncates every buffered event, and leaves a permanent tombstone that a |
| 3869 | session already running re-checks before it appends and before it sends. A |
| 3870 | failed wipe fails closed. `CODEWHALE_TELEMETRY=0` is a hard floor that beats |
| 3871 | `--telemetry true` and the config key, and a value the parser cannot read |
| 3872 | also resolves to off. Fleet workers are hard-off. A repo-local |
| 3873 | `.codewhale/config.toml` can set neither key. |
| 3874 | |
| 3875 | Never collected: prompts, completions, tool arguments, diffs, file contents, |
| 3876 | filenames, paths, git remotes, repo or branch names, memory entries, chat |
| 3877 | history, credentials (not even a boolean asserting one exists), model ids, |
| 3878 | custom provider table names, MCP server names, error or panic message bodies, |
| 3879 | per-event timestamps, keystrokes, clipboard, screenshots, or location. The |
| 3880 | full schema is [`docs/TELEMETRY.md`](docs/TELEMETRY.md), and a test parses the |
| 3881 | field names out of that file and asserts set equality with the structs the |
| 3882 | serializer uses. |
| 3883 | |
| 3884 | This supersedes the roadmap's previous "no Codewhale product telemetry" entry, |
| 3885 | which moves from "Ruled out" to an opt-in framing. What stays ruled out: |
| 3886 | always-on or silent telemetry, per-keystroke or per-tool-call phone-home, and |
| 3887 | any third-party ad or analytics SDK in the runtime binary. |
| 3888 | - Registered `GLM-5.3` (direct Z.ai) and `z-ai/glm-5.3` (OpenRouter) as |
| 3889 | selectable GLM routes, with their aliases (`glm-5.3`, `glm-5-3`, |
| 3890 | `zai-glm-5.3`, `zai-glm-5-3`). Z.ai had **not released GLM-5.3 as of |
| 3891 | 2026-08-03** — the ids are registered so they resolve to the Z.ai/OpenRouter |
| 3892 | routes instead of being rewritten to another vendor's model, and they will |
| 3893 | fail upstream until Z.ai ships the model. Metadata (context, output, |
| 3894 | reasoning controls) is inherited wholesale from `GLM-5.2` pending official |
| 3895 | Z.ai release metadata; pricing is intentionally absent, and `GLM-5.2` remains |
| 3896 | the default Z.ai model. No third-party gateway roster gained the model: |
| 3897 | OpenCode Zen, OpenCode Go, Alibaba Model Studio, and TelecomJS publish no |
| 3898 | glm-5.3 entry, so Codewhale advertises none. |
| 3899 | |
| 3900 | - Managed Codewhale account commands (`account login`, `status`, `logout`, and |
| 3901 | `keys`) with browser device flow, profile- and origin-scoped secure sessions, |
| 3902 | refresh/revocation, redacted BYOK-vault management, and a token-free Runtime |
| 3903 | account receipt. Provider authentication remains separate, and `cloud` |
| 3904 | remains a compatibility alias. |
| 3905 | - `/automation` operator controls to list, inspect, pause, resume, delete, and |
| 3906 | run durable automations. Creation remains on the approval-gated |
| 3907 | model-visible `automation` tool. |
| 3908 | - A provider-neutral `WorkflowSearchSpec` authoring and freeze boundary, plus |
| 3909 | structured 2–16-candidate experimental search in the best-of-N Workflow |
| 3910 | starter. It freezes baseline, route, evidence, evaluator, gate, score, budget, |
| 3911 | and review policy before admission; it validates gate/scoring commands but |
| 3912 | does not execute or certify them itself. |
| 3913 | - The bundled generation-9 `handoff` skill for compact, decision-ready |
| 3914 | continuation across sessions. |
| 3915 | - Expanded terminal LaTeX rendering for aligned and matrix environments, |
| 3916 | cases, arrays, text/font/accent commands, brackets, symbols, and |
| 3917 | command-aware scripts (PR #4981). |
| 3918 | - Exact 40-character build provenance and secure account-session capability |
| 3919 | receipts on `/v1/runtime/info`; unknown source provenance continues to fail |
| 3920 | closed. |
| 3921 | - Acceptance-level Gherkin coverage locking the existing user-command |
| 3922 | precedence, alias shadowing, fallback, and invalid-command error contract |
| 3923 | (PR #4992). |
| 3924 | - Agent Plugins v1.0.0: consume, publish, and slugify packaged sub-agent |
| 3925 | briefs, with an install/update/uninstall on-ramp in the TUI (PR #5182). A |
| 3926 | plugin bundles a prompt, posture, and routing as one shareable artifact; |
| 3927 | on-disk migration of the older `plugin.toml` scaffold is deliberately out |
| 3928 | of scope for this train. |
| 3929 | - `send_later`: a model-callable one-shot delayed continuation tool, so the |
| 3930 | model can schedule a single future nudge without an operator-approved |
| 3931 | durable automation (PR #5138). |
| 3932 | - `/advisor`: an opt-in background advisor watcher for live turns (PR #5139). |
| 3933 | - Notification quiet mode with per-category switches and action-first copy |
| 3934 | (PR #5066). |
| 3935 | - Automation scheduling forms — one-shot `ONCE`, five-field cron, and honest |
| 3936 | watcher modes — created through the approval-gated `automation` tool |
| 3937 | (PR #5183). |
| 3938 | - Sub-agent `resume_from` continuation chains (PR #5142), child-result |
| 3939 | diff-tainting when a claimed diff is not visible to git, per-turn usage |
| 3940 | receipts on the exec stream-json stream, and spawn receipts that report |
| 3941 | the model each sub-agent actually ran on. |
| 3942 | - Transport resilience: sub-agent exec transport retries with a 600 s |
| 3943 | default (PR #5210), SSE header stalls retryable instead of fatal, and |
| 3944 | headless turn resume after mid-stream network drops with an `EX_TEMPFAIL` |
| 3945 | exit. |
| 3946 | - Session durability and control: a deterministic compaction continuation |
| 3947 | contract (PR #5064), persisting interrupted output (PR #5206), stop-word |
| 3948 | cancellation (PR #5207), token-counter refresh (PR #5204), deny-by-default |
| 3949 | approval cards (PR #5090), and the Operate completion gate (PR #5067). |
| 3950 | - zh-Hant promoted to a full shipped locale with complete `en.json` parity |
| 3951 | (PR #5143). |
| 3952 | - A persistent update-available chip in the header, with the startup update |
| 3953 | check throttled and naming the right command. |
| 3954 | - RLM static intent extraction for code blocks (`rlm_block_intent.rs`) |
| 3955 | landed as groundwork for a future code-mode approval flow; it is not yet |
| 3956 | wired into the turn pipeline and ships dormant by design. |
| 3957 | |
| 3958 | ### Changed |
| 3959 | |
| 3960 | - `/fleet` is the familiar roster/setup face again. The operator row is the |
| 3961 | Fleet leader (session model); the header names the selected saved Fleet and |
| 3962 | whether it is user-global or folder-scoped. Named-Fleet switching lives under |
| 3963 | `/fleet fleets` (Enter selects in the row's own scope). Session route changes |
| 3964 | stay temporary until `/fleet save`, `/fleet save-as`, or `/model save-default`. |
| 3965 | - Waiting-for-subagents directions forbid peek/status polling and sleep-as-wait, |
| 3966 | but allow independent work that does not depend on a child's result — the |
| 3967 | parent no longer freezes mid-turn with useful non-conflicting work available. |
| 3968 | - `workflow run` no longer requires `--fleet`; a saved Fleet is an optional pin |
| 3969 | layer over roles + the session route. |
| 3970 | - Homepage and getting-started copy is shorter and scannable across locales, |
| 3971 | with dictionary key and `{brand}` token parity preserved. |
| 3972 | |
| 3973 | - Tool results now render as ordinary bounded previews with real expansion; |
| 3974 | storage, retention-ledger, and internal evidence language no longer leak into |
| 3975 | normal transcripts. |
| 3976 | - Prose wrapping, goal state, modal questions, composer-tail behavior, and |
| 3977 | ambient motion now follow one deterministic interface contract across narrow |
| 3978 | terminals and fast streams. |
| 3979 | - Scout and reviewer Fleet roles gain network access and the bounded |
| 3980 | verification surface for real reconnaissance while retaining the no-write, |
| 3981 | no-raw-shell security floor. |
| 3982 | - Workflow runs may describe up to 1,000 tasks while admitting at most 16 live |
| 3983 | tasks at once through the host concurrency gate. Tournament ordering now |
| 3984 | supports explicit score-first selection while retaining its cost-first |
| 3985 | default. |
| 3986 | - Runtime permission compatibility inputs resolve to one live |
| 3987 | `permission_posture`. Auto-Review can proceed without approval or structured |
| 3988 | question modals, unresolved holds fail closed, and a call planned under stale |
| 3989 | authority is retried after a posture change (PR #5025). |
| 3990 | - Duplicate and drifting per-turn metadata has been removed in favor of |
| 3991 | runtime-owned authority, and large inline account and skill tests now live in |
| 3992 | owned test seams. |
| 3993 | - Pinned Ratatui to 0.30.0 and ratatui-core to 0.1.0. ratatui-core 0.1.1+ |
| 3994 | makes `Terminal::clear()` issue a blocking cursor-position report that |
| 3995 | raced the TUI input loop and could kill first launch; both pins are |
| 3996 | load-bearing, because 0.30.0 declares `ratatui-core ^0.1` and would |
| 3997 | otherwise resolve forward on its own (PR #5192 by @bistack; upstream |
| 3998 | ratatui/ratatui#2640). |
| 3999 | - Updated globset to 0.4.19, clap-complete to 4.6.8, |
| 4000 | futures-util to 0.3.33, libc to 0.2.189, actions/stale to 11.0.0, and |
| 4001 | docker/login-action to 4.5.2. The locked graph also includes the |
| 4002 | event-listener 5.4.2 fix for RUSTSEC-2026-0221. |
| 4003 | - The progress surface now speaks plainly everywhere: the last user-visible |
| 4004 | "Work update is pending" notices say "To-do list", the tool constructor and |
| 4005 | the docs name `todo_write` as the single canonical progress tool, and |
| 4006 | `work_update`, `TodoWrite`, and `todo` stay registered as hidden |
| 4007 | compatibility aliases so saved transcripts keep replaying. |
| 4008 | - Sub-agent and `agents/wait` waits stay short by default and by cap: |
| 4009 | blocking waits default to 30 s and refuse to block past 120 s, because a |
| 4010 | blocked wait deafens the session to typed input and settled children |
| 4011 | already report back as `<codewhale:subagent.done>` sentinels. |
| 4012 | - `Bash` `action=wait` honors `timeout_secs` (seconds) and bare `timeout` |
| 4013 | (milliseconds) alongside canonical `timeout_ms`, and `block` as an alias |
| 4014 | for `wait`, so a habit formed on other wait tools gets the duration it |
| 4015 | asked for instead of silently falling back to the 30 s default; the result |
| 4016 | metadata reports the real `wait_timeout_ms` applied. |
| 4017 | |
| 4018 | ### Fixed |
| 4019 | |
| 4020 | - The memory journal is no longer indexed as memory. It is Markdown in the |
| 4021 | memory tree, so the source walk collected it and every retired note |
| 4022 | re-entered the searchable set under its `before:` line — putting the |
| 4023 | exact facts a revision had just removed back into the prompt. |
| 4024 | - `memory_path` pointed at an already-native store no longer derives a |
| 4025 | second store nested inside it, which silently wrote somewhere other than |
| 4026 | the file the user named. |
| 4027 | - `muse` and `muse-spark` resolved to `muse-spark-1.1` in the agent |
| 4028 | registry while config had defaulted to `muse-spark-1.2`, so the CLI and |
| 4029 | app-server routed those aliases somewhere the configured default never |
| 4030 | pointed. The registry now carries 1.2 and the contributor variant. |
| 4031 | |
| 4032 | - An explicit `type=builder` (or its `implementer` alias) plus |
| 4033 | `write_authority=read_only` now fails closed at spawn instead of launching a |
| 4034 | labeled write role that silently had only read-only tools and then self-BLOCKED |
| 4035 | after burning a turn (#5123). The check is deliberately narrow, because two |
| 4036 | neighbouring combinations are legitimate and stay legal: |
| 4037 | - `type=worker` + `read_only` — worker is the unnamed default (it renders as |
| 4038 | `general`) and takes its capability from authority, not from its name, so a |
| 4039 | read-only worker is an ordinary general-purpose child. Worker, scout, |
| 4040 | reviewer, and verifier remain the four canonical read-only Fleet roles. |
| 4041 | - any `role` + `read_only` — `role` is an identity for roster resolution, not |
| 4042 | a capability claim, so an acceptance Workflow can still resolve |
| 4043 | `implementer` to its saved profile while scoping that child to verification. |
| 4044 | |
| 4045 | Callers that spelled a read-only narrowing as `type: "implementer"` should |
| 4046 | move it to `role: "implementer"`. |
| 4047 | - User-global credentials survive an explicit workspace `CODEWHALE_CONFIG_PATH` |
| 4048 | that selects a route with no local key — readiness probes the user-global |
| 4049 | provider table before concluding a key is missing. |
| 4050 | - Sub-agent token figures on the work bar accumulate input+output (the same |
| 4051 | total the worker budget uses) instead of completion tokens alone; elapsed |
| 4052 | time still freezes when the child settles. |
| 4053 | - Live work-bar rows for sub-agents show how many to-dos they still have |
| 4054 | left (`N left`) when the child's own list has unsettled items — never a |
| 4055 | fabricated zero when no list exists. |
| 4056 | |
| 4057 | - Surfaces no longer claim an OS sandbox on platforms that cannot enforce one. |
| 4058 | The policy resolver takes no platform input, so on default Linux (bubblewrap |
| 4059 | is opt-in) and on all Windows the header chip read `files: workspace` and |
| 4060 | `/status` read `sandbox workspace-write` while nothing was restricted. Both |
| 4061 | now resolve the real backend and say `(unenforced)`. |
| 4062 | - `tool_category` hook conditions matched only retired tool names, so a |
| 4063 | `category = "shell"` **deny** hook — the security control `docs/HOOKS.md` |
| 4064 | documents — silently never fired. Categories now use the registered names, |
| 4065 | and multi-action tools classify by action. |
| 4066 | - A `Retry-After` header of `-5`, `nan`, or `1e300` crashed the request task |
| 4067 | (`Duration::from_secs_f64` panics on a negative). Parsing is now guarded and |
| 4068 | bounded to one hour. |
| 4069 | - Bearer tokens no longer leak into operator-visible receipts. `Authorization: |
| 4070 | Bearer <jwt>` split into two tokens and the JWT matched no redaction rule; |
| 4071 | prefix matching was also case-sensitive, so `SK-live-…` survived. |
| 4072 | - `prune_older_than` destroyed the NEWEST rollback snapshots and kept the old |
| 4073 | ones — on every boot, for any workspace with snapshots spanning the retention |
| 4074 | window. Both prune paths now share one orphan-chain rebuild and preserve each |
| 4075 | survivor's real timestamp. |
| 4076 | - An absolute or relative command path no longer defeats every execpolicy deny |
| 4077 | rule (`/bin/rm -rf /` did not match a `rm -rf /` rule), and a typed `Allow` |
| 4078 | rule no longer auto-approves a chained suffix such as `git log ; curl … | sh`. |
| 4079 | - Wrong types on `File` read range params and `Bash` stdin/cwd/task_id are now |
| 4080 | errors instead of silent defaults — a `start_line:"1200"` string used to |
| 4081 | return the head of the file, and a non-string `stdin` ran the command with no |
| 4082 | stdin and reported success. |
| 4083 | - Multibyte tool ids no longer panic the context inspector, wide (CJK) text no |
| 4084 | longer overflows the decision card, and a hostname like `127.evil.example.com` |
| 4085 | is no longer treated as loopback. |
| 4086 | - Refusals name calls the model can actually make (`rlm action='open'` rather |
| 4087 | than a retired `rlm_open`; `Bash` rather than `exec_shell`). |
| 4088 | |
| 4089 | - Sub-agent dispatch no longer aborts the process. The Tokio runtime was built |
| 4090 | by `#[tokio::main]`, leaving every worker thread on the 2 MiB default while |
| 4091 | only the owner thread received the explicit 16 MiB stack — and the engine runs |
| 4092 | on a worker. A debug-build `agent` dispatch exceeded that stack and raised |
| 4093 | SIGABRT, which is not a panic and so could not be caught; the process died |
| 4094 | mid-spawn with no child request ever issued. Release builds were unaffected. |
| 4095 | - Fleet profiles that pin a provider no longer leak a bare model id onto the |
| 4096 | session route. `model_overrides` exported each role's model while dropping its |
| 4097 | provider, so a scout pinned to another provider's model was dispatched against |
| 4098 | the active client and denied at the wire — visible as an instant auth failure |
| 4099 | on the first sub-agent of a fan-out. |
| 4100 | - The rail's Pinned panel no longer spends four rows saying "No active work". |
| 4101 | An empty panel now collapses like the Tasks panel always has, and the settings |
| 4102 | migration no longer folds the default `sidebar_focus = "auto"` into a pinned |
| 4103 | always-on strip, which had silently handed that panel to every user who had a |
| 4104 | settings file at all. (An *empty* panel collapses; a panel holding settled |
| 4105 | to-dos or finished workers is not empty — see the standing-register entry |
| 4106 | below.) |
| 4107 | - The work bar keeps settled to-dos and an honest Subagents header, while |
| 4108 | completed/cancelled workers collapse out of the Top strip so fan-outs do not |
| 4109 | permanently eat the transcript. Failed or interrupted workers stay visible |
| 4110 | (they still need attention). Settled agents remain reachable through the |
| 4111 | Agents panel and catalog. To-do rows say their state in words (pending / |
| 4112 | in progress / completed / cancelled), and sub-agent rows carry type, |
| 4113 | objective, elapsed, and input+output tokens. Every work row is a door in |
| 4114 | every rail panel and placement: click and Enter open the row's world |
| 4115 | (work inspector / agent details — finished agents included) instead of |
| 4116 | doing nothing. A click after the detail pager closed itself reopens the |
| 4117 | detail rather than being swallowed by a stale toggle. |
| 4118 | - The rail strip yields its rows to the transcript when the terminal cannot |
| 4119 | seat both, so the idle ocean survives at 24 rows instead of being evicted. |
| 4120 | - `code_execution` and `js_execution` no longer describe themselves to the model |
| 4121 | as sandboxed. Both are ordinary local subprocesses with no seccomp, jail, or |
| 4122 | container (PR #5221 by @h3c-hexin and @asto18089). |
| 4123 | - Model Studio reasoning controls now fail closed on the host rather than on the |
| 4124 | provider enum, so a custom `base_url` no longer receives Alibaba-specific |
| 4125 | `enable_thinking` fields, and `qwen3.8-max` is no longer sent a thinking |
| 4126 | switch it does not accept (PR #5233 by @Inference1, closing #5203). |
| 4127 | - `config.example.toml` no longer claims Shift+Tab cycles the reasoning tier. |
| 4128 | Shift+Tab cycles the permission posture; Ctrl+T cycles reasoning |
| 4129 | (found by @vFONGv, PR #5229). |
| 4130 | |
| 4131 | - Alibaba Model Studio reasoning controls are now route- and model-scoped |
| 4132 | instead of provider-wide (#5203, harvested from #5233 by |
| 4133 | [@Inference1](https://github.com/Inference1)). Codewhale sends |
| 4134 | `enable_thinking` / `preserve_thinking` / `reasoning_effort` only when the |
| 4135 | configured `base_url` is a verified Alibaba Chat Completions host, so |
| 4136 | pointing a `modelstudio-*` provider ID at a custom gateway no longer injects |
| 4137 | DashScope's dialect into it. `qwen3.8-max` and `qwen3.8-max-preview` are |
| 4138 | thinking-only and no longer receive an `enable_thinking: false` they cannot |
| 4139 | honor; `preserve_thinking` is sent for the models documented to accept it, so |
| 4140 | their reasoning trace survives into the next turn; and `deepseek-v4*` / |
| 4141 | `glm-5.x` map the reasoning tier onto the documented `high` / `max` ladder. |
| 4142 | |
| 4143 | - xAI device login now recovers from a config that points at a missing |
| 4144 | Codewhale-owned credential generation instead of failing every attempt |
| 4145 | with a generic activation error, and finalize failures report the full |
| 4146 | error chain (#5032). |
| 4147 | - API keys saved to the secret store no longer read as unconfigured for |
| 4148 | providers that are not currently active; a configured Kimi/Moonshot key |
| 4149 | survives provider switches and restarts without re-entry (#5033). |
| 4150 | - Switching to the Codex provider with no saved model now lands on the live |
| 4151 | roster's flagship model instead of a stale static default (#5034). |
| 4152 | - Worktree-isolated Fleet builders no longer contend on the per-workspace |
| 4153 | delegated-coordination lock, and a failed lock acquisition is retried on |
| 4154 | use instead of being memoized for the life of the process (#5036). |
| 4155 | - Fleet dispatch now rebinds the child client when the resolved profile |
| 4156 | model requires a different wire protocol (DeepSeek flash on Responses), |
| 4157 | instead of failing deterministically on the worker's first request |
| 4158 | (#5042). |
| 4159 | - DeepSeek Responses now sends `reasoning.effort: "none"` for the Off tier, |
| 4160 | shows a truthful notice instead of silently discarding server-side |
| 4161 | `web_search_call` items, and parses cache-hit, cache-miss, cache-write, and |
| 4162 | pricing telemetry while retaining the OpenAI-style nested fallback. |
| 4163 | - File edits now explain no-op and missing-search failures, reject newly |
| 4164 | unbalanced C/C++ preprocessor replacements, handle the reported |
| 4165 | CRLF/non-ASCII cases, and safely relocate stale unified-diff hunks only when |
| 4166 | whole-file context is unique (PRs #5008 and #5030). |
| 4167 | - Circled digits, enclosed alphanumerics, and keycap graphemes use consistent |
| 4168 | two-column measurement in Codewhale, Ratatui, and CJK terminals, preventing |
| 4169 | missing-character and phantom-space corruption (PR #5001). |
| 4170 | - SQLite connections install their busy timeout before locking setup and avoid |
| 4171 | rewriting persistent WAL mode on every open, removing the concurrent-open |
| 4172 | release-gate failure. |
| 4173 | - The Windows installer preserves long current-user `PATH` values, their |
| 4174 | registry type, and unrelated entries across install and uninstall (PR #5006). |
| 4175 | - Provider configuration no longer contains user-reachable panic paths when |
| 4176 | metadata or prior credential state is missing. |
| 4177 | - Resuming a session restores composer text only from a same-session persisted |
| 4178 | draft; submitted prompts and internal background-runtime envelopes remain in |
| 4179 | history instead of appearing in the composer (PR #5029). |
| 4180 | - Shared CI now handles bot-authored issue-link checks, provisions cargo-deny's |
| 4181 | toolchain, and fetches the locked test graph before offline runtime-budget |
| 4182 | validation. |
| 4183 | - Re-quote each linker argument in the Windows OpenHarmony clang launcher so a |
| 4184 | spaced SDK path (e.g. the default `D:\DevEco Studio\...` install) keeps its |
| 4185 | `--sysroot` intact through the final Rust link, and extend the no-SDK release |
| 4186 | guard to keep the re-quoting contract (PR #5095). |
| 4187 | |
| 4188 | - The shell tool reports the real elapsed wait time in its result content |
| 4189 | instead of echoing the requested timeout (PR #5240). |
| 4190 | - Transcript wheel scrolling under iTerm2: xterm alternate-scroll (DECSET |
| 4191 | 1007) now stays off while mouse capture is active, so wheel events arrive as |
| 4192 | mouse events instead of being converted into arrow keys (#5223, PR #5234). |
| 4193 | - A stalled model stream no longer ends the turn as `Completed` over a |
| 4194 | frozen reasoning block: a mid-stream chunk-timeout now counts toward the |
| 4195 | stream-error budget, so a stall with nothing streamed retries the request |
| 4196 | transparently, and a stall that exhausts the retry budget fails the turn |
| 4197 | with the real reason instead of reporting success. |
| 4198 | - A finished background shell task now wakes the engine even when no goal is |
| 4199 | active: the idle loop starts an ordinary runtime turn so the completion |
| 4200 | reaches the model immediately instead of sitting unclaimed until the user |
| 4201 | types (a dead provider route claims the completion once and reports where |
| 4202 | the output lives instead of re-arming the same error every tick). |
| 4203 | - Sub-agent final reports that exceed the summary budget are now spilled to |
| 4204 | a session artifact, and the truncation footer names the |
| 4205 | `retrieve_tool_result` ref for the elided middle instead of telling the |
| 4206 | model the bytes are unrecoverable; write failures degrade to the honest |
| 4207 | no-ref footer. |
| 4208 | - An interactive mid-stream network drop after partial output no longer fails |
| 4209 | the turn: the partial reply is preserved as a committed assistant message, |
| 4210 | a runtime continuation message is appended, and the request is re-issued |
| 4211 | bounded by the stream-retry budget. |
| 4212 | - Large pasted input is no longer sent to the model twice as inline text and |
| 4213 | as a backup `.md` paste file; the submitted message now carries only the |
| 4214 | `@`-mention so the model reads the file once. |
| 4215 | - A builder sub-agent can run ordinary shell writes again. Write claims |
| 4216 | outlive the agents that register them, so a workspace accumulated one per |
| 4217 | builder that ever ran — six completed agents left four standing claims in |
| 4218 | testing — and the shared-checkout gate counted those long-finished children |
| 4219 | as live contenders. Every later builder was refused `Bash` writes with |
| 4220 | "cannot prove a bounded file target" and pushed toward worktree isolation, |
| 4221 | which puts the work in a checkout the operator never looks at. The gate now |
| 4222 | asks the question it meant to ask: is another *running* child writing in this |
| 4223 | shared checkout. Concurrent writers are still gated; a lone builder writes in |
| 4224 | the workspace you are actually watching. |
| 4225 | - Ctrl-C during the first moments of startup no longer kills Codewhale |
| 4226 | outright. The terminating-signal handlers were registered inside the task |
| 4227 | that waits on them, and a spawned task does not run until the scheduler |
| 4228 | first polls it, so a SIGINT arriving in that window hit the default |
| 4229 | disposition — the process died with no exit code, no terminal restore, and |
| 4230 | no session record. The handlers are now installed synchronously, before |
| 4231 | the telemetry notice and before arming, so the window is closed. |
| 4232 | - The documented tool list on the docs site named `update_plan` and |
| 4233 | `work_update` as coordination tools. Neither is callable by the model — |
| 4234 | `update_plan` replays older Plan artifacts and `work_update` is a hidden |
| 4235 | compatibility alias — so the page listed two tools a reader cannot use and |
| 4236 | omitted `todo_write`, the one they can. |
| 4237 | |
| 4238 | ### Security |
| 4239 | |
| 4240 | - Bumped `nanoid` past GHSA-2v37-7h3g-55p8 (a custom generator given size |
| 4241 | zero could loop indefinitely), restoring a zero-advisory `npm audit` for |
| 4242 | the website. |
| 4243 | |
| 4244 | - Google Gemini is its own backend (`/provider google`) on the official |
| 4245 | OpenAI-compatible route with thought-signature capture/replay and |
| 4246 | fail-closed replay for thinking models. Antigravity (`agy` 1.1.13) joins |
| 4247 | as a separate credential-plane provider: consent-gated read-only import |
| 4248 | of the official CLI's login with `ANTIGRAVITY_API_KEY`/`AGY_ADC_AUTH` |
| 4249 | precedence; requests fail closed until the cloud-code wire protocol is |
| 4250 | implemented. |
| 4251 | |
| 4252 | ### Removed |
| 4253 | |
| 4254 | - The default model-facing SlopLedger implementation, its storage-oriented |
| 4255 | transcript language, and the `/debt`, `/cleanup`, `/slop`, and `/canzha` |
| 4256 | command surface. |
| 4257 | |
| 4258 | ### Contributors |
| 4259 | |
| 4260 | - [Sh1Zuku](https://github.com/SparkofSpike) (`@SparkofSpike`) contributed |
| 4261 | LaTeX rendering in PR #4981, completed circled-digit/keycap width handling in |
| 4262 | PR #5001, and delivered actionable File-edit recovery in PR #5008; for this |
| 4263 | train he resumed interrupted sub-agents from checkpoints in PR #5242, |
| 4264 | surfaced real shell wait elapsed time in PR #5240, and kept alternate-scroll |
| 4265 | off while mouse capture is active in PR #5234. |
| 4266 | - [XhesicaFrost](https://github.com/XhesicaFrost) (`@XhesicaFrost`) fixed long |
| 4267 | Windows user-PATH preservation in PR #5006. |
| 4268 | - [Paulo Aboim Pinto](https://github.com/aboimpinto) (`@aboimpinto`) added the |
| 4269 | user-command dispatch acceptance contract in PR #4992. |
| 4270 | - [DracheTek](https://github.com/DracheTek) (`@DracheTek`) provided the |
| 4271 | multilingual, CRLF-heavy File-edit failure report in issue #5003. |
| 4272 | - [An Ziwu](https://github.com/MuRongMoQing) (`@MuRongMoQing`) reported the |
| 4273 | Windows PATH-overwrite defect in issue #4685. |
| 4274 | - [shenjackyuanjie](https://github.com/shenjackyuanjie) (`@shenjackyuanjie`) |
| 4275 | fixed the Windows OpenHarmony linker re-quoting for spaced SDK paths in |
| 4276 | PR #5095. |
| 4277 | - [bistack](https://github.com/bistack) (`@bistack`) contributed MCP Registry |
| 4278 | discovery with Registry-first tool selection in PR #5238. |
| 4279 | - [vFONGv](https://github.com/vFONGv) (`@vFONGv`) wrote the zh-CN Windows |
| 4280 | beginner guide with screenshots in PR #5229, harvested after its base branch |
| 4281 | was accidentally deleted during maintainer cleanup. |
| 4282 | - [mky](https://github.com/mky) (`@mky`) fixed the FreeBSD build (PR #5254, `rquickjs` `bindgen` on FreeBSD). |
| 4283 | - [cacdcaecawae](https://github.com/cacdcaecawae) (`@cacdcaecawae`) contributed embedder-owned sub-agent state roots (PR #5252). |
| 4284 | |
| 4285 | ## [0.9.3] - 2026-07-31 |
| 4286 | |
| 4287 | This is the Codewhale v0.9.3 source candidate. It is not a published release |
| 4288 | until the matching tag, packages, checksums, and release assets exist. |
| 4289 | |
| 4290 | DeepSeek V4 Flash is now a first-class Codewhale route, and the agent-facing |
| 4291 | tool surface has been reduced to the canonical action tools that current |
| 4292 | models actually need. This release also hardens credential, authorization, |
| 4293 | durability, compaction, and macOS File Provider boundaries while deleting |
| 4294 | stale runtime and dependency surface. |
| 4295 | |
| 4296 | ### Added |
| 4297 | |
| 4298 | - Native `deepseek-v4-flash` support over DeepSeek's Responses API, including |
| 4299 | stateless reasoning-item replay, semantic SSE terminal events, structured |
| 4300 | function calls and outputs, `apply_patch`, and model-aware wire-format |
| 4301 | selection. Exact current Flash IDs use Responses; future direct |
| 4302 | `deepseek-vN-*` model IDs inherit that route conservatively, while custom |
| 4303 | DeepSeek-compatible endpoints retain Chat Completions unless configured |
| 4304 | otherwise. |
| 4305 | - A pipe-only `codewhale auth print-api-key` handoff for explicitly selected |
| 4306 | providers. It shares Codewhale's home-scoped credential authority, refuses |
| 4307 | terminal output, and prevents sentinel placeholders from becoming live |
| 4308 | credentials. |
| 4309 | - Per-turn `max_tool_calls` enforcement at the engine admission gate, plus a |
| 4310 | named-file write scope with a separate read seam. The runtime now rejects |
| 4311 | over-budget calls before execution and keeps the operator's write boundary |
| 4312 | explicit (#4415). |
| 4313 | - Runtime-contract, source-structure, and persistence-backlog ratchets that |
| 4314 | name drift instead of allowing large ownership surfaces to grow silently |
| 4315 | (#3921, #4785). |
| 4316 | |
| 4317 | ### Changed |
| 4318 | |
| 4319 | - Model-visible built-ins now use the canonical `Bash`, `File`, and `Run` |
| 4320 | action schemas. `apply_patch` remains available as the one direct custom |
| 4321 | edit tool supported by DeepSeek Responses. The bundled stop-ship workflow, |
| 4322 | Fleet fixtures, shell shortcut, and engine tests use the same canonical |
| 4323 | vocabulary. |
| 4324 | - Canonical `File { action: "write" }` requests now pass through the same |
| 4325 | semantic repo-law checks as the former write path. Approval, Full Access, |
| 4326 | and workflow execution cannot bypass the repository safety floor by choosing |
| 4327 | the canonical schema. |
| 4328 | - Codewhale home resolution is shared across the CLI, TUI, state, and secret |
| 4329 | stores. `doctor` is offline by default, distinguishes credential source from |
| 4330 | availability, and reports one consistent path snapshot. |
| 4331 | - Durable runtime event writes are serialized across simultaneous processes, |
| 4332 | blocking history waits move off async workers, and provider quota exhaustion |
| 4333 | remains typed and retryable through compaction (#4522). |
| 4334 | - Skill discovery caches the merged catalog behind watched-mtime validation; |
| 4335 | large skill, engine, subagent, UI, and ambient-ocean test blocks now live in |
| 4336 | owned test seams. |
| 4337 | - Reasoning summaries stay in the user's language, complete jellyfish |
| 4338 | silhouettes relocate around transcript text, and cached ocean frames include |
| 4339 | their palette identity (#4807). |
| 4340 | - The authorization-order contract now documents and tests how modes, hooks, |
| 4341 | permission rules, safety floors, repo law, approvals, and sandboxing compose |
| 4342 | (PR #4980). |
| 4343 | |
| 4344 | ### Fixed |
| 4345 | |
| 4346 | - macOS sandbox extensions cover CloudStorage/File Provider workspaces without |
| 4347 | broadening unrelated paths; thanks @Watcher24 for the #4085 report and |
| 4348 | reproduction. |
| 4349 | - Foreground shell state detaches before steering, so an interrupted command |
| 4350 | cannot keep owning the composer (PR #4979). |
| 4351 | - MCP application-level failures and malformed error envelopes fail closed |
| 4352 | instead of looking like successful tool output. |
| 4353 | - Optional PDF failures are truthful and PDF classification no longer misses |
| 4354 | supported inputs. |
| 4355 | - Bracketed-paste contents are redacted from traces, and credential diagnostics |
| 4356 | never treat placeholder sentinels as usable keys. |
| 4357 | |
| 4358 | - Google Gemini is its own backend (`/provider google`) on the official |
| 4359 | OpenAI-compatible route with thought-signature capture/replay and |
| 4360 | fail-closed replay for thinking models. Antigravity (`agy` 1.1.13) joins |
| 4361 | as a separate credential-plane provider: consent-gated read-only import |
| 4362 | of the official CLI's login with `ANTIGRAVITY_API_KEY`/`AGY_ADC_AUTH` |
| 4363 | precedence; requests fail closed until the cloud-code wire protocol is |
| 4364 | implemented. |
| 4365 | |
| 4366 | ### Removed |
| 4367 | |
| 4368 | - The legacy callable aliases `exec_shell`, `run_shell_command`, `read_file`, |
| 4369 | `write_file`, `list_dir`, `grep_files`, `file_search`, and the duplicate |
| 4370 | Work/RLM registrations. Historical transcript and policy semantics remain |
| 4371 | readable, but new model turns receive only the canonical action surface. |
| 4372 | - The bundled PDF parser dependency chain, replacing it with the smaller |
| 4373 | optional extraction boundary tracked by #4382. |
| 4374 | |
| 4375 | ### Contributors |
| 4376 | |
| 4377 | - [Turisla](https://github.com/greyfreedom) (`@greyfreedom`) documented and |
| 4378 | locked the authorization-order contract in PR #4980. |
| 4379 | - [Nightt](https://github.com/nightt5879) (`@nightt5879`) fixed foreground |
| 4380 | shell detachment before steering in PR #4979. |
| 4381 | - [Watcher24](https://github.com/Watcher24) (`@Watcher24`) provided the macOS |
| 4382 | File Provider report and reproduction for #4085. |
| 4383 | - [Fred Leitz](https://github.com/fleitz) (`@fleitz`) retains required |
| 4384 | source-candidate credit for the canonical `Bash` workspace fix from PR #4673 |
| 4385 | and issue #4674. |
| 4386 | |
| 4387 | ## [0.9.2] - 2026-07-29 |
| 4388 | |
| 4389 | This is the Codewhale v0.9.2 source candidate. It is not a published release |
| 4390 | until the matching tag, packages, checksums, and release assets exist. |
| 4391 | |
| 4392 | ### Changed — behavior |
| 4393 | |
| 4394 | - **Legacy `model = auto` no longer elects a network classifier on its own.** |
| 4395 | Holding a DeepSeek API key used to silently select `deepseek-v4-flash` as the |
| 4396 | classifier for every Auto turn — a per-turn cost on a route nobody asked for, |
| 4397 | and one provider privileged over the rest. Auto now stays local and free |
| 4398 | unless an explicit `[auto.router]` block names a provider and model. |
| 4399 | |
| 4400 | **If you relied on the implicit default**, restore it explicitly: |
| 4401 | |
| 4402 | ```toml |
| 4403 | [auto.router] |
| 4404 | provider = "deepseek" |
| 4405 | model = "deepseek-v4-flash" |
| 4406 | ``` |
| 4407 | |
| 4408 | `[auto.router]` remains legacy `model = auto` configuration. It is unrelated |
| 4409 | to a Fleet's Adaptive Reasoning Router, which is a saved service referenced by |
| 4410 | name from a Fleet file and decides only how hard an already-frozen route |
| 4411 | thinks. |
| 4412 | |
| 4413 | Landed since v0.9.1, not yet released. A cluster of defects found by a |
| 4414 | read-through audit of the policy engine, the MCP proxy, the session index, |
| 4415 | and the app-server bridge — several of them cases where the wrong outcome |
| 4416 | was reached silently, behind a response or a log line that looked fine. The |
| 4417 | release also adds opt-in session, reasoning, localization, and inspectability |
| 4418 | surfaces; existing defaults remain stable unless an entry below explicitly |
| 4419 | says otherwise. |
| 4420 | |
| 4421 | ### Added |
| 4422 | |
| 4423 | - `/permissions` now lists the active user permission-rule source, each rule's |
| 4424 | effective matcher and global/repository scope, and whether that scope applies |
| 4425 | in the current workspace. `/permissions remove <number>` previews deletion |
| 4426 | and requires a snapshot-bound confirmation token, so a concurrent edit |
| 4427 | cannot move a different rule under the confirmed index. Appends and removals |
| 4428 | share one adjacent lock, preserve unrelated TOML formatting and comments, |
| 4429 | atomically replace `permissions.toml`, and reload the live user ruleset |
| 4430 | without clearing session-only approvals. `/config ask-rules` remains a |
| 4431 | compatibility entry; rule creation, glob/directory rules, and deny |
| 4432 | persistence remain out of scope (#1186, PR #4960 by @greyfreedom). |
| 4433 | |
| 4434 | - `/preview-request` (aliases `/dryrun` and `/preview_request`) is a human-only, |
| 4435 | provider-free inspection of the next primary turn. Production dispatch and |
| 4436 | preview share one prepared-request seam across Chat Completions, Anthropic |
| 4437 | Messages, and OpenAI Responses, so the manifest reads the final wire model, |
| 4438 | reasoning controls, tool choice, tool schemas, and body hash from the same |
| 4439 | value production sends. Route, tool, or body facts that require Auto's |
| 4440 | provider classifier, an MCP connection, mutable hooks, compaction, or queued |
| 4441 | runtime injections remain typed unavailable. The manifest reports exact |
| 4442 | primary role/lane identity, upstream route-source provenance, requested and |
| 4443 | effective reasoning, canonical JSON sizes, conservative offline estimates, |
| 4444 | and provider-reported usage as unavailable because no request ran. It never |
| 4445 | adds a model-visible tool, sends a provider call, or prints prompt, message, |
| 4446 | credential, endpoint-path, or workspace-path content. The explicit |
| 4447 | `/preview-request base-prompt` mode prints only the exact effective base |
| 4448 | prompt; effective system text remains protected behind its final hash. The |
| 4449 | exact body includes the same authoritative transient Work/To-do tail used by |
| 4450 | production, including graph-backed state newer than the legacy projection. |
| 4451 | Preflight preserves production's separately framed base-plus-Work estimate, |
| 4452 | and fails closed when the authoritative projection is unavailable. An |
| 4453 | exhausted active goal token budget also produces a typed unavailable result |
| 4454 | before any outbound request is built. |
| 4455 | (#1004, #3928; dry-run concept harvested from PR #1099 by @GTC2080 / TaoMu.) |
| 4456 | |
| 4457 | - Slash commands, hotbar actions, and CLI entrypoints for the same Lane/Fleet |
| 4458 | lifecycle operation now share one typed control-plane contract |
| 4459 | (`codewhale-lane::control`): a stable `<domain>.<verb>` id, read-vs-write |
| 4460 | authority, persistence scope, exact-identity target selection, retryability, |
| 4461 | lifecycle outcome, and one bounded, sanitized receipt. `docs/COMMAND_CONTROL_PLANE.md` |
| 4462 | documents it (#1888). |
| 4463 | |
| 4464 | - `/lane [list|status|interrupt|restart|resume]` — durable Lane control from the |
| 4465 | composer, backed by the same executor `codewhale lane …` calls. `codewhale |
| 4466 | lane interrupt|restart|resume` are the matching CLI verbs; `lane stop` stays as |
| 4467 | a compatibility spelling of `lane interrupt`. Appending `@<lifecycle-seq>` to a |
| 4468 | lane id fences a write to the exact durable generation you observed, so a |
| 4469 | concurrent transition is rejected as a conflict rather than acted on (#1888). |
| 4470 | |
| 4471 | - `codewhale fleet list` and `/fleet [list|status|interrupt|resume]` — durable |
| 4472 | Fleet run inspection and control from either surface, through shared DTOs that |
| 4473 | carry the exact provider, provider-table id, model, effective reasoning tier, |
| 4474 | and route source when the ledger records them, and a typed `not_recorded` / |
| 4475 | `not_applicable` / `redacted` reason when it does not. Requested-vs-effective |
| 4476 | reasoning is never back-filled: the ledger persists the effective tier only, so |
| 4477 | the requested tier reports `not_recorded` (#4022). |
| 4478 | |
| 4479 | - The bundled skill pack now ships a `help` skill (catalog generation 7). It is |
| 4480 | `invocation: explicit-only`, so it never enters the model's ambient catalogue |
| 4481 | and costs no prompt budget. Its body is a routing card that points at the |
| 4482 | surfaces this build actually exposes — `/help` and `/help <command>`, |
| 4483 | `/skills` and `/skills inspect`, `/config`, `doctor`, and the `docs/` tree |
| 4484 | when the workspace is a Codewhale checkout — and explicitly forbids pasting a |
| 4485 | command list or settings table into context (#4698). |
| 4486 | |
| 4487 | - `crates/tui/assets/skills-catalog-matrix.json`: an authored, provider-free |
| 4488 | expectation matrix covering every bundled skill (tier, invocation, aliases, |
| 4489 | ambient-catalogue eligibility, shadowed aliases). Contract tests in |
| 4490 | `crates/tui/src/skills/catalog_matrix.rs` assert a bijection between the |
| 4491 | fixture and the shipped bundle, so the starter pack cannot change without an |
| 4492 | explicit fixture update. The matrix covers positive eligibility and explicit |
| 4493 | load, non-activation negatives, alias resolution, explicit-only exclusion, |
| 4494 | alias-vs-canonical collision precedence, and prompt-budget invariants (no |
| 4495 | duplicate catalogue entries, no aliases as extra entries, and the shipped |
| 4496 | pack fitting inside the 12 000-char budget with no omitted-skills line). These |
| 4497 | are deterministic registry/catalog/resolver assertions and make no claim about |
| 4498 | semantic model routing (#4698). |
| 4499 | |
| 4500 | - Locale-routing coverage for the complete bundled catalog across every shipped |
| 4501 | locale (`en`, `ja`, `zh-Hans`, `zh-Hant`, `pt-BR`, `es-419`, `vi`, `ko`). No |
| 4502 | bundled skill ships a localized routing description and none was invented; |
| 4503 | the tested contract is deterministic fallback to the canonical English |
| 4504 | description, with the rendered catalogue byte-identical across locales. |
| 4505 | Exact-tag match, primary-subtag fallback, and English fallback are covered |
| 4506 | against a synthetic authored fixture, and the parity test fails if a bundled |
| 4507 | skill ever gains localized metadata without source-backed coverage (#4698). |
| 4508 | |
| 4509 | - `docs/LIVE_SMOKE.md`: copy-pasteable, opt-in live-smoke instructions for Kimi |
| 4510 | K3 and a second provider/model (DeepSeek). The runs are manual only — nothing |
| 4511 | in CI, tests, or skills invokes them. They use `env -i` plus a throwaway |
| 4512 | `CODEWHALE_HOME`; `HOME` is left unset rather than repurposed, and ambient |
| 4513 | provider variables are not forwarded. The operator names the credential |
| 4514 | variable explicitly, and the isolated child reads its value with echo off, |
| 4515 | restores the prior terminal state on exit or interruption, and never persists |
| 4516 | the value or puts it in a command argument. The page states the expected |
| 4517 | route/model/reasoning/tool receipt fields while treating provider errors as |
| 4518 | unclassified until provider configuration, authentication/entitlement, and |
| 4519 | harness behavior have been corroborated independently (#4698). |
| 4520 | |
| 4521 | - Approval cards can now remember eligible safe shell and file-write approvals |
| 4522 | as exact `allow` rules scoped to the current repository. Remembered shell |
| 4523 | commands use complete-command matching, validated file and patch paths remain |
| 4524 | workspace-relative, and dangerous, critical, or repo-law-held requests stay |
| 4525 | ineligible and continue to require review. |
| 4526 | |
| 4527 | - `tui.header_items` (array of strings, optional, default `[]`): an opt-in |
| 4528 | header chip showing cumulative session token usage as input / cache-hit / |
| 4529 | output. Set `header_items = ["tokens"]` under `[tui]` to enable it. The |
| 4530 | chip is the only elidable element of the header — the git label, context |
| 4531 | meter, and version stamp keep their space, and narrow terminals drop the |
| 4532 | chip rather than the baseline chrome. Unknown entries are warned about and |
| 4533 | skipped so configs written by newer builds stay loadable by older ones |
| 4534 | (#4520 requested by @eugenicum; PR #4610 by @XhesicaFrost, harvested with |
| 4535 | co-authorship). |
| 4536 | |
| 4537 | - `thinking_default_expanded` lets reasoning blocks start open while keeping |
| 4538 | Space as the per-block toggle. The setting is persisted, available through |
| 4539 | native and runtime configuration, and documented for SSH/tmux accessibility |
| 4540 | (issue #4925 and PR #4928 by @M-Maciej). |
| 4541 | |
| 4542 | - The transcript renders a conservative subset of LaTeX math as readable |
| 4543 | Unicode without rewriting fenced/inline code, ordinary currency, escaped |
| 4544 | dollars, or unknown commands. The contribution from PR #4973 by |
| 4545 | @SparkofSpike was hardened and landed through PR #4974; reported by |
| 4546 | @antarikshraya in #4957. |
| 4547 | |
| 4548 | - Session control now includes a sessions rail, shared archive projection, |
| 4549 | picker archive controls, and opt-in interactive auto-resume with explicit |
| 4550 | handoff behavior. The work closes the remaining session-browsing direction |
| 4551 | from #2934; thanks @cy2311 for the original report. |
| 4552 | |
| 4553 | - The bundled contributor-onboarding skill can sync contribution context, |
| 4554 | select the appropriate gate, and prepare a digest without inflating the |
| 4555 | ambient skill catalog. It follows the contributor-navigation request in |
| 4556 | #4227 by @JayBeest. |
| 4557 | |
| 4558 | - Bahasa Indonesia now has a complete repository documentation suite and a |
| 4559 | registered website dictionary alongside the shipped TUI locale (PRs #4962 |
| 4560 | and #4972 by @atmosuwiryo, closing #4789). |
| 4561 | |
| 4562 | - Reasoning content can keep its rail, italics, cursor, and expansion controls |
| 4563 | while disabling only the warm background highlight. The independent setting |
| 4564 | is persisted and localized (#4089; reported by @elijahchan2019). |
| 4565 | |
| 4566 | - StepFun setup now asks whether a key belongs to PAYG or Step Plan, keeps the |
| 4567 | two endpoint/billing routes distinct, and localizes the choice across the |
| 4568 | complete packs (#4526; reported by @whp233). |
| 4569 | |
| 4570 | - OpenCode Zen is a separate model-aware API-key provider. Its curated catalog |
| 4571 | selects Responses, Anthropic Messages, or Chat Completions per model; |
| 4572 | unsupported Gemini and unknown models fail closed, and missing Zen |
| 4573 | credentials never fall through to ChatGPT/Codex OAuth guidance. The |
| 4574 | implementation from closed PR #4467 by @snail-vs (snailoniu) is preserved in |
| 4575 | the candidate. |
| 4576 | |
| 4577 | - Markdown exports correlate prompts with stable workspace restore-point ids |
| 4578 | and say when correlation is unavailable or ambiguous, completing the |
| 4579 | remaining restoration/export direction from #2494 by @wywsoor. |
| 4580 | |
| 4581 | ### Fixed |
| 4582 | |
| 4583 | - Permission setup now consistently presents the product postures Ask, |
| 4584 | Auto-Review, and Full Access instead of leaking the internal `never` token. |
| 4585 | The same resolved sandbox policy now drives execution and UI receipts: Plan |
| 4586 | stays read-only, Ask and Auto-Review stay workspace-scoped, and Full Access |
| 4587 | is actually unsandboxed unless a stricter effective configuration wins. |
| 4588 | |
| 4589 | - Fleet setup no longer stalls when a user explicitly selects a configured |
| 4590 | Codex or Grok external-consent route. The selected route is activated and |
| 4591 | validated before saving, roster roles open directly on their Model step, |
| 4592 | Review saves on the first Enter, and new profiles default to the personal |
| 4593 | profile directory that the roster loads on the next session. |
| 4594 | |
| 4595 | - Provider credential dialogs now share one wrapping, secret-safe API-key |
| 4596 | surface across every non-OAuth provider. A key already present in durable |
| 4597 | storage is reported as configured without rendering it, typing or pasting is |
| 4598 | clearly framed as replacement, narrow help text remains visible, and Codex |
| 4599 | and Grok OAuth flows remain token-free in this modal. |
| 4600 | |
| 4601 | - Ctrl+O again opens the complete recorded reasoning detail for the selected, |
| 4602 | active, or latest reasoning block. The whole-turn Turn Inspector moved to |
| 4603 | Ctrl+Alt+O and `/turn inspect`, removing the shortcut collision while keeping |
| 4604 | raw leaf detail and post-flush reasoning discoverable. |
| 4605 | |
| 4606 | - Failed child agents now deliver a distinct high-priority failure receipt to |
| 4607 | their owning parent with a sanitized failure class, elapsed work, and a full |
| 4608 | transcript handle. Parent-to-child message, follow-up, and interrupt tools |
| 4609 | now use one hierarchy-checked mailbox path, and persisted nested completion |
| 4610 | envelopes remain safely restorable across instruction-text revisions. |
| 4611 | |
| 4612 | - Background-shell completion events now carry only bounded tails plus a |
| 4613 | retrievable exact-evidence handle. Terminal foreground Bash results are |
| 4614 | acknowledged at the direct tool-result boundary and are no longer emitted a |
| 4615 | second time as background completion artifacts. |
| 4616 | |
| 4617 | - Providerless Fleet and child-agent fixed-model routes now reject only |
| 4618 | high-confidence foreign-provider model ids before creating a worktree, while |
| 4619 | explicit provider/model pairs, custom and local endpoints, unknown ids, and |
| 4620 | aggregator wire-id resolution retain their intended behavior. |
| 4621 | |
| 4622 | - Manual compaction now preserves and reports the supplied provider failure |
| 4623 | class instead of replacing it with an opaque generic error. This does not |
| 4624 | infer quota exhaustion when the recorded failure does not prove it. |
| 4625 | |
| 4626 | - The ambient jellyfish keep complete, readable silhouettes while animating, |
| 4627 | and the website favicon now uses the Signal Current desktop tile instead of |
| 4628 | the legacy whale mark. |
| 4629 | |
| 4630 | - ACP JSON-RPC responses preserve numeric request ids for avante.nvim while |
| 4631 | retaining the negotiated string-id exception for Zed (PR #4929 by |
| 4632 | @atmosuwiryo). |
| 4633 | |
| 4634 | - Restored shell cells whose job no longer exists stop displaying live |
| 4635 | spinners and settle into a truthful stale/no-output state across transcript, |
| 4636 | phase strip, and sidebar (PR #4937 by @LI-Jialu, closing #4547). |
| 4637 | |
| 4638 | - Interrupted checkpoints and timed recovery snapshots remain checkpoints |
| 4639 | instead of being promoted into orphan session files, preventing duplicate |
| 4640 | `/resume` entries (PR #4963 by @SparkofSpike). |
| 4641 | |
| 4642 | - Every shipped locale is admitted by the typed settings schema and native |
| 4643 | chooser, with complete/partial status kept independent and tested (PR #4856 |
| 4644 | by @nightt5879, closing #4786). Context-menu hover hit-testing also accounts |
| 4645 | for its title row (PR #4897 by @XhesicaFrost; reported by @SparkofSpike in |
| 4646 | #4803). |
| 4647 | |
| 4648 | - OSC 52 and SSH/tmux clipboard transport run on one bounded background worker |
| 4649 | rather than blocking input and rendering on the TUI loop; late transport |
| 4650 | failures still surface through the status path (PR #4896 by @nightt5879, |
| 4651 | closing #4159). |
| 4652 | |
| 4653 | - Non-streaming model calls receive a generation-length response budget rather |
| 4654 | than the SSE header-open timeout, while actual SSE opens share the bounded |
| 4655 | cross-provider transport seam. The equivalent fix direction came from |
| 4656 | closed PR #4743 by @vibecoding-skills. |
| 4657 | |
| 4658 | - Resumed sessions diagnose a deleted inherited workspace before shell launch |
| 4659 | instead of failing as an opaque Windows process error (report #4100 by |
| 4660 | @redjade75723). DeepSeek native tool-call wrapper tokens are also scrubbed |
| 4661 | from visible streaming and completed output as a grounded fail-soft follow-up |
| 4662 | to report #3880 by @hardy922; that report's exact emitted marker remained |
| 4663 | unconfirmed. |
| 4664 | |
| 4665 | - Auto model routing now preserves the user's requested reasoning effort |
| 4666 | through startup, provider/model changes, session restore, the picker, |
| 4667 | Ctrl+T, and Hotbar actions. The tier is normalized only after the concrete |
| 4668 | provider route is known instead of being silently replaced by Auto |
| 4669 | (#4941, PR #4961 by @nightt5879). |
| 4670 | |
| 4671 | - Auto-compaction now defaults on for every known model context window, |
| 4672 | including Kimi K3's 1,048,576-token routes. Persisting only an |
| 4673 | `auto_compact_threshold` or `auto_compact_threshold_percent` now counts as |
| 4674 | opt-in intent, while an explicit `auto_compact = false` remains authoritative. |
| 4675 | `/config` reports the effective state, percentage, and computed token trigger. |
| 4676 | |
| 4677 | - Per-provider `context_window` overrides are now documented and visible in |
| 4678 | `/config`, provider setup help, diagnostics, and the example configuration. |
| 4679 | The effective override consistently drives preflight budgeting, the context |
| 4680 | meter, and compaction; this lets a user cap a 1M Kimi route to 256K when their |
| 4681 | Coding Plan tier has the smaller window. |
| 4682 | |
| 4683 | - Agent Details now projects status, model, elapsed time, and step counts from |
| 4684 | the same row snapshot as the primary agents list, eliminating contradictory |
| 4685 | worker state between the two surfaces. |
| 4686 | |
| 4687 | - Composer submission and its hints now share one state machine. Portable |
| 4688 | terminals use Enter to queue during a running turn and Enter again to steer; |
| 4689 | Ctrl/Cmd+Enter is accepted only when an enhanced terminal reports it and is |
| 4690 | no longer advertised as universally available. |
| 4691 | |
| 4692 | - `edit_file` now matches LF-only model search text against CRLF files, |
| 4693 | preserves the file's line-ending style for replacement text, and still |
| 4694 | rejects newline-normalized duplicate matches as non-unique (#4764). |
| 4695 | Implemented in PR #4942 by @nightt5879; reported and root-caused by |
| 4696 | @LmeSzinc. |
| 4697 | |
| 4698 | - `/fleet status` read the current TUI session's sub-agents while `codewhale |
| 4699 | fleet status` read the durable `.codewhale/fleet.jsonl` ledger — two different |
| 4700 | things wearing one name, so a run started by `codewhale fleet run` never |
| 4701 | appeared in the TUI. `/fleet status` now reads the durable ledger through the |
| 4702 | same code path as the CLI; the session view keeps its own name as |
| 4703 | `/fleet workers` (`/subagents` and `n` still work). When a workspace has no |
| 4704 | ledger, both surfaces report a typed `no_fleet_ledger` reason instead of an |
| 4705 | empty-looking "all clear", and neither creates the ledger as a side effect of |
| 4706 | reading it (#4022). |
| 4707 | |
| 4708 | - `codewhale fleet status` (and `list`/`interrupt`/`resume`) created |
| 4709 | `.codewhale/fleet.jsonl` as a side effect of opening the manager, then |
| 4710 | reported `no_fleet_ledger` for the file it had just made — so the second |
| 4711 | invocation showed an empty Fleet where none existed. The CLI now refuses |
| 4712 | those verbs before the manager is constructed, matching `/fleet` (#4022). |
| 4713 | |
| 4714 | - `fleet resume <run-id>` accepted any string. An id absent from the ledger |
| 4715 | reconciled nothing but still wrote a run-status record keyed by whatever was |
| 4716 | typed, and reported `no_change`. Unknown ids are now refused as `not_found` |
| 4717 | before any durable write (#4022). |
| 4718 | |
| 4719 | - `lane interrupt` reported `transitioned` even when it changed nothing — |
| 4720 | another process's stop looked like our own. The Runtime backend now reports |
| 4721 | whether *this* call performed the transition, and a no-op is `no_change`. |
| 4722 | The `@<lifecycle-seq>` fence is also evaluated inside the registry's per-Lane |
| 4723 | lock rather than before it, so a stale fence refuses without running Runtime |
| 4724 | teardown instead of racing between the check and the stop (#1888). |
| 4725 | |
| 4726 | - `/lane` no longer runs Runtime teardown on the TUI composer thread. Reads on |
| 4727 | the slash surface skip reconciliation (which probes tmux and takes a lock) |
| 4728 | and say so on the receipt instead of implying freshness; `lane interrupt` is |
| 4729 | CLI-only until that work runs off-thread, and reports |
| 4730 | `surface_not_supported` naming `codewhale lane interrupt` (#4022). |
| 4731 | |
| 4732 | - The hotbar is no longer modelled as a third control surface. A slot binds a |
| 4733 | slash command and fires it with no argument, so it runs *as* the slash |
| 4734 | surface; the contract now declares which verb a bare press actually reaches |
| 4735 | (`hotbar_bare_dispatch`, true only for `lane.list`) instead of advertising |
| 4736 | target-taking verbs as hotbar-reachable (#1888). |
| 4737 | |
| 4738 | - `codewhale lane list --json` and `lane status --json` keep emitting the |
| 4739 | `LaneRecord` shape they always have — the receipt did not replace it. The |
| 4740 | human `lane status` output also regained `branch`, `session`, `socket`, |
| 4741 | `attach`, and `log`, which the first cut of the shared DTO had dropped |
| 4742 | (#1888). |
| 4743 | |
| 4744 | - No surface advertises a backend it does not have. `lane restart` and |
| 4745 | `lane resume` have no implementation — a Lane is re-created by |
| 4746 | `codewhale lane start`, and a stopped Lane's Runtime session is gone — so all |
| 4747 | three surfaces refuse them with `backend_not_implemented` and say why. |
| 4748 | `fleet restart` drives the manager loop to completion, which only the CLI |
| 4749 | runs, so `/fleet restart` reports `surface_not_supported` and names the CLI |
| 4750 | command rather than quietly doing a smaller thing (#1888). |
| 4751 | |
| 4752 | - Deny rules in `permissions.toml` no longer miss a command because of an |
| 4753 | intervening flag: deny matching is token-based with flag-skipping and |
| 4754 | backtracking, so a `git push` rule still catches |
| 4755 | `git -c foo=bar push`. Path matching folds case only on platforms whose |
| 4756 | filesystems are case-insensitive, and the default approval branch no |
| 4757 | longer proposes the working directory as a network host. |
| 4758 | |
| 4759 | - MCP tool calls run once. A failed call is no longer retried as if it |
| 4760 | were a failed lookup, qualified-name resolution collects every match and |
| 4761 | reports an ambiguity instead of taking whichever the hash map yielded |
| 4762 | first, and registering a server whose name collides with an existing one |
| 4763 | after sanitization is now an error rather than a silent overwrite. |
| 4764 | The equivalent call-once fix direction came from closed PR #4756 by |
| 4765 | @adity982. |
| 4766 | |
| 4767 | - The session index survives a torn line: an unparseable entry is skipped |
| 4768 | rather than aborting the whole read, appends carry their data through to |
| 4769 | disk, and appends and compaction share a lock so a compaction can no |
| 4770 | longer race an append into a lost record. |
| 4771 | |
| 4772 | - `Edit` counts as a write tool for workflow elevation, and the TUI's |
| 4773 | write/shell classification now delegates to one shared allowlist rather |
| 4774 | than keeping a second copy that could drift. |
| 4775 | |
| 4776 | - A rejected `app/config/set` stays a no-op. Previously an invalid value |
| 4777 | still tore down the cached runtime bridge, killing the child runtime and |
| 4778 | orphaning every other in-flight stdio thread behind a response that |
| 4779 | correctly reported failure. |
| 4780 | |
| 4781 | - A malformed project `config.toml` is no longer indistinguishable from |
| 4782 | having no project config. Because a project config may only *tighten* |
| 4783 | approval and sandbox policy, silently discarding a broken one dropped a |
| 4784 | repository's restrictions back to the looser user defaults; the setup |
| 4785 | wizard now says so, naming the file but never quoting its contents. |
| 4786 | |
| 4787 | - An expired lane worktree no longer leaves its branch behind, which made |
| 4788 | reusing the same lane name fail with "branch already exists". A branch |
| 4789 | still carrying unmerged commits is kept — a TTL lapsing is not consent |
| 4790 | to delete someone's work. |
| 4791 | |
| 4792 | - An in-flight `thread/message` turn can be stopped. The stdio loop keeps |
| 4793 | reading while a turn streams, so the new `thread/interrupt` request (and |
| 4794 | `shutdown`) can reach a runaway turn instead of waiting on the very turn |
| 4795 | they were meant to stop. |
| 4796 | |
| 4797 | - Precedence is stated only in the constitution's "Whose word wins" section. |
| 4798 | Memory hygiene no longer ships an inverted Tier list that put the |
| 4799 | constitution above the user's current request; approval, compaction, and |
| 4800 | personality overlays describe behavior without rank vocabulary; and the |
| 4801 | authority recap points at the single source rather than restating a second |
| 4802 | ladder. |
| 4803 | |
| 4804 | - `<turn_meta>` carries facts (mode, posture, model, workspace), not mode |
| 4805 | doctrine or permission-question essays re-asserted every user message. |
| 4806 | |
| 4807 | - The project context pack (pretty-printed workspace tree) is off by default |
| 4808 | and opt-in via `[context] project_pack = true`. Language law is compressed |
| 4809 | while keeping the English-constitution / user-language-reply contract. |
| 4810 | |
| 4811 | - Modal lists and config pickers wrap selection at both ends (Down past the |
| 4812 | last row returns to the top). Home-directory resolution prefers |
| 4813 | `HOME`/`USERPROFILE` via `effective_home_dir` across remaining call sites so |
| 4814 | Windows tests that fake the home env vars match production paths. The |
| 4815 | equivalent home-directory sweep came from closed PR #4760 by |
| 4816 | @EvanProgramming. |
| 4817 | |
| 4818 | ### Changed |
| 4819 | |
| 4820 | - Prefix-cache tool catalog entries store only the SHA-256 digest, not the |
| 4821 | joined catalog string. Unused plan-transition validation helpers are removed. |
| 4822 | |
| 4823 | - Settings sections now hold only what they claim (#4751). Fleet keeps |
| 4824 | Fleet/member concerns; `/goal` moved to a **Session** section and Workflow |
| 4825 | orchestration to its own **Workflow** section. The inert DeepSeek-only |
| 4826 | `default_model` fallback moved out of Model settings into an explicit |
| 4827 | **Legacy** section — exact-Fleet users switch Fleets, not fallback models; |
| 4828 | the config field is retained because the runtime still reads it. This is |
| 4829 | presentation only: the persisted keys (`goal_command`, `workflow`, |
| 4830 | `default_model`), their values, scopes, and runtime behavior are unchanged. |
| 4831 | |
| 4832 | - Auto model routing is scoped to the active provider. The classifier |
| 4833 | inventory no longer discloses other providers' runnable routes (or the fact |
| 4834 | that their credentials exist), a classifier reply naming another provider is |
| 4835 | refused, the local heuristic no longer falls back to a different provider |
| 4836 | when the active one is unusable, and the implicit DeepSeek-flash classifier |
| 4837 | is skipped for non-DeepSeek sessions. Auto receipts and the model picker |
| 4838 | hint report the active-provider-only scope instead of "runnable providers". |
| 4839 | Cross-provider Auto is available only through the persisted `[auto] |
| 4840 | cross_provider = true` opt-in (an explicit `[auto.router]` route remains its |
| 4841 | own opt-in for the classifier call). Same-provider strong/fast selection and |
| 4842 | `[auto] cost_saving` are unchanged. |
| 4843 | |
| 4844 | - The QA pseudo-terminal acceptance harness now parses frames with `rio-vt` |
| 4845 | behind its existing neutral frame/color surface, retaining the assertions |
| 4846 | while removing the `vt100` dependency (PR #4931 by @raphamorim). |
| 4847 | |
| 4848 | - Anthropic Messages and OpenAI Responses stream opening now share the |
| 4849 | `client/stream_entry.rs` seam already used by Chat Completions: one bounded |
| 4850 | response-header wait, shared dual/HTTP-1.1 policy selection, at most one |
| 4851 | HTTP/1.1 fallback on a classified HTTP/2 header stall, and common idle-timeout |
| 4852 | diagnostics. Wire-specific authentication, headers, endpoints, decoding, and |
| 4853 | rate-limit behavior remain at each adapter edge. The timeout-placement |
| 4854 | diagnosis and fix direction came from closed PR #4743 by |
| 4855 | @vibecoding-skills. |
| 4856 | |
| 4857 | ### Security |
| 4858 | |
| 4859 | - Release containers now publish an SBOM attestation and pin maximum-mode |
| 4860 | provenance explicitly so supply-chain metadata cannot silently weaken with a |
| 4861 | builder-default change (PR #4958 by @kobihikri). |
| 4862 | |
| 4863 | ### Contributors |
| 4864 | |
| 4865 | Thank you to the contributors whose code, reports, and reviews shaped v0.9.2: |
| 4866 | |
| 4867 | - [@greyfreedom](https://github.com/greyfreedom) — exact repository-scoped |
| 4868 | allow grants and cross-platform path semantics (PR #4761), plus safe |
| 4869 | permission-rule listing and snapshot-bound removal (PR #4960). |
| 4870 | - [@nightt5879](https://github.com/nightt5879) — off-event-loop clipboard |
| 4871 | writes (PR #4896), complete locale exposure in settings (PR #4856), CRLF-safe |
| 4872 | edits (PR #4942), and reasoning-effort preservation across automatic model |
| 4873 | routing (PR #4961). |
| 4874 | - [@XhesicaFrost](https://github.com/XhesicaFrost) — the configurable |
| 4875 | session-token header (PR #4610) and context-menu hover alignment (PR #4897). |
| 4876 | - [@cyq1017](https://github.com/cyq1017) — the hooks configuration/executor |
| 4877 | split from PR #4087. |
| 4878 | - [@snail-vs](https://github.com/snail-vs) (snailoniu) — OpenCode Zen's |
| 4879 | model-aware routes, authentication, documentation, and test isolation from |
| 4880 | closed PR #4467, whose contributor commits are preserved in the candidate. |
| 4881 | - [@SparkofSpike](https://github.com/SparkofSpike) — the zh-Hans translation |
| 4882 | quality review harvested from PR #4908, duplicate-session fix in PR #4963, |
| 4883 | LaTeX implementation from PR #4973 landed through #4974, and the context-menu |
| 4884 | reproduction in #4803. |
| 4885 | - [@GTC2080](https://github.com/GTC2080) — the request-preview concept from |
| 4886 | PR #1099. |
| 4887 | - [@h3c-hexin](https://github.com/h3c-hexin) — non-UTF-8 `fetch_url` |
| 4888 | decoding direction from PR #4909. |
| 4889 | - [@fleitz](https://github.com/fleitz) — required source-candidate credit for |
| 4890 | the canonical `Bash` no-`cwd` workspace fix and regression in PR #4673 |
| 4891 | (issue #4674). |
| 4892 | - [@LmeSzinc](https://github.com/LmeSzinc) — the Windows CRLF `edit_file` |
| 4893 | reproduction, root-cause analysis, and affected-code anchors in issue #4764. |
| 4894 | - [@atmosuwiryo](https://github.com/atmosuwiryo) — ACP numeric-id compatibility |
| 4895 | (PR #4929) and the Indonesian documentation and website locale (PRs #4962 |
| 4896 | and #4972). |
| 4897 | - [@M-Maciej](https://github.com/M-Maciej) — the expanded-by-default reasoning |
| 4898 | setting and its original report (PR #4928, issue #4925). |
| 4899 | - [@raphamorim](https://github.com/raphamorim) — migration of the QA PTY frame |
| 4900 | parser to `rio-vt` (PR #4931). |
| 4901 | - [@LI-Jialu](https://github.com/LI-Jialu) — truthful finalization of restored |
| 4902 | stale shell cells (PR #4937). |
| 4903 | - [@kobihikri](https://github.com/kobihikri) — release-container SBOM and |
| 4904 | explicit provenance mode (PR #4958). |
| 4905 | - [@EvanProgramming](https://github.com/EvanProgramming), |
| 4906 | [@adity982](https://github.com/adity982), and |
| 4907 | [@vibecoding-skills](https://github.com/vibecoding-skills) — equivalent fix |
| 4908 | direction for the effective-home sweep (#4760), MCP call-once behavior |
| 4909 | (#4756), and streaming/non-streaming timeout split (#4743). |
| 4910 | - [@antarikshraya](https://github.com/antarikshraya) — the LaTeX transcript |
| 4911 | rendering report in #4957. |
| 4912 | - [@eugenicum](https://github.com/eugenicum) — the token-header request and |
| 4913 | output-presentation measurements in #4520 and #4468. |
| 4914 | - [@whp233](https://github.com/whp233) — the StepFun/OpenCode subscription-route |
| 4915 | request in #4526. |
| 4916 | - [@redjade75723](https://github.com/redjade75723), |
| 4917 | [@hardy922](https://github.com/hardy922), |
| 4918 | [@JayBeest](https://github.com/JayBeest), |
| 4919 | [@elijahchan2019](https://github.com/elijahchan2019), |
| 4920 | [@cy2311](https://github.com/cy2311), and |
| 4921 | [@wywsoor](https://github.com/wywsoor) — reports and product direction behind |
| 4922 | the stale-workspace diagnosis (#4100), native-tool-token filtering (#3880), |
| 4923 | contributor onboarding (#4227), optional reasoning highlight (#4089), |
| 4924 | session control (#2934), and export/restore correlation (#2494). |
| 4925 | |
| 4926 | ## [0.9.1] - 2026-07-24 |
| 4927 | |
| 4928 | ### Dogfood follow-ups (2026-07-24) |
| 4929 | |
| 4930 | ### Added |
| 4931 | |
| 4932 | - `/compact [focus]`: the manual compaction command now accepts an |
| 4933 | optional focus argument that is injected into the summary prompt, and |
| 4934 | the compaction summary itself becomes a structured nine-section |
| 4935 | successor briefing (primary intent, key concepts, files and code, |
| 4936 | errors and fixes, problem solving, user messages, pending tasks, |
| 4937 | current work, next step) that carries earlier compaction summaries |
| 4938 | forward and explicitly forbids tool use — replacing the free-form |
| 4939 | "under N words" instruction. Codewhale's pin/working-set and |
| 4940 | V4 prefix-cache-aligned machinery are unchanged. |
| 4941 | |
| 4942 | - Saved workflows become slash commands: `*.workflow.js` files under |
| 4943 | `<workspace>/.codewhale/workflows/` and `~/.codewhale/workflows/` are |
| 4944 | discovered as `/name` commands that accept custom arguments (forwarded |
| 4945 | to the run's `args`), launch through the `workflow` tool in the |
| 4946 | background, and report their run id. Hand-written `.md` commands with |
| 4947 | the same name always win. The workflow tool's `source_path` now also |
| 4948 | accepts the user-global `~/.codewhale/workflows/` store, and every |
| 4949 | settled run leaves a durable synthesized report under |
| 4950 | `.codewhale/reports/<run_id>.md` (status, goal, gates, progress, |
| 4951 | result, verification). |
| 4952 | |
| 4953 | ### Fixed |
| 4954 | |
| 4955 | - Disambiguate the two Kimi K3 model-picker rows, which read as an |
| 4956 | unexplained duplicate: bare `k3` is now labeled "Kimi Code plan route" |
| 4957 | with its default 262K window annotated as the plan-tier floor (raisable |
| 4958 | via the provider `context_window` setting for plans that include 1M), |
| 4959 | and `kimi-k3` is labeled "Moonshot direct route" with its 1M window. |
| 4960 | Both remain distinct, valid routes for the same underlying model. |
| 4961 | - Close the model-facing `agent` tool role schema: the `type` property now |
| 4962 | publishes the canonical JSON Schema enum `["worker", "scout", "planner", |
| 4963 | "reviewer", "builder", "verifier", "custom"]` instead of describing the |
| 4964 | accepted values in prose. Legacy aliases are no longer advertised to |
| 4965 | models; they remain accepted only at replay/deserialization boundaries. |
| 4966 | Provider schema sanitizers (Chat Completions, strict mode, Anthropic |
| 4967 | Messages / OpenAI Responses, Moonshot/Kimi) are pinned by test to |
| 4968 | preserve the closed enum. |
| 4969 | |
| 4970 | ### Changed |
| 4971 | |
| 4972 | - Rework the ambient idle ocean: the water now holds exactly one loose |
| 4973 | wedge school of fish, jellyfish, bubbles, and the rare whale cameo — |
| 4974 | seaweed and bio-dust are removed. Fish swim on a wrap-around path and |
| 4975 | always face the way they move (direction can only change while the |
| 4976 | school is off-screen); the lead fish carries an eye (`><o>`). |
| 4977 | Jellyfish become a pulsing bell with a lagging swaying tentacle. All |
| 4978 | ambient marks now glow via background→ink color lerp: a travelling |
| 4979 | sin² wave through the school, a floor-bounded pulse for jellyfish, |
| 4980 | and occasional raised-cosine glints on bubbles, with deliberately |
| 4981 | non-matching periods so nothing strobes in sync. |
| 4982 | |
| 4983 | - Rename the internal delegated-worker role type from `SubAgentType` to |
| 4984 | `FleetRole` with canonical variants (`Worker`, `Scout`, `Planner`, |
| 4985 | `Reviewer`, `Builder`, `Verifier`, `Custom`) matching the public Fleet |
| 4986 | vocabulary one-to-one. Wire behavior is unchanged: serialization emits |
| 4987 | canonical Fleet values only, and persisted `agent_type` fields plus |
| 4988 | documented legacy spellings (`general`, `explore`, `plan`, `review`, |
| 4989 | `implementer`, …) continue to load at deserialization/parse boundaries; |
| 4990 | unknown role tokens still fail closed with the canonical vocabulary in |
| 4991 | the error. |
| 4992 | |
| 4993 | |
| 4994 | The Codewhale v0.9.1 source candidate includes a first-class local web client over the Runtime API, |
| 4995 | first-class OpenCode Go and TelecomJS TokenHub providers and restored xAI device login, |
| 4996 | calendar-correct hourly automations, a buildable OpenHarmony workflow-js |
| 4997 | target, and hardening for Auto routing, remote-terminal clipboard transport, |
| 4998 | restart recovery, and a coherent TUI, Work, evidence, and public release |
| 4999 | surface. |
| 5000 | |
| 5001 | ### Added |
| 5002 | |
| 5003 | - Add `codewhale web [--port 7878]`, a first-class loopback-only browser |
| 5004 | client over the canonical Runtime API. The dependency-free embedded shell |
| 5005 | supports thread lifecycle, snapshot-then-SSE transcripts, turn start/steer/ |
| 5006 | interrupt, approvals, and user questions, including pending-request recovery |
| 5007 | across tab reloads, while leaving unsupported managed, |
| 5008 | files, PTY, model-selection, and Fleet controls absent. Browser auth uses a |
| 5009 | short-lived one-time loopback capability exchanged for an opaque, bounded, |
| 5010 | process-local HttpOnly, SameSite=Strict session cookie with a same-origin |
| 5011 | mutation guard; Runtime tokens never enter URLs, HTML, browser storage, logs, |
| 5012 | or browser-launch arguments (#4423). |
| 5013 | - Add OpenCode Go as a first-class, subscription-backed Chat Completions |
| 5014 | provider with `[providers.opencode_go]`, `OPENCODE_GO_API_KEY`, and the eight |
| 5015 | models currently documented on its `/v1/chat/completions` endpoint. Models |
| 5016 | served only through OpenCode Go's Anthropic `/messages` endpoint remain out |
| 5017 | of this narrow route until Codewhale supports per-model wire selection |
| 5018 | (#1481 by @seanthefuturegorilla; implementation harvested from PR #773 by |
| 5019 | @zhangweiii and PR #1050 by @sternelee). |
| 5020 | - Add TelecomJS TokenHub as a first-class Chat Completions provider with |
| 5021 | `[providers.telecomjs]`, `TELECOMJS_API_KEY`, and a key-scoped live |
| 5022 | `/v1/models` refresh. Models.dev and provider-specific catalogs remain in |
| 5023 | separate source partitions so either refresh order preserves both; refreshes |
| 5024 | do not delete the other source's rows, matching model ids from unrelated |
| 5025 | providers do not fabricate metadata, and chat requests omit unsupported |
| 5026 | reasoning fields (PR #4370 by @baendlorel; harvested with co-authorship). |
| 5027 | - Prepare native Windows ARM64 `codewhale`, `codew`, and `codewhale-tui` |
| 5028 | binaries, npm selection, updater support, and standard/portable release |
| 5029 | archives. Build and smoke them on GitHub's native Windows 11 ARM runner, |
| 5030 | and move Linux ARM64 release builds to the native Ubuntu ARM runner to |
| 5031 | remove the slower multi-arch cross-link setup (#4267 by @w1w218). |
| 5032 | - `load_skill` tool now supports listing: omit `name` or pass `"list"` to |
| 5033 | see all available skills without loading one (#4651). |
| 5034 | - Add a unified `/skills` manager with one precedence-aware root catalog, |
| 5035 | bounded duplicate/shadow/conflict auditing, package provenance, and |
| 5036 | validated install, update, remove, and trust mutations (PR #4679 by |
| 5037 | @SamhandsomeLee). |
| 5038 | - Add a safe Agent Details view and bounded, structured `current_activity` to |
| 5039 | the single Work projection, sourced from worker events instead of renderer |
| 5040 | string inference. Rows stay compact, exact evidence is opt-in, and raw child |
| 5041 | output never enters the parent transcript (#2889 and #4636; design direction |
| 5042 | by @aboimpinto, preserved from #2694). |
| 5043 | - Make exact results and delegated coordination durable: non-inline tool output |
| 5044 | becomes immutable session-owned evidence behind bounded receipts; File |
| 5045 | mutations add configurable success-only diffs; and decisions and write |
| 5046 | contention survive restart with typed neutral-fan-in records (#4619, #4636, |
| 5047 | #4647). |
| 5048 | - Runtime API provider registry and atomic provider-switch endpoints |
| 5049 | (`GET /v1/providers`, `GET /v1/providers/{id}/models`, |
| 5050 | `POST /v1/providers/{id}/switch`) so the web GUI renders a dynamic |
| 5051 | provider/model picker without the setConfig+reload clobber (#4658). |
| 5052 | - Typed filter (`/`) in the Fleet setup wizard's Model step: substring |
| 5053 | match over provider id, display label, and model id keeps |
| 5054 | OpenRouter-scale catalogs navigable (#4639). |
| 5055 | - `[auto.router]` config: explicit provider/model/thinking for the Auto |
| 5056 | mode classifier route; unset keeps the DeepSeek flash default, and |
| 5057 | missing credentials fall back to the local heuristic. |
| 5058 | |
| 5059 | ### Changed |
| 5060 | |
| 5061 | - Keep the top activity bar literal and actionable: active To-dos appear first, |
| 5062 | followed by Sub-agents, while generic operations and coordination stay in |
| 5063 | the detail surface. Completed-only bars auto-hide, and top/side layouts can |
| 5064 | be resized by dragging their divider and retain the chosen size (#4700, |
| 5065 | #4702). |
| 5066 | - Use each theme's semantic colors for composer mode and permission rails, and |
| 5067 | show a larger inline reasoning preview with clearer local/full expansion |
| 5068 | affordances (#4699, #4701). |
| 5069 | - Simplify the model-facing runtime around stable action tools (`File`, `Git`, |
| 5070 | `Run`, deferred `Web`, and durable task and automation families), with legacy |
| 5071 | spellings hidden for replay. Fresh sessions no longer reserve a Work surface |
| 5072 | before real work exists (PR #4675). |
| 5073 | - Give the terminal shell one deliberate visual language: cool Plan → Act → |
| 5074 | Operate and warm Ask → Auto-Review → Full Access ramps match between header |
| 5075 | and split composer edges; transcript rhythm groups related activity; a |
| 5076 | refined whale keeps the empty state calm; and one-cell live motion with |
| 5077 | truthful labels distinguishes reasoning, reading, tool use, and verification |
| 5078 | without exposing private reasoning text. Reduced-motion and animation-off |
| 5079 | settings freeze it, while ASCII-safe terminals retain the signal (#4676, |
| 5080 | #4677). |
| 5081 | - Unified shell tool: the model now sees a single `Bash` tool with an `action` |
| 5082 | parameter (run/wait/interact/cancel). Legacy `exec_shell*` names remain as |
| 5083 | hidden compat aliases for transcript replay, and the tool-search catalog |
| 5084 | keeps `Bash` active by default (#4625). |
| 5085 | - Tool output inline preview increased from 6 to 12 lines (4 head + 4 tail) |
| 5086 | before the fold indicator; full pager (`v` key) unchanged (#4603). |
| 5087 | - Mode changes (`/mode agent|plan|operate`) now persist to `settings.toml` |
| 5088 | and restore across sessions (#4628). |
| 5089 | - Billing provenance: every outgoing API request carries an |
| 5090 | `x-codewhale-provenance` header with client version and provider (#4324). |
| 5091 | - The `/model` picker's typed search now ranks results: provider-name |
| 5092 | matches first (drill-down), then exact id, then id-prefix, then the |
| 5093 | active provider's rows (#4639). |
| 5094 | - System prompt text consolidated into a single `prompts/text.rs` |
| 5095 | module (byte-exact constants replacing 17 layered files); |
| 5096 | composition order, constitution-first binding, and locale/personality |
| 5097 | variants unchanged. |
| 5098 | - Ask, Auto-Review, Full Access, and Never resolve through one permission |
| 5099 | contract: `resolve_tool_permission` in the engine and |
| 5100 | `resolve_approval_request_disposition` in the UI share one truth table for |
| 5101 | session grants/denials, non-bypassable policy holds, and modal prompts |
| 5102 | (#4412). |
| 5103 | - Collapsed multi-struct tool families into single action-dispatched tools |
| 5104 | (`AutomationTool`, `TasksTool`, `GithubTool`, `RlmTool`) while keeping |
| 5105 | legacy tool names as hidden compatibility aliases for transcript replay. |
| 5106 | - Operate-mode children default to leaf depth (`max_depth=0`) unless the |
| 5107 | caller explicitly grants a deeper budget (#4598). |
| 5108 | |
| 5109 | ### Fixed |
| 5110 | |
| 5111 | - Restore `uwu` theme config round-tripping and keep header permission colors |
| 5112 | and authored idle-whale geometry aligned with the selected theme (#4696). |
| 5113 | - Default canonical `Bash` runs with no explicit `cwd` to the active |
| 5114 | `ToolContext.workspace`, including an isolated sub-agent worktree, instead of |
| 5115 | falling through to the shared shell manager's parent workspace. The regression |
| 5116 | test detects the selected workspace through marker files so it remains |
| 5117 | meaningful across PowerShell path spellings (#4674, PR #4673 by @fleitz). |
| 5118 | - Generate QuickJS bindings for `aarch64-unknown-linux-ohos` with the native |
| 5119 | SDK's libclang and sysroot, carry the OHOS target and sysroot through final |
| 5120 | linking, and keep unsupported persistent PTY dependencies out of the target |
| 5121 | while retaining non-PTY `exec_shell` support (#4470 by @shenjackyuanjie; |
| 5122 | original bindgen approach in #4384 by @shenyongqing). |
| 5123 | - Honor `[auto] cost_saving = true` in provider-aware heuristic and classifier |
| 5124 | routing, using only validated same-provider fast siblings and deriving |
| 5125 | fallback candidates from their actual provider so Auto cannot invent a |
| 5126 | cross-provider model. Providers without a known fast sibling stay on the |
| 5127 | active model (#4486; partial #4405). |
| 5128 | - Make terminal-client clipboard behavior truthful over SSH: use OSC 52 |
| 5129 | outside tmux, stock `tmux load-buffer -w` inside tmux, and bracketed paste |
| 5130 | for client-to-remote text. Graphical text and image access now requires |
| 5131 | credible forwarding or an explicit override, transport failures no longer |
| 5132 | claim success, and help distinguishes terminal text paste from graphical |
| 5133 | image attachment (#4484). |
| 5134 | - Keep a fresh TUI Work surface from rendering prior-session worker snapshots |
| 5135 | or durable-task terminal receipts whose creation or completion predates the |
| 5136 | current app start. Active durable tasks remain visible, and shared history |
| 5137 | stays available through `/tasks` and archived agent views (#4488; partial |
| 5138 | #4416). |
| 5139 | - Make doctor and setup output distinguish static configuration, command |
| 5140 | availability, MCP protocol readiness, and backend health instead of |
| 5141 | presenting configured routes as live-healthy. Ordinary doctor runs no |
| 5142 | longer wake loopback/self-hosted providers unless `--probe-local` is |
| 5143 | explicitly requested (#4485; partial #4406). |
| 5144 | - Serialize test-only configuration-path readers with temporary environment |
| 5145 | redirects so the Windows provider-persistence matrix cannot observe another |
| 5146 | test's transient `CODEWHALE_HOME` or config path (#4483, closing #4463). |
| 5147 | - Restore direct Moonshot `kimi-k3` to its documented 1,048,576-token |
| 5148 | context window and 131,072-token output limit instead of treating the live |
| 5149 | model as an unknown legacy 128K route. The existing Kimi Code tiered `k3` |
| 5150 | route and credential reuse remain unchanged (#4481). |
| 5151 | - Keep read-before-edit snapshots in the engine session so a file read remains |
| 5152 | valid across turns and context compaction, while a new session still starts |
| 5153 | with an empty tracker (#4475 by @Angel-Hair). |
| 5154 | - Make `apply_patch` expose the canonical `replace` operation while continuing |
| 5155 | to accept deprecated `changes` payloads through one validation path. Mixed |
| 5156 | patch, replace, and compatibility modes now fail before any write (#4476 by |
| 5157 | @Angel-Hair). |
| 5158 | - Show the prompt-cache hit rate in the phase strip when the Cache status item |
| 5159 | is enabled, using overflow-safe rounded integer math and leaving compact or |
| 5160 | disabled status layouts unchanged (#4474 by @dmitri-0). |
| 5161 | - Preserve Solarized Light's canonical Base3 (`#fdf6e3`) shell background |
| 5162 | instead of tinting it green-grey through the default underwater Ombre |
| 5163 | treatment, while retaining foreground ambient life (#4457 by |
| 5164 | @AiurArtanis; PR #4471 by @nightt5879). |
| 5165 | - Register `/slop` and `/canzha` as compatibility aliases of `/debt`, while |
| 5166 | keeping user-command ownership truthful across dispatch, help, slash |
| 5167 | completion, alias copy, and typo suggestions (PR #4680 by @nightt5879). |
| 5168 | - Fail closed on legacy Kimi CLI credential imports: remove Codewhale's |
| 5169 | hard-coded first-party-client impersonation and refresh request, never |
| 5170 | auto-enable or rewrite imported credentials, and label the compatibility |
| 5171 | route as a read-only imported token. An explicitly configured, still-valid |
| 5172 | access token remains usable until expiry; missing, malformed, and expired |
| 5173 | imports recover through the supported Kimi Code API-key route while |
| 5174 | first-class OAuth awaits Codewhale's own vendor registration (#4417, |
| 5175 | partially addressed). |
| 5176 | - Restore xAI/Grok device-code OAuth login against the live xAI OIDC |
| 5177 | contract: discovery with issuer/endpoint validation and documented |
| 5178 | fallbacks, user-principal scope set, RFC 8628 `slow_down` backoff capped at |
| 5179 | code expiry, bounded, sanitized error reporting for denial, expiry, and |
| 5180 | malformed responses, and a shared blocking-worker boundary for both CLI and |
| 5181 | TUI login so reqwest's blocking client never creates or drops its private |
| 5182 | runtime inside Codewhale's Tokio runtime (#4410). |
| 5183 | - Anchor `FREQ=HOURLY` automations with `BYHOUR`/`BYMINUTE` to persisted |
| 5184 | local-calendar slots so intervals keep their wall-clock phase across DST, |
| 5185 | restart, resume, RRULE updates, duplicate-slot recovery, and post-run |
| 5186 | advancement. Nonexistent clock slots are skipped and ambiguous slots run at |
| 5187 | their first occurrence (#4381 by @h3c-hexin). |
| 5188 | - Give content-watch drafts canonical identities: the link and semantic-drift |
| 5189 | watchers now write and dedup through one canonical draft-storage key with |
| 5190 | deterministic hash-suffixed IDs, validate and bound model drift output |
| 5191 | before any KV writes, and show truthful admin draft labels, so unchanged |
| 5192 | findings dedup and changed findings re-draft instead of colliding (#4453). |
| 5193 | - Make model-policy JSON repair consider object and array payloads in source |
| 5194 | order, matching nested delimiters across quoted strings and escapes and |
| 5195 | returning the earliest balanced candidate that parses, instead of letting |
| 5196 | an unmatched opening delimiter or object-first preference corrupt array |
| 5197 | payloads (#4430). |
| 5198 | - Convert persisted sub-agent completion and still-running control events into |
| 5199 | concise, non-authoritative resume checkpoints, keeping their raw runtime |
| 5200 | envelopes, sentinels, and retry instructions out of restored model and TUI |
| 5201 | conversation state (#4409). |
| 5202 | - Deliver failed, stopped, and stale sub-agent outcomes exactly once to the |
| 5203 | awaiting parent, lifecycle mailbox, and TUI before closing their runtime |
| 5204 | state. Restart now reconciles orphaned queued/model/tool-wait worker records |
| 5205 | to interrupted while preserving checkpoints, and cancelled workers no |
| 5206 | longer read as completed in the TUI (#4408). |
| 5207 | - Give host applications a cancellation boundary for MCP OAuth login so a |
| 5208 | stalled or abandoned provider login no longer hangs the calling session |
| 5209 | (#4380). |
| 5210 | - Avoid blocked reader joins after Windows process kills so terminated shell |
| 5211 | sessions cannot hang their readers (#4383). |
| 5212 | - Give stdin-less observer hooks immediate EOF and contain timed-out hook |
| 5213 | process trees so descendants and pipe readers cannot leak after the parent |
| 5214 | shell exits (#4489 by @luismateusvargas). |
| 5215 | - Preserve the full unsigned Windows PTY process status instead of collapsing |
| 5216 | every high-bit exception or NTSTATUS to `2147483647`, including decimal and |
| 5217 | hexadecimal diagnostic metadata for device retests (#4100 by |
| 5218 | @redjade75723). |
| 5219 | - Keep the Hotbar Setup action list synchronized with keyboard focus when the |
| 5220 | selection moves beyond the visible rows, including Down past `/export` |
| 5221 | (#4418). |
| 5222 | - Route Windows OpenHarmony Cargo links through the repository's target-aware |
| 5223 | clang launcher so the final Rust link keeps its target, sysroot, and MUSL |
| 5224 | flags, and extend the no-SDK release guard to protect that contract. This |
| 5225 | completes [@shenjackyuanjie](https://github.com/shenjackyuanjie)'s PR #4470 |
| 5226 | setup alongside [@shenyongqing](https://github.com/shenyongqing)'s original |
| 5227 | bindgen approach in PR #4384. |
| 5228 | - Reconcile the website roadmap with reality: the retired share-link |
| 5229 | direction is now an explicit non-goal, Workrooms is the considered |
| 5230 | direction, and the local web client appears as underway, in English and |
| 5231 | Chinese (#3418). |
| 5232 | - System-prompt skills block and skill-load warnings no longer embed absolute |
| 5233 | home/workspace paths; entries render workspace-relative or `~/…` so the |
| 5234 | byte-stable prompt prefix never leaks private paths. A new invariant test |
| 5235 | guards absolute paths, API keys, and workspace paths in the prefix (#4632). |
| 5236 | - Mode/permission baseline unit tests no longer read the developer's live |
| 5237 | `settings.toml`; they isolate config I/O to a temp directory (#4628). |
| 5238 | - Enter no longer freezes the composer on send: dispatch splits into a |
| 5239 | sync prepare phase (instant history + spinner) and a spawned async |
| 5240 | phase (auto-route, preflight, engine send), with submits gated while |
| 5241 | a dispatch is in flight (#4605). |
| 5242 | - Self-hosted routes keep explicit per-model output limits for unknown |
| 5243 | wire aliases instead of the generic 4K fallback (#4655 by @h3c-hexin; |
| 5244 | PR #4656). |
| 5245 | - Chat Completions idle-timeout errors now include received-byte and |
| 5246 | timing telemetry, distinguishing prefill stalls from mid-stream |
| 5247 | stalls with truncated tool-call arguments (#4657 by @h3c-hexin). |
| 5248 | - `set_config` provider writes now keep the in-memory route in step, |
| 5249 | so a following model write lands in the new provider's table instead |
| 5250 | of clobbering the previous provider's root default_text_model (#4658 |
| 5251 | by @gaord, with a follow-up route-sync fix). |
| 5252 | |
| 5253 | ### Security |
| 5254 | |
| 5255 | - Restrict cross-origin Runtime API browser preflights to the documented |
| 5256 | authentication and content headers, explicitly allowing `Authorization` |
| 5257 | instead of relying on a wildcard (#4454). |
| 5258 | |
| 5259 | ### Contributors |
| 5260 | |
| 5261 | Thank you to the contributors whose code, reports, and reviews shaped v0.9.1: |
| 5262 | |
| 5263 | - [@h3c-hexin](https://github.com/h3c-hexin) — calendar-anchored hourly |
| 5264 | automation recurrence (PR #4381), the MCP OAuth cancellation report |
| 5265 | (#4380), explicit limits for unknown local models (PR #4656 / #4655), |
| 5266 | and idle-timeout progress telemetry (PR #4657). |
| 5267 | - [@gaord](https://github.com/gaord) — Runtime API provider registry and |
| 5268 | atomic provider-switch endpoints (PR #4658). |
| 5269 | - [@SamhandsomeLee](https://github.com/SamhandsomeLee) — the unified `/skills` |
| 5270 | root catalog, audit/provenance model, validated mutations, manager UI, and |
| 5271 | acceptance coverage (PR #4679), plus Enter-send lag diagnosis and fix |
| 5272 | direction for #4605 (PR #4654; landed via the release-lane async-dispatch |
| 5273 | split). |
| 5274 | - [@aboimpinto](https://github.com/aboimpinto) — the Layer 5.1 user-command |
| 5275 | registry boundary from PR #3278; the exact authored evidence commit from PR |
| 5276 | #4046, preserved intact in the integration graph; and the #2870 follow-up |
| 5277 | audit whose metadata and malformed-sibling gaps shaped the final corrections. |
| 5278 | Paulo also provided the structured, redacted Agent Details and |
| 5279 | `current_activity` direction preserved from #2694/#2889 and the real-PTY |
| 5280 | lifecycle acceptance direction from #2886. |
| 5281 | - [@baendlorel](https://github.com/baendlorel) — TelecomJS TokenHub provider |
| 5282 | support and key-scoped live-catalog direction from PR #4370, harvested into |
| 5283 | the current provider architecture with co-authorship preserved. |
| 5284 | - [@zhangweiii](https://github.com/zhangweiii) and |
| 5285 | [@sternelee](https://github.com/sternelee) — the original first-class |
| 5286 | OpenCode Go implementations (PRs #773 and #1050), harvested into the |
| 5287 | current provider architecture. |
| 5288 | - [@seanthefuturegorilla](https://github.com/seanthefuturegorilla) — the |
| 5289 | canonical OpenCode Go/Zen provider request and acceptance direction |
| 5290 | (#1481). |
| 5291 | - [@nightt5879](https://github.com/nightt5879) — `/debt` compatibility aliases |
| 5292 | with dispatch-consistent user-command shadowing across discovery surfaces |
| 5293 | (PR #4680), plus the Solarized Light background preservation fix (PR #4471). |
| 5294 | - [@AiurArtanis](https://github.com/AiurArtanis) — the Solarized Light |
| 5295 | regression report and reproduction (#4457). |
| 5296 | - [@shenjackyuanjie](https://github.com/shenjackyuanjie) — the HarmonyOS |
| 5297 | workflow-js bindgen, portable-pty gating, and SDK environment work |
| 5298 | (PR #4470). |
| 5299 | - [@shenyongqing](https://github.com/shenyongqing) — the original HarmonyOS |
| 5300 | bindgen approach (PR #4384), carried into the landed implementation. |
| 5301 | - [@luismateusvargas](https://github.com/luismateusvargas) — the Windows hook |
| 5302 | process-leak reproduction, process-tree analysis, and EOF fix direction |
| 5303 | (#4489). |
| 5304 | - [@redjade75723](https://github.com/redjade75723) — the persistent Windows PTY |
| 5305 | report that exposed lossy high-bit process-status handling (#4100). |
| 5306 | - [@w1w218](https://github.com/w1w218) — the Windows ARM64 release request and |
| 5307 | real-device motivation (#4267). |
| 5308 | - [@Angel-Hair](https://github.com/Angel-Hair) — session-owned read-before-edit |
| 5309 | tracking and the explicit, backwards-compatible `apply_patch` replacement |
| 5310 | contract (PRs #4475 and #4476). |
| 5311 | - [@dmitri-0](https://github.com/dmitri-0) — configurable cache-hit visibility |
| 5312 | in the phase strip (PR #4474). |
| 5313 | - [@fleitz](https://github.com/fleitz) — the canonical `Bash` no-`cwd` |
| 5314 | workspace fix and regression test that keep isolated sub-agent commands in |
| 5315 | their own worktree (PR #4673, closing #4674). |
| 5316 | - [@SparkofSpike](https://github.com/SparkofSpike) — the Windows Ctrl+O |
| 5317 | reproduction that exposed pre-pager result truncation and conflicting composer |
| 5318 | shortcut routing (#4482), and the exact Vim-space regression reproduction |
| 5319 | verifying the v0.9.1 input path already contains the needed global binding |
| 5320 | (PR #4477). |
| 5321 | |
| 5322 | ### Security |
| 5323 | |
| 5324 | - Harden the public community-site boundary: scheduled review drafts now use |
| 5325 | one canonical freshness namespace, admin discard is restricted to validated |
| 5326 | draft objects, public feed requests cannot spend the server-held GitHub |
| 5327 | token, and maintainer login bodies are type- and size-bounded before parsing. |
| 5328 | |
| 5329 | ## [0.9.0] - 2026-07-16 |
| 5330 | |
| 5331 | Codewhale v0.9.0 replaces the default terminal shell with the underwater |
| 5332 | interaction system, makes Operate message-first, and hardens the Fleet, |
| 5333 | Workflow, routing, accounting, and release surfaces that support day-to-day |
| 5334 | agent work. The release also expands localization and gives the public site a |
| 5335 | quieter, docs-first community foundation. Its provider work replaces the old |
| 5336 | hand-maintained picker boundary with live ProviderLake discovery and adds the |
| 5337 | largest curated model-and-pricing expansion in the project so far. |
| 5338 | |
| 5339 | ### Fixed — final integration |
| 5340 | |
| 5341 | - Redact configured, environment, file-backed, and bare active credentials |
| 5342 | from every tool result before it crosses any model-provider wire protocol; |
| 5343 | retrieved spillover content is sanitized again at that boundary. The |
| 5344 | `read_file` tool also refuses CodeWhale configuration, backup, and |
| 5345 | credential-store paths, preventing routine tool use from exposing those |
| 5346 | local files. |
| 5347 | - Keep immediate TUI submit failures inside the shell: custom-provider route |
| 5348 | preflight and closed-mailbox errors now restore the exact composer draft and |
| 5349 | selected skill for retry, with a sticky visible error instead of exiting. |
| 5350 | - Anchor automatic compaction thresholds to the route's spendable input |
| 5351 | budget after output reservation and safety headroom, so large-output and |
| 5352 | tight self-hosted routes compact before provider context rejection. The TUI |
| 5353 | pre-send gate and warning copy now use the same token threshold as the |
| 5354 | engine. Preserve the 262K Kimi route's usable input budget and use the |
| 5355 | documented 32K default generation budget instead of mirroring the context |
| 5356 | window as output (#4293 by @SamhandsomeLee, #4368 by @bruce6135, and #4378 |
| 5357 | by @mvanhorn). |
| 5358 | - Fail closed instead of reporting base-rate dollar estimates for direct OpenAI |
| 5359 | GPT-5.4/5.4 Pro, GPT-5.5 (including dated snapshots), and GPT-5.6 |
| 5360 | Sol/Terra/Luna requests above 272K input tokens. Exact tiered accounting |
| 5361 | remains deferred to the generalized pricing schema; smaller 5.4 variants, |
| 5362 | GPT-5.5 Pro, Codex subscription, and foreign-provider routes are unchanged |
| 5363 | (#4317). |
| 5364 | - Retire `deepseek-chat` and `deepseek-reasoner` before they reach DeepSeek's |
| 5365 | first-party OpenAI or Anthropic wire APIs, migrating both to the documented |
| 5366 | `deepseek-v4-flash` replacement while preserving legacy non-thinking / |
| 5367 | thinking intent when no explicit reasoning tier is set. Aggregator, Wanjie |
| 5368 | Ark, self-hosted, and custom endpoint model ids remain provider-owned (#4320). |
| 5369 | - Make Operate a message-first multitask surface: ordinary prompts work without |
| 5370 | a Workflow, direct parent tools follow the same approval, sandbox, shell, |
| 5371 | ask-rule, and repository protections as Act, and follow-ups can queue while |
| 5372 | work is active. Bounded background workers remain preferred for independent, |
| 5373 | parallel, isolated, or long-running work; child handoffs cannot inherit |
| 5374 | standing Full Access, and each dispatch produces one durable completion |
| 5375 | receipt. |
| 5376 | - Let personal Fleet profiles in `CODEWHALE_HOME/agents` travel across |
| 5377 | repositories while project profiles in `.codewhale/agents` override them. |
| 5378 | Saving refreshes the live roster, and the UI now says explicitly that profile |
| 5379 | availability does not expand workspace, trust, or filesystem authority. |
| 5380 | - Move file-mention discovery onto one bounded, generation-safe background |
| 5381 | worker so a slow filesystem read cannot freeze composer input. Exact paths |
| 5382 | resolve on send; fuzzy matches stay in the completion popup instead of |
| 5383 | silently attaching an arbitrary same-name file (#4365 by @WavesMan, with the |
| 5384 | initial bounded-walk approach from #4367 by @LeoLin990405). |
| 5385 | - Keep the opt-in `remember` tool in the model-visible first-turn catalog so |
| 5386 | durable preference capture works without requiring a model to discover a |
| 5387 | tool it cannot yet know exists (#4373 by @Angel-Hair and #4377 by |
| 5388 | @mvanhorn). |
| 5389 | - Make `review` handle a staged snapshot relative to a base ref by comparing |
| 5390 | the branch merge-base tree with the index. This preserves committed and |
| 5391 | staged branch work, excludes unstaged edits, and avoids the invalid |
| 5392 | `git diff --cached <base>...HEAD` form. |
| 5393 | - Honor each MCP server's advertised discovery capabilities before calling |
| 5394 | optional tools, resources, templates, or prompts; keep optional probes |
| 5395 | independently bounded and fail-soft (#4308 by @nsfoxer). |
| 5396 | - Make offline `scorecard` pricing provider-aware: `turn_end` records carry the |
| 5397 | effective route and a non-secret billing surface, runtime exports and |
| 5398 | supported aliases ingest cleanly, legacy/unknown routes remain explicitly |
| 5399 | unpriced, and route-scoped cache and recorded-time pricing replace model-only |
| 5400 | guesses. Historical runtime aggregates use each turn's recorded time; |
| 5401 | costless catalog routes fail closed while exact provider-owned hand-price |
| 5402 | rows remain available. StepFun PAYG and Step Plan usage now stay distinct |
| 5403 | without persisting raw endpoint URLs, so subscription quota is never reported |
| 5404 | as token spend (#4335). Completion-only shell, manual-compaction, and purge |
| 5405 | events remain visible to `turn_end` observers as explicitly non-model |
| 5406 | lifecycle records. This builds on the scorecard introduced by @findshan in |
| 5407 | #3388. |
| 5408 | - Preserve named custom-provider identity across TUI sessions, `exec --resume`, |
| 5409 | runtime threads, exports, cache and Workflow receipts. Restores resolve the |
| 5410 | saved provider against live configuration before creating a client, never |
| 5411 | infer a provider from the model ID, and fail closed when the named route was |
| 5412 | removed, invalid, or ambiguous (#4334). |
| 5413 | - Bind credentials to the endpoint that owns them. Environment-selected custom |
| 5414 | hosts can no longer inherit saved provider keys, keyring entries, OAuth, or |
| 5415 | ambient provider variables; only an explicitly source-marked CLI key may |
| 5416 | follow an explicit CLI endpoint override. `auth_mode = "none"` also strips |
| 5417 | credential-shaped custom headers consistently in the TUI and app server, |
| 5418 | while keyless loopback routes remain usable as local runtimes. |
| 5419 | - Make hosted runtime threads deterministic and provider-exact: serialize |
| 5420 | thread, turn, and event mutation; keep cancellation ownership with the host; |
| 5421 | preserve the selected provider through every durable turn; terminalize |
| 5422 | exceptional streams once; and prevent the runtime manager from silently |
| 5423 | dispatching unclaimed goal continuations or child turns. |
| 5424 | - Treat required user confirmation as a real goal blocker instead of a failed |
| 5425 | goal, and explain how to recover when a previously cached approval is denied. |
| 5426 | Cached-denial recovery is also committed as a settled transcript receipt, so |
| 5427 | tool completion or a later status update cannot erase it from scrollback or |
| 5428 | accessibility output. The notice now describes matching, process-scoped |
| 5429 | denials truthfully across all shipped locales; approval audits honor |
| 5430 | `CODEWHALE_HOME`, and expired status toasts cannot remain trapped behind a |
| 5431 | persistent entry. Both states remain visible and actionable instead of |
| 5432 | looking like unexplained model or tool failure (#4374 and #4375 by |
| 5433 | @Angel-Hair, with the final hardening in #4385 by @nightt5879). |
| 5434 | - Make Fleet launch and teardown deterministic: route flags are placed before |
| 5435 | `exec`, workers are contained in owned Unix sessions or Windows Job Objects, |
| 5436 | and cancellation reaps surviving descendants with bounded escalation before |
| 5437 | manager state settles. Fence progress, terminal status, verification |
| 5438 | receipts, and evidence by durable attempt generation so a stale process can |
| 5439 | never complete or overwrite a restarted attempt; terminal state and receipt |
| 5440 | now commit atomically, stale-heartbeat decisions use a full lease CAS, |
| 5441 | exhausted-retry alerts are exactly once, and crash-truncated ledger tails are |
| 5442 | quarantined before the next append. Standalone CLI and Runtime API restart |
| 5443 | controls now drive the replacement attempt through a real executor to its |
| 5444 | terminal receipt, while per-run manager ownership prevents concurrent |
| 5445 | controllers from launching the same attempt twice. |
| 5446 | - Keep the stopship Workflow fixture bounded to measured 24k-per-turn role |
| 5447 | budgets and a 360k aggregate. Authored child step and wall-time limits now |
| 5448 | reach the live runtime, including launch-queue wait; promoted evidence stays |
| 5449 | intact between roles, tool-free handoff consumers omit tool fields on the |
| 5450 | provider wire, and a terminal `BLOCK` fails the Workflow instead of producing |
| 5451 | a successful Lane receipt. Free-form descriptions no longer fabricate write, |
| 5452 | shell, or network risk; unknown structured risk remains fail-closed. |
| 5453 | - Keep repository trust affirmative and explicit: only `1`/`Y` are advertised |
| 5454 | as acceptance keys, while Enter remains non-affirmative and explains the |
| 5455 | required choice. |
| 5456 | - Replace literal legal and doctrinal metaphors in Simplified Chinese setup and |
| 5457 | `/constitution` copy with direct collaboration terminology reviewed by a |
| 5458 | native speaker (#4369 by @hmr-BH). |
| 5459 | - Keep the transcript reviewable while an inline approval card is active: |
| 5460 | Page Up/Down, modified arrows, Home/End, and the mouse wheel now move through |
| 5461 | the visible evidence without changing or dismissing the pending decision |
| 5462 | (#4371 by @amuthantamil). |
| 5463 | - Match generated worker names to the active UI language while preserving |
| 5464 | explicit user names, and tighten the 89x50 shell rhythm across Fleet rows, |
| 5465 | choice dialogs, transcript boundaries, and the idle composer. |
| 5466 | - Put docs content and search before the full index on small screens, reduce |
| 5467 | mobile dead space, and keep the public community copy focused on issues, |
| 5468 | pull requests, and international contributors. |
| 5469 | |
| 5470 | ### Changed — the underwater shell |
| 5471 | |
| 5472 | - Replace the default TUI shell with the underwater interaction system: one |
| 5473 | renderer owns the header, top work strip, transcript ledger, composer, and |
| 5474 | footer, with explicit compact/normal/wide tiers and no legacy sidebar or |
| 5475 | dashboard in the default path. The legacy composition survives only behind |
| 5476 | the internal `classic` treatment. |
| 5477 | - Add a distinct pre-session launch screen — new session, new worktree (with |
| 5478 | inline naming and real lane provisioning), scoped resume count, changelog, |
| 5479 | quit — with reliable non-colliding keys and row/keyboard parity. |
| 5480 | - Render turns as a ledger: user message, short narration, settled tool |
| 5481 | receipts, and exactly one live row. Fast tool bursts land directly as |
| 5482 | batch receipts (no spinner churn), completed receipts stay inspectable, |
| 5483 | failures hold a coral receipt with stderr one `v` away, and one shared |
| 5484 | tool rail replaces nested card borders. |
| 5485 | - Make completion a one-shot exhale: `working -> finishing -> done` in the |
| 5486 | footer only, with no transcript repaint, no lingering loop, and no stale |
| 5487 | cancel action in the completed state. |
| 5488 | - Rebuild the secondary rooms on one hairline grammar — config, setup, |
| 5489 | sessions, help, context, theme, model/route, Fleet, file attach — each |
| 5490 | with a title hairline, row objects with focus/selection/mouse parity, |
| 5491 | one panel-owned scroll rail, and wrapped action footers. |
| 5492 | - Make `/model` a model-first atomic route picker across configured |
| 5493 | providers: provider and model switch together on apply, and every row |
| 5494 | prints the resolved model. `/theme` gains a live preview with truthful |
| 5495 | Esc revert across all 12 shipped themes. |
| 5496 | - Add a live context inspector (Alt+C) backed by the current route: exact |
| 5497 | system/messages/free token buckets, a proportional map, drill-down into |
| 5498 | the detail pager, and no frozen session while it is open. |
| 5499 | - Project Workflow runs as an in-stream run map: a collapsed one-line card |
| 5500 | that unfolds into per-lane rows with role, resolved model, worktree, |
| 5501 | elapsed track, and per-member running/waiting/failed/cancelled/done |
| 5502 | states, plus gates and a debrief built only from real run data. Child |
| 5503 | transcripts never flood the parent shell. |
| 5504 | - Unify Fleet into roster/setup/workers rooms: the operator is pinned first |
| 5505 | with the live session route, members show resolved route truth (inherit / |
| 5506 | fast lane / pinned), and the workers tab is a control surface with |
| 5507 | row-local open/stop and real lifecycle counts. |
| 5508 | - Distinguish repository-law approvals from ordinary approvals: the |
| 5509 | constitution prompt names its authority, source, matched rule, and target, |
| 5510 | and Full Access never bypasses it. Ordinary approvals render as a still |
| 5511 | coral band above the visible transcript. |
| 5512 | - Keep streaming honest and cheap: provider-unit deltas replace per-grapheme |
| 5513 | queueing, the transcript is top-anchored so appended lines stop shifting |
| 5514 | settled rows, ambient animation stops during real work, and ordinary |
| 5515 | completion no longer triggers full-screen clears (verified by render-diff |
| 5516 | logs: suffix updates of tens of cells while streaming, zero periodic |
| 5517 | full repaints). |
| 5518 | - Give every underwater treatment ambient life: ombre breathes its water |
| 5519 | column while flat and Terminal-owned keep the idle fish and bubble |
| 5520 | (foreground-only for Terminal), a typed treatment setting replaces string |
| 5521 | comparisons, reduced motion freezes life legibly, `fancy_animations = |
| 5522 | false` stills the chrome, and typing scatters the fish immediately. Fish |
| 5523 | keep a one-cell gap from occupied text; the whale remains the single brand |
| 5524 | mark and returns to stillness between caustic sweeps. |
| 5525 | - Bring the whale mark to life with a soft diagonal caustic sweep, then let it |
| 5526 | genuinely rest. Active markers now share a smoother 8 Hz clock after the |
| 5527 | existing earned-motion delay, while reduced motion, hidden/off-screen views, |
| 5528 | modal ownership, and compact-terminal redraw budgets remain authoritative. |
| 5529 | The motion is adapted from the Apache-2.0 Grok Build interaction language, |
| 5530 | not copied as a global pulse or high-frequency receipt cascade. |
| 5531 | - Keep compact terminals operable: `/config` and `/resume` collapse |
| 5532 | secondary chrome before sacrificing their selectable rows at 40x12 and |
| 5533 | 60x16, bodies budget for the footer's real wrapped height, and the |
| 5534 | selection stays visible through resizes. |
| 5535 | - Route footer notices through the classified toast system so informational |
| 5536 | acknowledgements (for example "Auto-compaction enabled") expire instead of |
| 5537 | becoming permanent idle chrome, while warnings and errors hold as sticky |
| 5538 | notices until their window passes. |
| 5539 | - Complete the `CODEWHALE_ASCII_SAFE=1` decorative tier: the whale mark, |
| 5540 | context meter, braille state markers (mapped by dot density so the working |
| 5541 | bubble still reads as a rising fill), bubbles, rails, and role/lane glyphs |
| 5542 | all narrow to semantic ASCII while user, model, and CJK text passes |
| 5543 | through untouched. Verified by whole-surface rendered-buffer sweeps. |
| 5544 | - Repair the Help catalog to match handler truth (`Alt+G`, `Alt+Shift+G`, |
| 5545 | `Alt+[`, `Alt+]`, `Alt+L`, `Alt+?`), and give theme, Help, model, and |
| 5546 | config rows direct mouse paths with the same activation as Enter. |
| 5547 | |
| 5548 | ### Changed — integrated runtime and TUI |
| 5549 | |
| 5550 | - Make worker delegation route-aware and identity-safe: workers receive a |
| 5551 | small role-scoped system prompt instead of stale parent/model boilerplate, |
| 5552 | faster routes resolve through the configured provider, and opening a worker |
| 5553 | shows its complete available transcript. Remove `token_budget` from the |
| 5554 | ordinary model-facing Agent schema so agents do not micromanage ad-hoc |
| 5555 | launches; explicit legacy calls remain readable for compatibility. |
| 5556 | - Mature `/config` interaction for enumerated and boolean settings with |
| 5557 | pickers/toggles, mouse-wheel scrolling, stable focus, and configured-provider |
| 5558 | selection. Startup mode is now only Agent or Plan; legacy `operate`/`yolo` |
| 5559 | settings migrate to Agent with permission posture represented separately. |
| 5560 | - Show where effective permission policy comes from and keep profile, |
| 5561 | environment, project, managed, and requirements-controlled posture read-only |
| 5562 | in the in-session editor. Runtime presets edit only proven user-owned root |
| 5563 | settings and no longer persist temporary environment overlays. |
| 5564 | - Restore the original four-line whale mark and make ambient ocean motion |
| 5565 | coherent across the full scroll surface: one continuous ombre, eased fish |
| 5566 | that face their direction of travel, fish in otherwise blank scrollback, and |
| 5567 | explicit reduced-motion and animation controls. |
| 5568 | - Keep model reasoning in the transcript rather than the Tasks strip, retain |
| 5569 | the live header status indicator, separate worker and success colors, and use |
| 5570 | the same rail grammar for both work-strip and transcript scrollbars. |
| 5571 | - Present the default Z.AI Coding Plan route, including child routes, as |
| 5572 | subscription quota instead of estimated per-token dollars. No undocumented |
| 5573 | account endpoint is called by this change. |
| 5574 | |
| 5575 | ### Added |
| 5576 | |
| 5577 | - Thinking Machines Lab's Inkling through Together using the exact wire model |
| 5578 | `thinkingmachines/inkling`, with `inkling` and `together-inkling` aliases and |
| 5579 | exact `none` / `minimal` / `low` / `medium` / `high` / `max` reasoning |
| 5580 | values. Codewhale does not invent a context window, price, or offline picker |
| 5581 | claim while the provider's public catalog metadata remains inconsistent. |
| 5582 | - Expand the verified offline catalog with Claude Sonnet 5, Claude Fable 5, |
| 5583 | GPT-5.3 Codex, and Qwen3.7 Plus, including time-aware Sonnet 5 introductory |
| 5584 | pricing and explicit cache rates. Refresh stale GLM-5.1, Kimi K2.6, Trinity, |
| 5585 | Qwen3.6, Nemotron, Anthropic, GLM-5.2, Kimi K2.7 Code, GLM-5 Turbo, and |
| 5586 | GPT-5 Codex price or limit rows; keep Xiaomi MiMo explicitly unpriced where |
| 5587 | the provider's token plan and pay-as-you-go surfaces cannot be distinguished. |
| 5588 | - MiniMax Messages provider support for MiniMax-M3 and MiniMax-M2.7, with |
| 5589 | OpenAI-compatible and Messages routes, regional endpoint guidance, request |
| 5590 | coverage, catalog limits, and tier-aware pricing (PR #4354 by @octo-patch). |
| 5591 | - Dynamic MCP server infrastructure and an approval-gated tool that lets the |
| 5592 | model start a configured MCP server from chat context. Harvested from |
| 5593 | #3869 and #3866 by @bistack with authorship preserved. |
| 5594 | - Parent `--disallowed-tools` restrictions now flow into sub-agents and Fleet |
| 5595 | workers by default, including deny-wins, wildcard, catalog-filtering, and |
| 5596 | multi-generation inheritance coverage. Harvested from #4096 by @JayBeest |
| 5597 | (#4042). |
| 5598 | - Korean (ko) UI locale with full key parity and onboarding/setup wiring |
| 5599 | (PR #4347 by @moduvoice). |
| 5600 | - Localize the entire underwater layer: 104 new UI strings — launch menu, |
| 5601 | phase words, mode/permission chips, footer hints, session picker, context |
| 5602 | inspector, route and theme pickers, Fleet roster, workflow status, sidebar |
| 5603 | work strip, repository-law approval copy, and file-attach titles — wired |
| 5604 | through MessageIds and translated into ja, zh-Hans, es-419, pt-BR, vi, |
| 5605 | and ko. Every complete pack now holds exact raw key parity with English |
| 5606 | (856 keys), enforced by new tests that the old English-fallback gate could |
| 5607 | not perform. The permission chip maps from typed state, so localization |
| 5608 | can never silently collapse it. Machine-authored translations follow each |
| 5609 | pack's existing terminology and are flagged for native review. |
| 5610 | - Anthropic adapter: sanitize top-level `oneOf`/`anyOf`/`allOf` in tool |
| 5611 | input schemas so affected tools no longer fail the whole request with |
| 5612 | HTTP 400 (PR #4346 by @qinlinwang). |
| 5613 | - Anthropic pricing: bill cache-write tokens at published rates |
| 5614 | (PR #4348 by @knqiufan, #4318). |
| 5615 | - NetBSD: generate QuickJS bindings at build time so `codewhale-workflow-js` |
| 5616 | compiles (PR #4349 by @ci4ic4). |
| 5617 | - Real-PTY release gates for six-worker fan-out liveness with Esc cancel, |
| 5618 | multi-terminal route isolation, queued steering via terminal-safe Ctrl+G |
| 5619 | (with Ctrl+S retained where the terminal forwards it), the one-shot |
| 5620 | completion footer, and per-theme ANSI output for every shipped palette. |
| 5621 | |
| 5622 | ### Fixed |
| 5623 | |
| 5624 | - Make release publication complete and source-anchored: every build checks out |
| 5625 | the resolved tag commit, tag movement is rejected before GHCR, GitHub |
| 5626 | Release, Homebrew, Cargo, or npm writes, and registry helpers require a clean |
| 5627 | checkout exactly matching the remote tag. Manual recovery runs are |
| 5628 | exact-tag-only and execute the same parity gate as automatic tag pushes. |
| 5629 | - Publish a coherent distribution set: both checksum manifests now contain |
| 5630 | usable public basenames and cover the full 29-asset matrix; GHCR, Homebrew, |
| 5631 | GitHub archives, and the Linux x64 CNB mirror carry `codewhale`, `codew`, and |
| 5632 | `codewhale-tui`. The CNB shortcut now fails clearly outside Linux/OpenHarmony |
| 5633 | x64 instead of promising assets that the mirror does not build. |
| 5634 | - Preserve task text when a skill is invoked through dollar, unified-slash, or |
| 5635 | explicit skill syntax, while keeping bare skill invocations and management |
| 5636 | subcommands intact (PR #4372 by @nightt5879, co-authored by @CCChisato; |
| 5637 | #3915). |
| 5638 | - Honor MCP server discovery capabilities: require advertised or legacy |
| 5639 | `tools/list`, keep optional resource/template/prompt probes independently |
| 5640 | bounded and fail-soft, and format descriptions Unicode-safely (#4308, |
| 5641 | harvested with co-authorship from @nsfoxer). |
| 5642 | - Age-evict terminal sub-agent worker records from the state ledger so |
| 5643 | long-lived, high-fan-out sessions do not keep rewriting multi-megabyte |
| 5644 | terminal history (#4217; root-cause and fix direction from @yekern). |
| 5645 | - Resolve the sub-agent completion/cancellation race with one terminal-state |
| 5646 | claim: cancellation suppresses late mailbox/parent/UI delivery, while a |
| 5647 | completed result remains publicly running until its notification is safely |
| 5648 | delivered. |
| 5649 | - Keep Workflow panel controls from stealing ordinary composer letters. Enter, |
| 5650 | Delete, Up/Down, and Esc own panel actions; typed characters return focus to |
| 5651 | the composer and start the message normally. |
| 5652 | - Preserve the composer prompt gutter from the first typed character through |
| 5653 | wrapping, scrolling, cursor placement, and mouse hit-testing so the `>` does |
| 5654 | not disappear or make input appear to jump. |
| 5655 | - Emit terminal-native OSC 8 metadata for rendered URLs without placing escape |
| 5656 | payload bytes in the measured text, keeping long links visible, selectable, |
| 5657 | and clickable in supporting terminals. |
| 5658 | |
| 5659 | - Keep headless structured output terminal-clean: `codewhale exec` engines |
| 5660 | no longer emit interactive terminal-title/taskbar OSC sequences, so |
| 5661 | `--output-format stream-json` stdout stays parseable, escape-free JSONL. |
| 5662 | Interactive TUI sessions keep their terminal chrome. |
| 5663 | - Localization honesty: the parity gate was blinded by its own English |
| 5664 | fallback — two keybinding rows (`KbCyclePermissions`, `KbCycleThinking`) |
| 5665 | were missing from all five "complete" packs and now ship translated; the |
| 5666 | Operate-mode copy that drifted in English was retranslated in every pack |
| 5667 | (including zh-Hant's slice); three MessageIds absent from |
| 5668 | ALL_MESSAGE_IDS are visible to tests again; and the `/config` |
| 5669 | theme/locale hints and the invalid-locale error derive from the shipped |
| 5670 | registries instead of stale hand lists that advertised 4 of 12 themes |
| 5671 | and 4 of 8 locales. |
| 5672 | - The setup wizard's constitution step no longer claims a "55-line core" |
| 5673 | in any language (the bundled core is larger today); the guided draft says |
| 5674 | "the bundled core stays active" instead. |
| 5675 | - In-app selection copy is rail-clean and now regression-tested: copied |
| 5676 | transcript text excludes the `▎ ╎ │ ●` decorations via cache metadata |
| 5677 | (#4208 — thanks @eugenicum for the report and code-aware fix direction; |
| 5678 | terminal-native selection with mouse capture off remains a product |
| 5679 | decision on the proposed `rail_style` option). |
| 5680 | |
| 5681 | ### Docs |
| 5682 | |
| 5683 | - Stamp every 0.9-era roadmap document with an explicit status (current, |
| 5684 | historical, superseded, principle-only, or future RFC), correct trackers |
| 5685 | that recorded unshipped work as done, and describe what remains after |
| 5686 | v0.9.0 in `docs/AGENT_RUNTIME.md`. |
| 5687 | - Add `docs/rfcs/UNIFIED_PROVIDER_LOGIN.md`: one `codewhale auth login` |
| 5688 | surface for Anthropic, OpenAI Codex, and xAI, with the Anthropic adapter |
| 5689 | gated on verifying flow permissions before any constants are adopted. |
| 5690 | - Refresh `docs/ACCESSIBILITY.md` for treatment-independent ambient life |
| 5691 | and the completed ASCII tier. |
| 5692 | |
| 5693 | ### Changed — runtime foundations |
| 5694 | |
| 5695 | - Make the advertised Android/Termux release target buildable by generating |
| 5696 | QuickJS bindings against the Android NDK instead of expecting an upstream |
| 5697 | pre-generated `aarch64-linux-android` binding file, and give Android CLI/TUI |
| 5698 | HTTP clients a preconfigured rustls root store (Mozilla WebPKI roots) so |
| 5699 | standalone Termux processes stop panicking inside |
| 5700 | `rustls-platform-verifier`'s JVM expectations (#4236, #4242). |
| 5701 | - Rebalance the bundled Constitution after the v0.8.67 prompt ablation: keep |
| 5702 | the procedural policy tail in mode-specific layers, while restoring concise |
| 5703 | behavioral guidance for momentum, causal investigation, constraint-first |
| 5704 | decisions, mechanism-backed guarantees, and clean continuity. |
| 5705 | - Wire live catalog cache into provider/model pickers without dropping stale or |
| 5706 | prior rows after TTL expiry / refresh failure (#4139). Remove the dead |
| 5707 | `OFFERING_SEEDS` hand table so the bundled Models.dev catalog is the sole |
| 5708 | seed source; pickers show a compact `stale` / `cache failed` chrome chip when |
| 5709 | the Models.dev layer is past TTL or last refresh failed. |
| 5710 | - Make `work_update` the sole model-facing To-do / Work progress tool (#4132). |
| 5711 | `checklist_*` and `todo_*` remain registered as hidden compat aliases for |
| 5712 | transcript replay; `update_plan` stays Strategy metadata/context/route, not |
| 5713 | a second checklist. Mode/approval prompts nudge the single surface. |
| 5714 | - Demote the bundled Models.dev snapshot to an offline/stale fallback after |
| 5715 | live catalog refresh (#4188). ProviderLake precedence is live Models.dev > |
| 5716 | bundled seed > legacy hardcoded completion names; pickers, inventory, and |
| 5717 | subagent validation stay catalog-backed, and Codewhale-only providers keep |
| 5718 | defaults when Models.dev has no rows. |
| 5719 | |
| 5720 | ### Added |
| 5721 | - Wire xAI device-code OAuth into `codewhale auth xai-device`, the TUI |
| 5722 | `/auth xai-device` command, and guided provider setup, with comment-preserving |
| 5723 | auth-mode persistence and loopback exchange coverage (#4257). |
| 5724 | - Add GPT-5.6 Sol, Terra, and Luna to the OpenAI API route, including their |
| 5725 | 1.05M context metadata, 128K output limits, pricing, and `max` reasoning |
| 5726 | effort. Add Meta Model API as a first-class OpenAI-compatible provider for |
| 5727 | Muse Spark 1.1 with 1M context, tool/reasoning metadata, provider aliases, |
| 5728 | and both `META_MODEL_API_KEY` and Meta's `MODEL_API_KEY` credential names. |
| 5729 | - Catalog automation: `scripts/catalog_models_dev.py` refreshes secret-free |
| 5730 | Models.dev / OpenRouter listings and validates the offline seed snapshot |
| 5731 | (`snapshot --check`) without ever persisting API keys (#4117). |
| 5732 | - `/model` picker cycles six catalog views with `A` (Configured → Catalog → |
| 5733 | Recent → Coding → Cheap → Long context) and richer row metadata from the |
| 5734 | live/bundled catalog (context, max output, tools, reasoning, price/M, |
| 5735 | freshness). Discoverability views do not auto-apply a surprising route |
| 5736 | (#4115). |
| 5737 | |
| 5738 | - Workflow runs are now durable: every run appends to a |
| 5739 | `.codewhale/workflow-runs.jsonl` journal and hydrates on startup, so |
| 5740 | `workflow status` survives restarts; runs left `running` by a dead process |
| 5741 | are recovered as failed (#4011). The transcript renders workflow tool |
| 5742 | output as a run card (status, goal, children, progress, verification) |
| 5743 | instead of a generic one-liner (#4038), and `workflow` accepts a `verify` |
| 5744 | flag that runs post-completion verification gates and fails the run when |
| 5745 | gates fail (#4013). |
| 5746 | - Hotbar sources for MCP tools and skills: MCP tool slots prefill the |
| 5747 | composer (execution stays behind the normal tool-approval flow) and skill |
| 5748 | slots activate through the existing `$skill` alias (#2068, #2069). |
| 5749 | - Mode & permission surface: Tab cycles Plan → Act → Operate; Shift+Tab |
| 5750 | cycles the Agent permission posture (Ask / Auto-Review / Full Access) with |
| 5751 | a footer permission chip; Ctrl+T cycles reasoning effort and Ctrl+Shift+T |
| 5752 | opens the live transcript overlay. Operate is the orchestration mode |
| 5753 | (delegate, wait, inspect, dispatch) and raises sub-agent fan-out while |
| 5754 | focusing the Agents sidebar. |
| 5755 | - Provider lake facade: the provider/model pickers, hotbar, and model |
| 5756 | inventory now enumerate configured providers' models from the bundled |
| 5757 | catalog (with an `A` toggle to browse the full catalog), replacing the |
| 5758 | hardcoded per-provider model table (#3830 follow-up). |
| 5759 | - Added Cursor-integrated-terminal dogfood evidence for the published v0.8.67 |
| 5760 | release, covering installed binary provenance, release/publication checks, |
| 5761 | headless runtime smoke, setup QA, and remaining manual visual TUI checks. |
| 5762 | - README and README.zh-CN now point users to the community-maintained |
| 5763 | CodeWhale for VS Code GUI frontend while clarifying that this repository's |
| 5764 | `extensions/vscode/` scaffold remains the read-only Phase 0 viewer (#4035). |
| 5765 | |
| 5766 | ### Fixed |
| 5767 | |
| 5768 | - Sub-agent waiting no longer peek→sleep polls: `agent(action="wait")` joins |
| 5769 | children, unchanged peeks are throttled (~30s) with an anti-polling nudge, |
| 5770 | and mode prompts teach the join primitive (#4097). Harvested from PR #4098 |
| 5771 | by [@Mr-Moon121](https://github.com/Mr-Moon121) (Jeffrey Luna). |
| 5772 | - `/provider` picker remembers catalog/configured view and highlighted row |
| 5773 | across reopen, matching `/model` picker memory. |
| 5774 | - Mode picker roster is exactly Act / Plan / Operate (no Multitask, no |
| 5775 | numeric `4`/`5` gaps). Legacy `yolo`/`4` remain invisible one-way |
| 5776 | permission shorthand for Act + Bypass. |
| 5777 | |
| 5778 | - Fleet setup is a role/profile roster editor, not a provider-scoped model |
| 5779 | picker: the Model step lists routes from every configured provider (not |
| 5780 | only the active one), a picked route's provider is persisted explicitly in |
| 5781 | the saved profile TOML (`provider = "..."`, never inferred from the model |
| 5782 | id), and the loader/route resolver read that field back out verbatim. The |
| 5783 | draft-preview save keypress no longer competes with a separate pager's |
| 5784 | `g`/`G` scroll bindings — the exact TOML preview now renders inline on the |
| 5785 | same Review step that saves it (#4093). |
| 5786 | - `codewhale fleet run` and interactive in-process Fleet launches now honor a |
| 5787 | profile-pinned provider/model route instead of merely recording it on the |
| 5788 | receipt. Headless workers receive the non-secret `--provider` and `--model` |
| 5789 | pair; TUI workers resolve the same explicit route in process. Credentials |
| 5790 | still come from the worker's environment, provider is never inferred from a |
| 5791 | model id, and unpinned workers continue to inherit the run route (#4093, |
| 5792 | #4193). |
| 5793 | - The Fleet setup `m` model-assisted redraft no longer drops a picked |
| 5794 | cross-provider route: the provider/model the operator chose are re-pinned |
| 5795 | onto the drafted profile (a model draft is always `provider: None`), so |
| 5796 | saving it keeps the explicit route instead of persisting an ambiguous, |
| 5797 | provider-scoped profile (#4093). |
| 5798 | - Saving a Fleet profile now fails with a clear message when it pins a |
| 5799 | provider that has no configured credentials, using the same |
| 5800 | configured-provider check the model picker uses (#4093). |
| 5801 | - Workflow correctness: completion polling fails closed instead of |
| 5802 | fabricating success when a sub-agent reports no terminal status; cancel |
| 5803 | interrupts the JS VM (cancel handle + abort) and blocks further spawns; |
| 5804 | and `budget.spent()` reports real manager-scope usage instead of always 0. |
| 5805 | - Sub-agent spawns validate the model↔provider pair before dispatch: |
| 5806 | inherited/faster routes remap foreign models to the provider's catalog |
| 5807 | default, and explicit pins fail fast with a diagnostic instead of an |
| 5808 | upstream model-not-found error. |
| 5809 | - TUI stability: engine event drains break every 8–16 events / 8 ms to keep |
| 5810 | input live (#1830, #2317, #1198); the terminal input pump restarts after |
| 5811 | stall recovery on macOS/Linux too; the startup raw-mode probe no longer |
| 5812 | leaks raw mode on timeout; recovery snapshots persist every 45 s during |
| 5813 | long turns and the offline queue persists on every push (#1830); |
| 5814 | queue/steer paths surface toasts while streaming (#2317, #1338); and |
| 5815 | modal submit errors re-open the modal instead of being swallowed (#1198). |
| 5816 | - Core/state: paused jobs persist as paused across restarts; unarchive |
| 5817 | updates the in-memory cache; tool dispatch has a timeout; MCP |
| 5818 | notifications no longer receive responses; corrupted checkpoints surface |
| 5819 | errors instead of loading empty state; the session index compacts instead |
| 5820 | of growing unbounded; and recording thread-goal usage no longer |
| 5821 | self-deadlocks the state store. |
| 5822 | - Runtime compaction summaries are now persisted into `/v1` thread records so |
| 5823 | engine reloads and restarts preserve compacted context. Contributed by |
| 5824 | MXAntian (@MXAntian) (#4091). |
| 5825 | - The TUI leaves xterm alternate-scroll mode off when mouse capture is disabled, |
| 5826 | preserving native terminal text selection in light-theme/no-mouse-capture |
| 5827 | sessions. Contributed by Nightt (@nightt5879) (#4088, #4026). |
| 5828 | - The public `/api/github/feed` endpoint is now forced dynamic on Cloudflare so |
| 5829 | it returns live GitHub activity instead of a build-time empty feed. |
| 5830 | |
| 5831 | ### Security |
| 5832 | |
| 5833 | - Require bearer authentication for `/v1/chat/completions`, compare tokens in |
| 5834 | constant time, return accurate 4xx/5xx statuses, bound request bodies and SSE |
| 5835 | frames, redact secrets from stdio `config get`, and reliably reap the runtime |
| 5836 | child during shutdown. |
| 5837 | - Keep trust precedence and secret persistence fail-closed: user ExecPolicy |
| 5838 | rules outrank agent-layer rules, chained commands cannot propose unsafe |
| 5839 | trusted-prefix amendments, and config and secret writes are atomic with |
| 5840 | filesystem synchronization on every supported platform. |
| 5841 | |
| 5842 | ### Changed |
| 5843 | |
| 5844 | - Tool-hang watchdog trimmed from 15 minutes to 10 (#1862); approval modal |
| 5845 | footer hints use a higher-contrast tier (#3380); status/mode copy is |
| 5846 | disclosed once across header, footer, cards, and sidebar instead of |
| 5847 | repeated per layer. |
| 5848 | - Removed the unused `tui::whale_routes` taxonomy module and its tests. |
| 5849 | Contributed by Darrell Thomas (@DarrellThomas) (#4041, #3852). |
| 5850 | |
| 5851 | ### Deprecated |
| 5852 | |
| 5853 | - YOLO mode: `--yolo`, `default_mode = "yolo"`, and the hotbar YOLO action |
| 5854 | now map to Act + Full Access permissions via a compatibility shim and |
| 5855 | show a one-shot deprecation notice. Removal is deferred beyond v0.9.0 so |
| 5856 | this release does not break existing scripts without a dedicated cutover. |
| 5857 | |
| 5858 | - Google Gemini is its own backend (`/provider google`) on the official |
| 5859 | OpenAI-compatible route with thought-signature capture/replay and |
| 5860 | fail-closed replay for thinking models. Antigravity (`agy` 1.1.13) joins |
| 5861 | as a separate credential-plane provider: consent-gated read-only import |
| 5862 | of the official CLI's login with `ANTIGRAVITY_API_KEY`/`AGY_ADC_AUTH` |
| 5863 | precedence; requests fail closed until the cloud-code wire protocol is |
| 5864 | implemented. |
| 5865 | |
| 5866 | ### Removed |
| 5867 | |
| 5868 | - Remove the deprecated `deepseek` and `deepseek-tui` binary shims in this |
| 5869 | breaking release. `codewhale`, `codew`, and `codewhale-tui` are the supported |
| 5870 | entry points; existing DeepSeek provider support and legacy config/session |
| 5871 | migration remain intact. |
| 5872 | |
| 5873 | ### Known issues |
| 5874 | |
| 5875 | - Android/Termux arm64 remains a preview in v0.9.0. The target, asset wiring, |
| 5876 | updater selection, dependency graph, and source-build path have automated or |
| 5877 | static coverage, but shell/PTY/config/TUI startup and runtime behavior remain |
| 5878 | unverified on a real device (#4236, #4242). Do not use a GNU/Linux arm64 |
| 5879 | archive in Termux. |
| 5880 | |
| 5881 | ### Contributors |
| 5882 | |
| 5883 | Thank you to the international community whose code, reports, reviews, and |
| 5884 | reproductions shaped v0.9.0: |
| 5885 | |
| 5886 | - [@amuthantamil](https://github.com/amuthantamil), |
| 5887 | [@bistack](https://github.com/bistack), |
| 5888 | [@bruce6135](https://github.com/bruce6135), |
| 5889 | [@CCChisato](https://github.com/CCChisato), |
| 5890 | [@ci4ic4](https://github.com/ci4ic4), |
| 5891 | [@cyq1017](https://github.com/cyq1017), and |
| 5892 | [@DarrellThomas](https://github.com/DarrellThomas). |
| 5893 | - [@eugenicum](https://github.com/eugenicum), |
| 5894 | [@findshan](https://github.com/findshan), |
| 5895 | [@gaord](https://github.com/gaord), |
| 5896 | [@hmr-BH](https://github.com/hmr-BH), |
| 5897 | [@hongqitai](https://github.com/hongqitai), and |
| 5898 | [@idling11](https://github.com/idling11). |
| 5899 | - [@JayBeest](https://github.com/JayBeest), |
| 5900 | [@knqiufan](https://github.com/knqiufan), |
| 5901 | [@LeoLin990405](https://github.com/LeoLin990405), |
| 5902 | [@moduvoice](https://github.com/moduvoice), |
| 5903 | [@mvanhorn](https://github.com/mvanhorn), |
| 5904 | [@Mr-Moon121](https://github.com/Mr-Moon121), and |
| 5905 | [@MXAntian](https://github.com/MXAntian). |
| 5906 | - [@Angel-Hair](https://github.com/Angel-Hair), |
| 5907 | [@nightt5879](https://github.com/nightt5879), |
| 5908 | [@nsfoxer](https://github.com/nsfoxer), |
| 5909 | [@octo-patch](https://github.com/octo-patch), |
| 5910 | [@qinlinwang](https://github.com/qinlinwang), |
| 5911 | [@SamhandsomeLee](https://github.com/SamhandsomeLee), and |
| 5912 | [@taixinguo](https://github.com/taixinguo). |
| 5913 | - [@WavesMan](https://github.com/WavesMan), |
| 5914 | [@wuisabel-gif](https://github.com/wuisabel-gif), and |
| 5915 | [@yekern](https://github.com/yekern). |
| 5916 | |
| 5917 | --- |
| 5918 | |
| 5919 | Older releases: [CHANGELOG.md](https://github.com/Hmbown/CodeWhale/blob/main/CHANGELOG.md) and [docs/CHANGELOG_ARCHIVE.md](https://github.com/Hmbown/CodeWhale/blob/main/docs/CHANGELOG_ARCHIVE.md). |
| 5920 |