v0.9.9

Wei-Shaw/sub2apiv0.9.9Aug 18, 2026by github-actions[bot]

AI Summary

v0.9.9 is a truth-and-resilience release ensuring the shell tool doesn't wedge on disk exhaustion. It introduces honest labeling for context windows and output ceilings across all surfaces.

Key Highlights

  • Shell tool no longer wedges when the host runs out of disk or file descriptors.
  • Unverified context windows and output ceilings are now labeled honestly at every surface.
  • Fleet shadowing is now visible in the interface.
  • Context-window honesty implemented in status line, picker, and auto-router.

New Features

  • Fleet read-only shell carve-out is now honored by posture gate.
  • `/rename` and `/title` now apply mid-first-turn.
  • Context-window honesty labels in model picker chips and context-pressure messages.

Full Release Notes

> **Codewhale** is the public product from Shannon Labs. The `codewhale`
> command, npm package, and release-asset names remain lowercase technical
> identifiers. The legacy npm package `deepseek-tui` is deprecated and
> receives no further releases. Users coming from v0.8.x legacy `deepseek` /
> `deepseek-tui` names should migrate with `docs/REBRAND.md`.

## Install

### Recommended — npm (one command, both entrypoints)

```bash
npm install -g codewhale
```

The wrapper downloads the matched `codewhale` and `codew` command assets
from this Release. Both contain the same compiled runtime.

### Docker / GHCR

```bash
docker run --rm -it \
  -e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \
  -v codewhale-home:/home/codewhale/.codewhale \
  ghcr.io/hmbown/codewhale:v0.9.9
```

The image exposes the same runtime as both `codewhale` and `codew`. The
`latest` tag is also updated on release.

### Cargo (Linux / macOS)

```bash
cargo install codewhale-cli --locked
```

The Cargo package installs `codewhale`. Cargo cannot create a second command
alias from one binary target; users who want the shorter spelling can add a
`codew` symlink to that installed executable. The npm, Homebrew, archive,
shell-installer, and container channels install both command names directly.

### Manual download — platform archives (recommended)

Each archive below contains the same runtime under the `codewhale` and
`codew` command names, plus an install script:

| Platform | Archive | Install script |
|---|---|---|
| Linux x64 | `codewhale-linux-x64.tar.gz` | `install.sh` |
| Linux ARM64 | `codewhale-linux-arm64.tar.gz` | `install.sh` |
| Android ARM64 (Termux) | `codewhale-android-arm64.tar.gz` | `install.sh` |
| macOS x64 | `codewhale-macos-x64.tar.gz` | `install.sh` |
| macOS ARM | `codewhale-macos-arm64.tar.gz` | `install.sh` |
| Windows x64 (installer) | `CodeWhaleSetup.exe` | NSIS setup |
| Windows x64 | `codewhale-windows-x64.zip` | `install.bat` |
| Windows x64 (portable) | `codewhale-windows-x64-portable.zip` | — |
| Windows ARM64 | `codewhale-windows-arm64.zip` | `install.bat` |
| Windows ARM64 (portable) | `codewhale-windows-arm64-portable.zip` | — |

**Unix (Linux / macOS):**
```bash
tar xzf codewhale-<platform>.tar.gz
cd codewhale-<platform>
./install.sh
```

**Windows:**
- For the installer path, run `CodeWhaleSetup.exe`; it installs
  `codewhale.exe` and `codew.exe` under
  `%LOCALAPPDATA%\Programs\CodeWhale\bin` and adds that directory to the
  current-user PATH.
- Extract the archive for your machine: `codewhale-windows-x64.zip` or
  `codewhale-windows-arm64.zip`
- Run `install.bat` (copies to `%USERPROFILE%\bin`)
- Add `%USERPROFILE%\bin` to your PATH

The **portable** Windows archive skips the install script — extract and run from any directory. The NSIS installer is currently unsigned and may trigger Windows SmartScreen until a signing certificate is wired into the release pipeline.

Each platform also has **bare, unarchived** `codewhale-<platform>` and
`codew-<platform>` assets. The seven `codewhale-tui-<platform>` filenames
attached to v0.9.5 are byte-identical compatibility copies used only to let
already-installed v0.9.4 clients discover and cross this single-binary
transition; current installers do not expose a third runtime. The legacy npm
package `deepseek-tui` is deprecated and is not republished. For migration
from v0.8.x legacy binary names, see `docs/REBRAND.md`.

### Verify (recommended)

Download the checksum manifests from this Release and verify:

```bash
# Linux — archive bundles
sha256sum -c codewhale-bundles-sha256.txt --ignore-missing

# Linux — individual binaries
sha256sum -c codewhale-artifacts-sha256.txt --ignore-missing

# macOS
shasum -a 256 -c codewhale-bundles-sha256.txt --ignore-missing
shasum -a 256 -c codewhale-artifacts-sha256.txt --ignore-missing
```

## What's in v0.9.9

Codewhale v0.9.9 is a truth-and-resilience release: the shell tool can no
longer wedge a session when the host runs out of disk or descriptors,
unverified context windows and output ceilings are labeled honestly at every
surface, DeepSeek V4 is priced on the published peak/off-peak tiers, SSE
UTF-8 fails closed in every dialect, Fleet shadowing is visible, bwrap gets
container essentials and extra roots, the `dsh` skin rides the bundle
profile, the `agent` tool schema is down to 12 fields, and README/website
locales grow to 18 and 8.

### Fixed

- The lowercase `bash` tool no longer wedges when its complete-output spill
  file cannot be created: a full temp volume or exhausted descriptor table
  used to fail *every* call — `echo ok` included — with the harness-internal
  "Failed to create streaming shell output" and never recover until the
  host was cleaned up. The spill is now best-effort (the bounded tail is
  still returned and the truncation notice says why the full-output path is
  missing), and any remaining spawn/stream failure names the exhausted
  resource — disk, file descriptors, memory — and says the next call is safe
  to retry (#5465; the wedge that took out the owner's own 0.9.9 session).
- A concrete route/offering output limit now outranks the conservative
  8,192-token compatibility guess for an uncatalogued model. Routes that
  publish no output limit remain fail-closed, documented model ceilings stay
  authoritative, and a route limit can never raise the requested cap (#5460).
- Context-window honesty at every surface (#5239, #5441): the
  `model-name hint` and `fallback` rungs of the context-window ladder are
  guesses, and every surface that renders one now says so — the status line,
  `/status`, `/config`, the context-pressure message, the model picker chips,
  and the auto-router inventory. Unverified windows still drive real budgets
  (compaction trigger, context meter, output reservation); they just stop
  reading as capabilities anyone checked. A window parsed from an `_Nk`
  model-name suffix (`qwen3-32b-256k` → 256K) is now its own
  `model-name hint` rung below `catalog`, because it is optimistic rather
  than conservative — a catalog or provider-reported value beats it. The
  `[providers.<name>] context_window` override remains the hard fix and
  renders as `configured` with no marker.
- Output-ceiling honesty (#5440): an Anthropic-family model the catalog does
  not describe keeps the 64K Messages floor as its clamp and the ChatGPT/
  Codex OAuth route keeps its 4K policy, but `OutputCeilingSource` gained an
  `unverified` rung for both, so exec-stream receipts and the model picker
  label them `unverified`/"assumed floor" instead of `documented`. Clamp
  values are unchanged.
- Telemetry default-on is visible (#5441): `codewhale doctor`'s
  runtime-posture section gained a `telemetry=on (default)`-style row with
  the source that decided it (cli | env | config | default), and
  `codewhale config get telemetry` reports the resolved consent with its
  source instead of `key not found` on a machine whose batches ship. Truth
  change only; resolution and behavior are untouched.
- Fleet: a scout's read-only shell carve-out (#5428) is now honored by both
  the posture gate and the execution envelope, so `git log`, `find | head`,
  `npm view` and the other bounded read-only commands run in-place instead
  of being refused as "Executes" (#5426). Delegation still never widens
  authority: the role-isolation test and docs/SUBAGENTS.md pin that a child
  cannot exceed its parent's posture (#5426, #5435).
- `/rename` and `/title` now apply mid-first-turn: the session file does
  not exist until the first autosave, so the rename fell through with
  NotFound; the shared path now prefers the per-session checkpoint and
  rebuilds from App state, with a PTY regression test through the live
  event loop (#5430).
- `integrations dsh plan` no longer refuses DeepSeek's default
  Responses-dialect route (`deepseek-v4-flash`); Responses and
  Anthropic-Messages routes are carried through pi-ai
  `openai-responses` / `anthropic-messages` instead of being approximated
  or refused; only credentialed base URLs are still refused, with an error
  that names provider and model (#5434).
- Session cost no longer sits at `unverified_live_pricing` when live pricing
  cannot be verified (control-plane 503, Models.dev capabilities-only
  overlays): provider-docs bundled fallback rates for the DeepSeek V4
  family on Fireworks / OpenCode Zen restore a usable figure, live
  per-provider rows still win, and `kimi-k3` stays unpriced until a
  published rate exists (#5241; harvested from #5402).
- Release assets: `release.yml` asset-freshness checks compare against the
  release job's own `started_at`, so job-level reruns of the npm step are no
  longer poisoned by earlier uploads (#5429).
- macOS CI: the `agent_focus_pty` auto-review receipt test waited on a
  worker that had already completed and raced the rail's focus; it now holds
  the child's wrap-up and waits for a settled live row (refs #5056, #5403).
- DeepSeek V4 pricing follows the published peak/off-peak tiers (peak
  01:00–04:00 and 06:00–10:00 UTC; off-peak is half of peak) for
  `deepseek-v4-flash` and `deepseek-v4-pro` in USD and CNY, resolved from
  each turn's recorded time; the stale single-tier rows understated cost up
  to ~4×. Because every direct DeepSeek first-party rate is now
  time-windowed, the scorecard fails closed (`missing_recorded_time`) on an
  undated DeepSeek turn instead of guessing a tier (#5470; #5241 follow-up,
  verified against api-docs.deepseek.com on 2026-08-17).
- SSE UTF-8 split across HTTP/2 DATA frames now fails closed in every
  streaming dialect: a shared strict decoder, tail flush, and
  `decode_failed` propagation (`InvalidSseUtf8`) replace the per-dialect
  approximations, with byte-chunk decoder tests (#5374; supersedes draft
  #5404).
- CI: `release_four_read_only_fleet_roles_launch_with_canonical_prompts`
  answered Fleet children with SSE while they call the blocking JSON path;
  the parse failure was retried and double-counted the worker on slow macOS
  runners (#5471; refs #5056).
- Context: every web tool surface (`Web`, `web_search`, `web.run`,
  `fetch_url`) now uses the noisy-result soft limit, so large fetches are
  compacted like shell output instead of consuming the ordinary hard limit
  (#5474, thanks @h3c-hexin).
- Routing: a lowercase saved selector such as `glm-5.2` resolves against the
  owning Z.ai / DeepSeek catalog row (case-fold fallback, only when exactly
  one provider-owned wire id matches) instead of being classified as another
  provider's bare model (#5475, thanks @h3c-hexin; diagnosis by @asto18089
  in Pinvou/CodeWhale#14).
- Model catalog brought current as of 2026-08-17 against the official
  pricing pages: gpt-5.6-terra / gpt-5.6-luna rates, `claude-sonnet-5` keeps
  $2/$10 (the announced September increase was withdrawn), `claude-opus-5`
  added, `kimi-k3` and `kimi-k2.7-code-highspeed`, `MiniMax-M2.7-highspeed`,
  Mistral first-party rows, xAI `grok-4.5` / `grok-4.3` with long-context
  tiers, Gemini and Qwen limits, and RedNote's `dots3-note` preview as an
  OpenRouter row (no first-party API exists yet) — every number carries its
  source and a pinned test (#5485).
- Website: copy on codewhale.net rewritten in plain declarative sentences —
  one idea per sentence, numbers from the generated facts, no self-narration
  — with a voice sheet at docs/design/WEB_VOICE.md (#5483).
- CI: the release workflows no longer restore npm/cargo caches after
  checking out a caller-supplied SHA — the CodeQL cache-poisoning Highs
  #88–#107 are closed with a contract test over the workflow files (#5463).
- Compact TUI rows below 60 columns no longer reserve a hidden session-metrics
  strip, so narrow terminals reclaim the row instead of clipping the
  transcript (#5486).
- Ghostty's truecolor underwater field now uses a dedicated synchronized
  60 FPS lane instead of the legacy 30 FPS compatibility cap, with continuous
  caustic fades replacing visibly stepped color changes.
- Live reasoning's advertised `Space:expand` action now runs before the
  composer's first-character paste-burst hold, while spaces in an active paste
  remain payload. The newest reasoning preview also spends only genuinely free
  viewport rows before truncating instead of stopping at the fixed 10/12-row
  fallback on roomy terminals.
- Strict `cargo doc` builds no longer fail on bare URLs in rustdoc comments;
  the remaining links are explicit Markdown targets (#5489).

### Changed


- The model-facing `agent` tool advertises exactly 12 fields — `action`,
  `prompt`, `type`, `profile`, `name`, `agent_id`, `message`, `until`,
  `detached`, `worktree`, `write_roots`, `resume_from` — down from 33
  (#5324, refs #5123). Budgets (`max_steps`, `wall_time_secs`, `max_depth`),
  routing overrides (`model`, `model_strength`, `thinking`), worktree-path
  knobs, the deliberate/spawn-contract fields and the wait/status/interrupt
  extras moved off the advertised schema. Every removed field stays
  parse-accepted and honored unchanged (same contract as `token_budget`), so
  saved transcripts, ACP/MCP clients and Fleet configs replay as-is; the
  #5426/#5435 containment clamps are untouched. Child budgets now resolve
  from role defaults (60/120 turns, 1800 s wall time, unchanged clamps) and
  new `[subagents]` keys `default_max_steps` / `default_wall_time_secs`.
  Because the tool catalog is part of the session-pinned prompt prefix
  (docs/CACHE.md), upgrading re-fills the KV prefix once per session.
- TUI prose — user messages, assistant answers, and reasoning/thinking —
  now wraps at the full content width on wide terminals, matching
  tool/status cells, instead of stopping at a 105-column rail that left a
  dead right margin on ultrawide displays (#5436).
- Configured skill prompts are stable across session roots and operating
  systems: only custom configured roots hide their physical path, ordinary
  workspace/global skills keep a discoverable privacy-safe path, warning
  replacements are boundary-aware (including non-UTF-8 Unix paths), and
  Windows separators render as `/`. The skills prompt is also 50 bytes
  leaner without raising a runtime-contract ceiling (#5492, #5473).
- Auto-router classifier requests accept `[auto.router] timeout_secs`, while
  preserving the existing default when the key is absent (#5494).
- Every `ci.yml` job now has an explicit 10–90 minute timeout appropriate to
  its workload, bounding stale assigned runners instead of inheriting
  GitHub's six-hour default (#5495).
- The docs shell and shared web components now route localized copy through
  the typed dictionary spine; these are two incremental phases of #5337,
  not completion of the full epic (#5488, #5490).
- Dependency: rusqlite 0.40.2 (#5391).
- Documentation: stale A/B/C-tier references, provider defaults, module
  descriptions, and line anchors now match the current code (#5481).

### Added

- `[transcript] prose_measure` (positive integer, optional): caps prose
  wrap at N columns for owners who want a bounded reading measure on
  ultrawide terminals. `0` or absent keeps the full width; negative or
  non-integer values are rejected with a clear config error. Tool, diff,
  and status cells never inherit the cap (#5436).
- Localization: README translations for Français, Deutsch, 繁體中文, हिन्दी,
  Türkçe, Italiano, Polski, العربية and Català join the existing nine
  (#5451); codewhale.net routes fr, de, ca, hi, tr, it, pl and ar (with
  `dir="rtl"` plumbing) as partial locales (#5453).
- Docs: README Integrations section (incl. the DeepSeek Harness `dsh` plugin
  path, docs/INTEGRATIONS_DSH.md) localized across all READMEs; RFC keeping
  the deterministic-first auto-review hybrid (#5427); Claude Code parity
  reference for agents/workflows/plugins/skills
  (docs/design/CLAUDE_CODE_PARITY.md); config.example.toml / SUBAGENTS.md /
  TOOL_LIFECYCLE.md brought back in line with the code (#5447).
- `dsh` integration: the Codewhale palette is applied through the bundle
  profile via dsh's documented `overrideTokens` (on by default;
  `codewhale integrations dsh update --skin false` turns it off), replacing
  the 0.9.8 exported-CSS skin that dsh's inline body variables overrode
  (docs/design/DSH_BUNDLE_SKIN.md, docs/INTEGRATIONS_DSH.md) (#5469).
- `dsh` integration: an ambient ocean scene behind the DSH web UI — slow
  whale silhouettes, a school of `><>` glyph fish, bubbles — drawn on a
  canvas under a translucent veil of the Codewhale palette, plus an explicit
  responsive `WHALE BROTHERS / CODEWHALE × DEEPSEEK HARNESS` lockup; light
  and dark, ~30 fps capped, paused when hidden, a static frame under
  `prefers-reduced-motion`; on by default with the skin,
  `codewhale integrations dsh update --ocean false` turns it off (#5484).
- Fleet: agent shadowing is visible — a roster-row badge, a Layers block in
  agent detail, and a `doctor` "Fleet roster layers" section (JSON
  `operate_fleet.roster.multi_layer`), in all 15 TUI locales. Layer collapse
  and `[fleet.profiles]` migration stay for 0.9.10 (#5098).
- Sandbox: bwrap containers get the `--dev/--proc/--tmpfs` essentials plus
  configurable extra roots (`bwrap_ro_roots` / `bwrap_dev_roots`) so
  toolchains that live outside the workspace stay reachable read-only
  (#5410).
- Tests: `crates/tui/tests/README.md` states the keyless assembled-journey
  rule and maps the Auto-Review guardian acceptance items to the engine
  journeys that exercise them (#5361).
- OrcaRouter's default endpoint is classified as an aggregator billing
  surface, so pricing and session-cost reporting use the correct billing
  posture instead of treating it as a first-party provider (#5493).
- Dependencies: ratatui 0.30.2, thiserror 2.0.20.

### Removed

- `dsh` integration: the exported-CSS skin file and its "skin export" status
  line (superseded by the bundle-applied `overrideTokens` skin, #5469).

## Contributors

- hexin (@h3c-hexin) — a concrete route/offering output limit outranks the
  8,192-token compatibility guess for an uncatalogued model (#5461, closes
  #5460); web tool results use the noisy soft limit (#5474); owned direct
  model casing resolves safely (#5475); and configured-skill prompts stay
  stable across ephemeral roots and operating systems (#5492, #5473).
- Gabriel-Degret (@Gabriel-Degret) — configurable auto-router classifier
  timeout (#5494; first contribution).
- @asto18089 — diagnosed the Z.ai `glm-5.2` casing collision and wrote the
  first provider-scoped fix in Pinvou/CodeWhale#14 (carried upstream in
  #5475).
- Reports and reproductions that shaped this release: @hardy922 (context-
  window honesty, #5239), @redstar (bwrap extra roots, #5410), @all-lopezg
  (SSE UTF-8 garbling on DeepSeek Flash, #5374), @alitvak69 (unverified live
  pricing, #5241), and @wuisabel-gif (the macOS filtered-suite hang
  investigation on #5056).

See [CHANGELOG.md](https://github.com/Hmbown/CodeWhale/blob/main/CHANGELOG.md) for full notes and [docs/CHANGELOG_ARCHIVE.md](https://github.com/Hmbown/CodeWhale/blob/main/docs/CHANGELOG_ARCHIVE.md) for older releases.