crates/tui/CHANGELOG.md
Rama main · réplica de lectura del repositorio original.
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
- **Sandbox:** a managed configuration can set `tool_launcher` (Linux) to run every sandboxed tool command as another user, in front of bubblewrap; commands then run inside the sandbox or not at all, masks are computed for that user, `/tmp` is private per command, and `GET /v1/runtime/info` reports `sandbox.kind` and `sandbox.tool_launcher`. Without the key nothing changes. A managed configuration named by `CODEWHALE_MANAGED_CONFIG_PATH` is now applied on every load; a configuration whose provider comes from a plugin no longer loads with the managed file skipped, it fails to load instead.
- **Receipts:** a terminal session's receipt (`/receipts`, `codewhale receipts`) now shows the provider's token counts and the same cost report `/cost` prints, saying "unknown" and why when the route's price is not known, never a guess. A Runtime thread's receipt shows token counts only; its cost line follows in a later release. `codewhale metrics` now counts usage saved in terminal sessions instead of reporting none. Sessions saved by 0.10.2 carry only a combined token total.
- **External agents over ACP:** Codewhale now drives external agents through the official Agent Client Protocol SDK. Request ids on the wire are strings, and an agent's error is treated as a sign-in problem only when it carries the protocol's auth-required code.
- **Website home page:** the page is reorganized around what a visitor does: a dated OrcaRouter offer strip with a visible referral tag, one proof strip (release, stars, contributors), a models section with the newest first-party models, one capabilities section that includes Computer Use, an "Everything is a plugin" teaser and a community panel whose live GitHub numbers fill in from the browser and hide when unavailable. Unused home copy was removed from all 18 site languages.
- **Website models and plugins:** /models leads with recently added models, three ways to connect (DeepSeek, first-party providers, any OpenAI-compatible endpoint) and a catalog grouped by maker; Ollama and OpenRouter are listed but no longer featured. /plugins leads with "Everything is a plugin" (credited to DeepSeek Harness) and shows MCP connectors from the connection catalog.
- **Model catalog:** Claude Fable 5.2 (`claude-fable-5-2`) and Gemini 4 Carbon (`gemini-4-carbon`) are in the bundled catalog, and a daily catalog-refresh workflow proposes new first-party models from models.dev as a pull request. The workflow has not run in GitHub Actions yet.
- **Gemini 4 output limit:** Gemini 4 Carbon and Gemini 4 Argon now allow 65,536 output tokens per reply, up from 32,768, matching Google's published limit.
- **Anthropic xhigh effort:** Choosing xhigh effort on an Anthropic model that documents it, such as Claude Fable 5.2 or Claude Opus 4.8, now sends xhigh instead of max, so the model uses and bills the level you picked.
- **Public model list:** The public model list gains GPT-6.1 Terra, Kimi K3.1 Pro (and its high-speed variant), MiniMax M3.1 Flash and Mistral Large 4, each marked unreviewed.
- **Model Studio Token Plan:** Token Plan users can now pick `qwen4-max-preview` on both the OpenAI and Anthropic dialects. It was added from the model table Alibaba publishes on its Token Plan pricing page and has not been exercised against the live endpoint. Alibaba publishes no context window, output limit, tool calling or thinking control for it, so Codewhale records image input only and sends it no thinking switch on either dialect. The Coding Plan does not list it.
- **Website brand and app pages:** the header, footer and favicon use the black-and-white Codewhale mark, keeping the colored whale for character moments. New /app and /docs/account pages say plainly that the desktop app is a development build, the browser app is not open yet, and how sign-in works where it exists. The terminal demo was recaptured from the 0.10.3 source.
- **DSH plugin client review:** the DSH importer now reviews a plugin's client (`dsh.client`) files: the review lists every file the client loads with its SHA-256 and which modules the host must provide, and says exactly why a client stays disabled (for example an npm package that is not in the bundle, or a module loaded by a computed specifier). Plugin UI is still not shown; that needs the Engine client bootstrap.
- **`codewhale exec` prompt input:** `codewhale exec "prompt"` no longer hangs when stdin is an open pipe that sends nothing (it continues after 2 s and says so, and a slow producer can be included by piping the prompt as well), and a flag typed after the prompt in full-width or typographic-dash form is rejected like `--auto` instead of being sent to the model as text. Tested on Unix only; no Windows, hosted CI or real-provider run.
- **Website docs:** documentation pages no longer stack a second "Codewhale documentation" header under the site navigation; the line saying which release the docs describe now sits under the breadcrumb.
- **Website languages:** the Roadmap and Contribute pages now show their titles, introductions and actions in all 18 site languages instead of English outside English and Chinese. The translations have had no native review yet.
- **Responses dialect profiles:** Codex, DeepSeek and Concentrate Responses behavior now comes from one checked dialect table instead of per-provider code, a custom `wire = "responses"` provider can set `responses_profile = "standard"` (the default when omitted), and preview shows the profile each Responses request used. A Responses client whose route cannot be resolved now fails when it is created rather than at its first request ([#7261](https://github.com/codewhale-hq/Codewhale/pull/7261)). Thanks [@SamhandsomeLee](https://github.com/SamhandsomeLee).
- **Read-only builtins over the Runtime API:** `POST /v1/threads/{id}/commands/builtin` runs `/system`, `/tokens` or `/cost` against a thread and returns the same answer the terminal prints, including the effective system prompt the engine sends. Any other command name answers 404, a thread whose engine is not loaded or has no live context estimate answers 409, and the route never starts an engine or writes settings ([#7277](https://github.com/codewhale-hq/Codewhale/pull/7277)). Verified by the app-server route tests and terminal-host tests; no editor client uses it yet. Thanks [@gaord](https://github.com/gaord).
- **Automations:** a run missed while Codewhale was closed now waits on reopen for Run now or Skip instead of catching up silently; each automation can choose "If missed: ask" (default), "run once" or "skip". Tested in the engine only; no HTTP route tests, no desktop client yet, and a Mac asleep longer than the grace window counts as closed.
- **Website maintainer:** a scheduled `web-maintainer` workflow proposes website upkeep as pull requests only: regenerated facts, and three DeepSeek lanes (stale version mentions, moved links, docs drift) that may edit only allowlisted copy files and must pass `npm run check` and the web tests. It is off until the repository variable `WEB_MAINTAINER_ENABLED` is set and a capped `WEB_MAINTAINER_DEEPSEEK_API_KEY` secret exists, and it has never run. The Worker's triage, PR-review, stale, duplicate and curate (Today's Dispatch drafting) cron tasks are removed; the digest stays.
- **Website measurement:** the first-party ingest now accepts a closed website funnel schema while preserving existing runtime and browser batches. Reader confirmations remain self-reports, new website data stays first-party, and no deployment or live conversion gain is established by the source change.
- **Website facts:** the website now reads the installed version, asset list and repository numbers from the published release and a dated snapshot instead of the source tree, shows nothing rather than 0 when a live number cannot be read, stamps its facts revision and date together, no longer calls the desktop app native, says when the release was read, and drops the price from its structured data. This is a source change and is not deployed yet.
- **Website surface status:** the status of the terminal, browser, desktop, cloud and accounts surfaces now comes from typed states with copy in every locale, the desktop download appears only for a signed, notarized release with a checksum, the cloud-invitation and plan switches are committed values that default to off, the partner strip expires at render time, and repository numbers show when they were read. This is a source change and is not deployed yet.
- **Website capabilities:** the website now lists a capability as available only when the published release has it, labels features that exist only in source as not yet released, keeps held features (cloud computers beyond invite-only, other vendors' agents over ACP, and plans) hidden behind committed switches that default to off, and prints provider route, catalog model and tool counts as they are at the published release tag instead of on main. This is not deployed yet.
- **Installer uninstall lines:** the installers now print the uninstall command, the update-mode sentence and the shell-profile marker sentence only when the Codewhale they just installed reports an `uninstall` command, and older releases such as a pinned v0.10.2 get the manual removal steps instead of a command that would be sent to the model as a prompt. (CW-8029) The installers reach people through the website, so this is not deployed yet.
- **Installer PATH ending:** when `codewhale` is not on PATH, the installers' last lines are now the copy-paste `export PATH=...; hash -r` command and `codewhale --version`, and when it is on PATH the last line is `Next: codewhale --version`; the Computer Use notice moves above them and shows on macOS only. (CW-8030) The installers reach people through the website, so this is not deployed yet.
- **Installer PATH setup:** when the install directory is not on PATH, the macOS and Linux installers now add Codewhale's marked three-line PATH block to your shell profile, print exactly which file and lines they added and the command that removes them, and skip this with `--no-modify-path` or `CODEWHALE_NO_MODIFY_PATH=1`; the Windows archive installer adds the directory to your user PATH the same way and skips it with `-NoModifyPath`. Release archives carry this from 0.10.3 on, and the Windows installer has not been run yet. (CW-8036) The website serves install.sh, so this reaches people only when the website is next deployed.
- **Website and docs:** installation now leads to a version check and a verifiable first task, article search finds text and commands with section links, and GitHub star links show the fetched count. The hero reuses the generated drone whale, and control/tool references distinguish the unpublished source candidate from v0.10.2; these website changes still await deployment.
- **External agent options:** `GET /v1/agents/external/{id}/options?cwd=` returns the models, modes and options an external agent itself offers for a folder, and which Codewhale actions it will not carry. A saved agent model the agent no longer offers is refused with a stable `choice_not_offered` code instead of being ignored, per-turn settings an agent cannot honor are refused as `unsupported_control`, and each agent turn records the context window and tokens the agent reported, with cost shown as unknown (CW-7879). Probing starts a real agent session in the folder, which the agent may keep in its own history. Mode and config choices are listed but cannot yet be chosen through thread creation. Verified on Linux by unit and local HTTP tests against a fixture agent; no real installed agent, macOS, Windows or hosted CI run.
- **External agent interrupts:** Interrupting a turn while an external agent waits for approval now answers the agent's permission request as cancelled. (CW-7958)
- **External agent quota:** The Runtime API route `GET /v1/agents/external/quota` reports each external agent's quota as unknown with a reason (flag off, consent missing, not implemented). The new `agents.quota.<agent>` and `agents.quota.<agent>.consent` settings, saved through `POST /v1/config`, record the opt-in and consent (at most 32 agent entries). No agent credential is read. (CW-7993)
### Changed
- **Docs for agents match the release:** `/llms-full.txt` and `/docs-markdown/*` now serve the documents as they were at the published release tag, from a committed snapshot that is checked against the published release.
- **Extension host (experimental): trusted plugins ask for review once more.** With `extension_host` turned on, plugins you already trusted are shown for review again after this update, because the capability table they were reviewed against gained the `remote` service. No plugin can use that service yet: none is granted it.
- **Website text for agents:** llms.txt now gives agents the install steps for the released version, the current release and the state of each part of Codewhale, from the same content as the pages. `/docs-markdown/install.md` serves those install steps as a page, and the main-branch documents beside it now say which release they can run ahead of.
- **Website design:** codewhale.net now uses the desktop app's 5.3 light and dark colour roles and Geist / Geist Mono, replacing the warm-paper palette and Shannon Sans; the vendored design copy is synced to 5.3.0 and the whale-road ocean bands are unchanged.
- ACP: editors can start, list, load, prompt and cancel Codewhale sessions and approve or reject tool permissions through the Runtime; prompts with image or audio blocks and relative session directories are now refused instead of ignored, and edit and read tools report the right kind. Sessions an editor drives now run the plugin tools (TypeScript and DSH, when the extension host is on) and the MCP servers configured in Codewhale; their calls show as ACP tool calls and ask through the session's permission setting, and `initialize` reports the state under `agentCapabilities._meta.codewhale`. MCP servers an editor passes in `mcpServers` and configured shell hooks still do not run in ACP sessions. A real-editor journey is not yet proved.
- Extension host: the `sessions` and `systemPrompt` services now come from a reviewed DSH adapter instead of inline shims, and `sessions.flush` refuses an empty checkpoint ticket. Session reads and events and the `agent/pre-step` hook are still not available to plugins. (CW-7959)
- Extension host: DSH service adapters now have one ticketed `dsh/broker` request to the core, each ticket is bound to the plugin, the service and the session, and every service (workspace, llm, network, settings, catalog, terminal and remote) refuses with a typed `not_available` until its broker lands. Nothing new is offered to plugins yet. (CW-8012)
- **Plugin host services and who approved:** a plugin can now be granted a Codewhale host service, and only by a review that shows it. The review names each service and the plugins it is shared with, and every review records who approved it: you, the agent (in Full Access, in Auto-Review, or from a shell command carrying the agent's mark), or the command line with `--yes`; who turned the plugin on is recorded too. Plugins share one process, so a service works only while every loaded plugin of the same kind holds the same grant. A plugin the agent approved is active only in its own project and its code does not run beside the plugins you reviewed until you review it. No service is offered yet, and a plugin reviewed before this release holds no grant until it is reviewed again. Once a plugin has been reviewed or turned on in this release, Codewhale 0.10.2 and earlier cannot read the plugin state file and turn every plugin off when run on the same home folder. (CW-8012)
- Fleet member starts are now durable: replaying an operation key after a timeout or restart returns the original worker, and GET /v1/threads/{id}/members/operations/{key} reports the outcome. A member start now answers with `state` `accepted` (200) or `unknown` (202) instead of `started` or `queued`. Verified by local HTTP tests on Linux; a real Engine restart is simulated, not exercised. (CW-7964)
- Plugin activation now says when a requested service belongs to the Codewhale core and is not exposed to plugins yet. No plugin, provider or installed-app run exercised it; checked by the extension-host tests only.
- Codex App Server v2 contract record (paused, not part of 0.10.3): the selected Codex v2 contract is frozen as a generated manifest in the protocol crate, with typed Rust and TypeScript shapes checked against the pinned Codex schema. It changes no wire behavior and adds no dispatch, so nothing is reachable through it yet.
- **Website copy:** The site's headline is now "The model can be anyone's. The agent should be yours.", with its subhead, belief and labelled product map in every language.
- **Website routes:** Pages that repeated each other now redirect to the one page that does the job, the header and footer list only pages that exist under their current names, the sitemap drops redirected and catalogue pages, and machine-drafted translations say so.
- **Website privacy:** The website no longer counts anything when your browser sends Global Privacy Control or Do Not Track, and the privacy page says exactly what is counted and how it is keyed.
- Plugin UI: the Runtime API now serves reviewed DSH client closures on six seats (customize.plugins.detail, conversation.composer.dock, conversation.chat.node, workpane.panel, sidebar.section, command.row) with coded refusals, drops a plugin's UI grants the moment it is disabled, revoked or uninstalled, and adds a plugin route bridge that refuses until a plugin web server exists. No real DSH package has been served end to end yet, and a client that imports `@deepseek-ai/dsh-client-*` modules is still refused. (CW-7956)
### Fixed
- **Starting after a hard kill:** the Engine now starts when its process was killed and its data directory was then deleted. A socket owner record whose process is dead and whose data directory, the one this start selected, no longer exists is discarded instead of failing every start with "Failed to resolve ... tasks/runtime". A home reached through a symbolic link, such as one under macOS /tmp, is not covered yet.
- The install guide's note for a first message that gets no answer now describes v0.10.2: connect a model with `/provider`, and restart if messages stay saved for later after you connect. It described v0.10.0's key screen. The Chinese guide carries the same correction.
- Project activity on the site now comes from a server-side snapshot with a freshness record, the browser no longer calls GitHub, and count sentences use the right plural form in every language.
- The install page now gives the exact steps for the released version on every platform, including what the installer adds to PATH, how to turn off usage counting, and how to remove it, and the install command no longer gets cut off on phones.
- After choosing "explore offline" on first run, connecting a provider or Custom endpoint with /provider now takes effect immediately; messages are no longer held as "Saved for later" until restart, and a message held while offline returns to the composer.
- The pet browser view opens with a one-time code instead of the long-lived owner token, so the token no longer appears in the URL or the launcher command line. The code lasts 30 seconds and works once; the owner token itself is still stored in the cookie and connection file and is not rotated. Not run in a real browser.
- On Windows with Caps Lock on, Ctrl+E moves to the end of the line again instead of opening the file tree; the file tree now needs an explicit Shift (Ctrl+Shift+E or Cmd+Shift+E), so a terminal that reports an uppercase E with Ctrl but no Shift flag can no longer toggle it. The Caps Lock key event is simulated from the input library source; no native Windows run.
- External agents installed through npm on Windows (`claude.cmd`, `codex.cmd`, ...) are now found instead of the unrunnable shell shim, `GET /v1/agents/external` says whether an agent answered with an unsupported protocol rather than reporting every failure as no answer, and a hung `--version` or handshake probe no longer leaves the agent's child processes running. Verified on macOS and Linux; the Windows code has never been compiled or run, and no agent row is qualified by this change.
- The Runtime API's `POST /v1/git/push` now pushes exactly one branch at one commit (`<commit>:refs/heads/<branch>`, no follow-tags or submodule recursion), so `push.default`, `remote.<name>.push` and `push.followTags` can no longer publish other branches or tags. Clients can bind a push to a named branch and expected HEAD with `branch` + `expect.head` (advertised as `named_push` in `GET /v1/git`); a stale branch or HEAD answers `409 git_state_changed` and pushes nothing. A bare push from a detached HEAD or an unborn branch is now refused, and the desktop app has not yet adopted the named form. Verified on macOS by unit tests against a local bare remote; no real network remote, Linux, Windows or hosted CI run.
- Cancelling or timing out a read-only Git tool (git_status, git_diff, git_commit_plan, git_log, git_show, git_blame, git_merge_tree) now stops the git process and anything it started, instead of leaving it running in the background. Verified on macOS by unit tests; Linux, Windows and hosted CI are not yet run, and the filter-override probe is still not contained.
- TUI: the launch resume confirmation no longer treats Meta+Enter, Meta+Y or Hyper+Enter as "resume"; only a plain Enter/Y or Shift+Y answers it. Verified by the focused unit tests only; not tried in a terminal that sends Meta or Hyper.
- TUI: mentioning a huge directory or a far-away line range (`@file:N-M`) now stops after a bounded scan and says the result is partial instead of claiming end of file. Verified by the focused `file_mention` unit tests; no real 64 MiB file was tried.
- Runtime `patch-undo` now restores a turn's own file changes in the default (Ask) posture without trust mode or Full Access; later edits and changes the turn did not make are still refused with nothing changed, and the `restore_requires_trust` error code is gone ([#6970](https://github.com/codewhale-hq/Codewhale/issues/6970)). Verified by app-server and TUI unit tests on Linux; no Windows `/undo` or process-restart run.
- **Website terminal frames:** The site can render terminal frames captured from the released version, and chooses each frame's caption from where it was captured.
- **Website docs truth:** Documentation pages now describe the released version first and show what exists only in source in a labelled section that switches on when a release carries it.
- **Website Arabic pages:** On Arabic pages, English text that has no translation yet keeps its own direction and language, so punctuation, commands and dates no longer appear reversed.
- A DSH plugin whose package includes a `.gitignore` at its root now installs instead of being refused as a hidden file; nested `.gitignore` files, other hidden files, credential files and links are still refused. (CW-8023)
- `install.bat` in the Windows release archive now passes its arguments to `install.ps1`, so `install.bat -NoModifyPath` declines the user PATH edit like the PowerShell installer does, and the install guide says so. It has not been run on Windows. The batch file reaches people in the next release archive, and the guide sentence when the website is next deployed, because the site serves the guide but not `install.bat`. (CW-8046)
## [0.10.3] - 2026-11-08
This is the Codewhale v0.10.3 source candidate. It is not a published release
until the matching tag, packages, checksums, and release assets exist.
### Work in progress and known limits
This source candidate is not the final 0.10.3 tag. There is no
`0.10.3-beta.2`: the next release is the full 0.10.3, and its final tag waits
for the full scope list. Codex App Server v2 is paused and is not part of
0.10.3; the legacy JSON-RPC dialect is not retired in this release. The coarse
Engine split and DSH all-33 compatibility stay in 0.10.3, and none of this
work is declared complete here. Items moved to 0.10.4 by name are marked below.
- **Terminal lifetime (0.10.3 work item):** deleting a conversation now ends the
terminal sessions and background jobs owned by that Runtime thread. The
desktop tab-close half remains; shells still survive quitting or updating the
app, and an Engine restart loses live shells (reported as a new terminal
`instance`).
Scrollback beyond the 512 KiB ring is not recoverable.
- **Windows suite (0.10.3 work item):** the Windows Test job has not been shown
green on this candidate. Windows fixes for plugin runtime-root permissions,
Fleet ledger compaction and the Fleet role profile lock have landed, but only
a green run on the exact final SHA closes this. Scripted journeys are being brought to zero on GitHub-hosted
native x64 runners; macOS and Linux results do not establish Windows.
- **Moved out of 0.10.3 — Codex App Server v2 compatibility:** finishing the
Codex App Server v2 contract is paused so this release can focus on ACP (both
Codewhale driving installed agents and editors driving Codewhale), the DSH
plugins and the rest of the release. The typed Tier A and B method names and
the committed inventory stay in the protocol crate, checked against the
pinned Codex export; dispatch, subscriptions, bidirectional interactions,
durable settlements, a TCP WebSocket transport and the full SDK are not in
0.10.3. The HTTP/SSE Runtime API remains the supported way for the desktop,
mobile and other clients to reach the Engine, and the legacy JSON-RPC dialect
is not retired in this release.
- **DSH plugins and MCP lifecycle (0.10.3 work item):** "full" compatibility
means all 33 surveyed plugins, unmodified, each passing its core journey on
macOS, Linux and Windows, against DSH 0.2.2-rc.1. The uplift comes first;
receipts from 0.2.1-rc.5 and earlier are not carried. The host uplift to
DSH 0.2.2-rc.1 (Cordis 4.1.0) is in the candidate; no plugin receipt has been
recorded against it yet. The source candidate
restores missing runtime snapshots only from canonical bytes matching the
current review, generation and policy. Existing mismatched or tampered
snapshots refuse and require review. Native lifecycle qualification,
authenticated DSH UI transport and revocation in Electron, and an end-to-end
published-plugin journey remain unfinished.
Imported DSH client UIs refuse descriptor and asset grants; their supported
Native and MCP contributions retain their existing lifecycle.
Downgrading a newly saved plugin marketplace catalog remains unqualified.
- **External agents as whole sessions (0.10.3 work item):** a session can run
on an installed agent CLI, and shutdown, restart recovery and durable approval
answers are now in the candidate. Verification so far uses fixture agents;
each real agent CLI, steering, compaction, forking and images remain
unqualified or unavailable.
- **One permission dial (0.10.3 work item):** Shift+Tab steps through every
posture and Plan, Accept Edits is the default, and saved choices and strict
managed startup are preserved. A founder pass through every stop on a real
terminal and on each client that reads the posture has not been recorded.
- **ChatGPT sign-in on Windows (0.10.3 work item):** the reported 0.10.2
post-browser identity verification failure has not been confirmed resolved in
the reporter's environment. More specific errors and clock-skew handling are
not a successful Windows sign-in receipt. The founder's Windows check uses
`codewhale auth chatgpt` plus one turn. ([#7203](https://github.com/codewhale-hq/Codewhale/issues/7203))
- **Moved to 0.10.4 — conversation recovery on Deepin:** scoped
interrupted-reply recovery and persistence checks do not establish a fix for
the original whole-history disappearance on Deepin 25.2.2. ([#7095](https://github.com/codewhale-hq/Codewhale/issues/7095))
- **Windows ACP and undo (0.10.3 work item):** the original Paseo
approval/sandbox journey and ordinary multi-turn `/undo` through Windows
ConPTY remain unqualified on the final candidate. Scripted journeys run on
GitHub-hosted native x64 runners; the founder runs Paseo with the reporter's
configuration. macOS and simulated checks do not establish those Windows
results. ([#6992](https://github.com/codewhale-hq/Codewhale/issues/6992), [#6970](https://github.com/codewhale-hq/Codewhale/issues/6970))
- **Install and update routes (0.10.3 work item):** final-candidate Windows and
Linux package, install, update, rollback and uninstall coverage is incomplete.
Earlier scoped platform receipts do not qualify the final package matrix or
ordinary Windows user journeys. ([#7091](https://github.com/codewhale-hq/Codewhale/issues/7091))
- **Workspace downgrade and rollback:** compatibility with older binaries after
a 0.10.3 workspace migration remains unqualified. The CLI self-updater guard
refuses recorded targets below 0.10.3 in `codewhale update --rollback` when
running 0.10.3 or newer, before replacing the executable. Five isolated
macOS development-candidate refusal/control cases passed with fixture trees
unchanged. This does not provide backward-compatible rollback or qualify
actual workspace migration or an allowed rollback. Manual or package-manager
downgrades and older builds reporting the same version remain outside the guard.
- **Moved to 0.10.4 — long-running ZAI sessions:** scoped watchdog and recovery
checks do not establish a fix for the original hours-long, tool-heavy silent
stall; any further hardening moves with it.
([#6184](https://github.com/codewhale-hq/Codewhale/issues/6184))
### Added
- **Approvals name the client that answered:** `POST /v1/approvals/{id}`
accepts an optional `client` (`desktop`, `phone`, `web`, `tui`, `acp`), and
the resulting `approval.decided` event carries it as `responder`. The phone
and web mirrors and the ACP server send theirs. It is a label the client
declares, not an authenticated device identity. Repeated answers from two
clients wait for the same saved decision before acknowledging success.
- **Sessions on your own installed agents:** `POST /v1/threads` with
`executor: {kind: "acp", agent_id}` runs a session on an agent CLI already
installed and signed in on this computer (OpenCode, Kimi Code, DeepSeek
Harness, Antigravity, and Claude or Codex when their ACP adapter is
installed). The agent's messages, reasoning, tool calls and plan arrive as
ordinary session events, its permission requests are approval cards answered
through the usual approvals route under the session's posture (Full Access
allows, Plan rejects, Accept Edits allows only edits inside the workspace,
everything else asks), stop cancels it and ends a process that does not
stop, and the session reopens the same agent session after a restart. The
agent keeps its own login; Codewhale never reads, stores or passes its
credentials and never downloads an agent or adapter. Refusals carry a code
(`not_installed`, `adapter_missing`, `below_min_version`, `needs_sign_in`)
beside the sentence, session summary rows name their agent, and the agent's
own usage reports are recorded as `agent reported` with cost unknown.
Steering, compaction, forking and images are not available in these
sessions. Quitting Codewhale, or abandoning a session while its agent is
still starting, ends that agent before shutdown finishes. See
`docs/RUNTIME_API.md`.
- **DSH market indexes are readable:** `/plugin marketplace add` and
`GET /v1/apps/marketplaces` now parse the DeepSeek Harness plugin market
index (format 1) alongside the Kimi, Claude, Codex and Codewhale catalogs.
Entries keep npm package identity, localized title and description, a
resolved icon, declared category and label ids, and every version ordered
by SemVer precedence; the highest version decides the row. A version whose
`engines.dsh` range admits none of the DSH versions this host targets is
refused before any download. npm sources are listed but not installable
(Codewhale does not execute npm), and a commit-pinned GitHub source without
a package subdirectory installs from the pinned commit.
- **Plugin catalog over the Runtime API:** `GET /v1/apps/plugins/catalog`
lists the built-in plugin settings (Subagent, Web search, Shell, Agent
loop), the experimental features and the remaining features as rows the
desktop Plugins page renders directly. Enable, disable and the subagents
concurrency setting persist through the same config writer and reload as
`/v1/config`; the agent loop itself cannot be turned off.
- **Optional host policy on model HTTP clients:** embedders can install an
in-memory `ModelHttpPolicy` that vets or configures the HTTP builder for
the primary, model-list, HTTP/1.1 and vision transports before a client is
built. Config files cannot install the hook, and transport behavior
without a policy is unchanged. Thanks
[@zhuowp](https://github.com/zhuowp)
([#7251](https://github.com/codewhale-hq/Codewhale/pull/7251)).
- **DSH bundles install from tarballs and admit CJS packages:** installing a
DeepSeek Harness bundle from a `.tgz` now detects the `dsh.bundle` manifest,
converts it during staging, and admits CommonJS packages (including
`require` exports and bundled `node_modules`) alongside ESM. Admission
checks `engines.dsh` as a real npm semver range against the host's supported
DSH versions and refuses bundles whose `dsh.bundle.platforms` excludes this
computer; native `.node` addons stay refused.
- **Prune pasted images:** `codewhale sessions prune-images` lists pasted
clipboard images that no saved session, checkpoint, Runtime thread, draft or
history still names and that are older than 7 days (`--older-than-days`);
`--apply` deletes them. If any file it must scan cannot be read, it deletes
nothing. Run it while no Codewhale session is open. Thanks
[@Asteria1028](https://github.com/Asteria1028) for the report (Refs #7221).
- **Task wall clock pauses for answerable human waits (#5898):** a durable task run by the Runtime API server no longer spends its wall-time budget while a prompt on that run waits for an approval or user-input answer. `[tools] task_human_wait_cap_seconds` (default 1800, maximum 86400) bounds the total wait and fails an unanswered task with `human_wait_timeout`, releasing its worker. Only a Runtime serving its HTTP API pauses the clock; local Stdio, Socket and ACP control frontends keep the wall deadline, and a wall deadline crossed before the prompt still ends the task. The TUI's own tasks are unchanged. Thanks [@asto18089](https://github.com/asto18089).
- **MCP servers say why they are not connected:** the Runtime API's
`GET /v1/apps/mcp/servers` now includes a configured server's last
connection error while it is retrying, so the desktop and other clients can
show the reason instead of only "disconnected".
- **Inspect and repair plugin snapshots:** `codew plugins status [name]
[--json]` reports bundle state and diagnostics without changing plugin
stores. Runtime loading restores a missing snapshot only from bytes matching
its enabled review and policy; `codew plugins restage <name>` or
`/plugin restage <name>` retries explicitly. Recovery preserves review and
generation and refuses an existing changed snapshot. Isolated macOS checks
exercised the published Code Review 1.0.8 Native status lifecycle and official
filesystem MCP reconnect; live review execution and other plugins remain
unqualified.
- **Shared optional account sign-in:** `/connect` offers Codewhale sign-in or
on-computer provider setup. Desktop and terminal use the same profile-scoped
Rust account session; sign-in preserves the selected model and local keys.
Ordinary logout removes the account session, while `logout --all` explicitly
clears saved model credentials. Startup prompts keep missing-model setup
visible instead of covering it with the optional working-agreement checkpoint.
Real sign-in acceptance remains open.
- **Refresh model catalogs during use:** Runtime provider refresh now checks
public Models.dev metadata alongside the exact provider's model list;
`force_catalog=true` bypasses the public cache TTL and retry backoff.
`GET /v1/providers` exposes catalog revision and freshness so clients can
pick up new models without repeatedly loading an unchanged catalog. The
runtime rechecks in the background, retains the last good snapshot on
failure, and preserves explicit model selections and account/route scope.
- **Tinker beta route:** configure Thinking Machines Tinker's OpenAI-compatible
endpoint and a serverless model or sampler checkpoint ID. Model-list discovery,
key verification through that list, and cost estimates remain unavailable;
live conversations, tools and image input have not been qualified in
Codewhale. See [provider setup](docs/PROVIDERS.md).
- **Worktrees for parallel workspaces:** `GET /v1/worktrees` lists a repository's worktrees, `POST /v1/worktrees` creates a branch and its own checkout under `<repository>/.codewhale/worktrees/` through the existing lane provisioning, and `POST /v1/worktrees/remove` archives a clean managed one without `--force`, keeping the branch. A client starts a thread in the new folder, so several agents can work on one project without sharing files. (codewhale-hq/codewhale-app#3500)
- **Thread-scoped snapshots:** `GET /v1/snapshots` and `POST /v1/snapshots/{id}/restore` accept `?thread_id=` and act on that thread's workspace under the same restore admission rule. (codewhale-hq/codewhale-app#3500)
- **Reviewed plugin UI assets (preview):** native plugin bundles with supported client entries can expose reviewed assets through the Engine's loopback descriptor and asset routes. Runtime and workspace authorization are required; exact asset bytes also require the current opaque grant. Responses keep bounded sizes, confined paths and safe MIME/no-store behavior. The desktop host binds grants to individual plugin frames; real Electron transport and teardown qualification remains open. Imported DSH client halves remain unsupported and refuse UI grants. (#2, #3)
- **Present final files:** the read-only `present` tool takes 1–32 existing
workspace files, streams their SHA-256 and byte counts, and returns an
auditable handoff receipt without copying, moving or uploading them. It is
eager in Act/Operate and Plan; the `present-handoff` feature is experimental,
and there is no dedicated app card yet.
- **Truthful background jobs:** shell job snapshots and completion events now
carry the exact start time, a typed termination cause (`producer`, `killed`,
`timed_out`, `unknown`) and whether the producer reported it. A killed job is
no longer indistinguishable from a failed one, and the bash guidance tells the
model to collect or cancel live jobs before a final answer.
- **`/export` writes HTML and JSON:** `/export file report.html` saves a self-contained page (light and dark, no scripts, a strict content-security policy, tool calls collapsed) and `report.json` a versioned, typed-block envelope. `--format md|html|json` overrides the extension, and `--no-tools` drops tool calls and results from the conversation. `/export file` with no path now writes an auto-named `codewhale-<title>-<timestamp>` file under `<codewhale home>/exports` and reports the format, line count and redactions; `~` expands and quotes keep a path with spaces together. `--force`, `--no-tools` and `--format` are accepted in any position. HTML and JSON are file-only; the clipboard and `/export turn` remain Markdown.
- **Tencent HY4:** the stable `tencent/hy4` model is available through OpenRouter with its published multimodal, tool, reasoning and context metadata. `/provider tencent` adds the direct TokenHub route with `hy4` and `TENCENT_API_KEY`; direct availability and prices remain separate from OpenRouter, and preview/HY3 selections are preserved.
- **WeCom steers a running turn (#7211):** a WeCom message sent while a turn is running is forwarded to the Runtime's steer endpoint instead of being dropped with the busy notice, which remains the fallback when the steer is rejected. Thanks [@gaord](https://github.com/gaord).
- **WeCom accepts media and voice (#7212):** the WeCom bridge downloads image, video and file messages into `WECOM_MEDIA_DIR` (default `<workspace>/media`) under a sanitized name and replies with the saved name, size and path; a failed download tells the sender the link expires after about five minutes. Voice messages use WeCom's transcription as the prompt, and other message types get an explicit answer instead of a blanket refusal. Thanks [@gaord](https://github.com/gaord).
- **Pinned local thread controls (preview):** initialized App Server clients can list retained loaded Engines with cursor paging and rename the canonical thread through `thread/loaded/list` and `thread/name/set`. Saved but unloaded threads stay out of the loaded list; existing aliases remain available. Full-tool turns and subscription parity remain unfinished.
- **Reply style and sub-agent limit over the Runtime API:** `GET /v1/config`
reports and `POST /v1/config` writes `verbosity` (`normal` or `concise`) and
`subagents_max_concurrent` (how many sub-agents may run at once, `0` to
`128`, where `0` turns them off), so the desktop's Settings can show and
change both. An unset limit reads as the one the Engine applies; nothing
writes a default for you.
- **Local whale voice (preview):** the host can edit its private, revision-checked SOUL.md through the Runtime API. The Engine captures it for the next turn within the existing instruction budget and records its source; invalid private files refuse the turn with a terminal failure.
- **MCP tool approval rules (preview):** exact tool names in the global server configuration can use Always, Ask or Off across workspaces. Off wins, server edits invalidate the prior grant, and required Computer Use consent and nested-program approval remain in place.
- **Attested watch-turn ingress (preview):** a configured Runtime master bearer can admit typed schedule or pull-request receipts through the existing thread and turn owner, with exact operation replay and read-only recovery lookup. This supplies the Native ingress prerequisite; it does not qualify the complete continuous-operation workflow.
- Goal continuations send the objective once per live conversation window. Later passes show the current goal state, estimated conversation input and the applicable compaction setting. Full notes stay available through `get_goal`. Thanks [@7jrxt42BxFZo4iAnN4CX](https://github.com/7jrxt42BxFZo4iAnN4CX) for measuring the repeated text and identifying the misleading token figure ([#7172](https://github.com/codewhale-hq/Codewhale/issues/7172)).
- **Composition on the first request:** `execute_tools` accepts a bounded named batch from the current MCP catalog, with argument names from its allowed members and the same nested gate as a JavaScript program. Exact tool-name searches work with regex anchors. Stream receipts hash the executable in the background; `CODEWHALE_TIMING=1` reports phase durations.
- **The model can read what compaction replaced (#7173):** two read-only tools,
`context_archive_search` and `context_archive_get`, search the session's
saved pre-compaction snapshots and read one archived message by id, with
bounded results (12,000 characters per read, 20 hits and a 200-character
query per search). Each message is masked whole for credential shapes and
currently configured secrets before it is searched or paged, and
`codewhale sessions scrub-secrets` now also rewrites those snapshots. A
`/fork` cannot read the archive its handoff note refers to, and a bare secret
absent from current configuration is not masked. Thanks
[@SparkofSpike](https://github.com/SparkofSpike).
- **Opper as a bundled provider (#7131):** `/provider` offers Opper, an
EU-hosted OpenAI-compatible gateway, with `OPPER_API_KEY`,
`https://api.opper.ai/v3/compat` and the `claude-sonnet-4-6` pool name as the
bootstrap model; `provider/model` ids pin one route. Live
`/v3/compat/models` is the model authority and billing stays Unknown. No live
Opper call was made here. Thanks [@Felixkw12](https://github.com/Felixkw12).
- **Runcrate is a bundled provider:** `runcrate` reaches the OpenAI-compatible host at `https://api.runcrate.ai/v1` with `RUNCRATE_API_KEY`, and `codewhale models --update --provider runcrate` refreshes its public model IDs before a key is configured. Inference requires the route key. Thanks @heydryft for the request and the vendor details. (#7085)
- **MCP connection status reaches the model:** one existing history snapshot now records permitted configured, connecting, failed, authorization-required, unknown and connected servers, with bounded inert names and no raw errors. Stale status and server guidance are withdrawn on contention, configuration/scope changes and restore; observation does not connect servers or promise callable tools. (#6866)
- **Bundled-skill policy:** `[skills.bundled]` separates automatic, authoritative and disabled installation from discovery, with per-name selection, disable and explicit-only controls. Aliases share policy; disabled shipped copies reveal user alternatives. Modified and managed files remain intact, and doctor plus `/skills inspect` show the effective policy. (#7066)
- **Configurable skill routing index:** `[skills] listing_max_description_chars` and `listing_budget_fraction` control the shared parent/child catalogue. Defaults use 120 characters and 0.2% of the route window, within the existing total bounds. Load warnings, localized inspect notes and `/context` explain shortening; full skill loading stays available. (#7073)
- **Compact approvals keep their authority visible:** cards show three choices and default to Deny. An exact saved rule requires its scope preview on screen. Shortcuts for additional actions require opening Details; a hidden saved-rule choice never falls back to granting the session.
- **Quicker everyday navigation:** top-level help separates everyday and advanced commands, `doctor --all` expands path/backend details, and the launch screen labels how to resume recent work. Up selects the newest recent session. Whale cameos stay out of transcript text.
- **Session-window diagnostics:** the audit log records when a saved window starts a new journal root while retaining the previous branch, helping distinguish window replacement from lost durable history. `session.window.rerooted` now names a `cause` (`engine_projection`, `session_restore` or `unattributed`) and also fires when a journal with entries has no active path. (#7142)
- **Usage reporting counts models, tokens and tools:** when usage reporting is on, each session now also reports, per provider and model, its turns by outcome, input, output and prompt-cache tokens, and turn-time buckets, plus how many times each built-in tool ran and failed. A model is named only when it is in Codewhale's bundled public model catalog; custom, local and fine-tuned names are sent as `other`, and MCP and plugin tools as `mcp` or `other`. No prompts, outputs, tool arguments or paths are sent. Runs under CI or the GitHub Action report the `ci` session source. The first-run notice is shown once more to describe this. `DO_NOT_TRACK=1` now turns usage reporting off for that run, like `CODEWHALE_TELEMETRY=0`; `codewhale config set telemetry false` still turns it off for good. See `docs/TELEMETRY.md`.
- **`exec` and `doctor` follow the TUI onto local Ollama:** with no cloud key and no explicit route, `codewhale exec` uses a running local Ollama chat model and says so, and `codewhale doctor --probe-local` checks that route. Nothing is saved. (#7115)
- **Thinking starts at auto:** new configurations and the built-in default use `reasoning_effort = "auto"` instead of `max`; an effort you set is never changed.
- **DSH Git review scopes:** the extension host brokers bounded, read-only Git metadata to reviewed DSH plugins through a new `git_review_scope` action (extension-host policy v8).
- **Safer, more complete uninstall:** for a receipted release copy, `codewhale uninstall --yes` now also removes this install's exact three-line `# >>> codewhale PATH >>>` block from your shell profiles and the Codewhale-generated completion files at their documented paths (bash, zsh and fish, honouring `XDG_DATA_HOME` and `XDG_CONFIG_HOME`). It touches nothing else in a profile, leaves a symlinked or unreadable profile for you to edit, keeps the completion files while another Codewhale copy remains on PATH, and exits non-zero if that cleanup fails after the program is already gone. The `codewhale.net/install.sh` hint and the install guide now print the PATH line as that marked block, so there is something provably yours to remove; a bare `export PATH=…` line you added earlier is never touched. Data purge requires a receipted removal in the same confirmed run. Both Unix installers reject unsafe or managed destinations before creating them and still never edit shell profiles themselves. Uninstall instructions match the explicit-home purge scope in English and Chinese. Not yet observed on a real Windows host or an installed release artifact. (Refs #7091)
- **Nested and deletable threads (Runtime API):** a fork (including a backtrack fork) records `parent_thread_id`, `POST /v1/threads` accepts one naming an existing thread, and `GET /v1/threads/summary` returns it so clients can nest child conversations. `DELETE /v1/threads/{id}` removes an idle thread with its turns, items, events and goal, and its saved session unless another thread shares it or a terminal holds it open; a running thread answers 409.
- **Hunk actions in Review (Runtime API):** `POST /v1/git/stage`, `/v1/git/unstage` and `/v1/git/discard` take a `patch` holding hunks of the one path in `paths` and apply only those hunks through `git apply`, under the same `expect` preconditions as whole-path writes. A patch that no longer applies fails with git's message and writes nothing; renames, mode changes and binary patches are refused. The tasks tool can also `suggest` a task, shown as a Start/Hide card, without starting anything.
- **Live `/models` ceilings reach the route:** a provider that states per-model context and output limits in its own `/models` body now keeps them instead of falling back to the legacy 128K window. OpenAI `limit` blocks, flat `context_length` / `context_window` / `max_model_len` / `max_context_length` fields, `max_output_tokens` / `max_completion_tokens`, and a relay `metadata` block (`context_limit`, `context_budget`, `output_budget`) are read; `metadata.context_limit` outranks `context_budget` because the first is the model capability and the second the share one deployment accepts. Each field is parsed on its own, so an unreadable one costs only its own candidate instead of hiding the readable fields below it.
- **Change mode and permissions while the agent works:** Tab, Shift+Tab, `/mode`, the hotbar and `/config mode` no longer refuse while a turn is running. A response that is already streaming is not restarted; the change applies at the agent's next step in the same turn (before its next tool batch, at every approval gate, and before its next model request, which carries the new mode notice). The status line says so until it applies. A call still waiting for approval goes back to the model under the new posture, and a call you already approved runs only if the new posture is equal or broader. Model, thinking level and provider stay locked until the turn ends.
- **Steering interrupts thinking:** a steer (Ctrl+Enter, or Enter twice after queueing) now closes the in-flight model request at once, whether the model is waiting on headers, reasoning, writing text or emitting a tool call, and continues the same turn with your message. Text already shown is kept as interrupted output; unfinished reasoning and partial tool calls are discarded, never run.
- **Modern MCP client:** MCP servers now connect through the official MCP SDK (2.4) behind Codewhale's Rust broker by default (`mcp_backend = "host"`; `"rust"` stays available for one release). Servers that speak the 2026-07-28 revision are discovered with `server/discover`; other stdio and HTTP servers fall back to the legacy `initialize` handshake, and configured SSE servers keep theirs. Rust keeps process, network, credential, catalog, approval and cancellation authority.
- **DeepSeek Harness plugins:** reviewed DSH plugins (definition API pinned to DSH 0.2.2-rc.1 in a shared compatibility table) run in the Native extension host. Tool output is validated against its declared schema, unsupported options are refused instead of ignored, and plugin commands can submit a prompt with visible plugin attribution. Terminal command receipts are kept in thread snapshots without entering model history. Changing the compatibility table invalidates earlier trust. A newly enabled plugin's tools are offered on the first turn: the turn waits up to 10 seconds for the plugin host to finish loading instead of adding them only from the next turn. The importer reports that it does not convert `dsh.client` UI; Engine routes and a desktop slot exist, but isolated end-to-end plugin UI remains unqualified, including network containment. A plugin tool can call `ctx.sessions.flush(exec.agent.session)` to have the Engine save the conversation so far before it continues (Runtime, terminal and `exec` sessions); it reports failure instead of claiming a save. Installing a plugin whose bytes changed after review now returns a 409 conflict instead of a server error. A plugin tool can ask you a question with `ctx.userQuestions.ask` and gets back the options you picked, your own text, or a skip; the question shows like any other Codewhale question in the terminal and through the Runtime API. A plugin tool can start a child agent with `ctx.subagents.startActivation` (the `spawn` provider): the child runs through Codewhale's own sub-agent manager, needs the same approval as the model's `agent` tool, can carry an extra persona section and a narrower tool list set in its `agent/created` handler, and returns its result to the plugin.
- **MCP catalogs stay fresh:** a server's tools, resources, prompts and skills are rediscovered on their own connection when an advertised `ttlMs` expires or the server sends a list-changed notice. A tool resolved against the old catalog is refused with "retry the call", a removed tool cannot run, and a failed refresh reconnects instead of serving stale entries. Catalogs are never shared across servers, credentials or reconnects.
- **MCP Skills extension:** servers that advertise the published Skills extension have their skills listed in `list_mcp_resources`. Listing never activates a skill, and reading a skill file is refused unless its size and sha256 digest match the listing. MCP skills do not yet join `/skills`.
- **Updates install themselves:** release-binary installs check for a new release every 6 hours (was 1), download and checksum-verify it in the background, and apply it the next time `codewhale` starts, never during a session. One line says `Updated to v… · What's new: … · Undo: codewhale update --rollback`. Until releases are signed, the download waits for your OK (one `[y/N]` question at the next start, or `/update install`); a release with a valid Ed25519 manifest signature applies on its own. `codewhale update --rollback` puts back the version the last update replaced and keeps the rolled-back version from returning automatically. Turn it down with `codewhale config set update.mode notify` (or `off`, or `CODEWHALE_UPDATE_MODE`); an organization's root-owned `policy.toml` overrides both. Offline and rate-limited checks retry about an hour later instead of on every launch. Package-manager and desktop-app copies only get their manager's command. Builds with the release key refuse a missing or invalid signature, and re-check the staged binary against the signed manifest at start. The checksum manifest now always comes from GitHub Releases; on Linux x64 the CNB mirror can still serve the binary, but only bytes that GitHub's manifest lists.
- **One view of every Codewhale on the machine:** `codewhale doctor` has an Installations section and `codewhale doctor --installs` (`--json`, `--brief`) lists every `codewhale`, `codew`, `codewhale-tui`, `deepseek` and `deepseek-tui` with its owner: install receipt, package manager (with its exact removal command), the desktop app, a backup, or not ours. Nothing found is ever run. `codewhale doctor --fix` adds one plan to tidy them: old backups move to `~/.codewhale/recovery/<stamp>/` (kept 30 days, then deleted by a later `--fix`), an unreceipted `codew` is brought in line with `codewhale`, and the directory gets an install receipt; each move prints its undo and `codewhale doctor --restore <stamp>` reverses the lot. Package-managed, desktop-app, symlinked and foreign files are never touched, and neither is user data. `codewhale uninstall` now lists other copies with the same classification.
- **Uninstall guidance on every install route:** `codewhale uninstall` previews receipt-owned release files and `--yes` removes only checked files, with the running command last. Both Unix installers and the Windows archive installer record command ownership; self-update renews existing receipts on both. On Windows the running `codewhale.exe` is renamed, then a hidden PowerShell process deletes it after the command exits. Package-managed copies are left alone, and the command prints their exact removal command: npm with its prefix, Cargo with its root, the Homebrew formula, `scoop uninstall codewhale`, `winget uninstall --id HunterBown.CodeWhale`, or the Windows setup's `Uninstall.exe`. Every other `codewhale`/`codew` still on PATH is listed. User data is kept unless you add `--purge-data`. With `--yes` it runs only after a receipted installation was removed in that same run, and then deletes only `~/.codewhale` (or a `CODEWHALE_HOME` named `.codewhale`) and `~/.deepseek/snapshots`, refusing symlinks, home ancestors and directories owned by another user. A copy from an older `curl | sh` installer that wrote no receipt is adopted on `--yes` when it sits in a known older curl-installer directory: the commands byte-identical to the running program get a receipt and are removed, anything else is preserved, and a symlink or hard link among them stops adoption before any receipt is written. (Refs #7091)
- **GitHub Action reviews:** analysis can export a structured Engine review for a separate trusted publisher job. The publisher checks the current PR revision and line anchors, deduplicates its findings, and keeps uncertain or preexisting claims out of inline comments.
- **DingTalk bridge:** an optional internal-app Stream adapter reuses the same Engine, shared admission and approval helpers. Tenant/staff allowlists, durable acceptance before acknowledgement and retained uncertain deliveries protect recovery. Managed account linking is separate from this advanced self-hosted bridge.
- **Answerless output-limit recovery:** opt into `[reasoning_only] on_output_limit = true` to request an answer again after a length stop with no answer or tool call, including hidden reasoning and ordinary Fleet workers. Retries share `max_reprompts`, retain existing output and control limits, and record request-scoped nudge receipts without adding them to resumed conversation context. RLM keeps its existing stop protocol. Thanks [@M-Maciej](https://github.com/M-Maciej) for the long-proof Fleet report. (#6990)
- **OrcaRouter recommendation:** `/provider` and `/model` offer a shared partner recommendation with the DeepSeek V4.1 Flash 30% top-up-match link, public referral disclosure and localized offer details. F7 or a click opens the existing pager while retaining the current route.
- **Per-scope instruction budgets:** global and project standing instructions now have separate token budgets (100,000 estimated tokens each, capped at 25% of the usable context window), every trim, skip or refusal reaches the model and `/context report`, and `[instruction_budget] policy = "refuse"` stops a request before dispatch. Other tools' instruction files stay opt-in through `project_instruction_imports` or `claude_fallback`, and the table is user config only. Thanks [@7jrxt42BxFZo4iAnN4CX](https://github.com/7jrxt42BxFZo4iAnN4CX) for the design and implementation. (#6526, #7086)
- The TUI Terminal dock now also shows the model's shell commands for the
session: each running or recent command is a read-only tab with its live
output, beside the interactive shells. "No live terminals" appears only when
there are neither.
- Preview: `dispatch --computer` starts an account cloud conversation that can
also be opened in desktop. `--thread` continues or inspects it; `--stop`,
`--approve` and `--deny` control its current task. Explicit `--key-stdin`
installs provider access in the running computer's memory. Retries retain
one operation key and the account/VM binding. Existing Agent Work dispatch
remains available when no computer conversation is selected.
- A long draft or paste now grows the composer past its density row limit, up
to half the screen (never less than that limit) while leaving room for the
transcript, so the text can be read and edited before sending. While a
slash, mention or history-search menu is open the composer keeps its usual
height (#7049).
- **Scheduled work can post into an existing conversation:** automations,
`send_later` triggers and tasks accept `destination_thread_id`. A run then
starts a turn in that thread instead of a new one, retrying while the thread
is busy up to the task's time limit, and a missing or archived thread fails
the task by name.
- **Audit receipt as Markdown (Runtime API):** `format=md` on the thread and
turn receipt routes returns the same text the terminal shows; other formats
return 400.
- **Native HarmonyOS binary:** releases build `aarch64-unknown-linux-ohos` as an
eighth target and publish a signed `codewhale-ohos-arm64`, so HarmonyOS users
no longer need a Rust toolchain and the OpenHarmony SDK, and
`npm i -g codewhale` there picks the native build.
- **Pinned whale routes (preview):** `codewhale account agents create NAME
--provider P --model M` pins the exact route on the whale's saved Agent, and
`account agents list` shows each whale's provider and model.
- **Cloud dispatch reuses a configured API-key model (preview):** plain
`dispatch` picks your only running account computer and carries a portable
configured model; the key is sent in memory only, bound to the account and
the exact HTTPS endpoint.
- **Mistral Vibe key setup documented:** the Mistral provider docs point to
current Vibe Code key guidance, with its shared-allowance and billing limits.
Live use in Codewhale is not verified.
- **Website:** an Enterprise page at `/enterprise` lists what Enterprise will
deliver, with no pricing or availability claim, and the FAQ is finished.
- **Runtime API: find the agent CLIs already installed on this computer.**
`GET /v1/agents/external` reports Claude, Codex, DeepSeek Harness,
Antigravity, OpenCode, Kimi Code, Mistral Vibe, Qoder, CodeBuddy and Grok,
with the version each one reports, whether it answers Agent Client Protocol
itself, and `runnable` when a thread can run on it now. The probe runs
`--version` and one `initialize` handshake, gets no Codewhale or provider
credentials, and stores nothing. Google's agent is Antigravity (`agy acp`,
1.5.0 or newer); Gemini CLI is no longer listed.
- **Runtime API: check a provider key before storing it.**
`POST /v1/providers/{id}/key/check` asks the provider's own `/models`
endpoint once whether it accepts a key, and never stores it. A key the
provider rejects answers `422`; a provider that cannot be reached answers
`502`, so a client can still save the key. The desktop app uses it so a wrong
key is refused with a clear message instead of being saved. See
`docs/RUNTIME_API.md`.
- **Website: the homepage whale comes alive.** It starts as the flat Codewhale
mark, is colored in as the live whale, then becomes a field of breathing
lights made of the same 64 points as the desktop app. Pointing at it or
picking a terminal view brings the whale back. Reduced motion keeps the still
whale. Not yet published to codewhale.net.
- **Website and docs:** installation now leads to a version check and a verifiable first task, article search finds text and commands with section links, and GitHub star links show the fetched count. The hero reuses the generated drone whale, and control/tool references distinguish the unpublished source candidate from v0.10.2; the homepage leads with the live project and a new headline, a public roadmap and contributing guide put issues first for features, the shared project sections are translated into all 18 site locales, task guides no longer carry the retired mode instructions, and the missing-reply guide diagnoses a failing provider call without assuming the key is missing. These website changes still await deployment.
- **Chinese docs:** a short setup page for people new to Codewhale ([zh_hans/PROVIDER_QUICKSTART.md](docs/zh_hans/PROVIDER_QUICKSTART.md)) walks through choosing a provider, setting an API key on macOS, Linux or Windows, picking a model and reading `codewhale doctor --probe-api` when the first call fails; the Receipts, Claude plugin compatibility and GitHub review bot pages are now translated into Simplified Chinese and linked from the Chinese index ([#7266](https://github.com/codewhale-hq/Codewhale/pull/7266), [#7264](https://github.com/codewhale-hq/Codewhale/pull/7264), [#7263](https://github.com/codewhale-hq/Codewhale/pull/7263), [#7265](https://github.com/codewhale-hq/Codewhale/pull/7265)). Thanks [@luochen211](https://github.com/luochen211).
### Changed
- **`read` pages in lines only (breaking).** One `read` call returns at
most 2,000 lines — the default and the maximum `limit` — inside a 50 KiB
output cap, and a line longer than 2,000 chars comes back truncated with
a marker instead of dead-ending the read. The model-facing `max_bytes`
parameter is gone: continuation is always the next line offset, and
footers say only that ("Showing lines 1-51 of 2000; output cap reached.
Continue with offset=52."). The byte cap stays as an internal bound;
operators can still widen it process-wide with
`[workshop] read_result_max_bytes`.
- **A leaner first request.** The pinned system prompt sheds its duplicate
guidance: the base layers shrink to about 4,300 characters, the skills index
no longer rides in every prompt (`load_skill` searches and lists the
catalogue on demand), and MCP Registry guidance moved into the
`registry_sync` and `tool_search` descriptions, where it is read when the
tool is used instead of on every turn. **This changes the session-pinned
prompt, so each session re-pins its prompt cache once after upgrade.**
- **Workspace instructions arrive as a conversation message.** `AGENTS.md` and
other standing instructions are delivered once as a user-role history
message instead of being pinned inside the system prompt, capped at 64 KiB.
The guidance is unchanged; editing the file now takes effect as a visible
message rather than silently rewriting the pinned prefix.
- **`grep_files` is eager; `workflow` and the context archive load on demand.**
The default first-turn tool set trades `workflow`, `context_archive_get`
and `context_archive_search` (now one `tool_search` away, including after
compaction) for `grep_files`, and tool descriptions are trimmed to the
first-relevant detail without changing any schema.
- **Sub-agent shell runs no longer wait on a peer's write claim.** A child that
holds a shared write claim can run `bash` while another child writes; the
claim still coordinates bounded `File`/`Edit`/`Patch` targets, and the
execution envelope, sandbox and approval posture govern executable work. A
bounded write tool whose target overlaps a live peer still refuses. The old
refusal told analysis agents to re-run with `read_only=true`, which cost
steps without protecting a peer's files.
- **The footer cost chip shows confirmed dollars only.** A session with some unpriced turns shows exactly the confirmed amount, such as `$0.34`, instead of `subtotal 0.34 + unknown (request outcome unknown)`, and a session with nothing priced shows no cost at all instead of `cost: unknown (…)`. The accounting is unchanged: unpriced turns stay excluded rather than guessed, and `/cost` still lists each one with its reason, now in plain words ("the provider never confirmed the request finished", "this session predates cost tracking"). The price view says `unknown` for a session with no confirmed price.
- **The transcript shows the work, not the decoration.** The idle footer no longer carries a `Work bar` label (its key still opens the dock); fish, bubbles and the whale cameo swim only on the empty start screen and never behind transcript text; a streaming reasoning block is one `Thinking…` line instead of `Thinking…` above `reasoning...`, and the hidden-reasoning line and window title say thinking too; the tool-card hint reads `⌥V details` in dim text instead of `⌥V:details`.
- **Sub-agents and goals by default.** The constitution now tells the agent to start independent parts of a request as parallel sub-agents in one message, keep working while their results arrive on their own, and end the turn when only waiting remains; to give each child a complete prompt and its own files; to inspect a write-capable child's evidence, review the diff and run the checks itself; to have an independent reviewer try to refute a non-trivial change before calling it done; and to start a goal for any request, in any language, whose verifiable end state needs more than one turn. Sub-agents, workflows and goals within the current request are in scope; spending real money (purchases, paid providers, billing) still needs the user's express authorization. Cost alone is not a reason to stop; only limits the user or configuration sets apply. **This changes the session-pinned prompt and tool descriptions, so each session re-pins its prompt cache once after upgrade.**
- **Operate's contract is retired.** The Engine no longer appends the Operate contract to a session; its review, cost and evidence rules now live in the constitution for every session. Saved sessions that contain it still replay.
- **The Operate mode is gone; Work and Plan are the two modes.** The Shift+Tab permission dial reaches both, `/mode` and the config editor offer only those two, and a saved `default_mode = "operate"` loads as Work with a one-time notice that `/fleet` runs parallel agents. `operate`, `operation`, `ops` and `3` still parse, as Work, so an old setting or script never errors. Fan-out is unchanged — 64 live sub-agents per message, workflows at a 64 default with a 128 ceiling — while the Operate-only launch-concurrency floor and its top-level child auto-accept posture are gone; a child's edits follow the permission posture like every other action. "Plan stays Read Only; this applies in Work" now says exactly that.
- **Clearer tool text.** The `agent` description leads with when to delegate, gives one trigger per role and an example child brief, and drops Operate and legacy wording; the start receipt says results arrive automatically. `create_goal` and `update_goal` say when to start a goal and what complete, blocked and yield mean (blocked means the same obstacle persists; difficulty is not blocked). `tool_search` lists the deferred tool groups. The eager tool schemas shrink by 681 bytes.
- **Workflow fan-out default 16 → 64.** `[workflow] max_concurrent` now defaults to 64 live agents per run, matching sub-agents; the per-run ceiling rises from 16 to 128. No spend caps were added.
- **Bundled skill `goals` is now `personal-goals`.** It tracks personal resolutions in `goals.md` and no longer collides with goal mode; `goals` still resolves to it. An untouched installed `goals` copy becomes `personal-goals` on upgrade; an edited one stays as `goals`.
- **Each sub-agent is told its name, its scope and that its final answer is delivered to the parent automatically.**
- **Thread-owned terminals (Runtime API, breaking):** Engine terminal shells now belong to the conversation that started them, so two conversations using `term-1` in one folder get separate shells instead of sharing cwd, running command and output. Clients list a thread's shells at `GET /v1/threads/{id}/terminals` and drive one at `/v1/threads/{id}/terminals/{terminal_id}/output|input|resize|kill`; a reset shell, another thread's or workspace's shell, or one from before an Engine restart answers 404 instead of attaching to a same-named shell. The name-addressed `/v1/terminal/{name}/*` routes now answer 410, and `/v1/runtime/info` advertises `thread_scoped_terminals` in place of the four `terminal_*` flags. Client input meets the thread's shell consent and sandbox-reuse guard, and a lone Ctrl-C uses the dock's confirmed interrupt. In the TUI, a new conversation starts its own `term-1` rather than reusing the previous conversation's shell, which the dock still lists.
- **Ask asks before every edit; new Accept Edits posture (#5185, #5186):** Ask now opens a
card for file edits inside the workspace too, as its name and the Plan
handoff ("Edits and commands ask you first") promise. The in-repository edit
rule moved to a new posture, **Accept Edits** (Claude Code's `acceptEdits`):
an edit whose every target stays inside the workspace git work tree runs
without a card, while `.git`, `.codewhale`, `.env*`, credential and key
files, folders without git, commands, network and connected apps still ask.
Accept Edits is the default (see the permission dial entry below).
`/permissions`, `/status`,
`/config` and the Plan handoff offer it; the Runtime wire spells it
`permission_posture: "accept_edits"`, settings and `config.toml`
`accept-edits`. Project config may tighten Accept Edits to Ask but never
loosen Ask to it. ACP sessions run it as Ask.
- **One permission dial; Tab no longer changes the mode:** Shift+Tab
steps Ask → Accept Edits → Plan → Auto-Review → Full Access → Ask. Plan is the
Plan mode; every other stop is Work with that posture. Tab only completes
commands, file mentions and suggestions. The footer shows one chip for the
current stop with `Shift+Tab to change`; the separate mode chip and its Tab
hint are gone. The dial moves mid-turn too, into or out of Plan, and applies
at the agent's next step without restarting a response or changing the pinned
prompt. When config or managed policy owns the posture, the dial still
alternates between that posture and Plan.
- **Accept Edits is the default posture:** new installs, unset settings and new
Runtime threads that send no `permission_posture` start on Accept Edits. A
saved permission posture, including `ask` from an earlier build, is preserved.
The "Normal agent" setup preset now writes Accept Edits and Settings shows it
as the unconfigured default. Saved choices, including Ask on existing and new
installs, survive upgrades and restarts, and managed approval policies keep
their stricter startup posture when the dial is used.
ACP still runs Accept Edits as Ask.
- **Full Access copy says what it does:** its settings description now reads
"Tools run without asking first, and commands can reach anything on this
computer." in every language, instead of implying a folder fence.
- **Operate compatibility:** `/mode operate` selects Work and says
Operate was retired; a Runtime API request with `mode: "operate"` runs as
`agent` with the default posture and logs one notice per process, never an
error. Agents forked from a conversation saved by an earlier Operate build no
longer inherit its contract message.
- **Brighter terminal working states:** the Ocean palette has stronger accents,
and active work uses a restrained left-to-right text sweep. Quiet and
reduced-motion settings keep stable working indicators. The shared
`codewhale-ratatui` kit carries the same palette and motion updates.
- **Managed ACP requirements outrank Full Access:** when organization
requirements manage approval policy, ACP no longer lets `--full-access`
override them. The TUI already locked YOLO this way; ACP now matches.
- **Cleaner, safer Markdown export:** headings no longer carry `Content N:` numbering, a text block that opens a message is bare, tool results show their tool name and appear under a `tool` role instead of `user`, and `Error:` appears only on an error. Tool output is now fenced, so a tool result can no longer forge a heading or a message in the transcript. A trailing `--force` is a flag rather than part of the path. `/share` now publishes the same HTML page as `/export file x.html`, still as a redacted secret gist after confirmation.
- Internal coarse split: Runtime owns bounded owner work, Paths owns the protected socket layout, and Protocol owns shared avatar data. App Server now owns the Runtime host and control transports previously embedded in the TUI. Engine and Sandbox do not depend on App Server; the remaining Stage B boundaries stay open (#5586).
- **Newer DeepSeek Harness plugin compatibility:** the Native host targets
DSH 0.2.2-rc.1 with Cordis 4.1.0 and refreshed reviewed composition
packages (loader, include and group 1.1.0). Reviewed compositions are still
never rewritten, and plugin module loading still goes only through the
reviewed closure. Boolean `deferLoading` hints are accepted while the Engine
keeps tool-loading policy; `when` remains refused. The services a plugin may
inject are unchanged, so plugins needing `llm`, `fs`, `subprocess`,
`configEditor` or `dsh.client` still do not run. The changed compatibility
digest requires fresh plugin review and trust. The legacy preset adapter keeps
its recorded source pin; this is local compatibility evidence, not release
qualification.
- **Goal tool guidance while awaiting an answer (#7177):** the tool schema now
tells the model to yield when it needs the user’s answer and reserves blocked
for stalled progress. Existing runtime semantics are unchanged; no live-model
qualification is claimed. Thanks [@SparkofSpike](https://github.com/SparkofSpike).
- **A goal pauses to ask instead of inventing the answer (#7175):** the goal
continuation prompts now tell the model to call `update_goal` with
`status: "yield"` when the next pass needs an answer only the user can give,
and that asking in prose does not pause the goal. This is prompt steering, not
enforcement: a model that ignores it still keeps the goal active. Thanks
[@SparkofSpike](https://github.com/SparkofSpike).
- **Newer model rows in the offline catalog:** the bundled seed now carries `kimi-k3.1-pro` and `kimi-k3.1-pro-highspeed` (Moonshot), `MiniMax-M3.1-Flash` (MiniMax and its Anthropic-compatible endpoint) and `gpt-6.1-terra` (OpenAI), which Models.dev already listed and Codewhale did not pin. Live refreshes from Models.dev were already showing these online; the seed is what a first run, an offline start and a deep-offline install read, so it is now re-locked at 2026-10-30 and rendered. `seed render --check` matches and `defaults audit` reports no stale default.
- **Skills ownership (internal):** skill discovery, provenance, mutation and bundled skill content move into `codewhale-skills`. Native roots still use the existing host manager's selection and lifetime checks. (S20, #5316)
- **Model pricing ownership (internal):** hand-sourced price metadata and recorded-time rules move into `codewhale-models`; cost auditing and live catalog callers use the same owner. (S24p1, #5316)
- **`codewhale-error-taxonomy` crate (internal):** `error_taxonomy` moves out of `codewhale-tui` into a new crate; the `LlmError` envelope conversion stays in the TUI crate until the model-wire split. No behavior change. (N13, #5316)
- **`codewhale-tui-kit` crate (internal):** terminal rendering helpers (markdown, diff, text width, paste burst, OSC-8, streaming) move out of `codewhale-tui` into a new crate, and `syntect` is no longer a direct `codewhale-tui` dependency. No behavior change. (S52, #5316)
- **Terminal kit on design tokens 5.0.0:** the vendored `codewhale-ratatui` reuses the current shared blue, Ocean grounds and contrast-checked state colors (upstream codewhale-hq/codewhale-ratatui 8311b65). Primary actions use blue fill with white text; raised panels keep a visible edge where 256-color backgrounds collapse. Built-in TUI palettes retain their own overrides, and existing working-motion and reduced-motion guards remain in place.
- **Fleet workers run the same Codewhale:** `codewhale fleet run` and Runtime API Fleet runs (`POST /v1/fleet/runs`) now start workers from the running `codewhale` binary instead of whichever `codewhale` is first on `PATH`, so they work with a minimal `PATH` and never pick up a stale copy. `CODEWHALE_FLEET_CODEWHALE_BINARY` still overrides it. (#7119)
- **Switching provider lands on its current model:** `/provider stepfun` now selects Step 5 Preview instead of the older Step 3.7 Flash; a model you saved for a provider is still kept. `/model` now lists the current provider's own models (bundled and live, newest first, up to 20) instead of only the selected one. Search also matches ids typed without separators (`step5`). While you search, Shift+P and Shift+F type their letters rather than pinning or adding to Fleet, so `Step-5-Preview` can be typed in full; Ctrl+P and Ctrl+F pin or add the highlighted row at any time.
- **First run without a key:** `/provider` now opens on the full provider list (DeepSeek and the other cloud providers) when only a keyless local runtime is set up, no longer shows a disabled Antigravity row that was never configured, and Shift+A toggles the view like `a`. A local Ollama model that is not loaded yet is loaded before the first turn, so the route uses its real context window (for example 32K for `qwen3:4b`) instead of an 8K fallback that refused the second message with "~5120 tokens usable"; the footer's context reading follows the same window. The TUI resolves an unknown Ollama default to an installed chat model on startup. If the daemon or chat model appears later, selecting `/provider ollama` retries discovery. Embedding-only tags keep the model unresolved. An installed Ollama model is listed in `/model` and `GET /v1/providers/ollama/models` once its own catalog has answered, even when another provider is active. (#7113, #7114, #7116)
- **Computer Use delivery:** the standalone Engine uses the separately released Computer Use plugin; desktop packaging owns its embedded background helper. The marketplace pins plugin 0.16.0 and its archive checksum. Consent tools load on first use, and decisions still require a human approval card.
- **First-party marketplace receipt:** the shipped catalog is pinned to marketplace revision `6096906d57a5a27460ec46eb916460c611aa32c8`.
- **Upgrading over older installs:** `codewhale update` writes an install receipt for a copy installed before receipts, and moves a mismatched `codew` to the recovery folder and replaces it instead of refusing the update. The `curl | sh` and archive installers upgrade an earlier Codewhale in the install directory instead of refusing, keep the old files in the recovery folder rather than as `.bak` files beside the commands, and finish with `codewhale doctor --installs --brief`; a symlink or a non-Codewhale file at the destination is still refused. The Windows archive installer keeps the replaced files in the recovery folder too.
- **The desktop app's Engine is never self-updated:** `codewhale update` refuses to write inside `*.app/Contents/MacOS/` or the app's pinned Engine store, and the update notice for that copy says to use Codewhale > Check for Updates.
- **GitHub Action needs an explicit provider:** the Action's `provider` input no longer defaults to the `codewhale` account relay. Name your BYOK provider (or `codewhale` for a separately verified account machine key); a missing provider stops with `configuration_missing` before any download or model call. The repository's own (disabled) review workflow now pins CLI `v0.10.2` by default instead of `v0.10.0`.
- Local Ollama defaults now come from chat-capable tags, and `/provider ollama`
refreshes the live catalog before switching. Exec and Runtime API defaults use
the same discovery path. Fresh context observations come from loaded models'
served windows; unloaded models retain an explicitly unverified fallback (#5848).
- The Runtime API's `turn.usage` receipts now carry each model call's priced
cost on the route that served it and the prompt size the provider billed, so
a client can follow a long turn while it runs. The mobile control page shows
live token usage and a partial cost estimate in its header, keeps the
estimate after the turn settles, starts fresh for the next turn, and counts a
replayed receipt once (#7074). Thanks @gaord.
- `--full-access` is now the documented flag for Full Access (`--yolo` stays an
alias), and `serve` accepts it after the subcommand: `codewhale serve --acp
--yolo` used to fail with "unexpected argument". `serve --acp` also writes one
stderr line naming the permission and sandbox it runs with, and the ACP
permission option's Full Access hint names the working command. A configured
`sandbox_mode = "danger-full-access"` still never widens Ask or Auto-Review
(#6992, #4955). Thanks @eugenicum for the request.
- Ctrl+C on an idle composer that holds a draft now clears the draft instead
of arming exit, and Ctrl+Z restores it. The "press Ctrl+C again" exit prompt
arms only once the composer is empty, and Ctrl+C during a running turn still
cancels the turn first. Clearing a draft with Ctrl+C or Esc also resets a
pending exit prompt (#6237, #7084).
- While a background job runs, the git status probe now backs off after 30
seconds without input or engine events, as it already did in an idle
session, instead of starting about a dozen git processes every 2 seconds for
as long as the job lives (#6728).
- An idle session wakes less often. While an approval, elevation or question
prompt waits on you, while a background job runs, or while only a
once-a-second label ticks, the event loop now relaxes to its 250 ms quiet
poll instead of polling every 24 to 48 ms; animations and the prompt's
timeout still wake it on their own deadlines. The terminal input thread
polls every 200 ms instead of 50 ms after 5 seconds without input. Measured
on macOS with release builds: an approval wait went from 29 to 12 timer
wakeups per second, a background job from 32 to 16 and an idle composer
from 25 to 11 (#6728).
- Saving a session no longer copies every message body: journal entries
share their content, so the snapshot taken on each update copies ids and
pointers. Resuming a session compares a leftover crash checkpoint against
the saved document's metadata instead of parsing the whole document first,
so `--resume` and attach read the document once (#6842).
- Multiline mode now has a send key on every terminal: with
`composer_multiline_mode = true`, `Enter` inserts a newline and `Alt-Enter`
sends. `Shift-Enter` also sends where the terminal reports it distinctly; on
Linux terminals that report it as plain `Enter`, multiline mode previously
had no way to send. `Ctrl-J` always inserts a newline. Thanks
[@luestr](https://github.com/luestr) for the report. (#7093)
- **Faster repository checks:** the Engine reads a repository's HEAD in-process
instead of starting `git`, without running the repository's filters or
fsmonitor.
### Removed
- **Claude subscription sign-in (breaking):** Claude subscription sign-in is
removed: it used Claude Code's sign-in, which Anthropic doesn't allow other
apps to use. Use an Anthropic API key instead, through
`codewhale auth set --provider anthropic`, `/provider setup anthropic` or
`ANTHROPIC_API_KEY`. `codewhale auth claude` and `/auth claude` now explain
the removal, and `/provider setup anthropic` goes straight to API-key entry.
A config that still selects `auth_mode = "oauth"` for Anthropic fails with
the same guidance instead of switching billing to an API key. Saved Claude
sign-in files are not deleted; `codewhale logout` removes them with your
other saved credentials (Refs #6932).
### Fixed
- **Saving a Fleet role on Windows no longer fails with a sharing violation:**
choosing a model for a saved project or personal agent profile wrote nothing
and reported "The process cannot access the file because it is being used by
another process". The write-lock identity check now reopens the lock without
denying the writer that already holds it.
- **A missing or unreachable state directory no longer breaks the turn:**
when sub-agent state under `.codewhale/state` does not exist or is a
symlink loop, the session warns once, naming the path, and keeps going
without durable sub-agent cleanup instead of erroring every cycle. A
state directory that exists but is invalid still refuses, and the
credentials-directory error now says which case it hit.
- **`resume` and `fork` work without a terminal:** run from a pipe, cron job
or other non-TTY launcher, `codewhale resume` (and `fork`, which forks
first) now continues the session through the headless `exec` path — prompt
from stdin or trailing words — instead of refusing to start. In a real
terminal both still open the TUI.
- **An MCP capture that fails no longer reads as an empty registry.** A
timed-out or changed-during-capture MCP snapshot emits nothing instead of
withdrawing every server's instructions; withdrawals now happen only on a
successful empty capture.
- **Deleting a conversation ends its terminal sessions and background jobs.** A Runtime thread's terminal PTYs and running background shell jobs are killed when the thread is deleted, and the PTYs leave the live registry with their durable record marked cancelled. Jobs that already exited and other conversations' shells are untouched. The desktop tab-close half remains separate work.
- **A question waits for you.** An answerable prompt from the desktop Runtime API no longer hits the 30-minute durable-task human-wait cap; it waits until you answer or cancel. Headless and unanswerable tasks keep the fail-safe cap.
- **A plugin refused for its runtime snapshot now says why.** The warning and the enable error carry the reason the saved snapshot was rejected (for example the stage root is not read-only, or its content identity differs) instead of only "no staged snapshot". On Windows, 119 of the 135 hosted test failures were this one message with the cause discarded, so the next run can name it. Not a fix for those failures.
- **Listing installed agent CLIs no longer blocks the runtime.** `GET /v1/agents/external` looks for each binary with `tokio::fs` instead of synchronous file calls on a runtime worker.
- **A failed custom-provider switch leaves the provider you were on.** When saving a custom provider succeeds but switching to it fails (its identity cannot be resolved, or the engine refuses the route), the next request keeps going to the provider the footer shows instead of the half-configured one.
- **A zero page size over stdio still advances.** `thread/loaded/list` on the App Server's stdio transport treats a requested limit of `0` as `1`, so a client that sends `0` reaches the next page. `GET /v1/threads` is unchanged.
- **Anthropic and Messages-compatible routes accept any tool name.** Tool names that Anthropic's pattern rejects, such as `web.run` from a loaded tool group, are encoded on the wire and decoded in replies, as the chat and responses routes already did, including when such a tool is forced through an object-form `tool_choice`. Before, one such name made every request fail with "tools.N.custom.name: String should match pattern", which stopped sub-agents that had loaded it ([#7252](https://github.com/codewhale-hq/Codewhale/issues/7252)). Thanks [@ychu824](https://github.com/ychu824) for the report.
- **A large sub-agent fan-out no longer exhausts the usage journal.** The per-session limit of live usage receipts rises from 64 to 256, above the workflow ceiling of 128, so a full fan-out keeps its cost receipts instead of running with cost unknown.
- **A turn that stalls before it starts is now bounded.** The stall watchdog covers the setup before the first model request, so a wedged start is logged, cancelled after 180 seconds with a stated reason, and leaves a stall record instead of waiting silently. A warning names the case where all four blocking-work slots are held. Refs #6184.
- **One unreadable saved session no longer empties the recent-sessions list.** The launch card and ACP `session/list` show the readable sessions and log the failure. Refs #7095.
- **Windows uninstall removes the receipt and update leftovers.** The installer's uninstaller also deletes `.codewhale-install.sha256` and `codewhale.old-*`/`codew.old-*` left by a self-update, so `bin` can be removed. Refs #7091.
- **Windows `/undo` matches recorded file paths regardless of case.** A write recorded under a different drive-letter or directory case, or a `\\?\` prefix, is no longer dropped from the restore plan. Refs #6970.
- **Windows: Fleet and metrics read live files again.** Replaying a Fleet ledger and reading audit or receipt records no longer fail with a sharing violation while their writer is still open; the same regular-file, link and identity checks apply. Plugin enablement now says which snapshot check refused (stage root, content identity or final check) instead of one generic message. Generated protocol and SDK exports keep LF line endings in Windows checkouts.
- **A held coordination lock no longer makes a new session read-only.** When another session owns the delegated-agent store, the new session starts on private state and says so, instead of refusing every sub-agent with “Failed to clean up sub-agents”.
- **A dev server can outlive the turn in an interactive session.** `persist:true` now works in the TUI and desktop when the thread has Full Access; restricted postures and Fleet/sub-agents still refuse it.
- **`codewhale exec --add-dir <path>`** (repeatable) and `addDirs` on `POST /v1/threads` let the file tools read and write a sibling directory, a second checkout or a shared scratch root without turning on Full Access.
- **Unsettled usage is persisted in production, not only in tests.** The interactive sink now records a legacy usage receipt when a provider response has no settlement, so children and turns stop reporting settlement failure.
- **A full usage journal no longer fails a turn before dispatch.** The request runs with cost unknown instead of stopping on “native usage journal capacity reached”.
- **Reverting a file works in any posture.** Restoring a file the thread's own turns changed no longer requires `/trust` or Full Access; the exact snapshot and reviewed-hash checks still apply. **`fetch_url` can reach a local or private host you allowed** with `/network allow <host>`; cloud metadata stays blocked. Both refusals now name the setting.
- **`codewhale exec` offers tools by default**, still under the configured sandbox and approval posture. `--no-tools` is the one-shot. A pipe on stdin is the prompt when no arguments are given, or is appended to them.
- **A child no longer dies when usage settlement is not acknowledged.** The turn continues and cost stays unknown, matching the parent path.
- **Workspace memory works without a git origin.** A plain folder or a repo with no `origin` remote gets a stable workspace id. `codewhale plugin list` is an alias of `plugins status`. A heavy command runs after 30 seconds instead of waiting forever for an admission slot. An MCP registration 4xx names the status and the manual client-id path.
- **Wafer** is a selectable OpenAI-compatible host at `https://pass.wafer.ai/v1`. The public model list is the catalog; the default is `GLM-5.3`. Inference uses `WAFER_API_KEY`.
- **Provider defaults follow the provider's own model list.** A same-line successor (`grok-4.6` to `grok-4.7`, `muse-spark-1.2` to `muse-spark-1.3`) replaces a stale pin. A different line, such as GPT-6 beside GPT-5.6, does not. The provider pane shows one current model per line and spreads a gateway list across authors, instead of filling the screen with every Claude snapshot.
- **Turns no longer fail on a cost bookkeeping error.** When Codewhale could not
settle its own usage record ("previous usage publication has not been
acknowledged"), the whole turn failed and sub-agents were interrupted, even
though the model had answered. The turn now continues, the receipt keeps the
accounting error, and the status line says the cost is uncertain.
- **OrcaRouter offer:** no longer shown when Codewhale is in Simplified Chinese
or your computer is set to mainland China, and its note now says the link is
part of a referral campaign.
- **Cost line: a finished request is never "outcome unknown":** the cost
line drops "request outcome unknown" (and "provider omitted usage") once
the requests behind it have settled, even when another turn is still
unpriced for a different reason, and a request that is still running now
reads "request in progress" instead. A request that an exit or crash left
unsettled still reads "request outcome unknown" after a restart.
- **Sub-agents in `codewhale exec`:** a sub-agent started from
`codewhale exec` now runs. It used to stop before its first provider
request with "child provider call has no captured accounting origin",
because the exec session's accounting origin never reached the turn's
tools, so a fan-out ran in one context instead.
- **IME candidate window under modals:** the hidden terminal cursor now
follows the caret in `/config` search and its value editor, so the
input-method candidate window can appear there instead of over the
composer. Real Pinyin input on macOS and Windows is not yet confirmed.
Thanks [@cmdcorp6534](https://github.com/cmdcorp6534) for the report
(Refs #2323).
- **Sub-agents beside an older session:** while a Codewhale 0.10.2 session
still uses a folder's older delegated-agent store, a 0.10.3 session in the
same folder keeps working sub-agents with private state that is not saved,
instead of refusing every sub-agent action. The older session's files are
left untouched, and the store upgrades when a session starts after the older
one exits (Refs #7232).
- **Fleet members:** a replayed member start now matches only within its own
session, so two sessions that reuse an operation key no longer receive each
other's agent.
- **Plugin stages created during a registry load are checked:** a plugin whose staged copy appears while the registry is loading now goes through the same restage lock, receipt and policy checks as any other stage instead of being left unstaged; invalid bytes are still refused and stay in the failure cache.
- **Host-provided model clients:** keep configured session isolation and
approval deadlines when optional credential preflight fails.
- **Runtime SDK exports:** include the existing thread-scoped Git, snapshot,
worktree and job-operation capabilities in the committed schema and types.
- **Plugin enablement revalidates its review:** enabling rechecks the staged
snapshot and, under the existing state lock, refuses a changed review
generation or trust receipt. The macOS stale-enable check passed (1/1);
a separate Linux run reported 202 passed and one ignored on an earlier base
with matching plugin files and lockfile. Snapshot checking is point-in-time;
missing-stage recovery reuses the current receipt and policy. Filesystem
race coverage and final-candidate native qualification remain open.
- **Plugin status and UI admission:** an enabled, trusted plugin whose reviewed
runtime snapshot is missing or invalid now reports
`runtime-snapshot-unavailable`. Both plugin UI metadata and assets require a
declared DSH client; ordinary plugins cannot expose staged files through the
client UI route. Missing snapshots recover only from receipt-matching
canonical source; authenticated assets require an exact current grant.
Native and Electron qualification remains open; existing modified snapshots
require review.
- **DSH package-directory imports:** the existing offline reviewer uses npm's
version-range parser with the pinned DeepSeek host's prerelease policy, and
bare self-package exports resolve inside the selected package directory.
Invalid or incompatible ranges and paths outside the reviewed package still
refuse. Real published-plugin activation remains unqualified.
- **Coordination lock diagnostics (#7232):** stale lock-file contents no longer
identify an owner PID. A refused legacy admission keeps its reason in Work
and shows one notice per cause instead of repeating cleanup warnings on
every sidebar refresh. Legacy migration still requires the actual holder to
exit and the refused owning Runtime to restart; locks and retained state
remain protected.
- **A local proxy that stops mid-session no longer strands the session (#7231):** the model, catalog, search, vision, finance, MCP-registry, profile and remote-control clients watch a loopback proxy port and go direct while it refuses connections, then resume proxying when it returns. Only a definite refusal from every resolved address changes the route; remote proxies, `NO_PROXY` matches, credentials and the existing precedence are unchanged. Set `CODEWHALE_LOCAL_PROXY_FALLBACK=0` to keep the old build-time snapshot.
- **Proxy diagnostic privacy ([#7233](https://github.com/codewhale-hq/codewhale/issues/7233)):** malformed MCP proxy warnings omit configured values; local-proxy log labels mask userinfo and omit URL paths, queries and fragments. Routing is unchanged. All 23 existing proxy tests passed on macOS; runtime log capture and other platforms remain unqualified. Thanks [@SparkofSpike](https://github.com/SparkofSpike) for the report.
- **Fork, undo and retry work after a workspace drift notice (#7234):** the history-boundary walks now treat a whole `<context_update>` envelope as engine-owned, so a session that received one can be cut at every saved turn. A person quoting a notice or a truncated envelope still counts as their own prompt.
- **Git writes land in the right workspace:** stage, unstage, discard, commit, push and branch take `?thread_id=` and run in that thread's recorded workspace, matching the read routes. Before, they always ran in the server's own folder, so a commit asked for a thread in another folder could land in the wrong tree.
- **ChatGPT sign-in no longer depends on the device clock (#7203):** identity- and access-token expiry and not-before times are checked against the issuer's clock, read from the `Date` header of the issuer's key response, with a 60-second tolerance; without that header the device clock is used as before. Time errors report how far the device clock is from the issuer's when the difference exceeds the tolerance. A token signed with a key missing from the first key download triggers one fresh download before verification fails, and a missing or malformed claim is named exactly. Signature, issuer, audience, subject, nonce, account and plan-scope checks remain exact. Thanks [@d-onistack](https://github.com/d-onistack) for the report.
- **Remaining long-blocking work moved off async callers (#6553):** route
credential and certificate preflight, worktree creation, Runtime Chat relay
and remote-control journal transactions, and the remaining session, branch,
tree, skill, plugin and memory command I/O now run on the supervised blocking
owner. Results are still awaited before state publication; sync APIs remain
where sync callers still use them.
- **Frozen prices on DeepSeek endpoints:** published rates are captured for DeepSeek's root, `/v1`, `/beta` and Anthropic endpoint variants, and remain bound to the exact endpoint on replay. Other providers keep their existing pricing scopes; official credential aliases alone do not establish equivalent regional or plan prices. Request outcomes, missing provider usage, legacy usage and unverified corrections now have distinct cost explanations; saved receipts without a frozen quote remain unpriced.
- **Clipboard image persistence:** the existing confined writer handles relocated user state directly, without a second filesystem fallback that bypassed its protections and exceeded the blocking-call budget.
- **Case-sensitive model selection (#7214):** the provider picker restores the exact configured or wire model ID before trying case-insensitive compatibility matches. Thanks [@liuyy2](https://github.com/liuyy2) for the diagnosis and [@SparkofSpike](https://github.com/SparkofSpike) for the compatibility-preserving fix.
- **WeCom replies carry the API's error (#7208):** a rejected WeCom call now shows its `errcode` and message in the bridge reply instead of `[object Object]`. Thanks [@gaord](https://github.com/gaord).
- **WeCom streams survive the ten-minute expiry (#7210):** the bridge finalizes the current stream and opens a fresh one before WeCom stops accepting updates, and reopens once on a rejected update. Thanks [@gaord](https://github.com/gaord).
- **Non-English packs lose stale mode-jump and rail copy (#7225):** the sweep covers every non-English locale and a test pins it. Thanks [@asto18089](https://github.com/asto18089).
- **`image_analyze` accepts absolute paths inside the workspace (#7226):** POSIX and Windows spellings that resolve under the workspace are read instead of refused. Thanks [@asto18089](https://github.com/asto18089).
- **Sub-agent follow-ups report what happened (#7228):** a message to an existing successor says whether it was delivered without a resume, the focus view follows the actual recipient, and an undelivered follow-up keeps focus and shows the failure. Thanks [@asto18089](https://github.com/asto18089).
- **A long turn no longer ends at 64 model requests:** a turn that had recorded 64 provider usage receipts failed on the next one with "captured usage sink did not acknowledge its source", discarding the person's answer. The per-turn receipt cap is removed. Receipts keep recording exactly once; a sink refusal now retains the exact receipt for a later admitted flush and continues the turn, while owner-lock loss or thread mismatch still fails closed.
- **The `verify` tool names a callable surface (#7223):** its description taught the model to use the retired, hidden `run_verifiers` name; it now says to use the Run tool with `action="verifiers"`, and the retired-name guard test now covers `verify`'s description. Thanks [@asto18089](https://github.com/asto18089).
- **A home-directory workspace no longer refuses its own state (#7207):** a session started in the home directory treated it as a confined workspace, which broke the supported layout where `~/.codewhale` is a directory junction onto another volume (Windows `mklink /J`); only the home state directory is now exempt, and confinement for links elsewhere is unchanged. Thanks [@SparkofSpike](https://github.com/SparkofSpike).
- **The command palette keeps your draft (#7205):** picking a command that takes an argument, such as `/rename`, no longer discards what was in the composer; the draft is stashed so history search can recover it. Thanks [@Lstarsky0](https://github.com/Lstarsky0).
- **Old sessions restore with the topology checkpoint in place (#7229):** sessions saved by v0.9.10 to v0.9.12 that compacted with live sub-agents placed the agent-topology checkpoint at the end of the history, which left a tool-then-user message pair that strict Chat Completions templates reject with HTTP 400. Restore now moves the checkpoint to where current saves place it, deletes nothing, and a restore followed by a re-compaction no longer keeps a superseded duplicate. Thanks [@asto18089](https://github.com/asto18089).
- **`/patch-undo` undoes the turn you chose (#7216):** `POST /v1/threads/{id}/patch-undo` ignored `turn_id` and undid the latest turn instead, so a caller got a different turn than `/undo` removes for the same request. It now removes the named turn and every turn after it. `GET` previews the exact turns and the files that would be restored; sending them back as `expected_turn_ids` and `expected_paths` makes a changed selection answer `409 undo_selection_changed` before any file is touched. Clients should require the `thread_patch_undo_turn_id` capability before sending a selected turn, because older Engines ignore the field. Thanks [@soarkit](https://github.com/soarkit) for the report.
- **`grep_files` matches brace and nested-directory globs (#7215):** `include` patterns such as `*.{txt,md}` and `**/*.{txt,md}` no longer return an empty result with no error; they match the same files the equivalent separate globs do, at the root and in nested directories. Nested brace groups and long runs of `**/` are now bounded, so a hostile pattern can no longer expand to billions of patterns or hang the search ([#7254](https://github.com/codewhale-hq/Codewhale/pull/7254)). Thanks [@Lstarsky0](https://github.com/Lstarsky0).
- **Sub-agent write claims accept absolute in-workspace paths (#7227):** a write-capable sub-agent that spelled an in-workspace target as an absolute path was refused while the relative spelling succeeded. Absolute paths that resolve inside the claimed workspace are accepted; paths outside it, `..` traversal and symlinked ancestors that escape are refused exactly as before. Thanks [@asto18089](https://github.com/asto18089).
- **WeCom replies are split by UTF-8 bytes (#7209):** the WeCom bridge now caps each reply chunk at 3,800 bytes (`WECOM_MAX_REPLY_BYTES`) on code-point boundaries, so a long Chinese reply is no longer delivered silently truncated at WeCom's 4,096-byte limit. Callers that do not pass a byte cap keep their behavior. Thanks [@gaord](https://github.com/gaord).
- **`file_search` reports workspace-root paths (#7213):** a search scoped with `path` now returns matches the way `read` and `grep_files` resolve them, so reading a result opens the file that matched. A `path` naming one file and glob searches under a subdirectory are fixed too. Thanks [@Lstarsky0](https://github.com/Lstarsky0).
- **Sub-agent worktree isolation no longer adopts unrelated checkouts (#7224):** only the session anchor itself may adopt nested repositories; ancestors are probed for containment only, so a workspace a few levels below the home directory no longer fails with "Multiple git repositories found" over unrelated projects. Thanks [@asto18089](https://github.com/asto18089).
- **`fetch_url` no longer claims to be sandboxed (#7222):** its description now says it is an in-process HTTP client guarded by the network policy and the SSRF/DNS checks, and attributes the sandbox contrast to `exec_shell`. Thanks [@asto18089](https://github.com/asto18089).
- **Usage on long tool turns:** physical model-call receipts remain available after the 64th response without dropping earlier sources. A completed tool-only provider response uses its terminal stream event for accounting, while incomplete streams retain unknown coverage.
- **Retained browser connections follow their desktop owner:** authenticated runtime registration binds the browser endpoint and credential to its workspace; existing Core catalogs and connections retire a replaced registration before reuse.
- **`/new` waits for the Engine:** the terminal keeps the current session, transcript and draft until the exact session switch is acknowledged. A refused closure preserves them; a late acknowledgement can finish once while retaining input edited during the wait. Pending or uncertain switches pause new work and retain the existing scoped Stop controls.
- **Interactive command confirmations keep their stack headroom:** the existing interactive startup chain heap-pins its large futures instead of embedding their debug state machines in each caller.
- **Live MCP status includes runtime servers:** the existing pool snapshot now includes workspace-scoped dynamic servers, retaining static-name precedence and the same permission and connection checks.
- **Plugin reload confirms its workspace:** the status translation receives the required workspace value instead of producing an empty acknowledgement.
- **MCP credentials fail clearly:** missing or invalid required credential configuration stops before connection, stored OAuth discovery failures retain their cause, and reviewed-plugin errors redact credential details. Explicit reconnect still reloads saved credentials.
- **Desktop browser MCP stays with its workspace:** the paired desktop host registers its authenticated loopback server at runtime, late registrations refresh the tool catalog, and another workspace cannot inherit the connection. Recognizable obsolete global browser entries are ignored without rewriting user configuration.
- **Closing an empty delegated fleet avoids an unnecessary writer lock:** a session with no locally owned agent or worker records can close while another Codewhale process coordinates the workspace. Read-only or failed-admission state and sessions with owned records retain the existing coordination checks.
- Child, review and Auto usage keeps its captured session and route through late completion and persistence retries. Unreported usage stays unknown, cache writes and reasoning remain distinct, and cost calculations use the quote captured for the request.
- Interrupted children persist their continuation checkpoint and complete their workflow task instead of leaving it waiting on a worker whose execution already ended. Live approval waits retain their existing behavior.
- Session publication compares the document and crash checkpoint captured before work was queued. A delayed save refuses changed records without replacing newer history or clearing its checkpoint. Ordered completion retains real checkpoint acknowledgments, and native turn/control identity follows restores, undo and terminal saves. Legacy checkpoints require explicit recovery; canonical history recovery retains its original source and exact prepared generation.
- Damaged usage sidecars keep valid recovery data readable with incomplete coverage and no publication receipt. Known retirement, changed raw records and unsafe writes still refuse.
- Local control and ACP output serialize within the existing 8 MiB frame limit and stop a damaged or stalled output stream. Compatibility replies, events and relay stdout now share the 30-second write deadline; owner forwarding keeps its tighter 5 seconds. Standalone and attached ACP recover after complete invalid UTF-8 or oversized input frames, discard oversized tails through the real newline, and preserve cancellation, permissions and actual Core receipts.
- MCP composition records actual schema or description changes before the next request, so a conservative batch withdrawal re-pins the declared tool surface instead of failing the C5 prefix guard. Semantically unchanged runtime refreshes preserve the original serialized catalog and schema key order. The `execute_tools` description also explains that visual input needs a direct capture call because nested results do not deliver inline images to the model.
- Runtime SDK declarations for event, image and dynamic-tool messages are generated from the same Rust wire contracts. Output schemas retain required nullable fields while request defaults remain optional.
- Inference requests stop after uncertain delivery or an interrupted stream instead of silently sending another request. Automatic retries require an ordinary rate limit or a transient connection failure before dispatch. Redirects and HTTP protocol retries cannot bypass this policy; retained output and missing usage coverage remain visible. Terminal `exec` failures return exit 1; error categories no longer imply that repeating a saved command is safe.
- MCP calls inside `execute_tools` expose a single bare JSON result directly through `content`. Rich or annotated results retain their envelopes, and oversized results keep the original raw size and spill receipt.
- Session metadata reads stop at a bounded scan and report unreadable records without hiding healthy picker rows. Queued saves preserve durable renames, archive state and Runtime ownership under the session write lock; uncertain metadata refuses writes and cleanup. Persistence batches run off the async executor, and explicit placeholder-title renames retain their intent.
- Worker coordination serializes durable admissions across processes, preserves foreign workers and winning completion receipts, and fences stale checkpoints. Fleet restart reservations retain uncertain prior processes until exact teardown is confirmed; final output, usage and the receipt publish together without duplicate accounting on retry. Retained transcripts follow committed ownership.
- JSONPath projections bound path length, traversal steps and intermediate matches before cloning results. Direct fetches share the same parser and enforce one aggregate serialized-field budget; oversized selections refuse with narrower-selection guidance.
- Long tool output and diffs use bounded display windows and a byte-limited row cache. Retained details load verified byte ranges and label what search and copy include; explicit source copy keeps stored text with control-sequence cleanup. Oversized Unicode is shown safely without changing question answers; long answers retain their exact bytes in the existing owned output artifact before bounded model-context projection. New pager notices are translated across all 15 complete language packs.
- **Markdown character references:** ordinary prose renders valid references once, while inline code, plugin approval text and argv retain their literal values. Long URL punctuation stays linear to scan. Thanks [@Lstarsky0](https://github.com/Lstarsky0) for the report and original fix ([#7192](https://github.com/codewhale-hq/Codewhale/pull/7192)).
- Managed Fleet validates overlapping write roots with a component-sorted scan and deduplicates roots once. Large valid request bodies no longer spend quadratic CPU before admission; existing write-scope refusals and execution limits remain in force (#6554).
- MCP transports, connection pools and child Engines retain the owning host credential context for placeholders, headers, bearer tokens and OAuth setup. Missing injected values never fall back to process secrets. Reviewed plugins keep their captured environment authority, whose Debug output now masks values. Durable OAuth token custody and full subprocess isolation remain separate work (#5637).
- Python REPL drains stderr while code runs, retains at most 64 KiB of diagnostics and reports omitted bytes, so noisy code cannot block request completion (#6554).
- Saved tool results use bounded streaming inspection while preserving session ownership, digest and generation checks. Text refuses oversized lines or selections with byte-recovery guidance; verification also has explicit scan and cancellation limits (#6554).
- Telemetry bounds its pending event queue and disk-tail reads, keeps final flush admission available, and skips invalid UTF-8 records without discarding intact neighboring records. Existing opt-out and privacy ordering remain in force (#6554).
- Workflow history summaries retain large child totals without allocating one row per claimed child. Missing outcomes, usage and elapsed time remain unknown, including in the workbar (#6554). The independent terminal kit advances to unpublished 0.2.0 for its `u64` total API; registry-based TUI packaging waits for separately approved kit publication.
- Web build dependencies cap glob preprocessing and stop cancelled directory traversals through compatible, verified upstream backports. Raw dependency findings remain visible. Thanks [@isaacs](https://github.com/isaacs) for the [minimatch](https://github.com/isaacs/minimatch/commit/77a0f5c4b80bdc641c3c930a1d9edf5ad2db57f8) and [glob](https://github.com/isaacs/node-glob/commit/4682e8c9babee1b385202ede36389634e12076d7) fixes (#6560).
- Repeated requests no longer make `/undo` restore files from an older invocation. `/undo select` chooses a request range and shows checking, restoring and saving progress. Missing, ambiguous or stale restore points refuse before changing files. Esc–Esc continues to rewind only the conversation. Thanks [@luestr](https://github.com/luestr) for reporting [#6970](https://github.com/codewhale-hq/Codewhale/issues/6970).
- `web.run` refuses more than 64 operations across its command arrays before starting network work or changing its session cache (#6554).
- Skill discovery and audit marker reads stop at 512 KiB. Approved linked global skills still load; oversized, invalid and non-regular files produce visible refusals instead of unbounded reads (#6554).
- OpenSandbox caps successful responses at 8 MiB before parsing and limits remote error details to 4 KiB with terminal controls removed. Oversized responses fail explicitly. Remote execution cancellation remains a separate requirement (#6554).
- The WinGet manifest generator now selects the published x64 portable executable by exact name and records its checksum and Visual C++ dependency.
- The Windows setup uninstaller preserves a trailing separator in the current-user PATH and retains other settings stored in the CodeWhale registry key.
- Inline code in terminal replies preserves embedded backticks. Text after an unmatched delimiter keeps its normal styling. Thanks [@Lstarsky0](https://github.com/Lstarsky0). [#7185](https://github.com/codewhale-hq/Codewhale/pull/7185)
- Windows Ctrl+Break and terminal-close events now request the same bounded session checkpoint and persistence flush as Ctrl+C.
- When a keyless local Ollama route has no resolved chat model, retrying `/provider ollama` refreshes the catalog in the background. You can keep typing while the daemon responds. [#5848](https://github.com/codewhale-hq/Codewhale/issues/5848)
- Auto checks the served context window on an active keyless Ollama route when its default model still has an unverified limit. A later turn can use the running model’s window once Ollama has loaded it. [#5848](https://github.com/codewhale-hq/Codewhale/issues/5848)
- The bundled catalog recognizes the bare `deepseek-v4.1-flash` model ID. It reports a 1,000,000-token context window and a 384,000-token output ceiling. [#7183](https://github.com/codewhale-hq/Codewhale/pull/7183)
- After `/undo` restores files, Codewhale saves the conversation rewind before reporting completion. Pressing Esc twice and choosing an earlier request also saves that exact conversation boundary, even when two requests have identical text. The picker keeps workspace files as they are. Thanks [@luestr](https://github.com/luestr) for reporting [#6970](https://github.com/codewhale-hq/Codewhale/issues/6970).
- Feishu and Weixin persist each incoming message ID before handling it. Concurrent deliveries share one result. After a restart, a message with an uncertain outcome stays pending until the bridge can tell the user to check its status. Thanks [@7jrxt42BxFZo4iAnN4CX](https://github.com/7jrxt42BxFZo4iAnN4CX) for the durability audit (#6555).
- Custom OpenAI-compatible routes now honor explicit output requests within the
configured window and serving limits. A hosted model with the same name
could previously truncate reasoning at 32,768 tokens. Thanks
[@Gabriel-Degret](https://github.com/Gabriel-Degret) for reporting [#7179](https://github.com/codewhale-hq/Codewhale/issues/7179).
- Saving a user turn when the Engine adds its metadata preserves the journal entry and its place in history. Sessions with a fork keep the earlier branch intact. Thanks [@SparkofSpike](https://github.com/SparkofSpike). ([#7180](https://github.com/codewhale-hq/Codewhale/pull/7180))
- **Star keycaps stay intact in Markdown (#7176):** plain and escaped text
preserve the full grapheme, and a keycap cannot open emphasis. The separate
Windows Terminal font-fallback issue remains unqualified. Thanks
[@SparkofSpike](https://github.com/SparkofSpike).
- **Codewhale runs from a HarmonyOS user directory (#7168):** on HarmonyOS hmdfs (the 2in1 `/storage/Users/currentUser` mount), which reports its own owner and a group-writable mode for every object and refuses `chmod` and advisory locks, a GUI start failed one feature at a time — the workspace lease, the owner control socket, then the OAuth credential directory. Private directories, the secret store and credential files now probe the mount once, keep the strict ownership check everywhere it can be expressed, and on a mount that cannot express ownership still enforce no-follow, single-link and atomic publication, with one warning naming what the mount reported. A filesystem without advisory locks serialises secret-store writes within the process instead of refusing; a held lock is still contention. Not observed here on a real HarmonyOS device. Thanks [@gaord](https://github.com/gaord).
- **Notes stop swallowing a backslash:** a transcript note is machine-generated and names paths, but it went through the markdown renderer, where CommonMark §2.4 reads a backslash before ASCII punctuation as an escape. A note naming `C:\Users\asus\.codewhale\setup_state.json` therefore printed as `C:\Users\asus.codewhale\setup_state.json` — a directory that does not exist, in the one line a user would copy to find the real one. Notes are now escaped where they are rendered. Fenced blocks, and lines carrying inline code or a table row, are passed through untouched, because the renderer already copies those verbatim and doubling a backslash inside one would print it doubled.
- **Setup state survives a second instance:** two running Codewhale windows share one home, and both rewrite `setup_state.json` when the provider or model changes. The replacing rename is now retried briefly when the destination is held open for a read — Windows refuses it outright while that handle lives — instead of surfacing a write the caller could have made. The failure message also carries the underlying I/O error instead of only the outer context, so the next occurrence is diagnosable.
- **`doctor` stops flagging a user's own temp-named logs:** the `stale_setup_temp_files` check matched any file whose name starts with `.tmp`, so scratch files such as `.tmp-build-release.log` made a clean home report as half-applied. It now matches the shape a staged write leaves when it never lands (`.tmpXXXXXX`, no extension).
- **Approval cards are translated in every locale (#7071):** the "Do you want to proceed?" question, the Why and Stop explanations on destructive actions, the Approve, Edit plan and Cancel choices on workflow plans, the Save row, the details pager's title and the card's impact lines (one sentence per tool category plus the Reads, Writes, Target, Connected app, Agent type and Primary input rows) came from English literals, or from Simplified Chinese only. They now use the shared message catalogs, so all 15 packs carry them. The 14 non-English translations were written without native-speaker review. Still English outside Simplified Chinese: a workflow plan's own impact lines and detail labels, and the delegated-authority rows.
- **Local vLLM models keep their own reasoning ladder (#7124):** a vLLM or SGLang route treated every model as low/medium/high and folded low and medium onto high. Reviewed model-template facts (`crates/config/src/local_reasoning.json`) now give Qwen3.8, Qwen3.6-35B-A3B, Ornith, GLM-5.3-Flash and DeepSeek-V4-Flash-Vision-Exp the controls their template accepts, and the effort picker offers exactly those tiers, so low stays low and medium stays medium where the model has them. Unreviewed models are unchanged. Not yet observed against a real vLLM or SGLang server. Thanks [@gannp](https://github.com/gannp).
- **`/undo`, retry and fork-at-turn work on large and attachment-heavy conversations again (#7147):** a fork was measured by the shape it is stored in (a saved session repeats its conversation while it carries a journal, so the file can be twice the history) against the 8 MiB bound the reader judges by what the conversation carries, so a conversation the runtime kept opening and extending could still refuse `/undo` with "full history exceeds byte transport bound". The saved-history boundary also counted MCP-server notices, shell-completion handoffs, the deferred-toolbox snapshot and `<image>` attachment tags as prompts you typed, so a conversation that had received one refused with "Cannot identify an exact saved-history boundary". Both now use what the conversation carries. Thanks [@gaord](https://github.com/gaord).
- Table cells retain code, bold text and clickable links when they wrap. Inline code that fits its cell keeps its indentation and any space-only content. Thanks [@Lstarsky0](https://github.com/Lstarsky0). [#7181](https://github.com/codewhale-hq/Codewhale/pull/7181) · [#7184](https://github.com/codewhale-hq/Codewhale/pull/7184)
- **Markdown shows what was written:** a paragraph nested under a list item keeps its indent (#7146), `~~~` fences render as code blocks and keep backtick lines inside them as code (#7156), asterisks that do not open emphasis (`5 * 60 * 60`, `*args`) stay literal (#7157), a bare URL ends at full-width punctuation such as `。` and `)` instead of swallowing it (#7158), a link whose target has its own parentheses (`…/wiki/Rust_(programming_language)`) keeps its closing `)` (#7170), and inline code and links inside bold, italic or strikethrough render as code and links instead of their raw backticks and brackets (#7171). Thanks [@Lstarsky0](https://github.com/Lstarsky0).
- **Fleet changes no longer put a stray English status in the footer (#7152):** the engine's "Fleet roster refreshed for subsequent turns" arrived after the change's own receipt, stayed for seconds, took over the footer, pushed the Shift+Tab hint off the row and stayed English in every locale. `/config stream_chunk_timeout_secs` no longer leaves the engine's "Stream chunk timeout set to …" status in the footer after its own note either (#7169). Thanks [@Lstarsky0](https://github.com/Lstarsky0).
- **Simplified Chinese uses one form per term (#7150):** the pack addresses you as 你 throughout (the telemetry notice mixed 你 and 您), says 提供商 for provider and token for usage, and drops two stray spaces after full-width punctuation. Thanks [@luochen211](https://github.com/luochen211).
- **A turn can no longer wedge forever after a tool returns (#6184):** the heartbeat's tool phase carried no bound, on the assumption that per-tool timeouts covered it. They cover a *running* tool, not the engine's own work after a result comes back, so that window had no owner: the in-app watchdog deferred to the engine because the engine still looked like the owner, and the engine watchdog only reported. A real turn sat there for 56 minutes, produced no stall record and never cancelled. The tool phase now has a ceiling, and a watchdog report cancels the turn so it ends with a stated reason instead of hanging.
- **A restored conversation can be undone again:** a saved document keeps each turn's `<turn_meta>` envelope before the prompt while a thread rebuilt from its turn records keeps it after, and only the leading shape was stripped before comparing the two. Every record-side prompt was therefore longer than its transcript twin, so the exact-boundary search never matched and `/undo` on a resumed thread refused with "Cannot identify an exact saved-history boundary" instead of answering. Both shapes are now stripped, so the comparison sees the prompt text alone.
- **MCP servers that reject the modern probe now fall back to the legacy handshake:** a server answering `server/discover` with HTTP 400 and a JSON-RPC error (for example `-32600 Unsupported protocol version`) was treated as a hard failure instead of evidence that it speaks the older handshake, so such a server could not connect at all. Codewhale now reads a parsed JSON-RPC error on the probe as a transport refusal and negotiates the legacy `initialize` handshake, which is what a server that clearly answered in JSON-RPC means. Reproduced against `mcp.deepwiki.com` (three tools after the fix); Linear is unaffected.
- **MCP servers reject requests that carried two framing headers:** Codewhale sent every Streamable HTTP request with a duplicated `Accept` and `Content-Type`, because the extension host forwarded the SDK's headers and the Rust send path added them again. A server that validates those headers answered `415`, which Codewhale read as "this endpoint is not Streamable HTTP" and answered by switching to the deprecated SSE transport; servers that refuse `GET` then returned `405` and the connection failed with only `SSE error: Non-200 status code (405)`. Linear was unreachable this way. The send path now collapses the framing headers to one value each. Verified against Linear: discovery, tool listing (77 tools) and connection succeed.
- **One context window from planning to compaction (#7133):** the window a route resolves (from provider facts, your configuration or a fallback) and where it came from now travel together. Turn planning, automatic compaction, tool-output sizing, output caps, child agents, the context inspector and the model picker all use the same window. Previously a custom model with no context metadata was sent with a 128K fallback while compaction planned against 1M. A model switch or re-sync that keeps the same model and limits keeps that window. On resume, `/context` shows the last Auto route’s saved window and its source. Each new turn resolves its own window from current settings and provider facts. After a model switch, the `/preview-request` body hash includes the compaction setting the new route will send. The `/context report` command identifies the Engine as the source of both its bundled constitution and the session relay template. The original Windows report has not been reproduced.
- **Session saves no longer fail silently (#7095):** if the session store has stopped, a checkpoint or reset save now reports the failure in the status line instead of being dropped with only a log line.
- **Saves keep your recovery checkpoint (#7095):** a finished turn is saved even when a newer in-progress checkpoint arrives at the same time, and a `/clear` or `/new` reset no longer drops its own snapshot when saves queue up. If the reset snapshot cannot be built or written, the previous recovery checkpoint is kept and the save failure is shown in the transcript and status line instead. Retrying an interrupted session deletion finishes it without removing the shared checkpoint an older Codewhale may still be writing. These fixes do not yet reproduce the original report.
- **Context inspector shows the real compaction trigger (#7133):** `/context` uses the current route's effective threshold, including when it is zero. When automatic compaction is off, it says so, and the Work rail points to manual `/compact`.
- **`doctor --probe-local` changes nothing (#7115):** when a configured route rules out local Ollama, the check skips credential inspection. Otherwise it reads credentials without migrating the legacy secret store; `exec` keeps its normal resolver.
- **Blockquotes keep their rail when wrapped (#7144):** every wrapped row of a blockquote keeps the quote rail, and copying a selection still leaves the rail out. Thanks [@Lstarsky0](https://github.com/Lstarsky0).
- **Localized activity and file receipts:** grouped tool activity, file counts, patch outcomes and tool status use the shared 15-language catalog. Language changes refresh cached summaries; filenames, diffs and execution receipts keep their original data.
- **Automatic compaction stays off when disabled:** preflight and provider context-overflow recovery preserve the conversation and report the setting instead of forcing a summary. Manual compaction remains available, and a rejected recovery request retains its actual cause in both paths. (#7142)
- **VS Code packaging security:** use patched MSAL Node in the extension packager, addressing [GHSA-xcx6-jx8p-x3h5](https://github.com/AzureAD/microsoft-authentication-library-for-js/security/advisories/GHSA-xcx6-jx8p-x3h5).
- **Compaction preserves task state:** a summary that is empty, a placeholder or only leaked reasoning tags (as local models sometimes return) no longer replaces your history. The recent tail is chosen by token budget on whole tool exchanges, the older span and any earlier checkpoint are summarized, and the original history is saved before the swap. Context budgeting learns from provider-reported usage within a turn and reports repeated rapid refills instead of looping. (#7133)
- **Vim Normal mode works on every terminal:** with `composer_vim_mode = "vim"`, Normal-mode keys no longer land in the draft as text on Windows terminals or on any terminal that does not report bracketed paste (everything except ghostty, iTerm, WezTerm and Apple Terminal, tmux and VS Code's terminal included). A held key now reaches Normal mode, shifted keys such as `G` move instead of typing, and `k` history recall repaints at once. Keys that arrive in one burst are still taken as a paste. (#7126, #7130) Thanks [@Lstarsky0](https://github.com/Lstarsky0).
- **Remote-control start failures stay visible:** a refused or failed `/rc` start now leaves the controller in the Failed state with its reason, logs a redacted line, and keeps `/rc status` in the footer after the toast expires instead of reporting "off". (#7127, #7120) Thanks [@laozidabo](https://github.com/laozidabo).
- **`/undo` follows your language:** what `/undo` reports (the request it undid, each file it restored, what it left in place) now comes from the locale catalog in all 15 complete packs instead of English text in the code; English output is unchanged. If a localized report cannot be built, the restore still syncs with the Engine and an English report is shown. (#7121, part of #7071) Thanks [@Aboysky](https://github.com/Aboysky).
- **TSX files get TSX diagnostics:** the language server now opens `.tsx` documents as `typescriptreact`, so valid JSX is no longer reported as a TypeScript syntax error. (#7140) Thanks [@Ricardo-M-L](https://github.com/Ricardo-M-L).
- **Work stays with the session that was saved (#7118):** saving, forking, renaming and rewinding a conversation now publish only the Work (To-do) state that belongs to the session just saved, and a newer update stays pending instead of being overwritten. A rewind that applied but could not be saved says so and puts the retry or replacement prompt where you can copy it. Tasks missing from `/task list` while the tracker shows them are not explained by this change.
- **Interrupted session hint stays visible (#7095):** when a plain `codewhale` launch finds a session whose turn never finished, the "Run `codewhale --continue` to resume it" hint now appears in the TUI's status line instead of being printed to the terminal just before the TUI covered it.
- **Interrupted sessions are kept and listed (#7095):** crash checkpoints are no longer deleted after 24 hours. The resume picker shows a session that exists only as a checkpoint, labelled Interrupted, `--resume <id-prefix>` finds it, and `codewhale sessions` lists it with an `interrupted` mark. A newer checkpoint is promoted into its saved session only under the session lease, and only for the same workspace. Retained checkpoints are not yet capped in number.
- **Resume an interrupted reply (#7095).** Escape preserves the visible partial reply. On SIGINT, SIGTERM or SIGHUP the terminal has up to two seconds to save the active turn and flush pending writes. A second signal exits immediately. On Ubuntu, killing the process after its regular checkpoint preserved the visible text through that checkpoint. On resume, the transcript marks the partial reply interrupted, and `/copy` returns the last completed answer. Thanks [@laozidabo](https://github.com/laozidabo) for the signal handling in [#7122](https://github.com/codewhale-hq/Codewhale/pull/7122).
- **Remote control works again:** `codewhale rc` (`/rc`) can attach to the hosted control plane for web Chat again. The control plane had only accepted the retired 0.9.13 runtime identity, so every 0.10.x Engine was refused with `runner_runtime_identity_unavailable`; it now accepts the exact released runtime identity (commit, image and digest) and fails closed when they are not configured.
- **MCP compatibility fixes:** older servers that answer the discovery probe with an error or an unrelated result now connect through the legacy handshake instead of being refused after the probe. A server that rejects sign-in reports its real 401 and the `/mcp login` hint rather than the probe's "method not found". A stale OAuth token is refreshed once when the probe itself is rejected. A server whose command cannot start now says why (for example, command not found) instead of a generic broker refusal.
- **Image-heavy session recovery:** ordinary image reads use a 256 KiB delivery budget. Requests measure serialized bytes; over the local budget, older images are omitted from the outbound copy first, with receipts. An initial HTTP 413 is retried exactly once without image attachments, each replaced by an omission note. Saved images and executed tool actions remain intact.
- **Composer history honors `CODEWHALE_HOME`:** with `CODEWHALE_HOME` set, prompt history reads and writes `$CODEWHALE_HOME/composer_history.jsonl` instead of sharing `~/.codewhale` across isolated homes; an invalid `CODEWHALE_HOME` keeps no history rather than falling back to your real home. (#7069)
- **Slow tools are not reported missing:** a tool whose `--version` probe is still running at its 3-second deadline (for example the `cargo` rustup shim on a busy machine) now counts as installed instead of being cached as missing for the rest of the session.
- **Telegram recovery:** prompts and their initiating identity are durable before the polling cursor advances. Restart recovery reuses the original Engine operation, questions preserve human ownership, and uncertain final replies remain available through `/status` without an automatic resend.
- Long drafts now show a localized external-editor hint when the actual composer
viewport clips their text. The hint uses the shared F4 binding and preserves
queue, running-turn, history, and menu hints (#7049). Thanks @Lstarsky0.
- Archived context markdown now uses the active theme's palette when rendered
in the transcript, preventing unreadable dark text on dark backgrounds (#7043).
Thanks @Statter.
- Plan-to-Work handoff now names the seeded To-do item in a localized reminder
to keep it on the list and complete it after the plan (#7068).
- Localized question footers, approval and plan-handoff chrome, tool waiting
status, and /color receipts use the shared locale packs (#7071).
- Clearing a conversation with no goal no longer shows a misleading "Goal cleared."
receipt. Clearing an existing or configured goal still reports it (#7089).
Thanks @Lstarsky0.
- A fatal engine error no longer turns on offline queueing by itself. When the
error came from a step that never starts a turn (a finished background
shell, a goal continuation or a child completion that cannot resolve its
route), every later message used to be queued behind it; it is now sent
normally. An environment-only authentication failure still reopens provider
setup and queues until you fix it (#6561).
- `codewhale --provider <name> resume <id>` now moves the saved session to the
named provider, as `exec --resume` already did, so a session whose provider
table was deleted can be reopened on a provider you still have. It takes
that provider's default model unless `--model` is also given. Without
`--provider` the resume still refuses rather than fall back, and the refusal,
now also on the `codewhale resume` and `fork` mount path, names this command
beside `codewhale sessions export <id>` (#6996). Thanks @luestr.
- The model's skills index now says when it shortens skill descriptions.
When a description hits the 400-char row cap, or rows are cut to fit the
context budget, the index ends with "descriptions shortened for N of M
skills" and points to `load_skill` with `name="list"` for the full text;
`/context report` and `/context json` show the same count on the skills entry.
`/skills inspect` now
flags a description by the same rule the index uses (#7073).
- A shell command that spans several lines (a heredoc, a loop, an `&&` chain
split across lines) now shows those lines on its Live card while it runs and
after it succeeds, within the card's usual line limit, instead of only the
first line. Transcript shows the whole command. Single-line cards are
unchanged (#6436, #7082).
- `codewhale review` no longer accepts leaked tool-call markup as a review: a
pass whose reply is a DeepSeek DSML (or other) tool-call wrapper outside code
now fails as incomplete, with no tally and nothing posted (#7072). Reviews no
longer have fixed per-risk output caps (a Low-risk review used to get 4,000
tokens, which a reasoning pass could spend entirely on thinking): every pass
may use the route's own output limit, and the step, tool and money budgets
still stop a review early as a named partial review rather than truncating
it. The `review` tool bounds its reasoning level to leave room for the review,
and an exhausted pass reports the allowance and reserve actually sent and
says "cut off" when visible text came back (#7067).
- A delegated agent still marked running that has reported no progress for 10
minutes no longer holds its parent turn open: the turn's stall watchdogs can
recover again, and the stall record names the agent. A child's running time
stays unlimited; only silence counts (#6184).
- Code blocks inside reasoning cells now take their syntax colours from the
active theme instead of the terminal's detected light or dark mode, so a dark
theme such as Shoreline in a light-profile terminal no longer paints
near-black code on its dark reasoning surface. The pager and clipboard copies
still follow terminal detection (#7043).
- `/balance` and the balance status chip work on the default DeepSeek route
again. The balance request now goes to the DeepSeek API root instead of the
`/beta` inference path, which failed with "Could not fetch DeepSeek account
balance". A failed balance request now names its reason, such as HTTP 401
Unauthorized (#7055).
- An `AGENTS.md` or global instruction file over 100 KiB is no longer
skipped (which could let a sibling file load in its place): Codewhale loads
its first 100 KiB, ends it with a marker giving the bytes omitted, and names
the file in `/context report`. The shared 48 KiB instruction budget still
applies after that, and the marker it leaves when it drops broader scopes
now gives the bytes dropped and the total (#6526).
- `write` over an existing file now says when it kept that file's CRLF or LF
line endings, so the agent no longer reports a line-ending conversion that
did not happen (#7070).
- The To-do that a Plan-to-Work handoff seeds is now titled with the plan's
first non-heading line outside code fences, without list or emphasis
markdown, instead of the whole plan run together
(#7068).
- Right-click "Open in editor" on a transcript cell now also offers a bare
workspace file path with no line number, opening it at line 1 (#2342).
- Composer history is no longer rewritten from a partial read: when the
history file cannot be read, new entries are not saved over it and a
warning is logged. An empty declarative workflow is refused ("workflow must
contain at least one node") instead of succeeding with no work (#6559).
- A `SKILL.md` that is not a regular file is reported as a skill load warning
instead of being read, so a FIFO in a skills directory can no longer stall
discovery (#6554).
- `app-server`: a turn whose `response_start` could not be written to stdio
is now interrupted instead of running on with nothing able to stop it
(#6558).
- Session saves no longer fail with "Fleet artifact path must stay within the
workspace" when the Codewhale state root is a symlink or Windows junction to
another volume: the state root is resolved before session-side state is
opened. Thanks [@SparkofSpike](https://github.com/SparkofSpike). (#7097)
- **Dollar signs stay dollar signs:** `$5 a month`, `10$ per year` and
`PATH=$HOME/bin:$PATH` no longer start inline math that swallows the text up
to the next `$`.
- **Math with non-ASCII text no longer crashes the TUI:** a reply with
`\text{如果}` or Greek letters inside `\begin{cases}` or `\begin{aligned}` used
to panic, and the saved reply panicked again on `--continue`. Escaped
characters (`\%`, `\{`, `\$`) and delimiters such as `\left\{` now render.
- **Markdown tables, rules, images and tabs:** table columns size to their
content instead of taking equal shares; `<br>` in a table cell breaks the
line; `- - -` and `* * *` are rules, not bullets; images render as their alt
text; and tabs in replies and sent messages expand, so Go and Makefile code
keeps its indentation.
- **The read tool opens text that starts with "BM":** a note beginning "BM25
is..." came back as "[Image omitted...]". A file is treated as a bitmap only
when its header is valid.
- **The launch card keeps the folder you are in:** on a narrow pane its path
drops to the folder name before it clips, and `/context` keeps the end of the
workspace path instead of its root.
- **A narrow rail keeps urgent notices:** warnings and errors are cut to fit
instead of vanishing when their first clause does not fit.
- **Truer status text:** "Model set to" appears only when the model changes, so
`/effort high` shows its own message; `/status` shows an unpriced session's
cost as unknown instead of `$0.0000`; and `/cache` no longer prints
`Σ hit: 0` for routes that report no cache tokens.
- **Compaction never drops history to fit:** when a complete summary cannot fit
the context window, the pass fails and your history stays, instead of
retrying with older messages silently left out.
- **`/diff` keeps its place on resize:** resizing the terminal no longer jumps
the pager and its search match back to an earlier line. (#7087)
- **First downloads for `npx` and `uvx` MCP servers:** a stdio server started
through `npx`, `pnpx`, `bunx` or `uvx` with no `connect_timeout` of its own
now gets at least 120 seconds to connect, so a recommended server such as
Playwright no longer fails its first `/mcp add` on a cold download.
- **The Linux extension host falls back to Node when Bun cannot run in the
sandbox:** a Bun that is a shim or script (asdf's, for example) now triggers
the `runtime = "auto"` fallback instead of failing the start.
- **Shell jobs hold their worktree (Runtime API):** removing a managed worktree
while one of its tracked shell jobs runs is refused with 409
`worktree_busy`, and the folder stays until the job ends.
- **The installer reuses an identical download:** `codew` is not downloaded
again when its manifest digest matches `codewhale`'s. (#7102)
- **The zsh missing-key hint reads as guidance:** the first-run hint no longer
looks like a shell error.
- **Website:** recovered warm paper, clear-blue actions and original drawn water accents; added Computer Use and automatically refreshed terminal/plugin release links; shortened copy, clarified contribution paths and checked setup guidance against published versions.
- **Edit tool:** when an edit only matches after quote, dash or full-width normalization, the rest of the touched line keeps its original characters instead of being rewritten (`:100()` no longer becomes `:100()`), and two adjacent fuzzy edits no longer overlap ([#7257](https://github.com/codewhale-hq/Codewhale/pull/7257)). Thanks [@Lstarsky0](https://github.com/Lstarsky0).
- **File mentions:** an `@` mention typed straight after Chinese or Japanese text, such as `请看@src/main.rs`, now attaches the file, completes with Tab and shows its chip, and full-width closing punctuation after a mention is no longer read as part of the file name; mentioning two line ranges of one file attaches both instead of dropping the second ([#7258](https://github.com/codewhale-hq/Codewhale/pull/7258), [#7259](https://github.com/codewhale-hq/Codewhale/pull/7259)). Thanks [@Lstarsky0](https://github.com/Lstarsky0).
- **Footer context meter:** after `/load`, resume, `/branch` or a fork, the context percentage shows the restored conversation instead of the size of the one you left ([#7256](https://github.com/codewhale-hq/Codewhale/pull/7256)). Thanks [@Lstarsky0](https://github.com/Lstarsky0).
- **Custom commands:** a custom slash command now runs when its arguments follow a full-width space or start on a new line, instead of being reported as unknown ([#7260](https://github.com/codewhale-hq/Codewhale/pull/7260)). Thanks [@Lstarsky0](https://github.com/Lstarsky0).
- **/config:** the detail pane lines its values up in one column in every language, including locales with long or full-width labels such as Ukrainian and Chinese ([#7267](https://github.com/codewhale-hq/Codewhale/pull/7267)). Thanks [@Lstarsky0](https://github.com/Lstarsky0).
- **Recovery safeguards:** workflows reject results that cannot yet exist, implicit session storage refuses an unresolved home, and future-dated provider catalogs cannot stay fresh indefinitely.
- **A provider timeout no longer reads "after 0ns":** a timed-out request used to report `Request timed out after 0ns`, which looked like a zero-length budget and hid the real failure. The retry loops now measure the elapsed time per attempt, and where it is unknown the message says so instead of printing a made-up duration ([#7253](https://github.com/codewhale-hq/Codewhale/pull/7253)). Thanks [@gaord](https://github.com/gaord).
- **A failed send keeps what you typed since:** when a message fails to send after you have started a new draft, the failed message is stashed rather than written over the draft, so it stays recoverable ([#7255](https://github.com/codewhale-hq/Codewhale/pull/7255)). Thanks [@Lstarsky0](https://github.com/Lstarsky0).
- **Windows: plugins enable again on a finalized runtime root.** The sandboxed plugin host adds its own AppContainer read and execute grant to the finalized plugin root, and Windows stored the root's inheriting read/execute entry as more than one entry; both made enabling refuse. The root now carries one non-inheriting entry, the verifier still requires a protected owner-only DACL with nothing above read and execute, and the refusal names the underlying check. Fleet ledger compaction is no longer blocked by a live appender, and a blocked checkpoint inspection is reported as such instead of clearing save health. The Windows suite has not been shown green on this candidate, so this is not a Windows qualification.
### Security
- **Pet companion owner token compared in constant time:** the local companion server's Bearer and cookie checks no longer use plain byte equality, so response timing cannot reveal how much of a guessed token matched. The surface was already loopback-only with Host and Origin pinning and a private owner-checked directory.
- **MCP client advisory (RUSTSEC-2026-0462):** the MCP library moves to
rmcp 3.9.0, closing unbounded response-body buffering in its Streamable
HTTP clients that a hostile or broken MCP server could use to exhaust
memory.
- Saved tool-result reads refuse links in the selected session, including a linked session directory, while preserving deliberately relocated application storage. Owned files and digest-checked legacy results keep their existing access paths.
- **Pinned marketplace archives:** a Codewhale or Claude marketplace entry whose tarball source carries a `sha256` now installs only when the downloaded bytes match it; a mismatch, a malformed pin or a pin on a non-archive source refuses the install with nothing written. The pin also applies to direct installs as `https://…/x.tar.gz#sha256=<hex>`.
- **Sandboxed commands cannot plant git hooks or edit git config:** in workspace-write mode, `.git/hooks` and `.git/config` (and a linked worktree's shared `hooks` and `config`) are read-only to sandboxed commands, so a command cannot leave a hook or `core.hooksPath` that later runs outside the sandbox. The workspace's `.codewhale/` is protected even before it exists (on Linux it is created first, because bubblewrap can only protect existing paths). `git commit` and ordinary file writes are unaffected; `git config` writes and hook edits need an approved unsandboxed command.
- **Tool image validation:** an image returned by a tool must decode before it is sent, so truncated or corrupt files are omitted with a receipt even when they are already within the delivery budget.
- **Terminal graphics advisory (RUSTSEC-2026-0430):** the terminal emulator
library moves to rio-vt 0.5.29, closing a path traversal in its Kitty
graphics handler that could read or delete files outside the intended
directory.
- **Workspace status no longer runs repository filter drivers:**
`GET /v1/workspace/status` and the Git status detail neutralize clean and
process filters a repository defines, so opening a cloned repository cannot
run its code. A failing filter used to make the route report a clean tree; it
no longer does.
- **Bridge and extension dependency advisories:** the Feishu and WeCom bridges
move to `follow-redirects` 1.16.2 (high severity), and the VS Code extension
build no longer pulls a vulnerable `minimatch`.
- **Approval answers must match their request (Runtime API):** an approval,
user-input or tool answer that names a different thread, turn or call is
refused with 403 instead of being delivered. Callers that send no binding,
such as the existing HTTP route, behave as before.
- **Bounded release discovery:** `codewhale update` reads at most 8 MiB of
release metadata and 4 KiB of error text, strips control characters from
remote errors and no longer echoes malformed input.
### Maintenance
- **Windows release harness:** the terminal-clipboard check strips Windows PowerShell's UTF-8 BOM before parsing cleanup receipts and still runs the bounded private-path cleanup fallback after its controller has exited; the vendored terminal kit lock follows Protocol 0.10.3.
- **Windows release import floor:** the 10 ARM64 import pairs that the native export probe resolved on Windows 11 ARM64 are qualified, and 12 x64 pairs are recorded as documented API contracts until a native x64 export probe exists. The Windows 10 build 14393 floor, the guard and the x86 profile are unchanged; the next frozen candidate's import job is the real check.
- MCP regression fixtures retain private extension-host roots and wait for their own workers to finish, preventing parallel checks from borrowing a deleted fixture home. Production connection and credential policy is unchanged.
- **Independent terminal kit candidate 0.2.0:** its workflow totals use `u64`, and its existing avatar API reexports the shared Protocol contract. All local consumers pin 0.2.0. Protocol 0.10.3 must be published and verified before the kit, followed by the dependent Engine packages; each publication retains its separate approval.
- **`codewhale-plugins` crate:** plugin discovery, review, install and marketplace parsing move out of `codewhale-tui` into a new crate; MCP server config types move to `codewhale-mcp`, and the skill parse core and recommendations to `codewhale-skill-install`. Review and trust behavior is unchanged. (S19, #5316)
- **`codewhale-config` modules (internal):** the 8,100-line `lib.rs` is split into 23 modules (provider TOML, permissions, fleet, config resolution, env overrides, state dirs, config store and backup, and others); `codewhale_config::` paths are unchanged. No behavior change. (S57, #5316)
- **`codewhale-app-server` modules (internal):** `lib.rs` is carved into `http`, `stdio`, `turns`, `bridge` and `config_rpc` modules; `BoundedLines` and `runtime_compatibility_router` now live at `codewhale_app_server::stdio` and `::http`. No behavior change. (S49, #5316)
- **`codewhale-account-cli` crate (internal):** the cloud account, cloud computer and dispatch CLI commands move out of `codewhale-cli` into a new crate. No behavior change. (S50, #5316)
- **`runtime_threads` store and manager (internal):** `runtime_threads` is split into the durable store (`runtime_threads.rs`) and the thread manager (`runtime_threads/manager.rs`); callers import from `runtime_threads::manager`. No behavior change. (S35, #5316)
- **Crate split S24a (internal):** the workshop byte-budget slot moves to `codewhale-runtime`, `AutoRouteDecisionEvidence` to `codewhale-models`, and cost-status session persistence to a tui `usage_persistence` module, so billing no longer reaches the session manager or model routing. No behavior change. (#5316)
- **Provider pre-cuts B (internal):** client wire helpers, reasoning-effort mapping and the Ollama catalog parsers move into their own client modules, and test-only provider gates use the shared test-isolation predicate. No behavior change. (#5316)
- **`codewhale-dependencies`, `codewhale-snapshot`, `codewhale-lsp`, `codewhale-repl` crates:** external-tool resolution, workspace snapshots, the language-server client and the Python REPL runtime moved out of `codewhale-tui` into their own crates; `write_context_file` now lives in `codewhale-repl`. No behavior change. (#5316)
- **`codewhale-skill-install` crate:** the community-skill installer, package content digest and `SKILL.md` frontmatter reader move out of `codewhale-tui` into a new crate; the install SSRF guard and timeouts are unchanged in production builds. (#5316)
- **`codewhale-util` crate:** shared utilities, confined workspace file access, link and file-identity checks, bundle file readers, the `.git` name rule and the owner file lock move out of `codewhale-tui` into a new crate; no behavior change. (#5316)
- **Crate-split contract hygiene:** the `canonical_action` policy table now lives in `codewhale-execpolicy`, `required_action`, the file path-alias folding and the `apply_patch` preflight parser in `codewhale-tools`, and `DEFAULT_SPAWN_DEPTH`, `PermissionCeiling` and `ShellCeiling` in `codewhale_protocol::fleet`, so `codewhale-agent-contract` no longer depends on `codewhale-config` or `codewhale-workflow`. Approval and authority behavior is unchanged. (#5316)
- **Provider pre-cuts (internal):** schema sanitizing, prompt-turn classification, image-window capping, tool-projection warning names and the reasoning-effort tier moved into `codewhale-models`; stall records and route-label sanitizing moved into `codewhale-runtime`. No behavior change. (#5316)
- **Linux hardening tests:** the NoNewPrivs child matrices now respect a parent that already holds the irreversible flag, keeping the full assertions on unpinned hosts and checking the kernel ratchet on pinned hosts. Thanks [@asto18089](https://github.com/asto18089) for diagnosing the hardened-container failure. (#7021)
- Removed the internal config re-export facade and its model-constant wrapper;
provider types, shared constants, credential helpers, and notification types
now come directly from their shared owners. Configuration and saved settings
keep their existing behavior.
- Removed superseded home-directory and Fleet-role re-export shims, unused
tool-context sandbox/MCP fields, and the redundant core tool-parser facade.
Consumers now call their existing owners directly; tool denial rules, approval
posture, strict tool schemas, home resolution, and legacy saved-role migration
retain their behavior. The cleanup removes three dead-code suppressions and
keeps the engine as the sole owner of human approval attestations.
- Removed unused plan/journal accessors, an unused plan-status glyph helper,
and a cancellation case that no execution path issued. Active mailbox and
cancellation wiring stays in place; its stale unused-code suppressions are
removed. No supported command or feature is retired by this cleanup.
- README translations carry refreshed source stamps after the 0.10.3 batch.
Thanks [@Aboysky](https://github.com/Aboysky). (#7104)
### Contributors
- **[@cmdcorp6534](https://github.com/cmdcorp6534)** — reported the Chinese input-method candidate window appearing away from the field being typed into ([#2323](https://github.com/codewhale-hq/Codewhale/issues/2323)).
- **[@Asteria1028](https://github.com/Asteria1028)** — reported pasted clipboard images piling up with no way to remove them ([#7221](https://github.com/codewhale-hq/Codewhale/issues/7221)).
- **[@zhuowp](https://github.com/zhuowp)** (git author `z27014`) — added bounded HTTP rate-limit recovery and corrected retry deadlines, quota guidance and recovery receipts ([#7220](https://github.com/codewhale-hq/Codewhale/pull/7220)). Allowed an optional host policy on model HTTP clients ([#7251](https://github.com/codewhale-hq/Codewhale/pull/7251)).
- **[@printf033](https://github.com/printf033)** — enabled exclusive rename on Android so Fleet publication does not fall back to SELinux-denied hard links (`fbe9f24ee`).
- **[@liuyy2](https://github.com/liuyy2)** — diagnosed case-sensitive model selection collisions in the provider picker ([#7214](https://github.com/codewhale-hq/Codewhale/issues/7214)).
- **[@isaacs](https://github.com/isaacs)** — upstream minimatch preprocessing and glob cancellation fixes reused in compatible web build dependency backports.
- **[@Gabriel-Degret](https://github.com/Gabriel-Degret)** — reported that a hosted output limit truncated reasoning on a custom endpoint ([#7179](https://github.com/codewhale-hq/Codewhale/issues/7179)).
- **[@soarkit](https://github.com/soarkit)** — reported that `/patch-undo` ignored `turn_id` and undid the latest turn ([#7216](https://github.com/codewhale-hq/Codewhale/issues/7216)).
- **[@d-onistack](https://github.com/d-onistack)** — reported ChatGPT sign-in failing token verification on Windows after a successful browser sign-in, with clock and endpoint checks that narrowed it to local verification ([#7203](https://github.com/codewhale-hq/Codewhale/issues/7203)).
- **[@Felixkw12](https://github.com/Felixkw12)** — added Opper as a bundled provider ([#7131](https://github.com/codewhale-hq/Codewhale/pull/7131)).
- **[@7jrxt42BxFZo4iAnN4CX](https://github.com/7jrxt42BxFZo4iAnN4CX)** — per-scope instruction budgets with visible truncation ([#7086](https://github.com/codewhale-hq/Codewhale/pull/7086), [#6526](https://github.com/codewhale-hq/Codewhale/issues/6526)).
- **[@Lstarsky0](https://github.com/Lstarsky0)** — kept the `/diff` pager's place across a resize ([#7087](https://github.com/codewhale-hq/Codewhale/pull/7087)), said "Goal cleared." only when there was a goal ([#7089](https://github.com/codewhale-hq/Codewhale/pull/7089)), and stopped printing an unpriced session cost as `$0.0000` in `/status` ([#7090](https://github.com/codewhale-hq/Codewhale/pull/7090)), kept Normal-mode keys out of the draft on terminals without bracketed paste ([#7126](https://github.com/codewhale-hq/Codewhale/pull/7126)) and let shifted keys such as `G` reach Normal mode ([#7130](https://github.com/codewhale-hq/Codewhale/pull/7130)), kept the quote rail on every wrapped row of a blockquote ([#7144](https://github.com/codewhale-hq/Codewhale/pull/7144)), kept a nested list paragraph's indent ([#7146](https://github.com/codewhale-hq/Codewhale/pull/7146)), rendered `~~~` fences as code ([#7156](https://github.com/codewhale-hq/Codewhale/pull/7156)), left asterisks that do not open emphasis literal ([#7157](https://github.com/codewhale-hq/Codewhale/pull/7157)), ended bare URLs at full-width punctuation ([#7158](https://github.com/codewhale-hq/Codewhale/pull/7158)), kept a link target's own parentheses ([#7170](https://github.com/codewhale-hq/Codewhale/pull/7170)), rendered code and links inside emphasis ([#7171](https://github.com/codewhale-hq/Codewhale/pull/7171)) and stopped the engine's fleet-roster and stream-timeout statuses from taking over the footer ([#7152](https://github.com/codewhale-hq/Codewhale/pull/7152), [#7169](https://github.com/codewhale-hq/Codewhale/pull/7169)). Preserved indentation and space-only inline code in table cells ([#7184](https://github.com/codewhale-hq/Codewhale/pull/7184)). Reported `file_search` matches relative to the workspace ([#7213](https://github.com/codewhale-hq/Codewhale/pull/7213)). Matched brace and nested-directory globs in `grep_files` ([#7215](https://github.com/codewhale-hq/Codewhale/pull/7215)). Kept the draft when the command palette inserts a command ([#7205](https://github.com/codewhale-hq/Codewhale/pull/7205)). Bounded nested brace expansion and repeated globstars in `grep_files` ([#7254](https://github.com/codewhale-hq/Codewhale/pull/7254)) and kept a typed draft when a failed send comes back ([#7255](https://github.com/codewhale-hq/Codewhale/pull/7255)).
- **[@gaord](https://github.com/gaord)** — a running turn's cost and context in the Runtime ([#7074](https://github.com/codewhale-hq/Codewhale/pull/7074)) forks that measure the history they carry ([#7147](https://github.com/codewhale-hq/Codewhale/pull/7147)), and private state on a HarmonyOS mount that cannot express ownership ([#7168](https://github.com/codewhale-hq/Codewhale/pull/7168)). Capped WeCom reply chunks by UTF-8 bytes ([#7209](https://github.com/codewhale-hq/Codewhale/pull/7209)). Accepted media and voice messages on the WeCom bridge ([#7212](https://github.com/codewhale-hq/Codewhale/pull/7212)). Steered a running turn from the WeCom bridge ([#7211](https://github.com/codewhale-hq/Codewhale/pull/7211)). Surfaced WeCom API error details in bridge replies ([#7208](https://github.com/codewhale-hq/Codewhale/pull/7208)) and rotated WeCom stream replies before the ten-minute expiry ([#7210](https://github.com/codewhale-hq/Codewhale/pull/7210)); both were harvested with the original commits kept. Stopped provider timeouts reporting "after 0ns" ([#7253](https://github.com/codewhale-hq/Codewhale/pull/7253)).
- **[@luochen211](https://github.com/luochen211)** — one form per term in the Simplified Chinese pack ([#7150](https://github.com/codewhale-hq/Codewhale/pull/7150)) and dropped blanket dead-code allows in fleet alerts and the pet worker ([#7149](https://github.com/codewhale-hq/Codewhale/pull/7149)). Added a Chinese provider setup page ([#7266](https://github.com/codewhale-hq/Codewhale/pull/7266)) and translated the Receipts ([#7264](https://github.com/codewhale-hq/Codewhale/pull/7264)), Claude plugin compatibility ([#7263](https://github.com/codewhale-hq/Codewhale/pull/7263)) and GitHub review bot ([#7265](https://github.com/codewhale-hq/Codewhale/pull/7265)) pages.
- **[@gannp](https://github.com/gannp)** — reported vLLM effort values that ignored the local model template and fixed it with a reviewed template registry ([#7124](https://github.com/codewhale-hq/Codewhale/issues/7124), [#7125](https://github.com/codewhale-hq/Codewhale/pull/7125)).
- **[Sh1Zuku / @SparkofSpike](https://github.com/SparkofSpike)** — resolved a relocated state root before session-side state opens ([#7097](https://github.com/codewhale-hq/Codewhale/pull/7097)) and made a goal pause to ask instead of inventing the answer ([#7175](https://github.com/codewhale-hq/Codewhale/pull/7175)), and gave the model a way back into the transcript compaction replaced ([#7173](https://github.com/codewhale-hq/Codewhale/pull/7173)). Also preserved journal history when a provisional input receives its Engine metadata ([#7180](https://github.com/codewhale-hq/Codewhale/pull/7180)). Added the bare DeepSeek V4.1 Flash catalog entry ([#7183](https://github.com/codewhale-hq/Codewhale/pull/7183)). Stopped a home-directory workspace from refusing its own state ([#7207](https://github.com/codewhale-hq/Codewhale/pull/7207)).
- **[@ddlw](https://github.com/ddlw)** — repaired main for the 0.10.3 batch: clippy `-D warnings` across protocol, runtime, util and tui (boxed review and MCP-add payloads, scoped dead-code expectations, cfg-gated platform test helpers), rustfmt, split extension-host imports, the provider-registry identity check, Windows-stable DSH receipt bytes, and the first-party marketplace receipt ([#7108](https://github.com/codewhale-hq/Codewhale/pull/7108), [#7109](https://github.com/codewhale-hq/Codewhale/pull/7109)).
- **[@laozidabo](https://github.com/laozidabo)** — localized `/diff` feedback ([#7101](https://github.com/codewhale-hq/Codewhale/pull/7101)), flushed queued saves before signal exit ([#7122](https://github.com/codewhale-hq/Codewhale/pull/7122)) and kept `/rc` start failures visible ([#7127](https://github.com/codewhale-hq/Codewhale/pull/7127)).
- **[Boyce / @Aboysky](https://github.com/Aboysky)** — refreshed the README translation source stamps ([#7104](https://github.com/codewhale-hq/Codewhale/pull/7104)) and localized `/undo` feedback ([#7121](https://github.com/codewhale-hq/Codewhale/pull/7121)).
- **[@Ricardo-M-L](https://github.com/Ricardo-M-L)** — opened `.tsx` documents with the `typescriptreact` language ID ([#7140](https://github.com/codewhale-hq/Codewhale/pull/7140)).
- **[@M-Maciej](https://github.com/M-Maciej)** — reported answerless output-limit stops in long Fleet proofs ([#6990](https://github.com/codewhale-hq/Codewhale/issues/6990)).
- **[@asto18089](https://github.com/asto18089)** — diagnosed the NoNewPrivs child-matrix failure on hardened containers ([#7021](https://github.com/codewhale-hq/Codewhale/issues/7021)). Dropped the false sandbox claim from the `fetch_url` description ([#7222](https://github.com/codewhale-hq/Codewhale/pull/7222)) and limited nested-repository discovery to the sub-agent worktree anchor ([#7224](https://github.com/codewhale-hq/Codewhale/pull/7224)). Accepted absolute in-workspace paths in sub-agent write claims ([#7227](https://github.com/codewhale-hq/Codewhale/pull/7227)). Repaired pre-0.10.0 topology checkpoint placement on session restore ([#7229](https://github.com/codewhale-hq/Codewhale/pull/7229)). Pointed the `verify` description at the Run tool instead of a retired name ([#7223](https://github.com/codewhale-hq/Codewhale/pull/7223)). Swept stale mode-jump and rail copy from the non-English packs ([#7225](https://github.com/codewhale-hq/Codewhale/pull/7225)), accepted absolute image paths that resolve inside the workspace ([#7226](https://github.com/codewhale-hq/Codewhale/pull/7226)) and reported follow-up delivery truthfully ([#7228](https://github.com/codewhale-hq/Codewhale/pull/7228)); all three were harvested with the original commits kept. Paused the durable task wall clock while an answerable prompt waits ([#7230](https://github.com/codewhale-hq/Codewhale/pull/7230)).
- **[@Statter](https://github.com/Statter)** — reported black-on-black text on terminals that do not report their background ([#7043](https://github.com/codewhale-hq/Codewhale/issues/7043)).
- **[@eugenicum](https://github.com/eugenicum)** — asked for a visible Full Access flag for `serve --acp` ([#6992](https://github.com/codewhale-hq/Codewhale/issues/6992)).
- **[@luestr](https://github.com/luestr)** — reported file and conversation rollback diverging ([#6970](https://github.com/codewhale-hq/Codewhale/issues/6970)), the Linux multiline send key ([#7093](https://github.com/codewhale-hq/Codewhale/issues/7093)) and session export guidance ([#6996](https://github.com/codewhale-hq/Codewhale/issues/6996)).
- **[@ychu824](https://github.com/ychu824)** — reported every Anthropic request failing with a 400 once `tool_search` added a tool whose name contains a dot, such as `web.run` ([#7252](https://github.com/codewhale-hq/Codewhale/issues/7252)).
## [0.10.2] - 2026-10-22
Codewhale v0.10.2 adds an animated pet view (`/pet on`), a live Terminal work
dock, per-chat composer colors (`/color`) and a one-time note on the first
start after an update that says what changed. It closes three session
data-loss paths and a `codewhale web` session leak; adds the default Runtime
daemon socket locations to the sandbox deny-list; holds a `curl` or `wget` that uploads a
credential; refuses shell commands containing invisible Unicode; keeps the
Linux sandbox working when a hidden credential directory is a symlink; and
reduces idle TUI redraw work. `/undo` takes back a whole
request, including long and multiline prompts. `exec --auto` explains its
Full Access default, honors an explicitly stricter sandbox, and saves
tool-enabled runs and their failure receipts. Local runtimes appear during
onboarding, `/diff` works outside a Git repository, DeepSeek's Responses route
no longer rejects replayed tool history, and contributor fixes improve token
accounting, relay model lists, localized replies and Windows launcher
guidance. Delegated work continues without model-invented turn or time caps,
and independent workflow steps can continue after another child fails.
### Latest fixes
- Linux sandboxed terminals deliver Ctrl-C to the foreground program without
killing the bubblewrap wrapper. A program that handles SIGINT can keep running
and accept more input. PTY jobs and persistent terminals retain their sandbox
and process-tree cleanup; this path requires util-linux `setsid`.
- Full Engine integrations now point explicitly to `codewhale app-server --http`.
Compatibility HTTP, stdio and socket turns require `allowed_tools: []` and
reject interactive execution and goal starts before work begins, closing the approval and
clarification dead end. ACP new/load rejects unsupported supplied MCP servers
instead of silently ignoring them; ACP v1 MCP support remains partial. The
Runtime SDK guide states its Fleet/event coverage and provides authenticated
HTTP examples for the remaining client controls.
- `tokio` moves to 1.53.3, which retires `RUSTSEC-2026-0386`. The advisory
covers `tokio::io::unix::AsyncFd`'s safe constructors accepting a file
descriptor they do not own; the lock now sits in a range the advisory lists as
patched, and Codewhale never calls `AsyncFd` at all.
- A signed-in ChatGPT account refreshes its model list at launch. The plan roster
was only fetched at sign-in or on an explicit `models --update`, so an account
that never re-authenticated kept reporting models it no longer offers and never
heard about new ones; the launch sweep that refreshes the other catalog layers
now refreshes a missing, stale or invalid roster too, at the cost of one
freshness probe when it is current. A roster past its 24-hour limit also lists
its last known models instead of none, and only a fresh fetch supplies the
preferred default.
- Two sessions can share one folder again. The embedded TUI runtime mounted its
delegated-coordination lock exclusively, so a second `codewhale` in a workspace
that already had one running was refused with `another Codewhale process owns
delegated coordination for <workspace>`; `codewhale resume <session B>` beside a
running session hit the same wall. The exclusive holder is now only
`codewhale serve`, which the architecture doc already reserved it for (`#7042`).
- A reasoning effort the route cannot honor is no longer sent to it. OpenAI wire
requests resolve the session's effort through the row's declared ladder and
clamp to the nearest rung upward, because `gpt-5.5-pro` declares only
`["medium","high","xhigh"]` and was being handed `off` and `low`, while
`gpt-5.5` and `gpt-5.3-codex` start at `none` and `gpt-5.6*` add `max`. An effort
the row already declares is passed through untouched (`#6396`).
- ChatGPT-plan routes report their reasoning controls. The plan roster carries
only ids and labels, so every `openai-codex` row advertised
`reasoning_effort: unsupported` with no levels at all. Rows are now joined
against the merged catalog for the fields the roster leaves blank, and
`gpt-6-astra` reports `["low","medium","high","xhigh","max"]`. Context windows
are deliberately not filled from that join: the plan snapshot's 272,000
describes a different wire than the 1,050,000 the catalog lists.
- A boot that never reports back no longer claims to be connecting forever. The
launch card's prediction for configured MCP servers now carries the moment it
was made and retires after five minutes without a receipt, so a pass that dies
before posting its finished event settles on the last known snapshot instead
of leaving rows that never resolve (`#7035`).
- `python3 scripts/catalog_models_dev.py defaults audit` is the release step
that staleness needs: it re-reads a models.dev payload and reports every
provider whose shipped default a newer stable row in its own namespace has
overtaken, failing the run on an unrecorded one and taking an explained hold
from `DEFAULT_AUDIT_REASONS` otherwise. And the `anthropic` default moves to
`claude-sonnet-5-5`: a forced `tool_choice` is now softened to `auto` for
Opus 5.5 and Sonnet 5.5, which reject it, instead of being sent and refused.
- The model picker's browse views list models you can talk to. `Catalog`, `New`,
`Coding`, `Cheap` and `LongContext` now skip image, embedding, video, speech,
transcription, reranking and realtime rows — 445 of the 8,849 live catalog
entries — instead of threading them between the chat models you were scanning
for. `Configured` is untouched, so a route you already set up stays visible,
and a search still reaches everything: typing an image model's id finds it.
- The model picker can be read one provider at a time. `Sort: Provider` now
prints a provider header for each block instead of one flat run of names,
and `⇧T` narrows the list to one provider at a time and clears on the next
cycle; the title names the active filter and the footer advertises `⇧T`
beside `⇧A`, so a shortened list is never unexplained. Choosing a provider sort
also browses the whole roster rather than the rows the current view admitted,
so one keystroke turns the Configured view into a full catalog grouped by
vendor — which is what "sort by provider to find models" needs to mean.
- `openai-codex` defaults to `gpt-6.1-sol`. Its ChatGPT plan roster served
seven ids and no bare `gpt-5.6`, which the descriptor defaulted to: a fresh
roster redirected the choice, but a stale, expired or absent roster sent a
model the account does not serve and the request failed. `codewhale models`
also stops claiming "availability not verified" for a route that did use a
fresh snapshot, and now reports the real snapshot layer, fetch time and row
count. The offline seed check compares every descriptor default against the
seed default and refuses to write when they disagree, and
`seed lock --dry-run` reports providers whose default a newer upstream id
has overtaken, plus locked rows the spec no longer references.
`docs/CATALOG_REFRESH.md` states the limit plainly: nothing offline can
detect that a vendor shipped a model.
- A persisted `/models` partition from an official endpoint no longer hides a
newer catalog snapshot. `openai` listed a two-generation-old roster while
the shipped snapshot already carried `gpt-6-astra`, `gpt-6-luna`, `gpt-6-sol`
and `gpt-6.1-sol`, and refreshed `anthropic` and `deepseek` ids were
suppressed the same way. A route that owns its live catalog (a relay, a
private endpoint, a custom base URL) stays authoritative however old the
fetch; an official endpoint's partition must be fresh to shadow the
snapshot, and an unfresh one still contributes its own ids as an offline
tail so a withdrawn model does not vanish by omission.
- One catalog row without a price no longer costs you every model in its
provider. `models --update` reported `failed / cache_write_failed` with
`model_count 0` for OrcaRouter while the endpoint answered 468 rows, because
a row whose price was dropped still carried a live cost stamp and one such
row rejected the whole refresh as `invalid_response`; the same all-or-nothing
rule also discarded an entire cached scope on the next read. Rows are now
judged one at a time, a refresh fails only when rows arrived and none
survived, and a cached scope that loses every row to validation is still
dropped rather than loaded. A failed refresh names its typed reason instead
of `cache_write_failed` and still reports the rows you have left.
- A new OrcaRouter session with no saved wire model defaults to
`deepseek/deepseek-v4.1-flash-1017`. Every OrcaRouter catalog row has
`default_for_provider` false, so the descriptor was the only thing deciding
the default and it named an older model. The `deepseek-v4-pro` and
`deepseek-v4pro` shorthands still select `deepseek/deepseek-v4-pro` on this
provider, so naming a pro model never silently lands on Flash.
- `POST /v1/threads` is replay-safe. A retry under the same `operation_key`
returns the original thread — after a restart too — instead of minting a
second one and orphaning the conversation; a changed request under the same
key is refused with 409 rather than replacing or duplicating. The
capability is advertised as `thread_create_idempotency`, and clients must
require it.
- A sandboxed shell can read a tool's own auth config again. The credential
deny-list still refuses those files to Codewhale's file tools, but it no
longer refuses them to the programs that own them, so `gh`, `glab`, `aws`,
`npm`, `cargo`, `docker`, `kubectl` and `git` can authenticate from a
`read-only` posture. Key material, keychains, other agents' credential
stores and Codewhale's own secret stores stay denied to subprocesses.
- The website and README link the supplied Codewhale × OrcaRouter offer
graphic to its redemption page, with readable link text and referral disclosure.
- Development test builds use a boxed future at the shared Engine event-loop
boundary, keeping its large concrete async type out of callers. One local
warm-build comparison fell from 29m 31s to 2m 24s with the same compiler,
profile and features; this is not a cold-build or cross-platform guarantee.
- Delegated workers no longer inherit model-selected turn, time or output
caps, and the default 30-minute child deadline is removed. Launch receipts
identify ignored legacy limits and show
the limits that actually apply. The 75% child "wrap up" and 80% parent
"stop exploring" prompts are removed, as is the instruction to give up after
two failed tool calls. Explicit owner limits are no longer silently shortened
to 100,000 turns or 24 hours. The stopship example also drops forced response
counts and its two-call discovery limit. Children can use the final allowed
turn for useful work; the host preserves partial results without reserving
time or issuing an extra model request for a forced summary. Default child
and workflow nesting caps are removed; explicit owner bounds still apply.
Existing installations receive the updated delegation guidance while keeping
customized or deleted skills intact (#7044).
- Workflows can continue independent steps after a child fails, with dependent
steps recorded as skipped. The cumulative 1,000-child cutoff is removed;
owners can still configure a total child limit. Recursive work no longer
stops at 25 rounds, three replies without code or printed output, or an
invented enclosing or subquery deadline. Code-mode scripts can make more
than 50 admitted tool calls. Cancellation,
permissions and inherited owner deadlines still apply. Long-running live
children are no longer treated as abandoned merely because 35 minutes passed.
- Read-only workflow children receive their response schema in the first
request; write-capable children keep the verification report contract.
Unmetered workflow usage is shown as unknown instead of zero. Mode history
follows changes between Plan and Operate, and `/goal resume` can restart an
idle active goal without replacing its identity or clearing stall evidence.
- ChatGPT sign-in opens your regular browser and returns to Codewhale with
credentials and a model list for the account you selected. The unsupported
`originator` parameter that caused `invalid_authorize_request` is removed
(#6925). PKCE, account binding and granted-scope validation remain in place.
A real browser sign-in, account model list and model response were verified
for this release candidate.
- Renaming a session in `/sessions` shows its title prompt once, preserving
the validation and saved-title messages (#7054). Thanks @Lstarsky0.
- Deferred-tool admission measures schemas after the provider's wire conversion.
Search results show the active toolbox, soft-limit overflow and readmission
state. Per-request receipts join those wire measurements with the current
prefix change and reported usage, including separate transparent retries.
Missing cache usage remains unknown; these receipts do not add charges.
- The community website uses Next.js 16.4.1, which includes the upstream
security fixes for cache deserialization, image optimization and Server Actions.
- Haiku 4.5 metadata preserves its image input and extended-thinking support,
keeping review output reserves consistent with its provider capabilities.
- Clearing or replacing an OrcaRouter key cancels pending browser sign-in,
including a code exchange already underway. A late callback can no longer
restore the cleared key, and disconnecting the client does not interrupt
credential cleanup.
- Cloud Runtime provider keys can stay in process memory. Session-only mode
disables saved-key, environment and OAuth fallback, keeps keys bound to their
exact endpoint, and advertises support for memory-only set and clear.
Clearing affects subsequent turns; already running turns retain their key.
In-process subagents remain available; external Fleet execution is refused
in this mode because its processes do not share the session-key overlay.
Supervised HTTP servers can adopt a validated inherited loopback listener,
preserving supervisor ownership across Engine restarts.
- Opening a folder in the desktop Runtime no longer fails because a terminal
session is already using it, including when attaching a second folder.
Delegated workers still respect the folder's writer lock, including after
a restart. If the Runtime starts without its own coordination lock, stop and
restart its process after the other session exits to regain delegated writes.
It cannot overwrite newer coordination records with the snapshot it opened earlier.
- Credentials in tool-call arguments are now redacted before a session is
saved. A command the model wrote with a key in it (`curl -H
'Authorization: Bearer …'`, `API_KEY=… ./run`, a `.env` write) was stored
verbatim in the saved session and journal and replayed on resume; only tool
output was redacted. `codewhale sessions scrub-secrets` now also cleans tool
arguments in sessions already on disk. `[redaction] model_bound = false`
still lets the model see exact file bytes for edits, but no longer turns off
redaction of what is written to disk.
- Provider requests follow redirects only on the same host. A cross-host
redirect or a downgrade from HTTPS to HTTP now stops the request, so an open
redirect on a configured `base_url` can no longer collect an `x-api-key`
header. The network guard also refuses IPv6 forms that reach private
addresses: NAT64 (`64:ff9b::/96`, checked as its embedded IPv4 address),
6to4, Teredo, site-local and IPv4-compatible addresses. An MCP server can no
longer grow the resource-template cache without bound, and a prefix allow
rule no longer matches a command that adds shell metacharacters after the
allowed prefix.
- On Windows, a session in Russian or another language written in a
non-Latin script no longer crashes the TUI with `start byte index N is not a
char boundary` when Codewhale checks a shell command before running it
(#7048). Thanks @8sero.
- Computer Use can be authorized in Full Access. Asking for an app grant was
refused before it ran, so the most permissive mode was the one mode where
Computer Use could never work. Ask and Full Access now show the approval
card; Auto-Review and Never still refuse, because nobody is there to answer
it. A grant still always needs your answer and is never approved
automatically.
- A plugin state file larger than 1 MiB no longer makes every plugin fail to
load. The limit is now 16 MiB, and the read stays bounded.
- The OrcaRouter model list now shows only models OrcaRouter serves over Chat
Completions, the protocol Codewhale uses with it. Models offered only through
another protocol, such as Gemini-only image models, no longer appear and fail
when chosen. OrcaRouter price estimates now include its long-prompt price
tiers instead of quoting every prompt at the base rate; a model whose tiers
cannot be read is shown without a price.
- The first `/pet on` in a new session no longer shows `Source changed;
review the current source before interacting`. The pet view acted on a frame
older than the source it had just selected and sent a second, stale
selection.
- Resuming a session after Codewhale was killed mid-turn no longer undoes a
rename or archive made while it was down, for example from the desktop app
or the Runtime API. The interrupted turn is still restored. A restored
session also no longer shows Codewhale's internal note about sub-agents
still running in the background as a message you typed.
- The `Web` tool now tells the model which JSONPath its `fields` option
accepts (`$`, `.field`, `[index]`, `[*]`, `['field']`, for example
`$.items[*].name`) and that recursive descent (`..`) and filters are not
supported, so it stops sending projections that fail. Thanks @zhuowp
(#7046).
- MCP servers are started, reconnected and stopped more carefully:
- Editing your MCP config, or changing a plugin's MCP servers, restarts
only the servers whose own entry changed. `/mcp reload` still restarts
all of them.
- `/mcp retry` no longer freezes the session while a slow server connects.
- A tool call that loses its stdio server stops the dead process before
reconnecting, so no second copy runs beside it. Sub-agents no longer
start or supervise the parent's servers a second time. A Streamable HTTP
server whose connection was cancelled reconnects.
- `list_mcp_resources`, the resource-template list and `/mcp validate`
(`/mcp doctor`) without a name report the servers already connected and
the failures already recorded, instead of connecting every configured
server.
- `/mcp login` is no longer offered when the server's authorization server
has no dynamic client registration and no `oauth.client_id` is set; the
row says to set `bearer_token_env_var` or `oauth.client_id` instead. A
token refresh no longer undoes a logout made in the meantime, and a token
rotated by another process is picked up.
- ACP sessions no longer start MCP servers they cannot use. With
`[features] mcp = false`, MCP tools are neither listed nor run. The
Runtime API's MCP management uses your `[network]` policy and OAuth
callback settings. `codewhale exec --resume` starts MCP servers once
instead of twice.
- `@git` and `@diff` mentions and the review Git-config check stop after 10
seconds instead of freezing the TUI on a stalled `git`. They say "git
command timed out" instead of "not a git repository", and one slow check no
longer leaves later reviews asking you to upgrade Git. On Wayland,
`wl-paste` and `wl-copy` get 2 seconds and are stopped if they hang, so a
stuck clipboard no longer freezes the interface. Refs #6561.
- The provider lists in first-run setup and `/provider` line up their status
column; before, each status started wherever the provider name ended.
Thanks @Lstarsky0 (#6984).
- Runtime API: each `pending_approvals[]` entry, and `approval.required` on the
authenticated thread surface, now carries the captured tool `input`. An
omitted `input` means nothing was captured; an explicit `null` is a
captured value.
- The WeChat bridge (`integrations/weixin-bridge`) now stays inside what
Tencent's ClawBot allows. A bot may reply only within 24 hours of your last
message and a handful of times per message, so the bridge sends at most 8
replies per message you send (`WEIXIN_MAX_SENDS_PER_MESSAGE`). A longer
answer ends with a "继续" prompt: reply 继续 for the rest. An answer that
finishes after the window waits for your next message. An expired WeChat
session (`errcode -14`) now pauses the bridge for an hour, as Tencent's own
client does, instead of retrying forever. A rejected or rate-limited reply
is held or backed off rather than resent every second. A reply that WeChat
accepts without a message ID is reported by `/status` as possibly filtered.
- WeChat approvals are now answered with a short code: reply `1 k7m2fz` to
allow or `2 k7m2fz` to deny. Codes are single-use, expire after 30 minutes,
and `/status` issues fresh ones; `/allow` and `/deny` still work. Questions
the agent asks now reach WeChat, and your next message answers them, by
option number or in words. A typing indicator shows while the agent
writes. Chinese command aliases (`/状态`, `/新对话`, `/停止`, …) and `/stop`
are available.
- The WeChat bridge now accepts only the WeChat account that scanned the
login QR code unless `WEIXIN_CHAT_ALLOWLIST` says otherwise. Other chats get
one refusal that names their user ID, where they used to be dropped
silently. A lock file stops two bridges from sharing one state directory,
and `dev-up.sh` no longer allows every user by default.
- Skill and plugin downloads and skills registry sync now check the first
request and every redirect. They refuse `localhost`, loopback, private,
link-local and cloud-metadata IP addresses and hosts the network policy
denies, refuse a redirect from HTTPS to HTTP, and stop after five
redirects. Without a proxy, Codewhale resolves each host itself, refuses
private answers and connects only to the address it checked. With
`HTTPS_PROXY` or `HTTP_PROXY` set (lowercase works too), these downloads
go through the proxy unless `NO_PROXY` matches the host; Codewhale then
leaves host-name checks to the proxy and checks only IP addresses written
in the URL. `ALL_PROXY` is not used. If your `[network]` default is deny,
allow `codeload.github.com` as well as `github.com` for GitHub skill and
plugin installs.
- `NO_PROXY` now accepts space-separated entries and `*` for MCP servers you
configure and for skill and plugin downloads, an empty `HTTPS_PROXY` no
longer hides `HTTP_PROXY`, and a `socks5://` or `socks4://` proxy is asked
to resolve host names itself instead of Codewhale resolving them locally.
- Local state no longer follows links planted inside a workspace or session
directory. The continual-harness lock file must not be a link, workspace
notes are appended without following links below the workspace, session
snapshots refuse a linked or multiply linked session file, and saving a
project Fleet profile checks existing project identities without
following a linked profile directory or file. New lane records and lane
logs are readable only by their owner.
- The command splitter behind the destructive-command checks treats a
backslash-escaped quote outside quotes as an ordinary character, as the
shell does.
- Outside Full Access, background and headless runs now stop for review
before a disk- or filesystem-destroying command placed inside a subshell
or a command substitution, including one inside a `sh -c` script.
- Read-only agents and Fleet workers can now reach the network. In Full
Access, `bash` with `read_only: true` allows outbound connections, so
`curl`, `git ls-remote` and HTTPS clients work, while all local file writes
stay blocked. `read_only` does not stop requests that change things on
remote services. Ask and Auto-Review keep the mode offline, as do a
`[network]` policy that defaults to deny and a role without the network
grant. On macOS it reaches internet hosts over IPv4 and a local proxy set
in `HTTP_PROXY`, `HTTPS_PROXY` or `ALL_PROXY`, but not IPv6 or any other
port on the Mac's own addresses. On Linux it shares the host network
namespace, including loopback and abstract unix sockets, like a networked
workspace-write shell. A networked run is marked `sandbox_network: true`
in its tool result, and `codewhale run sandbox run --policy read-only
--network` now honors `--network`. Refs #7040, #5904.
- Plugin suggestions no longer treat Codewhale's own vocabulary as a reason
to offer a plugin. A message about MCP servers stuck at connecting, or one
that mentions agents, code, data, models, sessions or tools, no longer
offers an unrelated vendor plugin; distinctive names, phrases and domains
still match. The first-party marketplace check rejects the same words as
manifest keywords. Refs #7036.
- When a route declares its own output limit in `[[custom_models]]`, on a
named custom (`openai-compatible`) route or a built-in provider such as
OpenRouter pointed at your own endpoint, `CODEWHALE_MAX_OUTPUT_TOKENS` can
now raise a request up to that limit instead of stopping at the bundled
limit for a model with the same name. Automatic requests keep their usual
size. Without a declared limit the bundled limit still applies, and on a
named custom route run receipts label it unverified rather than
documented. Refs #6396.
- When a route publishes its own reasoning levels, Codewhale no longer
refuses a level the route lists. It sends the level you chose, or the
nearest level the route publishes, on Chat Completions routes and on
named custom endpoints that use the Responses or Anthropic Messages
wire, including `/cache warmup`. When a level still cannot be sent, the
error names it and lists the levels the route publishes. Refs #6396.
- `codewhale resume` and `codewhale fork` now size a saved session the way
it is handed over: compact JSON, with the conversation counted once
instead of also as its derived message copy. A session that is over 8 MiB
on disk only because of that copy, indentation, abandoned branches or
finished shell operations opens again. A session whose current
conversation and Work state alone exceed 8 MiB is still refused before
anything is written: its file and archive are left unchanged and the
refusal gives the size it would hand over. Reading the history through the
Runtime API or the desktop app still applies the 8 MiB limit to the whole
document. Refs #6955. Thanks @7jrxt42BxFZo4iAnN4CX.
- Saved sessions and crash checkpoints are now written as compact JSON
instead of indented JSON. Files are smaller (16–27% on the two measured
sessions from the report), and a session that was over the 8 MiB resume
limit only because of indentation resumes again. Refs #6955. Thanks
@7jrxt42BxFZo4iAnN4CX.
- A `codewhale resume` or `codewhale fork` that is refused before it
reserves anything no longer tells you to recover it with an operation key.
Refs #6954.
- The input, output and context limits your Codewhale account states for a
model now apply to its requests. The desktop app and interactive sessions
take them from the account's model listing, and `codewhale exec`,
`codewhale review` and the workflow tool read that listing once before
their first request; if it cannot be read, the run continues with built-in
limits and says so on stderr.
- When a route states an output limit larger than half its context window,
as a server that shares one window between input and output does,
Codewhale compacts the conversation to keep a quarter of the window (at
most 64K tokens, and never more than the route's request cap) free for the
reply, instead of reserving the whole request cap, which on a small window
left about a thousand tokens for the conversation. A request is still
admitted while at least 128 tokens of output fit, so Codewhale's own
instructions and tools can fill more of a small window when there is
nothing to compact. Every request on such a route asks for no more output
than the window has left after its input, up to the route's usual request
cap, so a long prompt gets a shorter reply allowance instead of
overflowing the window. When too little is left, nothing is sent: a turn
compacts or stops with the usual context message, a compaction summary
leaves out its oldest history until at least half the reserved allowance
fits, and any other request fails with a context-length error. Other
routes are unchanged.
- Once a session file passes 8 MiB, autosave moves all of its abandoned
branch history to the session's journal archive, instead of keeping up to
4,096 off-branch entries in the document. `/branch` can still restore
archived entries. Refs #6842. Thanks @7jrxt42BxFZo4iAnN4CX.
- When a tool result is longer than the share of the context window one
result may take, the model sees its head and tail and is told to read the
rest with `retrieve_tool_result`. That tool is now offered whenever a
result names a saved copy, and `codewhale exec --allowed-tools` no longer
filters it out. A model on a small window, where most tool output is cut,
is no longer told to recover output through a tool it does not have.
- A window that cannot save its queued messages because it holds no queue
lease for the current session now logs both session ids, and failed
session, checkpoint and queue writes log the raw OS error code. Refs
#6978. Thanks @SergiuSSoluS.
- When the Linux sandbox cannot be set up (a bubblewrap mount error), the
shell result says the command did not run, quotes the bubblewrap error and
gives the ways forward, instead of the generic escalation hint. Nothing
runs outside the sandbox, and each sandboxed call still fails while the
cause remains. Refs #7007. Thanks @rafacouto.
- Auto-Review stops a turn after three guardian denials in a row, or ten of
the turn's last fifty reviews, and the status line says why; the remaining
calls in that batch are refused without another review. Timeouts and
failed reviews do not count. Refs #6478.
- Runtime API: `POST /v1/threads/{id}/read` records the newest item a client
has shown, and `GET /v1/threads/summary` now reports `last_read_item_id`
and `unread` for each conversation. Marking a conversation read does not
change `updated_at` or list order, and a marker never moves backwards.
Refs #6164.
- On Linux, a Runtime owner record from before the last reboot no longer
blocks recovery when its process id has been reused.
- The HarmonyOS guide now says the Linux ARM64 release runs inside the
HarmonyOS PC Linux subsystem, an openEuler virtual machine, and lists
Huawei's documented limits for it. It no longer describes a
"glibc-compatible userspace", and native HarmonyOS stays on the source
build. Refs #1072. Thanks @SakuraNeko.
- On native HarmonyOS, npm still installs the Linux build as a best effort.
If it cannot start, Codewhale prints directions to use the Linux subsystem
or build from source. The install script also warns that the build is
untested there; npm 7 and later show that warning only with
`--foreground-scripts`. Refs #1072.
- Fetching a page that builds its content with JavaScript no longer ends in
a "no readable page content" error when the page has a title or
description. `Web` fetch and `web.run` return those, marked `partial`,
with a note that says why and what to try next. When a Playwright,
Puppeteer, Chrome DevTools or Computer Use browser tool is connected, the
note names it so the agent can render the page there. Refs #7038.
- Web search through a model provider's own search tool now checks each
cited link before returning it, so Codewhale contacts the cited sites
directly. The check uses the same protections and `[network]` policy as
`Web` fetch, runs at most four checks at a time for five seconds each, and
never requests a link that repeats your search query. Links that do not
load are dropped and listed in the search receipt. The provider's written
answer moves to a separate `unverified_synthesis` field, and the result
says how many of the requested sources passed. When none pass, or when
you ask for recent results only, the search falls back to your configured
search provider. A cited site your `[network]` policy denies is dropped;
one the policy would ask you about stays in the results, marked as not
checked, until you allow its host. A backend that returns fewer results than
asked is reported as a shortfall instead of an honored result cap, and a
cited page the provider left untitled is named by its path or host rather
than shown as a bare domain. Refs #7039.
- Searching for tools no longer unloads tools the agent is using. When the
deferred toolbox is full, `tool_search` makes room from tools that were
never called, then the least recently called, and keeps any tool called in
the current or previous turn. Matches that do not fit, and tools it
removes, come back with the exact `tool_search` input that loads them
again. Refs #6969.
- Rendered markdown keeps nested list indentation, a to-do row keeps its
status word when its title is long, and the approval footer's separators
sit between its hints. Thanks @Lstarsky0 (#7030, #7033, #7034).
- Fleet tasks can choose an execution environment by declared data,
capabilities, capacity, persistence and cost, with a preview explaining
each decision (experimental). Configured Tailscale workers use a pinned
node identity; placement and transport receipts preserve the selected
environment and attempt. Declared resources do not reserve capacity.
- A runnable WhaleNet example uses real DeepSeek tasks, Python and a
TypeScript MCP server to create a bounded analysis capability and reuse
it in a fresh task after the first worker exits. The example records
usage, process lifecycles, content hashes and a one-hour capability lease.
- ACP session history uses shared message recognition without depending on
terminal rendering. Malformed archived-context text stays visible instead
of panicking during history restoration.
- Linux and OpenHarmony credential storage can traverse directories that allow
access without directory listing. The private credential directory still
requires current-user ownership and protected permissions; symlinks remain
refused. Filesystem-root errors now include the OS cause.
- Each file read and search keeps its own details when activity is grouped.
Expanding the group and opening a selected item shows that call’s input and
output instead of an arbitrary sibling’s.
- Local Skills setup creates its example in the project folder Codewhale
discovers, and its setup and doctor output explain the workspace trust
requirement. Skills help now points to the searchable Skills view and
distinguishes it from management.
- Stopped shell jobs read as stopped instead of failed. Their detail view stays
available after completion, a missing terminal exit code reads as unavailable,
and delegated jobs identify their named agent. Refs #6931.
- `model list` respects the selected route's catalog instead of adding unrelated
bundled models. `app/models` reads the captured Runtime's current catalog,
including named custom routes, regional routes, limits and capability facts.
Model listing remains available during a running task and reports an
unavailable owner instead of returning a stale static list. Refs #6396.
- The model picker distinguishes stale catalogs and stale, unverified or
unavailable pricing instead of calling them live or priced. Unknown
reasoning support stays unknown, and unusable rates do not drive price sorting.
- Automatic Rust formatting no longer inherits Engine or provider credentials.
The formatter keeps its normal toolchain and project configuration.
- If an exec session cannot be saved, text, JSON and streaming JSON now
report the failure and exit unsuccessfully. The answer remains in the output,
and the lifecycle receipt also records failure. This is not a retryable
provider error: actions may already have completed.
- Unrelated or malformed requests to the local OAuth callback no longer abort
sign-in. The listener keeps waiting within the original deadline; state and
issuer checks still apply, and an authenticated provider denial still ends
the attempt.
- Automatic goal turns no longer start with an obsolete objective when the
goal is paused, completed, cleared or replaced while the turn is preparing.
- Updated certificate validation, MCP, and web dependencies to address
dependency security advisories.
- Shell cards in the default view drop their `output:` and `time:` labels.
Output rows follow without a label, and a command that ran for a second or
more shows its duration after its status. Hidden output reads
`… (+27 lines) · Alt+V:output`, translated, instead of `27 lines omitted`.
A thought shorter than a second reads `Thought`. A notice that mentions
"cycle" is no longer drawn as a bold divider.
- A shell card in the default view leads with the model's description, as
written, and shows the command on its own `$` row underneath, in every state
and at every width. A card without a description leads with its `$`
command. A finished, successful command shows only `✓` (ASCII `Y`), without
`done`; running, waiting for approval, queued, failed and "loaded, not run"
keep their word, and a narrow terminal shortens the headline before the
status. A failed card shows its whole command, up to six rows. The `▶ run`
marker, the `note:` label and the `╭ │ ╰` rail shared by neighbouring tool
cards are gone in this view; card rows are indented under their headline
instead. `docs/ACCESSIBILITY.md` now says that every status carries a glyph
and every state except this one also carries a word. With
`show_tool_details = true` and `calm_mode = false` the labeled card is
unchanged.
- ACP editors loading a saved session now receive its earlier messages and tool
results instead of an empty conversation. Sessions saved by `codewhale exec`
can also resume through ACP and the Runtime API. Saved reasoning and images
are not replayed to the ACP editor.
- Replayed ACP tool results and Runtime receipts created from saved history
now use the live receipt masking rules: private question answers become
`User input submitted`, and configured credentials are redacted. This also
covers history import, fork and rewind. Saved model history and the owner's
session-export view keep their existing behavior.
- `serve --acp` refuses a second ACP owner in the same Codewhale home while
still allowing an editor to attach to the desktop or HTTP Runtime. If that
Runtime exits, the ACP guest exits with a recovery message instead of waiting
for another line from the editor. An unsupported `approval_policy = "never"`
is refused at startup, before it can fail every new session.
- A web fetch stopped at `max_bytes` returns the readable text received so far,
marked as truncated. If the cap arrives before readable text, the error names
the cap and the available recovery instead of making a second request and
misdiagnosing the page as JavaScript-only. Complete pages retain their normal
extraction rules.
- Windows state-file publication allows a longer retry window for transient
sharing, locking and access-denied errors, reducing failures when another
process briefly holds the destination. Permanent errors are still reported;
the retry window is now about 1.27 seconds.
- `codewhale doctor --help` lists the doctor's actual options. Account and
dispatch help no longer promise unavailable account-key storage or cloud
execution. `codewhale review` rejects `--post` and `--repo` with local-diff
options before loading credentials or contacting a model.
- `/model` reuses provider catalog data and route-readiness results instead of
rebuilding them for every row. Its Auto hint no longer constructs the full
model inventory. Thanks @SparkofSpike (#7026).
- `/feedback` marks shortened descriptions, including with `...` in ASCII-safe
mode; `/statusline` shows a scroll rail when its list does not fit and then
drops its padding rows, so a short terminal shows more items; and wide
`/keys` layouts leave descriptions in the detail pane instead of repeating
clipped fragments beside it. Thanks @Lstarsky0 (#7025, #7027, #7028, #7029).
- DeepInfra lists newer DeepSeek model IDs alongside its existing defaults.
The defaults remain unchanged pending a live route check, and the new
selections do not reserve bare model names that other providers accept.
- `/undo` takes back the latest request and its file changes without requiring
trust mode, while refusing ambiguous snapshot matches. Trailing whitespace
in a prompt label no longer prevents a match, and an empty first line in
another request no longer blocks the whole conversation.
- `exec --auto` help and documentation now state its default Full Access:
automatic tool approvals, no Codewhale shell sandbox, and trust mode on.
Selecting any sandbox other than `danger-full-access`, by flag or config,
keeps trust mode off. This includes `external-sandbox`, which relies on
host-managed isolation and no longer grants file tools trust-mode access.
Stream metadata reports whether the requested sandbox is actually enforced.
- Exec flags go before the prompt. A known long flag or `--flag=value` after
the prompt now produces an error instead of silently becoming prompt text;
use `--` for literal flag text or a prompt starting with `-`.
- Exec runs that offer tools save sessions in every output format. Exec and
interactive sessions each keep their own retention allowance, so CI runs
cannot archive interactive conversations. Live and saved receipts include
retained terminal failures, and conversation rewinds discard outcomes from
removed turns so they cannot be attributed to later requests.
- Onboarding lists Ollama, LM Studio, and vLLM even before a local runtime is
detected, so they can be selected and configured. The `L` filter is available
during onboarding after local-runtime detection.
- `/fork <id>` now shows the forked conversation. Before, the screen kept
the previous conversation while the model already had the fork's history.
- With `/translate` on, each translated thinking block lands in its own
cell. Before, two translations finishing out of order could swap them.
- Pasting text that contains an escape sequence written out, such as
`print("\x1b[?25l")`, keeps it as pasted. Before, part of it was removed
from the message box as if it were a stray mouse report.
- A question that appears while you are typing no longer takes an Enter you
pressed for your message as its answer.
- `/new` and `/clear` start without the previous conversation's goal.
Before, a paused goal followed you into the new conversation, where
`/goal resume` picked it up again. The old session keeps its saved goal.
- After `/edit`, sending the revision with Ctrl+Enter replaces the earlier
message as Enter does. Before, it was appended instead, and the next
message then undid the wrong exchange.
- In `/resume`, pressing `d` and then scrolling with the mouse before
answering `y` could delete the session you scrolled to instead of the one
you chose. The prompt now ignores the mouse, and `y` deletes only the
session `d` was pressed on.
- Typing a stop word (`stop`, `wait`, `pause` by default) while a turn is
running cancels it at once. Before, Enter queued the word behind the turn
it was meant to stop.
- Runtime API fixes:
- `POST /v1/threads/{id}/undo` accepts `{"turn_id": "turn_…"}` to
remove that user turn and everything after it. A client that edits a
message can name it, instead of counting messages back, so a turn
another client appends meanwhile can no longer make it edit the wrong
message.
- Goal events on a thread's event stream now follow the order the goal
changed in. A set and a clear racing each other could leave the stream
reporting an active goal after it was deleted.
- `PUT /v1/sessions` for a thread with a queued or running turn now
answers 409. Before, it waited for that turn to finish while blocking
new turns, steering and compaction on every thread.
- `PATCH /v1/threads/{id}` with a new `system_prompt` now takes effect
on the next turn. Before, a thread whose engine was already loaded kept
the old prompt. The change is refused while a turn is running.
- `POST /v1/threads/{id}/retry` with a blank prompt now answers 400
without first creating a fork.
- Connecting a remote computer stops reading the probe response at
64 KiB instead of buffering all of it first.
- The computer event cursor can no longer move past an event that has
not been published yet.
- `POST /v1/stream` ends when the turn's own record fails to save,
instead of sending keepalives forever.
- `web_search` can use DeepSeek's new Search API: set
`[search] provider = "deepseek"` and give it your DeepSeek key through
`[search] api_key` or `DEEPSEEK_API_KEY`. It returns raw results without
a model round trip. DeepSeek bills $0.75 per 1,000 searches from
November 1, 2026.
- In the desktop and web apps, a conversation stays compacted after
Codewhale restarts or unloads it. Before, reloading replayed every earlier
turn and then added the summary, so the next request carried everything
compaction had removed. Each compacting turn now stores the history the
model continued from, and forks, `/undo` and session exports start from
it as well.
- When a provider stream fails before any content and Codewhale quietly
resends the request, the tokens the failed attempt reported are now added
to the session, goal and sub-agent totals instead of being merged away.
The context meter still reflects only the request that succeeded.
- Esc, or a Runtime interrupt, now stops a `tool_call_before` hook that is
still running: its process tree is killed and reaped, hooks queued behind
it are skipped, and the turn stops at once. Before, the turn waited for the
hook to finish, and the hook could still change files after the turn was
reported as stopped.
- With a sub-agent open in the main pane, scrolling and redraws reuse its
rendered transcript instead of re-rendering every message on every frame,
and a finished sub-agent's transcript file is no longer reread from disk
every 400 ms.
- While a slash command is in the composer, the TUI rereads your command
folders and `config.toml` at most once a second instead of on every frame.
A command file you add still shows up in completion within about a second.
- In a session long enough to fold its oldest transcript cells (past
5,000), tool details, expanded tool runs, sub-agent cards and a streaming
reply keep pointing at the right rows. Each fold had shifted them one row
too far, so the inspector opened the previous cell's details.
- A sub-agent started with the parent's context that ends without writing
anything no longer reports the parent's last message as its own result.
- When one reply carries several text blocks, as the Responses route sends
for separate message items, the conversation now keeps all of them. Before,
each new block replaced the previous one in the history sent back to the
model, so it forgot what it had just said even though you saw it. Text a
provider puts in a block's opening event is also shown now.
- `codewhale serve --insecure` and `codewhale app-server --insecure-no-auth`
answer only requests addressed to `127.0.0.1`, `::1` or `localhost`.
Without auth, a website could point its own domain at 127.0.0.1 (DNS
rebinding) and drive the Runtime API from your browser; such requests now
get `421 Misdirected Request`. Servers with auth are unchanged.
- Sandboxed commands can no longer reach Codewhale's Runtime daemon socket.
On Linux with bubblewrap, and on macOS with sandbox network access on, a
command the agent ran (a test script or a postinstall hook, say) could read
the owner receipt and attach to the socket that `codewhale serve`, the
desktop app, the VS Code extension or an ACP session holds. From there it
could change the sandbox mode, the approval policy or a provider's base URL
in your config, or start an unsandboxed turn. The daemon's default run
directories are now on the sandbox's default deny-list, and on macOS no
socket under a denied path can be connected to. Turning the default
deny-list off (`sandbox_read_denylist_defaults = false`) also turns this
off.
- `codewhale web` no longer gives its request proof to whoever holds the
session cookie. The cookie is scoped to the host, not the port, so a
listener on another `127.0.0.1` port could receive it, and `GET /` then
returned the proof that unlocks the whole Runtime API. The proof now stays
in the tab that opened the session, which keeps working across reloads
when the browser allows session storage; a new tab opened by typing the
address needs a fresh `codewhale web`.
- The `codewhale web` approval card shows the request summary, Codewhale's
reason for asking (such as a sandbox escalation) and every argument of the
call in full, with the model's own description below, labeled as such.
Before, when the model had written anything, the card showed only that
text and never the command, so a prompt-injected model could describe a
harmful command as a harmless one.
- `/settings` choice lists that don't fit, such as Language and Theme, show
a scroll rail. Thanks @Lstarsky0 (#7024).
- During an `/mcp` search that finds nothing, the status line says "No
matches" like the list does, instead of "Nothing on this tab". Thanks
@Lstarsky0 (#7023).
- Read and list cards show a path inside the workspace relative to it
("Reading src/lib.rs") instead of the full absolute path the model sent.
- `/statusline` shows its last two items, Workspace and Git branch, without
scrolling. The picker had not counted its padding rows. Thanks @Lstarsky0
(#7022).
- A shell or gate command that the safety check will refuse, such as one
spanning several lines, is refused at once instead of first asking you to
approve it.
- Diffs in the TUI number each line only on its own side: a removed line
shows its old line number and an added line its new one. Unchanged
context lines keep their indentation instead of starting at the left
edge.
- A shell card shows a multiline command one line per row instead of running
the lines together.
- A shell card whose command is waiting on your approval now says
"waiting for approval" with a still mark, instead of "running (Ns)" with
a spinner. A command queued behind it in the same step says "queued".
Elapsed time starts when a command actually begins to run.
- `/color` gives a chat's composer box its own color. Bare `/color` cycles
through red, orange, amber, green, cyan, blue, purple and pink; `/color
<name>` picks one and `/color off` returns to the theme. The color is
saved with that session and survives resume; other chats and the theme are
untouched. It shows while you are typing, so the focus signal stays.
- Importing a session container or starting a new chat from the launch
screen no longer carries the previous chat's `/title` onto the new one.
- Shell cards in the TUI:
- A tool card that finished inside a turn that is still running opens its
raw detail (tool id, input, output) with Alt-V or a click, instead of a
rendered message view.
- The work dock no longer shows a ✓ for a background job that was killed
or timed out. Killed jobs get a neutral mark; timed-out jobs get the
failure mark.
- The keybinding docs now say what Alt-V opens with nothing selected, and
that clicking a card keeps Alt-V on it while newer cards arrive.
- The TUI uses less CPU while it waits. With an approval, elevation or
question prompt open, or with only background shells still running after a
turn, the status spinner and elapsed-time labels refresh once a second
instead of five times a second.
- On Windows, Codewhale processes that start at the same moment no longer
lose the built-in plugins. The rename that publishes the built-in plugin
snapshot now retries a brief sharing or access refusal, as the other atomic
writers already did, instead of starting without built-in plugins.
- Six fixes from @asto18089, several ported from the Pinvou/CodeWhale fork
with @zhuowp:
- Claude 5 models and Haiku 5.5 no longer receive `temperature`/`top_p` on
routes without exact catalog facts (custom or proxy base URLs, dated
snapshot ids, Messages-wire gateways), which those models reject with a
400 (#7014).
- Kimi keeps a tool whose schema has an empty `items`: the empty node is
dropped, as Moonshot's schema rules allow, instead of excluding the whole
tool (#7015).
- In a session that already has a stamped compaction checkpoint, a user turn
that pastes a legacy summary header stays an ordinary turn: it anchors the
round, is kept verbatim and no longer counts as a duplicated summary
(#7017).
- Turn-complete events carry their own `turn_id`, `submission_id` and
`compaction_id`. A send whose route fails to install, and a manual
compaction whose route is rejected, now end with a failed terminal event
instead of only an error, so waiting hosts no longer hang (#7018).
- Anthropic `redacted_thinking` blocks are captured and replayed byte-exact
on native Anthropic routes, so a tool loop after a redacted block no
longer fails with the same 400 on every retry. Other hosts withhold the
block (#7019).
- A named `[providers.<name>]` table with `wire = "responses"` or
`"anthropic"` now uses that wire on every turn and across model switches,
not only for the first request. The app-server's legacy
`[providers.custom]` table now refuses a non-Chat wire with
`provider_wire_format_unsupported` instead of forwarding a Chat body
(#7020; Refs #6997).
- A background shell job that finishes while the agent is still working now
reaches the model before its next step, instead of only when the turn ends.
In `codewhale exec`, which stops at the end of the turn, that output used to
be lost. The background notice now says that a job still running when the
turn ends is stopped unseen in a headless run, so the model knows to wait
explicitly when its answer depends on it. Sub-agents no longer pick up the
parent's finished jobs, and the parent no longer consumes a sub-agent's.
- `codewhale review --base <ref>` gives the reviewer the `base..HEAD` commit
messages as the author's stated intent, in a field of their own that it
checks against the diff and reports on when the two disagree. They are
treated as claims, not instructions, and capped at 8,000 characters.
- `codewhale --resume <id>` after the TUI was killed mid-turn keeps the
interrupted turn. Before, the resume stamped the older saved document as
newer than the crash checkpoint, and the checkpoint, the only copy of
that turn, was then discarded as stale. `--continue` was not affected.
- Three session data-loss paths are closed:
- `/load` of an older exported copy of a session no longer replaces the
newer saved conversation with the same id. It refuses and points to
`/resume`. Before, the next autosave deleted every turn made after the
export.
- A journal archive append that was cut short (disk full, or a kill)
is trimmed back to its last complete line before the next append.
Before, the next save glued new entries onto the torn line. That made
the whole archive unreadable, and the document had already dropped
those entries.
- Launching with a legacy crash checkpoint keeps it when migrating it to
the per-session format fails, instead of deleting it.
- Sub-agents stay within a turn's tool allow-list. `exec --allowed-tools`, a
Runtime API `allowed_tools`, and a command's `allowed-tools:` frontmatter
narrowed only the parent. A sub-agent it started got the full tool
surface, including `bash`, `write` and `edit`.
- A `workflow` plan written with `nodes` (the declarative shape in
`docs/WORKFLOW_AUTHORING.md`) is now judged for approval from its compiled
plan, the same one the run uses. The old reader missed fields nested inside
`agent` and `branch` nodes. A plan with write children could then start
with no approval card, the card could say "Read-only plan", and the
receipt recorded the run as approved.
- The other whole-file writers now refuse to replace an existing file that
is unread or stale, as `write` does: `apply_patch` with `replace`, and the
`write_file` and `File action=write` paths that older prompts still call.
A successful patch counts as a read, so patch-then-write still works.
`fim_edit` honors the read deny-list. It also refuses to write when the
file changed while its completion was running, which used to overwrite
your edit.
- `grep_files` (also `File search_content`) aimed at a single file, `rlm`
`open` with `file_path`, and the cache-maximal working set now honor the
read deny-list. Each read files such as `.env` past the check and returned
their lines to the model. A deny-listed working-set file is skipped with a
note.
- A `tool_call_before` hook that answers `ask` now always shows the approval
prompt, as `docs/HOOKS.md` promises. Before, an earlier "approve for
session" or a conversation grant for the same command answered it
silently, so a hook could not re-gate a command the person had already
approved once.
- `validate_data`, `review` and `verify` honor the read deny-list, as `read`
does. They read files such as a workspace `.env`, or in trust mode
`~/.aws/credentials`, without the check. `validate_data`'s TOML parse
error could quote a line of such a file back to the model, and `review`
and `verify` sent the whole file to the provider.
- Commands that start outside the shell tool now get the same sandbox as
shell commands:
- `terminal_*` PTY sessions used a default sandbox with no credential
deny-list, so on macOS they could read `~/.ssh` or `~/.aws` while `bash`
could not. On Linux they skipped bubblewrap, so workspace-write refused
them. They now use the session's shell sandbox, and they refuse to start
when commands run in an external sandbox backend.
- Runtime API thread jobs (`POST /v1/threads/{id}/jobs`) started before the
thread's first turn ran without bubblewrap and without the deny-list.
They now get both, and they are refused when an external sandbox backend
is configured, since a job starts a local process.
- `codewhale run sandbox run` ignored `prefer_bwrap` and the deny-list.
When no OS sandbox could enforce the policy, it ran the command
unconfined. It now refuses.
- On Windows, `bash` with `interactive: true` skipped the read-only check
that every other command path applies. It is now refused like the
others.
- A sub-agent's posture line could say the local OS sandbox applied when
its shell did not use one. It now reports what that shell actually
uses.
- `write` refuses to replace an existing file that has not been read in this
session, or that changed after it was read. The File `edit` action already
made this check. Before, a whole-file write could overwrite contents the
model never saw, or a change you or another agent made after the model's
last read. Creating a new file is unchanged, and a file Codewhale wrote
itself counts as read. The refusal names the recovery: read the file, then
write again.
- `codewhale exec` warns again when the sandbox posture asks for confinement
but no OS sandbox can enforce it, for example on a Linux host or container
where bubblewrap cannot start. With no external sandbox backend configured,
which is the default, the check read the absent backend as present, so the
warning never printed and commands ran unrestricted with no notice on
stderr. Found while proving the #7007 fix end to end in a container.
- The middle working mode is called Work everywhere in the TUI: the footer
chip, the mode name and description, the hotbar action, settings errors,
`/context` and exports, and the matching locale strings, which now use each
language pack's existing word for it. The hook contract is unchanged:
`DEEPSEEK_MODE` and `DEEPSEEK_PREVIOUS_MODE` still report `ACT`, and saved
settings still read and write `agent` (Refs #6466). The `/statusline` Mode
hint says Work too. Thanks @Lstarsky0 (#7012).
- The model catalog now carries current models from Anthropic, Google and
Meta. Anthropic: `claude-opus-5-5`, `claude-sonnet-5-5`, `claude-haiku-5-5`
and `claude-fable-5-1`; the Auto router's cheap tier and the Scout companion
stay on `claude-haiku-4-5`. The `anthropic` default moves to `claude-sonnet-5-5`, and no default
uses `claude-sonnet-4-5`, which retires on 2026-11-30. OpenAI's GPT-6
family (`gpt-6-sol`, `gpt-6.1-sol`, `gpt-6-luna` and `gpt-6-astra`) is left
out of the direct route because OpenAI does not support normal tool calling
for them over Chat Completions. Google: `gemini-4-argon` and
`gemini-3.8-flash`. Z.ai: `GLM-5.3-FlashX` is not offered because the
Coding Plan endpoint the zai route defaults to does not serve it. Meta:
`muse-spark-1.3`, `muse-spark-1.3-contributor` and the `muse-wonder-1.0`
preview join the route, which stays on its previous `muse-spark-1.2`
default.
Several ids are retired. Xiaomi MiMo now defaults to `mimo-v2.6-pro`, and
configs naming `mimo-v2.5-pro` or `mimo-v2.5` send `mimo-v2.6-pro` and
`mimo-v2.6-flash`, because Xiaomi rejects the old names from 2026-10-21.
A `[vision_model]` that names either old id gets the same mapping.
`gemini-3.7-flash` and `gemini-3.5-flash`, which Google already serves as
`gemini-3.8-flash` and `gemini-3.6-flash`, are now selector aliases of those
models. `qwen3.8-max-preview` is gone from the Model Studio rosters. MiniMax
M2.7 and M2.5 (including highspeed) leave the fallback picker before
MiniMax closes them to new users on 2026-10-19, and keep working for
existing configs until they retire on 2026-11-18.
- Direct DeepSeek routes now send `deepseek-flash` for `deepseek-chat`,
`deepseek-reasoner`, the `flash`, `deepseek-v4flash`, `flash-vision` and
`deepseek-v4flashvisionexp` shorthands, and the Auto router's fast tier.
`codewhale model set` and `/provider` now write `deepseek-flash` for those
shorthands too, matching what `model = "flash"` and `/model flash` resolve
to.
DeepSeek has retired the V4 Flash and V4 Flash vision models. It still
accepts `deepseek-v4-flash` and `deepseek-v4-flash-vision-exp`, but serves
them with V4.1 Flash, bills them at the Flash price, and calls that routing
temporary. Turns on either name from 2026-09-10 04:00 UTC are now priced at
the Flash rates ($0.003 cache hit, $0.15 cache miss, $0.60 output per
million tokens off-peak, doubled at peak) instead of the old V4 Flash rates,
which overstated a cache hit by about 2.3 times. The vision name was not
priced at all before. Earlier turns keep the rates they were billed at,
including turns recorded under a shorthand. On NVIDIA NIM, OpenRouter,
Novita, Fireworks, SiliconFlow, SGLang, vLLM, DeepInfra and Together,
`deepseek-flash` selects that host's V4 Flash model, so the `flash`
shorthand keeps working there. On OpenCode Go, `deepseek-flash` and the
`flash` shorthand select Go's `deepseek-v4.1-flash`; until this fix,
`/provider opencode-go flash` was rejected as an invalid model.
- When `$SHELL` is zsh, the `bash` tool now runs commands with zsh's NOMATCH
and EQUALS options off. Common Bash idioms such as `grep --include=*.rs`
and `[ "$a" == "$b" ]` now run instead of failing with `no matches found`
or `= not found`. In 310 local DeepSeek sessions, 334 commands had failed
this way, which silently dropped searches the model believed it had run.
- `task_shell_wait` is now in the first-turn toolbox. A `bash` command that
moves to the background now tells the model to call it directly. Before,
every long build or test cost a `tool_search` round trip and a tool-catalog
re-pin, and models often polled with `sleep` instead.
- `codewhale exec` receipts no longer report an empty final answer when a
background shell finished after the model answered. This happened in 52
of 185 DeepSeek exec runs, and a fleet worker then recorded no answer.
- A reasoning-only response cut off at the output limit is no longer re-sent
up to two more times on Responses routes such as `deepseek-flash`. It now
fails with the output-limit message. The engine's own check missed the
`incomplete:` prefix that the Responses parser adds.
- `tool_choice: "none"` now reaches the provider on Responses routes and on
DeepSeek Chat routes with thinking on. Compaction and final-report
requests rely on it; DeepSeek documents it as valid in thinking mode.
`required` and named choices are still not sent while DeepSeek is
thinking, because that returns a 400.
- A DeepSeek Chat response that ends with `insufficient_system_resource` or
`aborted` is now treated as incomplete, not as a finished answer.
- On DeepSeek, the Auto-Review guardian now asks for low reasoning effort.
It used to leave thinking at DeepSeek's default (high), so the reasoning
could use up the guardian's 4,096-token answer budget, report the review
as unavailable, and stall auto-approval.
- Durability and blocking-call fixes from the #6553 and #6555 audits:
- On Windows the updater syncs the staged binary, tries an atomic replace
first, and reports where the previous binary is if restoring it fails.
- Config writes sync the temp file before the rename.
- The task store, Fleet run and receipt reads, and session listing now
run off the async runtime.
- Worktree names that are empty, start with `-`, or contain `..`, `\` or
control characters are refused. `git worktree add` gets a `--`
separator before the path.
- The boot snapshot prune repairs a HEAD that names a missing commit
before pruning, instead of logging "bad object HEAD" (Refs #6978).
- Typing into a terminal dock that has no sessions no longer shows the
"reset or lost" error. Thanks @Lstarsky0 (#7010).
- The `/mcp` Extensions panel's detail pane grows to fit its wrapped text,
up to a third of the panel, so names, descriptions and details are no
longer cut off at 80×24. Thanks @Lstarsky0 (#7011).
- When a `tool_search` activation pushes an earlier deferred tool out of the
bounded conversation toolbox (8 tools, 16 KiB of schemas), the search
result now names it under `evicted_tool_references`. Before, the tool
silently disappeared from the next request, and a model could go on
calling it. A tool called in the current or previous turn is never
evicted, so the toolbox can briefly hold more than that. Thanks @asto18089 for the cost and correctness analysis
(Refs #6969).
- An ACP client that asks how to turn on Full Access is now told the
routes that work: start the server with `codewhale --yolo serve --acp`,
or set `yolo = true` in config.toml. The hint used to recommend
`--approval-policy full-access` or `approval_policy = "full-access"` in
config.toml. Both are refused when Codewhale starts, because config.toml's
`approval_policy` only accepts on-request, untrusted, never, auto and
suggest. Thanks @harryvizcaino-oss for the Paseo report (Refs #6992).
- On Linux, a credential directory the sandbox hides no longer breaks every
sandboxed command when it is reached through a symlink, such as `~/.kube`
linked into a synced dotfiles folder or a `~/.config` that links
elsewhere. Each command used to abort before running with a bubblewrap
mount error ("Can't mount on symlink destination"), because the mask was
placed on the link. The mask now goes on the directory the link resolves
to, so the credentials stay hidden through the link. Thanks @rafacouto for
the report and the standalone bubblewrap reproduction (Refs #7007).
- `/help` keeps its head-noun shortening to English. In German and
Indonesian it had kept the first and last words of a long description,
which can say something else (`Periksa penyedia aktif` instead of
`Periksa saldo akun`). Other languages now shorten to whole words from the
start. Thanks @Lstarsky0 (#6995).
- `/theme` right-aligns its row numbers, so names, swatches and taglines in
rows 10 and later line up with rows 1–9. Thanks @Lstarsky0 (#6998).
- `GET /v1/settings/schema` accepts `?locale=<tag>` and resolves row labels,
descriptions and option labels in that locale, with the configured
`locale` as the default. The desktop sends the interface language it
shows, so a desktop opened from the Finder or the Dock on a Chinese
system, which has no `LANG`, no longer lists its Settings rows in English
under Chinese headings.
- `codewhale --continue` reopens a session whose terminal was closed or
killed mid-turn. It used to print "Recovered interrupted session" and then
exit with "session … is open in an interactive Codewhale session": the
recovery had registered the session as this process's own live session,
and the resume step that follows refused it. Recovery now holds the
session's lease only while it promotes the checkpoint, as `--resume <id>`
does.
- Queued messages restored from an earlier launch or another session are no
longer sent automatically. They wait in the queue until `/queue send <n>`
sends one or `/queue clear` discards them. The restore notice says so and
is now also written to the transcript, because the "Resumed session" status
used to hide it. Messages queued in the current session still send in order after each turn,
ahead of the held ones. Before, restored messages went out one by one after
your next message. On a machine where the queue file could not be cleared,
that re-sent the same old messages at every launch (#6978). Editing a held
message with ↑ and cancelling the edit puts it back as an ordinary queued
message. A failed queue write is logged with the OS error and session id.
Thanks @SergiuSSoluS for reporting the re-delivered turns (#6978).
- A long session whose history holds more images than its model accepts in
one request no longer becomes permanently unsendable. When a provider
refuses the number of images (for example vLLM's "At most 3 image(s) may
be provided in one prompt", "too many images" or "maximum number of
images"), Codewhale learns that limit for the provider and model (the
number the provider states, otherwise half the images sent) and resends
with only the newest images attached. Each older image is replaced by a
fixed note telling the model it remains in the session and not to guess
what it showed; a tool image's note says to take a fresh observation, such
as a new screenshot, rather than repeat the action. Each resend carries
strictly fewer images, there are at most three per turn and never an
unchanged one; after that the turn ends with an `image_count_exceeded`
error and the next message uses the learned limit. A stated limit of 0
sends images as text, as for a model without image input. Before, a count
rejection either ended every later turn the same way or was misread as
"no image input" and stripped every image. The window moves in steps of a
quarter of the limit, so the cached history prefix changes only once every
few new images. Each change is recorded as a `request_image_window` event
(runtime threads store it as a status item with that code, `exec
--output-format stream-json` prints it and the TUI shows it), and
`/preview-request` and the compaction summary request apply the same
window. A summary request refused for its image count teaches the limit
too, and the context recovery that sent it retries under that limit. A
sub-agent no longer retries a count rejection as a transient
failure. Known limits: nothing changes until a provider has refused once,
and no documented per-model limits are applied; the learned limit is kept
in memory per engine and per sub-agent, so a restart learns it again with
one refused request; the oldest images go first, user attachments
included; a refusal that arrives mid-stream ends that request and only the
next send uses the limit; a gateway that reports the refusal as a 5xx is
retried unchanged by the transport first; a request-body size (HTTP
413) refusal on an ordinary turn still has no recovery; and the context
budget estimate still counts every stored image, including those the
window sends as notes, so a small context window can still trip context
recovery.
- Switching provider is now refused while a turn is running, as model,
thinking and permission changes already were. The refusal covers
`/provider <id>`, the provider picker, a custom provider, setup and login
flows, and adopting a local Ollama. The status line reads "Provider is
locked while a turn is running — press Esc to interrupt first". Before, a
mid-turn `/provider <id>` replaced the engine under the running turn
(Refs #2982).
- `/init` now asks the model to write `AGENTS.md` in the interface language
(for example Simplified Chinese when the TUI runs in zh-Hans), headings
included, keeping commands, file paths and code identifiers as they are.
Before, the prompt always said "Write in English". The non-interactive
`codewhale init` template is unchanged and still English
([#6964](https://github.com/codewhale-hq/Codewhale/issues/6964)). Thanks
@Asteria1028.
- A shell command, shell input or verifier that contains an invisible or
bidirectional Unicode character is now refused before any approval card or
reviewer call in Ask, Auto-Review and Never. This covers zero-width spaces
and joiners, bidi marks, overrides, embeddings and isolates such as U+202E,
tag characters, stray variation selectors and terminal control characters;
ASCII control keys sent as input to a running program, such as Ctrl-C or an
arrow key, stay allowed. The refusal names the code point and its position,
because the approval card and other clients cannot show the character: the
terminal drops it and other renderers may reorder the line around it. To
use the character on purpose, resend the command with it written as a shell
escape, for example `$(printf '\342\200\256')`. Emoji sequences, keycaps,
subdivision flags and one variation selector after CJK or emoji text are
unaffected; a joiner or mark inside Persian, Arabic-script, Indic or Hebrew
words is refused too.
The executed command is never rewritten, and Full Access is unchanged.
- A `curl` or `wget` whose request body uploads a credential is now held by
the built-in safety gate. This covers `-d`/`--data*`/`--json`/`-F`/
`--url-query`/`-T`/`--upload-file`/`-H @file`/`--post-file`/`--post-data`
(and wget's abbreviations of them) carrying `.env`, `~/.ssh/id_*` (public
`.pub` keys excepted, judged per comma or brace alternative),
`~/.aws/credentials`, `.netrc`, a key file, a secret-named variable such as
`$GITHUB_TOKEN` or `$OPENAI_API_KEY`, or stdin fed from one of those, from
`env`/`printenv`, or from `echo`/`printf`/`<<<` of a secret-named variable.
A shell command, shell input or verifier over 64 KiB or 4,096 words whose
text contains `curl` or `wget` anywhere, or one nested too deeply to read,
is held the same way under its ordinary heading, with a reason saying it
was too large or too deeply nested to check. Ask shows a card headed
"Upload credentials (…) with `…`" that a session grant or saved allow rule
cannot answer; Auto-Review and Never deny the call. Runtime clients receive
the same heading as the approval `summary`. A literal request header
(`-H "Authorization: Bearer $TOKEN"`) is not affected, and other upload
tools (scp, rsync, nc, httpie, `aws s3 cp`), secrets inside an ordinary
file, here-documents, `$(printenv NAME)` inside a value and a credential
name split across a brace or quotes (`.net{rc,}`, `.n""etrc`) are not
detected. Full Access is unchanged.
- Switching provider, model route, profile or workspace, or changing plugins,
while a `/compact` is running or queued no longer leaves the session stuck.
The pass on the replaced engine is stopped and the transcript says "Making
room stopped; the conversation was not changed". Before, `/new`,
`/new --force` and `/resume` were refused with "context compaction is
running" or "a manual compaction is queued", and `/compact` answered
"Already making room.", until Codewhale was restarted. A `/compact` still
waiting for a free engine slot is carried to the new engine as before. A
context purge caught by a switch cannot be stopped: the replaced engine may
still finish and bill its request, and the transcript now says "Session
cleanup was abandoned with the replaced engine; the conversation was not
changed" instead of blocking `/new` with "session cleanup is running". A
turn still running when the engine is replaced is not covered and can keep
`/new` refused. Thanks @luestr for reporting the refusal in #6981; this is
one way to reach it, and the report stays open until the blocker that
0.10.2 names confirms its cause (Refs #6981).
- DeepSeek on the Responses route (the `deepseek-flash` default) no longer
fails with `400 reasoning_text must be passed back` when a session replays a
tool call that has no stored DeepSeek reasoning: a turn that was interrupted,
ran with thinking off, came from another provider, or where the model wrote
text before its tool calls without visible reasoning. Codewhale now sends each
assistant turn's reasoning first, ahead of its text and tool calls, using the
same `(reasoning omitted)` placeholder the Chat route already uses when there
is none. Live probes on 2026-10-19 returned 400 for text → reasoning → tool
call and for no reasoning, and 200 for reasoning → text → tool call. The same
multi-step task that failed in 2 of 4 runs on the first 0.10.2 candidate
passed 6 of 6 with the fix. On Chat, DeepSeek enforces this only for
tool-call turns, which were already covered.
- At reasoning effort `max`, the first-party DeepSeek route now asks for up to
131,072 output tokens, DeepSeek's documented default at that effort, instead
of 65,536. Every other provider and effort keeps 65,536, and explicit
overrides and route limits still apply.
- `codewhale exec --output-format stream-json` adds the provider's
`finish_reason` to each `turn_usage` record, so a tool-call stop can be told
apart from an output-limit stop or a provider abort. The field is omitted
when the provider reports none.
- The `/statusline` picker's item hints are localized in all 15 UI languages
instead of always showing English.
- A custom OpenAI-compatible relay's model list is now discovered. Four
separate defects kept it out of `/model`: a roster answering both `data` and
`models` was rejected as a duplicate field; only the active route was probed;
`/v1/models` was authenticated with `x-api-key` whenever the route declared
`wire = "anthropic"`, which a relay that rejects that header answered with
`401 missing_api_key`; and the picker's default view then hid the relay's own
rows. The startup probe now covers every configured relay, a built-in
provider name pointed at a private endpoint (`[providers.openai]` against a
relay) counts as a relay, and the provider panel no longer reports its
catalog missing while listing it. Thanks @SparkofSpike (#7013).
- The footer preview in `/settings` now uses the footer's own words and
colours, in the UI language: Startup mode Work previews `● ask work`
and Plan previews `● read only plan`, as the footer under the composer
shows them. Thanks @Lstarsky0 (#6993, Refs #6466).
- `/resume`, `/load`, and a provider, profile or plugin change keep
configured stdio MCP servers running, as `/new` already did: the replacement
engine adopts each live process when its workspace, MCP backend and server
config are unchanged. A workspace switch still restarts every server, and
servers added at runtime still close.
- Provider lists no longer show two "MiniMax" rows or four "Alibaba Cloud
Model Studio" rows. The variant endpoints are labelled "MiniMax (Anthropic
API)", "Alibaba Cloud Model Studio (Token Plan, Anthropic API)", "Alibaba
Cloud Model Studio (Coding Plan)" and "Alibaba Cloud Model Studio (Coding
Plan, Anthropic API)"; the default MiniMax and Model Studio rows keep their
names.
- Compaction no longer fails with "Chat API response missing choices" on
gateways that wrap a non-streaming Chat Completions response as
`{"data": {"choices": ...}, "success": true}`, such as Sub2API in front of
Cline. A response with top-level `choices` parses as before, and an envelope
without `success: true` still fails. Thanks @luestr for the response headers
and sanitized body in #6981; the `/new` refusal reported there is not
changed by this fix.
- Experimental extension host: a plugin can no longer provide the core
`subagents` service. Its activation fails with "extension may not provide
core service `subagents`", as it already did for `agents`, `approval` and
the other core names. Codewhale's own sub-agents and the tools they can use
are unchanged.
- OpenHarmony builds on Windows select Ninja, with an SDK-bundled fallback and
a clear error when it is unavailable. The CLI keeps its download and Work
context integrity checks available on OHOS by sharing an ungated SHA-256
helper (thanks @shenjackyuanjie, #6989; reported in #6988).
- Windows mouse-wheel scrolling is restored after returning from the external
editor. The handoff now releases both Windows console mouse capture and
terminal mouse modes. Thanks @SparkofSpike for distinguishing terminal
scrollback from transcript scrolling in #6652; the separate hours-long
scrolling slowdown still needs reproduction.
- Shell classification accepts PowerShell’s call operator, quoted ampersands
and combined output redirection without losing destructive commands in
nested shell payloads or after command separators. Thanks @SparkofSpike
for the diagnosis and fix in #6929, and @jayanthvee for the detailed
Windows report in #6963.
- Windows commands that cannot be classified use the normal approval path
with a direct explanation. Ask can request approval and Auto-Review can
consult its reviewer; an unclassified command is no longer reported as an
npm-launcher kill. Actual unbounded `node.exe` image kills keep their hold
in reviewing modes; Full Access continues to bypass that floor. Thanks
@jayanthvee for separating these cases in #6963.
- Pasting while a modal is open no longer changes a history-search query
hidden underneath it. Existing modal key ownership and hidden-caret guards
remain in place. Windows Terminal IME preedit is still controlled by the
terminal; native IME retesting remains open (#2323).
- `codewhale model list`, `model resolve`, the model picker, sub-agent model
validation and Runtime facts read endpoint-scoped catalog facts. `model set`
saves the exact route selection, and `app/models` projects the captured
Runtime's catalog. Compatibility aliases, advisory route checks, the agent
`ModelInfo` capability flags and HTTP app-server route admission still read
the bundled curated overlay; admission uses it only to reject a model the
catalogue knows for a *different* provider. `model resolve` now prints
`limit_overrides` whenever the resolver applied a sourced override, so a
context or output limit names its origin instead of looking catalog-native.
Cost estimates
preserve complete price tiers, calculate exact decimal amounts per request,
and freeze rates at dispatch.
Missing rates or required usage breakdowns stay unpriced; public prices do
not establish account access. A model priced only by a live models.dev
refresh gets a cost estimate at the same confidence as bundled models.dev
prices instead of showing as unpriced. The offline seed records its source snapshot
and keeps absent default wire IDs as dated compatibility fallbacks. Refs #6396.
- Desktop and HTTP app-server turns feed an existing shared pet companion when
its followed session has no live producer. Automatic selection is checked
atomically by the owner; a live TUI keeps its source. The Runtime producer
forwards activity metadata only and releases its connection after a 12-second
completion tail. Refs #6155, #6139.
- `bash` accepts an optional `description`, shown on its card. It never
changes execution, approval matching or Auto-Review input.
- A first launch with no key or route now opens the composer. Codewhale asks
for a provider when you send your first message, keeps the message in the
box, and offers a local model only when a local Ollama server answers. The provider list
now shows what you type to filter it during first-run setup.
- Removed the own-sandbox cloud dispatch (`--own-sandbox`, `/dispatch`,
`agent runtime:"cloud"`, the `cloud-agent` alias, and the `--confirm`,
`--remote`, `--branch`, `--cwd`, `--status` and `--list` options).
`codewhale dispatch "<task>"` now runs only through the signed-in account,
with its quote and EU-compute consent. Cloud computers and accounts are
paused for new users, so `codewhale dispatch` is not available to them.
- `codewhale dispatch` uses the account's neutral wording for cloud errors,
runs for the quoted seconds unless `--seconds` is given, and asks for consent
only when both stdin and stdout are terminals. It refuses a message that was
not read as new Work, and prints the Message ID.
- MCP servers now connect when a session starts, including servers from
enabled plugins; set `lazy = true` on a server you configure to connect it
on demand instead. Finishing an OAuth login reconnects just that server, and
`/mcp reload` redials every server that is not `lazy` and reports how many
are not connected out of the configured total.
- The MCP status no longer stays at "connecting" after the servers have
finished. The final status was lost when it arrived while a reply was
running, when the interface was busy, or when the last server was removed;
the newest status is now kept until the interface can show it. Refs #7035.
- `/new` keeps configured stdio MCP servers running: the next conversation
adopts each live process when its workspace, MCP backend and server config
are unchanged, and dials only what is missing. HTTP/SSE servers reconnect
so they pick up current credentials and network policy; servers added at
runtime and plugin-contributed servers are closed with the conversation.
A workspace switch still restarts every server, and the MCP panel and
`/mcp` now show the new engine's status instead of staying stale.
- The mobile page retires an approval card's Allow and Deny buttons when that
approval is decided from another client, cancelled or timed out, and shows
which happened.
- Settings name compaction "Compact at" with a plain-language hint, explain
Input history as the number of sent messages kept for recall, and label the
Anthropic-compatible DeepSeek endpoint "DeepSeek (Anthropic API)".
- Running shell commands open an inspector with their output and status. It
follows new output until you scroll back, and drops Stop once the command
ends. `Alt+V` opens the card you clicked, even after newer cards arrive or a
tool run collapses around it. `/jobs wait` and `/jobs poll` open the same
inspector instead of freezing the screen for up to 5 s, a shell row in the
work dock opens it too, and a task row opens `/task show` instead of failing
with "Job … not found" (#6931).
- In `/setup`, `u` and `d` act only on the working-agreement step. Pressed on
another step they no longer close the wizard and switch your agreement off.
- `/setup` no longer says "You're ready." when no model is connected; its last
step asks for a provider and lists the P and C keys it accepts. A rejected
API key's reason stays visible at narrow widths.
- First run with a local Ollama model continues to the trust question and the
ready screen instead of ending onboarding, and the next launch no longer
starts onboarding again.
- A turn that ended in failure reads as an error, live and after resume. Retry
notices stay in the transcript instead of flashing a red error that hid the
recovery.
- File edits show as patches with their change summary once. Tool status
words read `done`, `failed` and `loaded, not run` everywhere, and a tool
that only loaded no longer gets a done check.
- Delegated agents' cards name the tool they are running instead of
"Core tool <call id>".
- Markdown: a line like `#6235 fixed it` is no longer a heading, headings
render inline code and emphasis, and tables draw one rule under the header
instead of one between every row.
- The approval card shows its field labels and description in your language in
every locale, not only Simplified Chinese.
- `/mode work` says "Switched to Work mode.", and `/zidong` says it switched to
Full Access. `/overview` and `/setup` call the mode Work.
- The language screen points to `/config locale <tag> --save`, the Korean
Never chip says it allows nothing, and the elevation dialog's Abort says it
skips only that tool call.
- Less work on the UI thread and less memory per turn:
- the context meter keeps its estimates for unchanged history;
- tool calls share the turn's history instead of copying it;
- compaction checks pressure with one pass;
- write_atomic sweeps a directory for stale temps at most hourly;
- the pet costs nothing while hidden;
- `GET /v1/usage` reads the turn store once, not once per thread;
- each save's session cleanup no longer reads every session's cost ledger;
- sub-agent checkpoints copy only the tail they keep;
- the underwater theme paints its background once per frame.
- `/resume`, `/load` and other session changes that cannot run yet now list
what is still busy and how to stop it. Thanks @SparkofSpike (#6948).
- Sessions that ended without a clean exit show `interrupted` with their age
in the session list.
- `codewhale logout` also deletes a stored legacy sandbox token.
- `codewhale lane list` prints an empty list instead of failing when no lane
has been started, `codewhale completion` no longer errors when its output
pipe closes early, and `session-diagnostics`, `receipts` and `features` help
and errors say what to pass and where to find saved sessions.
- A missing `--config` file, a missing `-C` workspace directory and an unknown
`--profile` now fail at startup with a clear message.
- `codewhale web` works when `$HOME` sits under a root-owned symlink.
- Typing `/exi` and pressing Enter now completes the command instead of running
a different destructive command (`/exit`, `/clear`, `/new`, `/logout`,
`/restore`).
- The Shift+Tab permission hint stays in the footer while in Auto-Review and
Full Access.
- An idle pet view no longer builds animation frames while nobody is
looking at it (#6728).
- On the pet main view, `Ctrl+]` cycles the pet's views: the
companion `whale`, a crisp local `cove` whale without the fog, `braille`,
`pixels` (kitty graphics), `particles`, `whale-girl` and installed avatar
packs. Terminals with the kitty keyboard protocol can also send `Ctrl+Tab`
and `Ctrl+Shift+Tab` to move forward or back; Terminal.app uses those to
switch terminal tabs, so use `Ctrl+]` there. The footer names the view, and clicking
it cycles. A view that cannot draw shows its fallback and says what it
needs, for example `pixels needs kitty graphics · showing particles`.
`/pet avatar <key>` jumps to a view, and the `/pet` usage lists every view,
`style` and `language`.
- `F6`, `F8` and `F9` work on the pet main view, not only in the `F5`
inspector. Every F-key hint on macOS, including the help overlay, reads
`fn+F5`, `fn+F8` and so on, including in ASCII-safe mode. `/pet on`, `F8`
and `F9` restart a companion view that stopped, so "/pet on retries" is
true. A failed launch shows its own reason, a successful one says
`habitat open`, and pressing `F8` several times while the companion starts
opens one tab. `F8` and `F9` also restart a stopped companion from the inspector.
- The live dot whale stays dense in large panes, the whale-girl sprite scales
by whole pixels, and avatars, the particle grid and the pixel view no longer
show the whale through them. Avatars follow your theme and
`CODEWHALE_ASCII_SAFE`, the pixel view's image is a whole fraction of the
terminal's pixel size, and the pet's view worker sleeps until its next
deadline instead of waking every 2 ms.
- The terminal dot whale respects studio brightness and sleep dimming. Normal
companion startup no longer shows a missing-service notice, avatar atlas
notices match the current frame, and pet fallback descriptions are translated.
- README: `codewhale exec --auto` is shown for headless runs that edit files
or run commands.
- `bash` now moves a foreground command to the background after 30 s and
reports the elapsed time and how long ago it last printed output.
`task_shell_start` is removed.
- Every change of effective permission now writes a `Permissions changed to …`
line in the transcript, and runtime threads record it as a `status` item and
a `thread.permissions_changed` event.
- The bundled first-party catalog pins marketplace revision
`2e3a6fba453c9b34d5b1444ab5bd6edc7b119189` with 19 catalog entries,
including the bundled Skills pack. Installed bundles carry the reviewed
Computer Use and bridge fixes and the MIT license.
- `codewhale app-server` no longer serves `GET /jobs`, which was always empty;
background jobs are `GET /v1/jobs` on the Runtime API (#6513).
- `codewhale app-server` started inside a project no longer writes
`.deepseek/events.jsonl` there; with no configured path the hook log sits
beside the state database in the Codewhale home. Thanks @Lstarsky0 (#6921,
Refs #6513).
- Streaming requests honor the configured retry count even when provider
backoff or `Retry-After` exceeds the response-header timeout. Chat,
Responses and Anthropic apply that timeout to each physical request;
waiting between attempts does not consume it. HTTP/1.1 responses receive
the same error classification and retry handling. Explicit weekly,
five-hour and plan-reset usage exhaustion stops as a quota error, while
temporary request-rate limits remain retryable. Closing retry receipts
label each per-kind counter so it does not imply which failure ended the
turn. Failed Chat opens retain the provider's `reasoning_content`
diagnostic. Ambiguous transport failures can still replay a request the
provider accepted and incur a second completion charge; protocol fallback
remains limited to one HTTP/1.1 attempt per transport open. Refs #7045.
Thanks @7jrxt42BxFZo4iAnN4CX.
- Body text on a screen that paints its own background now uses the theme's
primary text colour, and on a terminal that does not report a background
colour it uses the terminal's own foreground instead of an assumed ivory
tone. The System and Blue Stage themes showed ivory text on a light
terminal because Codewhale could not measure the ground it was drawing on;
modals, the nested underwater surfaces, fleet setup, the automations view,
the live transcript and the worktree manager now carry body ink explicitly.
A theme that never sets an ink colour for one of its own surfaces can still
be hard to read. Refs #7043. Thanks @Statter.
- A saved session that cannot be resumed because the provider it recorded is
gone now says how to keep its history: the refusal names
`codewhale sessions export <session id>` with that session's real id. The
hint now appears at three resume sites - the TUI resume, the executor
resume and the Runtime API - instead of only one. A Runtime resume refused
because the persisted provider route needs an exact custom provider is now
reported as a bad request rather than an internal error. Other persist
refusals keep their current status; `codewhale resume` and `fork` on the
mount path still refuse without the hint. Refs #6996. Thanks @luestr.
- A read-only role whose shell command is refused now reads that the run has
no network, that a read-only command reaches the network only in Full
Access with an allowing session sandbox, a `[network]` policy that does not
deny by default and a network grant, and that it should use a web tool or
report the source unreachable. That replaces a child reporting "bash denied
for non-admitted programs". The same hint covers a command that starts with
`cd ... &&` and the contract bash path as well as the legacy one. A network
attempt made from Python or `gh` still gets no hint. A read-only child's own
briefing states up front that its shell has no network and that `web` is its
only route to a page, so it reports a source it could not fetch with the
error it saw instead of blaming a blocked program. Refs #7040.
- A `codewhale resume` or `codewhale fork` that is refused no longer leaves a
half-bound session behind that blocks the next attempt. A saved session
whose beginning changed after an earlier resume, through a compaction
checkpoint, contract pruning or a restored sub-agent handoff, now resumes
instead of failing with "saved holder checkpoint differs from the saved
history" or "saved holder has a successor outside the selected document".
Refs #6954. Thanks @7jrxt42BxFZo4iAnN4CX.
- On Windows, Python run through the shell tool no longer garbles Chinese and
other non-ASCII output. Windows shells were meant to start with
`PYTHONIOENCODING=utf-8`, but adding hook variables replaced the whole
environment and dropped that default on every run, so piped Python output
used the system code page while Codewhale read UTF-8. The default now
survives. A `shell_env` hook can still set its own value (on Windows,
variable names match regardless of case), and the default replaces a
different `PYTHONIOENCODING` inherited from your environment. Refs #4202.
Thanks @zhuowp (#7041).
### Added
- **Herdr pane integration** reports Codewhale's idle, working and blocked
state, releases the pane on quit, and supplies the current session's resume
command to Herdr 0.9.2 or newer. Thanks
[Dhruv Singal (@dsingal0)](https://github.com/dsingal0) (#7064).
- The desktop app can connect an OrcaRouter account without a terminal. The
Runtime API's `POST /v1/providers/orcarouter/connect` returns OrcaRouter's
consent link, waits for the browser to come back and saves the key the same
way `codewhale auth orcarouter` does; `GET` and `DELETE
/v1/providers/orcarouter/connect/{attemptId}` report and cancel the attempt,
and `GET /v1/providers` marks the route with `browserConnect`.
- `codewhale review`, the `review` agent tool and `/review` now share one
reviewer. It can read the repository with read-only tools (read, list,
grep, file search and `git status/diff/log/show/blame`) when the checkout is
clean and, for a pull request, `HEAD` is the PR head; otherwise it reviews
the diff alone and says so. Findings use one severity scale, `blocker`,
`concern` and `nit`; the old `error`/`warning`/`info` words map onto it.
Review effort follows the change's risk: sensitive paths (auth, billing,
migrations, secrets, sandbox, schema and similar) or large changes get more
steps and tool calls, small low-risk changes get one pass over the diff.
- Every review body now ends with a severity tally as one HTML comment,
`<!-- codewhale-review: {"blocker":0,"concern":0,"nit":0,"introduced":0,"preexisting":0} -->`,
so a repository can gate a merge on "no blockers" without scraping prose or
granting Codewhale `checks: write`. Findings also say whether the line they
point at was introduced by this change or was already there, decided from
the diff rather than from the model's own label. `codewhale review`,
`codewhale review --pr --post` and the extension-host path write the same
body.
`--money-cap-usd`, with `--input-usd-per-mtok` and `--output-usd-per-mtok`,
stops a review at a spending cap; without both prices the receipt says the
cap could not be applied. A review that stops early names the limit and says
that files it did not reach were not reviewed. Each finding says whether it
was reproduced, traced or only suspected; suspected ones move to a short
"worth a human look" list, and on high-risk changes a second pass tries to
refute each finding and can only remove findings, never add them. A defect in
code the change did not add is labelled pre-existing, kept out of inline
comments and listed separately, and on its own does not raise the merge
risk. The summary lists what the reviewer checked and found sound under
"Checked, nothing wrong".
- Runtime API: `GET /v1/workspace/status` reports `workspace_trusted`, and
`POST /v1/workspace/trust` with `{"trusted": true|false}` records the
server workspace's project trust in the same record `/trust on|off --save`
writes. It takes no path and needs write authority; watch tokens can read
but not write. The answer is the decision read back, with the `config_path`
that holds it. Revoking trust does not remove `AGENTS.md` or project rules,
project hooks still need their own approval, and project MCP servers change
only after the engine restarts. Thanks @gaord (#6959).
- Runtime API: when `capabilities.account_model_owner` is true, a turn can
name the signed-in account in `account_model_owner`, with provider
`codewhale` and an exact `provider/model` route. That turn runs only on that
account's credential, never a local key, an environment variable or another
provider, and is refused if the account's model access is missing, expired
or revoked. The Chat relay takes the same field as `accountModelOwner`.
- The model can hand a goal back at a milestone: `update_goal` with
`status: "yield"` ends the turn with the goal still unfinished, and your
next message resumes it. A goal the model reported blocked, or one you
paused, still needs `/goal resume`. Thanks @SparkofSpike (#6930).
- Bundled Computer Use can re-read only what changed in an app
(`get_app_state` with `since`) and run up to eight steps in one
`run_actions` batch. Each step can target a unique element found just
before it runs, and the batch receipt says which steps completed and
whether input was sent, so a failed batch is not replayed. On Linux, keys
and pointer events go only to the window that will receive them, and are
refused when that window cannot be determined (including under Wayland) or
while a menu is open. Linux also gains AT-SPI focus, value reading and text
selection, app-window capture, ffmpeg screen recording, `kill_app` and
`list_sessions`. Computer Use remains a preview.
- Standard Compute is available as a bundled compatible provider, with the
`standardcompute` router default and authenticated model discovery. Its
billing basis remains Unknown (#6985).
- Sub-agents retain permitted code-mode tool composition. Nested calls keep
the child's approvals, write scope, tool timeout and work deadline; approval
waits do not consume that tool timeout. Refused nested calls still do not
count toward Fleet's denial-loop guard. Refs #6841.
- `/connect [<provider>]` signs in to a model provider that a plugin adds,
inside the TUI, and `/disconnect <provider>` removes that sign-in.
`/login` and `/logout` are for your Codewhale account only.
- `codewhale install <source>` installs a plugin from the terminal through the
same installer as `/plugin install`, without starting a model or needing
model credentials. Both accept `git:github.com/<owner>/<repo>[@<ref>]` and
`npm:<package>@<exact version>` as well as a local folder, GitHub archive or
tarball URL. The plugin stays disabled and untrusted until you review and
enable it; no Git hooks, npm lifecycle scripts or dependency installs run.
Experimental. Thanks @LIghtJUNction (#6950).
- `codewhale auth claude` and `/auth claude` add Claude subscription sign-in
to the existing Anthropic route, with protected owned credentials, refresh
before requests, a provider-picker choice and local sign-out. API-key billing
remains an explicit separate choice. This is experimental: live subscription
grant and inference acceptance have not been qualified (#6932).
- `/pet on` makes the animated GPUI whale the main terminal view, with the
existing message box, queued messages and permission controls always available.
F5 or `/pet inspect` opens streamed replies, errors and the current session's
agents; Escape returns to the same pet view and draft. `/pet off` restores the
ordinary shell. Whether `/pet on` is active is remembered across launches,
and the
inspector can copy the last finished reply with c or its footer action.
Motion preferences and unknown usage stay truthful (#6920, #6907),
using the shared `codewhale-ratatui` components
([#23](https://github.com/codewhale-hq/codewhale-ratatui/pull/23), [#25](https://github.com/codewhale-hq/codewhale-ratatui/pull/25)).
- The pet view uses the latest Ratatui particle-whale renderer. Choose a
smooth aurora or pixel whale with `/pet style smooth|pixel`, and choose
English, Simplified Chinese, Traditional Chinese or Japanese activity words
with `/pet language auto|en|zh-Hans|zh-Hant|ja`. Language follows the interface
by default; a fixed choice lets you learn another language beside the normal
status text. The 980 drones form the same full phrases as the interface,
including `读取`, `搜索` and `调用工具`, then return to the whale. The appearance
studio saves the same choices. Reduced motion uses a stable pose, and the
reply inspector keeps priority on small terminals.
- A Terminal work dock (`/workbar terminal`) shows the model’s live PTY sessions
in the current workspace, with ANSI-styled output, session selection, resize
and direct keyboard input. `Ctrl+N` starts a separate shell; `Alt+Down` and
`Alt+Up` switch sessions, and Esc returns input to the composer. Input remains
bound to the selected shell’s identity across resets. Available on macOS and
Linux; Windows names its current PTY limitation. The view shows a bounded
output tail rather than emulating full-screen terminal programs (Refs #6912).
- When a Plan turn finishes with an answer, the TUI asks "How do you want to
continue?". **Work (Ask)** and **Work (Auto-Review)** switch to Work with
that permission and send the plan as the next message (a plan written only
as prose adds one pending To-do); **Keep planning**,
or Esc, stays in Plan and sends nothing; typed feedback is sent as the next
message in Plan. The question appears only when the composer is empty, no
message is queued, no other view is open and no agent is focused. If the
chosen permission cannot be applied (for example it is locked by config),
the session stays in Plan and the reason is shown
([#6902](https://github.com/codewhale-hq/Codewhale/issues/6902)).
- `/undo force` undoes a request whose end was never recorded, including
edits made to its files since it started. Any other `/undo` option is
reported as unknown and nothing runs.
- `/diff` opens the changed lines in a pager titled "Changes since session
start", rendered like an edit in the transcript, under the file list and
stat it already printed. Patch text is cut at 256 KiB and left out past
200,000 changed lines; the message then says "The diff is too long to show
in full. The file list above is complete."
- The model can stop a background shell command it owns: `task_shell_wait`
takes `cancel=true`. That call needs approval, its card reads "Stop a
running shell command", and it is refused when sent together with `gate`.
The notices for a command moved to the background now name `cancel=true`.
- Each turn tells the model which configured MCP servers it may load, so a
question can reach a server you never named. The note lists enabled, allowed
server names only (at most 24), asks the model to `tool_search` a name
before searching files or saying no tool exists, and is recorded again only
when the list changes or a compaction dropped it. No server is started and
no schema is loaded until the model searches.
- `codewhale mcp --help` lists the `mcp` subcommands with their descriptions
and shows `Usage: codewhale mcp [OPTIONS] <COMMAND>`.
- A file-edit approval card in a folder with no Git repository says "No Git
repository here, so edits ask first." on its question row. It appears only
for `write_file`, `edit_file` and `apply_patch` in the posture where the
same edit runs without a card inside a repository.
- Clients that start `codewhale serve` can declare a telemetry surface with
`CODEWHALE_TELEMETRY_SURFACE`, including `vscode-extension`. This changes the
session label while preserving collection settings and opt-outs
([#6916](https://github.com/codewhale-hq/Codewhale/pull/6916)).
- `codewhale account computers files` saves a Computer's workspace file (up to
16 MiB) to account storage, lists its versions, and restores (up to 4 MiB)
or downloads one. Restoring over an existing file needs its current
`--expected-revision`; a download verifies size and SHA-256 and never
overwrites a local file. `codewhale account computers delete` now asks for
`--discard-files`. This is experimental.
- Runtime API: `GET /v1/goals` lists goal records across threads, newest
update first, with `status` and cursor paging. Goals whose thread no longer
exists are left out, and a cursor issued under a different `status` is `400`.
- Runtime API: `GET /v1/approvals` rows add a redacted `target` (a URL's host
or a workspace path) and a one-line `summary`, plus `standing_rule` (`allow`
or `deny`) when a remembered rule or grant answered instead of a person. A
shell command keeps only its program name and plain arguments. Rows recorded
earlier omit these fields.
- Runtime API: automations carry a `revision`. `PATCH`, `run`, `pause` and
`resume` accept `expected_revision` and answer `409` `revision_conflict` on a
mismatch. Create and those four accept an `Idempotency-Key`; a retry replays
the first success instead of creating or running twice. `DELETE` honors
neither. Clients check `capabilities.automation_mutation_preconditions`.
- The first start after an update says what changed, once: the version you
moved to, how many features, fixes and other changes its notes list, and a
link to that version's release notes on codewhale.net, in the UI language.
The TUI shows it on the startup card, so the recent-sessions card no longer
disappears on the first launch after an update; it moves into the
transcript when the card leaves. Report and setup commands such as
`codewhale doctor` print it to stderr in a terminal. `exec`, JSON output
and non-terminal runs never show it, a fresh install or a downgrade shows
nothing, and `[update] show_whats_new = false` turns it off.
codewhale.net has a page for every version at `/en/changelog/<version>`
and `/zh/changelog/<version>` with all of its entries.
### Changed
- `transcript_spacing` has two settings, `compact` and `spacious`, and
`spacious` is the new default. `comfortable` drew the same conversation as
`compact` everywhere except between activity rows, so the settings list
offered a choice that did nothing. `spacious` leaves two blank rows between
activity rows and three between turns. A saved `comfortable` (or `default`,
`normal`) now reads as `spacious`; set `compact` to keep the denser layout.
- The OrcaRouter consent link that `codewhale auth orcarouter` and
`/auth orcarouter` open now carries Codewhale's public `ref` identifier.
- The OrcaRouter sign-in origin can no longer be moved to another HTTPS
address. `ORCA_AUTH_BASE_URL` and `ORCAROUTER_AUTH_BASE_URL` accept only a
plain-HTTP loopback address, for local test fixtures, and `ORCA_BASE_URL`
now moves only the inference origin.
- `codewhale account agents work-quote` and `work-launch` quote and start Work
on your computer balance as well as the trial. `--seconds` picks whole
seconds within the served offer; without it `work-launch` uses the default
its quote showed instead of a fixed 300 seconds, so a balance-funded launch
can no longer disagree with its quote. `--recovery-from <workspace id>`
recovers a failed workspace on a fresh computer under the same Work ID.
`codewhale account agents work` accepts `--context-file` (UTF-8, at most
64,000 UTF-16 units) and up to ten `--file FILE_ID@VERSION` saved files, so
Work needs no repository. `account computers create --computer-trial`
replaces `--boat-trial`, which still works. Experimental, and available only
to existing accounts while new accounts are paused.
- Goal mode has no step limit when `[goal].max_steps` is omitted or `0`.
Positive values still limit the goal, with values above `100000` clamped to
`100000` ([#6512](https://github.com/codewhale-hq/Codewhale/issues/6512)).
- MCP and provider browser sign-in allow 15 minutes for the callback instead
of five ([#6865](https://github.com/codewhale-hq/Codewhale/issues/6865)).
- `/undo` takes back your last request in one step, in every access mode:
every file the request changed, plus the request and its reply. It no
longer asks for `/trust on`. Its report names the request and lists each
file as `restored`, `brought back` or `removed`, then says whether the
request and its reply were removed from the conversation. It changes
nothing if one of those files was edited after the request, and names the
file. For a request whose end was never recorded it changes nothing and
points to `/undo force`. `/undo` no longer steps back one tool call at a
time; `/restore` still reaches those points. When only the conversation is
rolled back, the message adds "No file changes to undo." or says that
workspace files were not reverted.
- `/restore` without trust mode or Full Access now says that it rolls every
file in the folder back to the chosen point, including later edits, that
nothing was changed, and that `/undo` takes back only your last request.
- `/diff` compares the workspace with this session's first restore point, so
it works in a folder that is not a git repository and includes files
created since. Before the session has a restore point it shows the
workspace repository's uncommitted changes. With neither, it says "Nothing
to compare yet: this session has not saved a restore point here, and this
folder is not a git repository." instead of "No changes since session
start".
- `/trust on` and `/trust off` leave a line in the transcript saying what
changed; with `--save` the line also says what was saved for the folder.
- After Esc Esc the footer reads "Files not changed. Use /restore.
Conversation rewound.", replacing "Rewound to previous user message — edit
and Enter to resend" and the "`/undo` puts them back" promise it used to
carry. `/restore` rolls the whole folder back to a point you pick and needs
`/trust on` or Full Access; `/undo` still takes back the last request's
files where it can prove which snapshots belong to this conversation.
Refs #6970. Thanks @luestr.
- `/relay` writes the session relay to `.codewhale/handoff.md`, the path a
new session reads first, instead of `.deepseek/handoff.md`. A relay left at
the legacy path is still read when the primary file is absent, and the
prompt block names the file that was actually read.
- The highlighted option on an approval card is tagged `(Enter)`, so the
default `[3 / d / n] Don't allow (Enter)` row shows what Enter does.
- The edit approval card shows only the lines an edit changes, as `- ` and
`+ ` rows. Lines shared at the start and end of the old and new text are
left out, the "replace this" and "with this" sub-labels are gone, and a
single edit is no longer headed "edit 1". Lines left out on a side are
counted (`... (+2 more lines)`); several edits are numbered and each shows
its first changed line.
- The three-row preview of a successful command shows one opening row and two
closing rows, preferring closing rows that say something passed or failed.
Blank rows no longer take a slot, and lines hidden after the last row shown
are counted in the `… (+N lines)` marker too.
- An MCP server the session has not needed yet shows as `not connected` in
`/mcp` instead of "not started", with its transport and "Not connected in
this session yet. Connects when a tool is needed, or connect it now." in
place of zero tool counts.
- `codewhale doctor` adds "works without an API key (limited quota; set
FIRECRAWL_API_KEY or [search] api_key to raise it)" to the
`search_provider` line when Firecrawl is the provider and no key is set.
- The stalled-tool notice now ends "Run /jobs to see it and /jobs cancel <id>
to stop it." instead of naming `exec_shell_cancel`.
- A DeepSeek Harness (`dsh`) package refused with "No portable components in
this package" now lists the skipped rows, each with its package and reason,
and the Native composition refusal names the unresolved rows. Both name at
most five rows and count the rest.
- Full Access runs the calls it grants. The built-in Auto-Review floor
(publish-like commands, destructive background or headless work, and the
Windows npm-launcher hold) applies only in Ask, Auto-Review and Never, and no
longer blocks a call under Full Access, including a detached agent's.
- `file_search` is one of the model's default tools from the first turn
instead of being loaded through `tool_search`
([#6934](https://github.com/codewhale-hq/Codewhale/issues/6934)). It also
accepts globs (`src/**/*.rs`) and several space-separated terms that must
all match. Literal matches rank above fuzzy ones, build and dependency
folders are skipped by default, and `limit` goes up to 200. An `exclude`
list replaces the default exclusions, and `[]` turns them off.
- `fim_edit` is offered only on routes that can run it: Chat Completions
routes other than OpenCode Zen. The default DeepSeek Flash route speaks
Responses and no longer lists it
([#6933](https://github.com/codewhale-hq/Codewhale/issues/6933)).
- Runtime session grants (`"remember": true`) are stored in the Runtime data
directory instead of memory. After a restart a thread's grants stay
suspended, and matching calls ask again, until an authenticated client
resumes the thread. A grant store that cannot be read holds no grants, so
every call asks.
### Fixed
- Delegated work uses the full explicit turn and time limit. Default child nesting and Workflow plan depth caps are removed; explicit owner restrictions remain. The host no longer reserves the last turn or part of the deadline for a forced report, or makes an extra reporting request after the limit; recorded work and files remain available in the partial-result receipt.
- Runtime child completions retain their original parent turn after the parent
becomes idle or starts a newer turn; terminal receipts remain durable and
deduplicated.
- Windows Native extension hosts resolve `DeriveCapabilitySidsFromName`
at runtime and return an unsupported error during LPAC setup when the
export is unavailable (#6953). Windows 10 1607 startup and Native-host
acceptance remain unverified.
- `codewhale resume` no longer refuses a session whose saved history still
holds a raw sub-agent handoff (#6954).
- Snapshot restore and `/undo` work with older git, such as the 2.43 that
Ubuntu 24.04 ships. They failed there with "only one reference expected".
- When the model cancels its own background job, it no longer gets a
"finished" event or starts a new turn from it; when you stop a job the
model started, the model is told it was killed. Cancelling a job that had
already exited keeps its real exit status instead of reading "killed, exit
0", and `/jobs cancel all` no longer reports exited jobs as cancelled.
- A shell command that moves to the background after 30 seconds shows the
same "keep running in /jobs" notice as `Ctrl+B`, and its card no longer
shows the instructions written for the model.
- `todo_write` returns a short receipt (counts and the item in progress) to
the model instead of repeating the whole list on every call.
- Goal usage counts the turn that completes, yields or blocks the goal, so
`tokens_used` and `time_used_seconds` no longer stay at 0. `update_goal`
accepts a progress estimate with `yield`.
- Waiting on a running shell job reports how long ago it last printed and
whether it is still compiling or already running tests or the program.
Stopping a job from `/jobs`, and the completion the model then receives,
say whether build artifacts already on disk survive the kill (#6944).
- A shell command that has printed nothing for a minute still reads as
running ("no output for 1m 05s"), keeps its Stop action and is reachable
through the Runtime API; only a job whose process is gone after a restart
is stale. `/jobs poll` and `/jobs stdin` no longer consume the output the
model has not read yet (#6931).
- `/constitution`: `ratify` checks the digest you reviewed in `suggestions`,
so a fi