118 Commits
Author SHA1 Message Date
CodeWhale Bot 92b4900d15 fix(engine): stop replaying inference with unknown outcomes [skip ci]
Use typed dispatch confidence at retry owners; only proven transient
pre-dispatch failures, ordinary429 and actual read-only operations may
retry. Stop opened-stream replay and reqwest retry/redirect bypasses.
Keep Interrupted child handback and source-bound primary unknown coverage
through existing Runtime/TUI/exec owners; terminal exec failure exits1.
Reconcile retry promises and parsed compatibility knobs in maintained docs.

Validation: ordinary CLI build passed; 131 existing Engine and28 TUI
checks passed via126+28 unchanged-source reuse,3 corrected fixtures,2
corrected multi-thread SSE fixtures. No new tests or comments. Original
failed builds/check receipts retained. 40 local ordinary controls yielded
38 qualified and2 isolated safety-only observations retaining their full
source-accounting failure underP04. Old CLI reproduced2acceptedPOSTs/
2simulated effects; candidate ambiguous requests retained1/1 without
replay. Existing bounded429/GET/pre-dispatch and manual next-turn controls
passed. All2315 source inputs held frozen during each build/observation.

Limits: full primary late/historical/isolated source accounting and broader
P02 recovery remain open. HTTP/1 local proof only; no provider spend,
Windows/Deepin/FreeBSD, installed package or final CI/release claim.
Receipts: CW/artifacts/engine-0103-execution-20261102/
inference-retry-v4/RECEIPT.json and inference-retry-qa/RESULTS.json.
2026-11-02 02:32:26 -08:00
CodeWhale BotandClaude Opus 5.5 0cf390f01e feat(tui): change mode and permissions mid-turn; record steering in Unreleased (CW-7552)
Mode and permission posture can now change while a turn is running. Tab,
Shift+Tab, Alt shortcuts, /mode, the hotbar, /auto and /config mode|approval*
no longer hit the #2982 turn lock; model, thinking and provider stay locked
because they change the route the in-flight request is on.

Decision: a change applies at the engine's next step in the same turn, not at
the next turn and not by restarting the streaming response. The engine already
drains the live authority snapshot before each tool batch, at every approval
gate and at the per-step preparation boundary; a call nobody approved, or one
whose approval is narrowed, is returned to the model to retry. New: the
preparation boundary now records the mode notice (and Operate contract) via
Engine::record_mode_context, so the next model request is told the new mode
and the notice is a session message (model-visible means logged). While a turn
runs, the TUI shows "<Mode> · <permissions> — applies at the agent's next step
in this turn"; the engine's existing "Permissions: … · <mode>" status confirms
the apply.

Reference comparison (CW/refs): Codex steers at the next safe point and applies
/model and /permissions to the next turn; Grok Build queues by default, injects
steers at tool/model safe points and allows Plan/permission toggles mid-turn
with turn-start reminders. Neither preempts the in-flight request.

Steering itself: the preemption source from 4cf2d2cfff was proven, not changed.
Changelog entry added for it (it had none).

Touched paths:
  CHANGELOG.md, crates/tui/CHANGELOG.md (sync-changelog.sh output)
  crates/tui/src/core/engine.rs (record_mode_context; turn start uses it)
  crates/tui/src/core/engine/turn_loop/preparation.rs
  crates/tui/src/tui/app.rs, crates/tui/src/tui/app/tests.rs
  crates/tui/src/commands/config_main_host.rs
  crates/tui/src/tui/ui/provider_routes.rs (sync_mode_update takes &mut App)
  docs/MODES.md
Not included: uncommitted extension-host first-sync hunks in engine.rs,
extension_host/mod.rs and plugins/install/dsh.rs belong to another writer.

Evidence (candidate = 3400ebb5c9 + this diff + then-dirty provider files,
debug codewhale sha256 9f6d1934…052e):
- Live TUI (private tmux, sandboxed, loopback provider holding a reasoning
  stream): Tab×2 mid-turn moved Work→Plan with the pending notice, no lock
  message; double-Enter steer reached the provider 143 ms later before the held
  response was released; next request carried the steer once and the Plan
  notice once; obsolete text never shown. PASS_SCOPED. Installed 3400ebb5c9
  baseline: steer 130 ms OK, mode refused "Mode is locked while a turn is
  running". CW/artifacts/cw7552-steer-20261027/tui-runs/{baseline-3400-b,candidate-1}
- Runtime steering-probe.py on candidate: headers, reasoning, text, tool_json
  all PASS_SCOPED (also PASS on installed 3400ebb5c9, 28-33 ms).
- Tests (hermetic home, crate dir): tui::app::tests 238 passed 0 failed;
  commands::config_main_host 109/0; runtime_handoff 22/0;
  core::queued_approval_tests 1/0; tui::ui::tests::plan_handoff 13/0;
  core::engine::tests 524 passed 9 failed: 8 MCP extension-host fixtures
  ("built-in extension host is down"), failing identically before the test
  edits and outside touched code, plus recursive_rlm_round_waits_on_the_
  code_execution_gate, flaky under load (5/5 alone).
- Updated obsolete lock tests in app/tests.rs and config_main_host.rs; removed
  approval_aliases_are_inert_while_a_turn_is_running.
- rustfmt --check clean on touched files. No CI run (release step only).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-27 01:38:37 -07:00
CodeWhale BotandClaude Opus 5.5 f421390771 feat(tui): Ctrl+C clears a non-empty idle composer before arming exit
Founder decision on #6237 (option A, 2026-10-25): plain Ctrl+C on an idle
composer that holds a draft clears it recoverably, and Ctrl+Z restores it
through the existing ClearedInputRestore path. The two-tap exit prompt arms
only once the composer is empty. Cancel still beats clear: a selection
copies first, then an in-flight turn, compaction or goal-continuation wait
is cancelled, and only after that does a non-empty composer clear. This
reverses the #1757 one-meaning-per-key split for Ctrl+C. It matches the
muscle memory from sibling tools that the issue describes.

ctrl_c_disposition gains a ClearInput branch between CancelTurn and
ConfirmExit. The clear body that the Esc ClearInput arm had inline is now
App::clear_composer_draft: it resets backtrack, disarms quit, drops
edit_in_progress, makes the recoverable clear and shows the restore tip.
Esc and the new Ctrl+C arm both call it. Disarming quit on clear means a
cleared draft restarts the order clear, then arm, then exit. Without the
disarm, Ctrl+C on an empty composer, then typing, then Ctrl+C twice would
exit right after the clear. On main, an armed prompt plus a draft exited
on the very next Ctrl+C. Esc-clear now disarms a pending exit too.

PR #7084 also added a ClearInput arm to the launch-screen Ctrl+C block.
That arm is left out because the block cannot be reached:
LaunchState.composer_focus is always true. handle_launch_composer_key
returns ComposerAuthority for Ctrl+C, so the key falls through to the
session-shell arm, which also clears a launch-screen draft.

The PR's three new tests and its added rationale comments are not carried.
The existing doc comments are updated to the new priority order.
docs/KEYBINDINGS.md now lists the global Ctrl-C row in real priority order
and adds an editing-table row. The [Unreleased] CHANGELOG entry is added. In-app key help now names
draft clearing in all 15 locale packs; the install guide agrees. The
pre-existing vocabulary failure is corrected by advertising only the
canonical --full-access flag in the TUI guide; the parser alias remains.

Verified as one frozen batch at 7db526a725 plus consensus patch
sha256 d6418055436eaada55f4cbedc954a0eeeb51d9d922716a3588006cf7932fab45:
- scripts/with-hermetic-test-home.sh scripts/dev-cargo.sh nextest run
  -p codewhale-tui -p codewhale-localization --lib --locked:
  15343 run, 15341 passed, 2 failed, 25 skipped; build 3m41s.
  The two fixed-width rendered-fixture failures came from the long SSD
  TMPDIR wrapping paths mid-needle. Same source/binary, shorter SSD TMPDIR,
  only those two tests rerun: 2 passed, 15312 skipped. Distinct passing
  coverage across both runs: 15289 TUI + 54 localization tests.
- scripts/with-hermetic-test-home.sh scripts/dev-cargo.sh test
  --manifest-path vendor/codewhale-ratatui/Cargo.toml --locked --all-targets:
  145 passed, 0 failed (128 library and 17 example tests).
- fmt and diff checks passed; changelog sync passed; runtime boundary PASS
  (120 closure modules); dead-code budget 212; blocking-call budget 543
  across 165 files; locale parity 2583 keys in all 15 packs.
- The vocabulary guard initially failed on an already-published advertised
  legacy alias. Both refuters confirmed the docs-only correction; the
  unchanged guard then passed. Web prebuild and check-facts passed.
Before peer reconciliation, only .gitignore, docs/MODES.md and generated web
documentation changed after native tests; frozen compiler inputs were identical.
Published peer commits aa45bf84ef/485382f81d then advanced main. Their exact
diff was integrated, preserving their ancestry and regenerating web docs.
Focused reconciliation nextest (TUI ops/runtime_info/spawn and CLI cloud
callers): 117 passed, 0 failed, 15698 skipped; source remained frozen
(104 TUI, 13 CLI). Command/filter and source SHA256
are retained in coordination/land-0103-20261025/reconciliation-test-run.json.
Final integrated tree f297b67c73 is checked against the regenerated commits.
macOS ld emitted its __eh_frame size warning. No hosted CI, FreeBSD/Linux
compile, paid provider call, install, deploy, or release is claimed.

Based on PR #7084 by @Hmbown.
Fixes #6237

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-25 02:15:38 -07:00
CodeWhale BotandClaude Opus 5.5 135319aa1a feat(acp): --full-access flag for serve --acp, accepted after the subcommand
Probing the installed 0.10.2 binary over ACP showed three things:
- `codewhale serve --acp` runs under Ask;
- `codewhale --yolo serve --acp` runs under Full Access;
- `codewhale serve --acp --yolo` is rejected ("unexpected argument", exit 2).
That last form is the one editors write in their agent config. Founder
decision: Full Access is yolo (ApprovalMode::Bypass). A configured
`sandbox_mode = "danger-full-access"` must not widen Ask or Auto-Review, and
no state may have the sandbox off while the agent still asks.

Changes:
- `--full-access` is the visible flag; `--yolo` stays an alias
  (runtime_options.rs).
- The dispatcher lifts `--full-access` and `--yolo` out of the `serve`
  passthrough arguments (`capture_serve_full_access`), stopping at a `--`
  separator. It sets the same runtime option as the global flag, so the
  value still flows through the CODEWHALE_YOLO env layer, and managed
  config above that layer still wins. Setting `config.yolo` after load
  would have bypassed a managed `yolo = false`.
- `serve --acp` writes one stderr line naming the ACP permission and
  sandbox it will run with, computed with `sandbox_policy_for_turn`. When
  Full Access is off, the line says how to turn it on.
- The ACP hint and the approval_policy "never" error name `--full-access`.
- `SandboxPolicy::config_value()` replaces a duplicated match in
  `apply_requirements`.
- docs/MODES.md, docs/RUNTIME_API.md and CHANGELOG are updated.

Verified:
- `scripts/dev-cargo.sh build -p codewhale-cli --locked`: built, 0
  warnings.
- The built binary was probed over ACP. For each launch, a fresh
  CODEWHALE_HOME and runtime dir; then `initialize`, `session/new`, and a
  read of the `permission` configOption:
  - `serve --acp`: ask. stderr: "ACP permission: ask; sandbox:
    workspace-write. For Full Access start with `codewhale serve --acp
    --full-access` ...".
  - `--full-access serve --acp`: full-access, with sandbox
    danger-full-access.
  - `serve --acp --full-access`: full-access.
  - `serve --acp --yolo`: full-access.
- nextest codewhale-cli, filtered: 36 passed, including
  `clap_command_definition_is_consistent` and
  `yolo_flag_writes_only_the_codewhale_env_var`.
- nextest codewhale-tui, filtered to acp_server, requirements,
  sandbox::policy and runtime_options: 61 passed (38 acp_server, 6
  requirements).
- Not run: clippy, Windows, hosted CI.

The Seatbelt half of #4955 is not done.

Refs #6992 #4955

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-24 22:27:30 -07:00
CodeWhale BotandClaude Opus 5.5 7d9ebfffeb fix: retry Chat opens on both HTTP versions, give body text an explicit ink, name the export command at every resume, and tell a read-only shell it is offline
Five founder-approved 0.10.2 riders, each independently reviewed by an
adversarial reader before landing.

#7045 — the Chat (SSE) stream open now goes through `client_for_policy` and
`send_stream_open_with_retry` on both the default HTTP/2 policy and the
HTTP/1.1 fallback, instead of a separate single-send fallback path that
returned a raw response. The `reasoning_content` diagnostic moved onto the
open error, so it also covers the default path, and the post-open non-success
branch is a typed `LlmError`, matching the Responses adapter.
`open_stream_json_with_retry` had no other caller and is deleted.
Still open from #7045: the retry budget is bounded by
`[stream] open_timeout_secs`; a plan-usage 429 is still classified as a
transient rate limit; the "Retry stopped" line still names a per-kind counter.

#7043 — the modal and underwater surfaces, fleet setup, the automations view,
the worktree manager and three sites that had only a background now set
`fg(palette::TEXT_PRIMARY)` for body text, so a surface's ink no longer
depends on what was painted before it. `color_compat::enforce_cell_contrast`
now maps `TEXT_BODY` to the terminal's own ink when the cell is unpainted (a
`Color::Reset` background) and no ground was measured, which covers the
ivory-on-white case on an unmeasured light terminal. Measured and painted
grounds keep the previous behaviour.
Existing test updated: `unknown_background_leaves_unpainted_cells_alone`
became `unknown_background_gives_unpainted_body_text_the_terminal_ink`, which
is what the change makes true.
Deliberately NOT changed: the live transcript's block style. Its parity test
`mounted_transcript_live_overlay_stream_resize_preview_and_links_match_frozen_painter`
renders the legacy painter and the new one and asserts identical buffers; an
`fg` on one side only breaks that contract, and the transcript's body text
already gets correct ink from the contrast floor above.

#6996 — `session_export::export_recovery_hint(id)` words the remedy once and
names the real session id. It is used at the TUI resume, the executor resume
and the Runtime API. `map_resume_thread_create_err` takes the session id and
also treats "persisted provider route requires exact custom provider" as a
client error, where it was previously reported as a 500.

#7040 — `READONLY_OFFLINE_NETWORK_HINT` tells a refused read-only command that
the run has no network, what would grant one, and to use a web tool or report
the source unreachable. Emitted only when the command plausibly needs the
network AND the result was sandbox-denied or looks like a network failure, and
never over a bwrap setup failure that has its own hint.
`finish_contract_bash_result` takes the hint as a new trailing parameter; both
test call sites are updated. Known limit: a network attempt from Python or
`gh` still gets no hint.

#6992 — SANDBOX.md and CONFIGURATION.md, English and Chinese, now state that
`sandbox_mode` can only narrow the sandbox the permission mode already
chooses, so `danger-full-access` and `external-sandbox` take effect only in
Full Access. Documentation only.

Verification: k90 nextest (crates/tui lib, 22 filters): 4838 tests run, 4835 passed, 3 failed; after the three fixes below, the same 4838-test binary rerun of exactly those 3: 3 passed, 0 failed. cargo check -p codewhale-tui --lib --tests: exit 0 (12m26s). cargo fmt --all -- --check: exit 0.

Refs #7045
Refs #7043
Refs #6996
Refs #7040
Refs #6992

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-21 20:35:59 -07:00
CodeWhale BotandClaude Opus 5.5 7b16979c64 feat(auto-review): stop a turn after repeated guardian denials
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. The breaker sentence is carried as the turn's
error, so hosts and runtime threads record it. Docs: docs/MODES.md and the
zh_hans edition. Observed on the batch binary with a loopback mock whose guardian
replies always deny: exactly three reviewer requests, then the footer
reads "Auto-Review denied 3 actions in a row, so the turn was stopped."
(artifacts/takeover-0102-20261021/obs/sessions).

Refs #6478

Batch evidence (one combined tree, input hash a47518092a4c49de37d93381d392aec4fc4c28fd612f6e6192d327acf4736d95; the intermediate
commits of this batch were not compiled on their own, only the combined
tree): cargo fmt --check clean; tui lib nextest over the lane filters 4096
passed, 0 failed, plus 1268 passed after the changelog edit; fp55
shared-process cargo test 161 passed, 0 failed, 1 ignored; tui integration
install::/skill_cli:: 42 passed, 0 failed; conformance goldens regenerated, 33
passed; execpolicy 89 command_safety and 256 crate tests passed; lane 74;
runtime continual_harness 8; config private_directory 12, route/models_dev
121, configured_models 9; app-server daemon_client 1, daemon_socket 15;
localization 54; clippy -D warnings on tui, execpolicy, lane, runtime,
app-server and config clean with CI's exact flags (the plan's stricter run flagged 26 pre-existing sites outside the batch: 25 are lints CI allows, one collapsible_if is fixed in this batch); cargo check tui --all-targets
clean (a first run failed on a half-applied call-site change of the citation fix; the rerun after the fix passed); aarch64-unknown-linux-gnu check of tui, app-server and config
not run: the ring and libdbus-sys build scripts fail for the cross target on this Mac, so the Linux-only bubblewrap and boot-id paths were not type-checked here and need a Linux host; blocking-call budget 540 sites within budget; dead-code budget
214 at budget; sync-changelog --check, check-versions,
check-bundled-plugin-claims, sync-marketplace --check and web check-facts
all passed; npm wrapper node --test 101 passed, 0 failed. No hosted CI ran;
final validation owns that.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-21 08:59:21 -07:00
ac5b611fe0 fix: complete 0.10.2 terminal and release blockers
Match undo snapshots conservatively for long, multiline and trimmed prompts;
keep terminal outcomes attached to the unchanged conversation prefix through
rewinds, replacement and branching. Document exec Full Access, reject misplaced
flags, honor stricter sandboxes, and report actual enforcement. Save tool-enabled
exec sessions in every format with terminal failures and separate retention.
Restore local-runtime onboarding and update complete locale packs and docs.

Serialize RC test-binary builds to avoid the reproduced linker OOM. Replace
both Chocolatey NSIS consumers with a checksum-pinned official installer and
verified compiler version. Put the release summary first, retain detailed notes
and contributor credits, and set an explicit release title.

Validation on frozen 849af501cf plus this diff: workspace check and CI-flag
Clippy passed; formatting passed; focused TUI 683 passed, 0 failed, 1 ignored;
CLI 541 passed, 0 failed; feature registry 2 passed; localization 54 passed.
The registry ran with the empty default feature disabled; an earlier redundant
build was intentionally interrupted before tests. Source hashes stayed fixed.
After excluding the held change and folding the pending changelog into
0.10.2 dated 2026-10-19, regenerated web data and ran the literal gate:
npm test && npm run check:web passed. Wrapper 101, runtime SDK 19,
extension host 413 passed/7 skipped, web 772 passed, dependency security 7
passed; all failure counts zero. Source hashes remained unchanged.
The earlier stale-catalog failure was repaired before this final gate.
README translations (18), locale coverage (16), release-body tests, dated
version/changelog contracts and OHOS dependency guard passed. Final release
body rendering preserves all notes and credits outside the held entry.
Workflow syntax passed; full ShellCheck retained the same 12 pre-existing
warnings. Independent reviews found no remaining concrete issue in scope.

Held session-only key commit 849af501cf is excluded before pushing. The final
candidate still needs exact-SHA hosted CI, RC artifacts and binary walkthrough;
local checks do not qualify Windows provisioning, deployment or publication.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Codex <[email protected]>
2026-10-19 11:55:30 -07:00
CodeWhale BotandClaude Opus 5.5 ecf50ab598 fix(engine,shell): harness fixes from the DeepSeek/DSH parity comparison
On 2026-10-17 Codewhale and DeepSeek's own harness, DSH 0.2.1-rc.2, were
compared on deepseek-flash (DeepSeek-V4.1-Flash-1017). The comparison
covered wire format, multi-turn state, cache, prompt and tool surface, and
mined 185 exec runs and 310 local sessions. A skeptic re-checked every
finding. A blind patch A/B scored Codewhale's edit mode 5/5, DSH 3/5 and
read-only JSON patches 2/5. Evidence is in
CW/artifacts/deepseek-harness-parity-20261017/. This commit fixes the
contained defects; CW-7450 tracks the rest.

- zsh: the tool named bash runs $SHELL, and zsh's NOMATCH and EQUALS
  options broke Bash idioms the model writes, such as
  grep --include=*.rs and [ "$a" == "$b" ]. That caused 334 failures in
  196 of 310 sessions, and in exec runs 175 greps never ran.
  ShellDispatcher::build_command_parts now starts zsh with
  +o nomatch +o equals (ShellKind::is_zsh), and ZSH_GUIDANCE says so.
  Display still uses the requested command. The same dispatcher runs
  user ! commands.
- task_shell_wait is now in DEFAULT_ACTIVE_NATIVE_TOOLS. bash and its
  backgrounded results tell the model to call it directly and not to
  sleep-poll. Before, every long job cost a tool_search round trip plus a
  change:tool_surface re-pin (188 tool_search calls, 208 "sleep N"
  commands). KV-cache effect: the frozen prefix grows by one small tool
  schema, and the mid-session re-pin goes away. TOOL_SURFACE.md (en and
  zh_hans), MODES.md, public-surface-facts.json, web tools copy, the
  conformance goldens and the tests that pin the default list are updated.
- exec_stream_final_answer_text skips runtime-owned user messages
  (runtime_handoff::is_runtime_owned_user_message) when locating the turn
  start. A background-shell completion appended after the answer no longer
  makes the receipt report an empty final answer, which happened in 52 of
  185 runs; fleet then recorded no answer.
- The engine's local stop_reason_is_output_limit is deleted, and
  continuation.rs now uses codewhale_models::is_output_limit_stop_reason,
  which strips the incomplete: prefix that the Responses parser adds.
  A reasoning-only output-limit stop on deepseek-flash is no longer
  re-sent up to two more times, and it now reports the output-limit
  message. The three extra spellings the local helper knew (model_length,
  output_limit, max_completion_tokens) move into the shared helper. The
  misplaced should_fail_no_sendable_content doc comment goes back on its
  function.
- tool_choice "none" now reaches the provider. The Responses builder
  forwards none and keeps sending auto for every other choice, and the
  DeepSeek Chat path keeps none while thinking is on; required and named
  choices are still dropped there because DeepSeek returns a 400 for them.
  The compaction known-limit comment is updated to match.
- is_incomplete_stop_reason treats insufficient_system_resource and
  aborted, DeepSeek Chat's interrupted-generation finish reasons, as
  incomplete.

Every item except the zsh change was drafted by Codewhale running
DeepSeek-V4.1-Flash-1017 in scratch exports. Claude reviewed each diff and
corrected two of them: the stop spellings the shared helper lacked, and
the stale compaction comment.

Gates for this batch (source 0d906da665 plus the six commits of this push,
before rebasing onto 20234af6d6):
- cargo fmt --all --check: clean.
- check-blocking-calls-budget: 539 sites, within budget.
- codewhale-models lib: 40 passed.
- codewhale-config lib: 800 passed, 1 skipped.
- codewhale-cli lib: 501 passed, 0 failed.
- codewhale-tui lib: 15,326 run, 15,320 passed, 6 failed.
  - Three failures were expected from the tool-text change. The
    conformance goldens were re-recorded (CODEWHALE_CONFORMANCE_UPDATE=1)
    and the zsh guidance assertion updated; conformance plus that test
    then passed 34/34.
  - Three are tools::test_runner tests that fail on this host only: the
    nested cargo inherits dev-cache CARGO_BUILD_BUILD_DIR and gets
    "Operation not permitted". Not touched here.
- CI-form clippy -p codewhale-models -p codewhale-cli -p codewhale-tui
  -p codewhale-config --all-targets --all-features -D warnings: clean,
  after one needless_question_mark fix in runtime_api.rs.
- check-facts OK; check-versions OK.

Refs CW-7450

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01NBKbhx19BRbZtvWK8rVKjz
2026-10-17 05:13:54 -07:00
CodeWhale BotandClaude Opus 5.5 b093b61cea docs(modes): list /provider among the slash surfaces the turn lock covers
docs/MODES.md (en, zh_hans) said every live-route change, provider included,
is refused mid-turn on every surface. For /provider and the provider picker
that was only true from faaf61be64 on. The slash-surface list now names
/provider as well. web/data/agent-docs.generated.json was regenerated by
`npm --prefix web run prebuild`.

Verification: npm run check:web exit 0. node web/scripts/check-facts.mjs OK.

Refs #2982

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01NBKbhx19BRbZtvWK8rVKjz
2026-10-16 12:06:11 -07:00
Hunter BownandClaude Opus 5.5 be980da403 0.10.2 candidate: endpoint-scoped catalog, tiered pricing and release verification (#6968)
Squash of the 0.10.2 candidate branch wip/0.10.2-6396-handoff-20261012:
endpoint-scoped model catalog and tiered pricing (#6396), the takeover
fixes found while qualifying it, and the release-verification tooling.
The full commit list and per-commit evidence are in PR #6968.

Qualification of the squashed tree (head 704d435db1, a clean merge of
main b5e270b690 into ba01538bc9 with no manual conflict resolutions):
- Hosted CI on 704d435db1: 40 checks passed, 4 skipped (Cloudflare
  deploy and its approval gate, fork-only macOS budget/eval, docs), 0
  failed. Run 38848133339.
- nextest: Ubuntu 19101/19101 passed (34 skipped), Windows 18357/18357
  passed (27 skipped), macOS 19104/19104 passed (33 skipped).
- Local on the same head: clippy with CI's flags clean; 667/667 focused
  nextest; npm test 547 Node (540 passed, 7 skipped, 0 failed) and 772
  Vitest passed; npm run check:web exit 0.
- Main was frozen from b5e270b690 until this squash, so the squashed
  tree is the tested tree.

Not covered here: the crates.io publish, tags and the GitHub release,
which remain the founder's. Merged under the founder's 2026-10-13
authorization to squash #6968 after its final head passes CI and review.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01NBKbhx19BRbZtvWK8rVKjz
2026-10-16 14:35:46 +08:00
CodeWhale BotandClaude Sonnet 5.5 e6c08cf168 docs: drop the Full Access confirmation from modes, keybindings, runtime API and the 0.10.2 notes
Refs #6470. Follows the removal of the confirmation modal: MODES, KEYBINDINGS
(en, zh-Hans) and RUNTIME_API (en, zh-Hans) no longer describe the popup,
full_access_repos or the full_access_confirmation 400, and the 0.10.2 bullet
now says only what ships: a 'Permissions changed to ...' transcript line plus a
status item and thread.permissions_changed event in runtime threads.
crates/tui/CHANGELOG.md regenerated with scripts/sync-changelog.sh; web
lib/changelog.generated.ts is unchanged (derive-changelog.mjs reports current).
web vitest: 772 passed; check-versions, readme translations, locale parity pass.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-11 00:05:11 -07:00
CodeWhale BotandClaude Sonnet 5.5 f51193b368 docs: resync 18 README translations with the 0.10.2 README and drop retired vocabulary from MODES
34bf6568f2 changed README.md (exec --auto, the exec table row, bubblewrap wording) without retranslating, and 94549b79e0 Lint failed check-readme-translations on every locale. The three edits were applied to all 18 translations and the source stamp moved to sha256:75bb6a506af5 (translations drafted by a Sonnet subagent; fr and ja spot-read by me, other locales unreviewed by a native speaker). docs/MODES.md no longer names the legacy launch flag, which the product-vocabulary ratchet rejects.

check-readme-translations: OK, 18 translations in sync. check-readme-locales, check-tui-locale-parity, check-tui-product-vocabulary and web check-locales: PASS.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-10 08:25:39 -07:00
CodeWhale BotandClaude Sonnet 5.5 58d082898c docs(modes): Shift+Tab away from repo-kept Full Access removes the saved grant
Observed in the real-terminal full-access journey on 0.10.2 (e4867e34ad); documents current behavior, no code change.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-10 06:22:10 -07:00
CodeWhale BotandClaude Sonnet 5.5 34bf6568f2 0.10.2 candidate: MCP connects at start, background promotion, shell inspector, Full Access confirmation, Daytona and Sprite removal, composer-first launch, QA fixes
One integrated slice of the 0.10.2 release work, three-way merged onto
64bb073a4. User-visible changes (details and per-item evidence in CHANGELOG.md):

- MCP: user-configured servers connect in the background at session start
  (`lazy = true` opts out, `required` still blocks, plugin-contributed servers
  stay on demand); a finished OAuth login reconnects that one server;
  `/mcp reload` redials every non-lazy server; the reload summary reports a
  not-connected count and the configured total.
- #6944: bash promotes itself to the background after 30 s with elapsed time,
  last-output age and a cargo-shaped phase hint; kills say how far it got;
  task_shell_start is removed in favour of one background path.
- #6931: a live shell inspector (cwd, owner, state, bounded output, stop);
  Alt+V opens the newest running shell when nothing is selected; dock rows
  share the formatter.
- #6470: entering Full Access asks first (session by default, per-repo opt-in
  full_access_repos), chip text carries the scope, permission changes are
  receipted in the transcript and as a runtime status item; a saved
  full-access posture migrates to Ask once. Runtime API: PATCH into Full
  Access without full_access_confirmation is a 400 (documented).
- Daytona and Sprites are gone from the engine: own-sandbox dispatch
  (`--own-sandbox`, `/dispatch`, `agent runtime:"cloud"`, cloud-agent alias),
  cloud_dispatch.rs, dispatch_runner.rs, cloud_proposal.rs, computer_meter and
  the computer-use Sprite task-hold are deleted (archived in
  codewhale-hq/codewhale-sandboxes b68803e); logout sweeps a stored legacy
  sandbox token. `codewhale dispatch` is account-only, requires an actionable
  or queued intent, prints the Message ID, and prompts only when stdin and
  stdout are terminals. The CLI never prints a code or prose naming the VM
  vendor or retired providers.
- CW-7167: a keyless first launch opens on the composer; the first send opens
  the provider picker with the draft kept; the first-run picker shows the typed
  filter (CW-7170). A local runtime is offered only when Ollama answers.
- QA fixes: unknown --profile and a missing explicit --config fail loudly, -C
  on a missing directory errors, `codewhale web` works under a root-owned
  symlinked HOME ancestor (user-controlled symlinks are still rejected),
  `/exi` Enter fills instead of running destructive commands, Shift+Tab hint
  stays in Auto/Full Access, a crashed session shows an interrupted marker,
  help/exit-code fixes, README exec examples, zh docs. #6728: the pet owner
  stops building frames while nobody views.
- Credit: @xiaoray-blip (0.9.8) and @xyzs996 (0.9.11) added to AUTHOR_MAP,
  CONTRIBUTORS and the CHANGELOG; 0.9.9 placement for @Lstarsky0 and
  @SparkofSpike.

Evidence (2026-10-10, local only, on this exact tree):
- cargo clippy --workspace --all-targets --all-features --locked with CI's
  flags: exit 0.
- cargo nextest run --workspace --locked: 18981 tests, 18978 passed, 3 failed;
  the three are tools::test_runner::tests::* (environment-only: nested cargo
  inherits this machine's build-dir wrapper; they pass in CI).
- scripts/check-dead-code-budget.py PASS 221; check-blocking-calls-budget.py
  within budget (537 sites; private_directory.rs records one canonicalize and
  one std_fs: sync startup path resolution, not on the async runtime);
  check-command-crate-boundaries.py PASS; module_graph.py --check PASS;
  check-contributor-credit.py v0.10.1 clean; check-versions.sh OK (0.10.2).
- cargo fmt --all -- --check clean. Conformance goldens regenerated for the
  tool-catalog change (task_shell_start removed, bash description).
Not verified: hosted CI on this commit, a real-TTY run of composer-first
launch, MCP default connect, the shell inspector and the Full Access modal,
bwrap on Linux, a real provider turn, the live ChatGPT sign-in (#6925), a real
dispatch against the account service, and re-measuring
runtime-contract-budget on Linux.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-10 03:19:16 -07:00
CodeWhale Bot bdcc8cfc5f fix(tui): let Full Access actually grant Full Access; finish the file-search surface
Full Access is ApprovalMode::Bypass, but the deterministic Auto-Review floor
still hard-blocked calls under it: publish-like commands, destructive
background/headless work, and the Windows npm-launcher platform hold all
returned AutoReviewPlanDecision::Block. The founder's own semantics for the
posture are the opposite, and the engine already reports "Full Access" for it.

The floor now applies only in the reviewing postures (Suggest/Auto/Never).
ForcePrompt stays unchanged there; the Bypass arm of the disposition is gone
rather than merely unreachable, because it was the code that authored the
contradiction.

Existing tests updated to the posture they now describe (no new tests):
- policy-level: destroyer and publish-shape assertions run under Suggest,
  Bypass coverage asserts no hold, the Windows platform-floor test splits
  Bypass from the reviewing postures
- engine-level: the background-destructive test now requires execution
  (victim fixture asserted written) instead of a block
- child gate: a detached agent's catastrophic shell is held in Auto/Suggest/
  Never and runs under Bypass
- ACP: the Full Access case asserts one fewer failure and one more completed
  and in_progress update, matching the call that now executes

Also completes the file-search promotion rows: the eager inventory literal
gains file_search behind FIM's already-landed exclusion, the hook classifier
table gains ("file_search", "other"), the canonical-action comment no longer
calls it deferred, the zh TOOL_SURFACE mirror matches the shipped twelve, and
file_search.rs is rustfmt-clean under the repo build lock.

Names the built-in safety floor as a reviewing-posture guard in docs/MODES.md,
docs/SUBAGENTS.md and the zh mirrors.

Test evidence: nextest -p codewhale-tui focused set (auto_review, acp_server,
child_permission_gate, child_host, test_cases_08/09/11/12, subagent tests)
34 passed / 0 failed on the final run; the wider 708-test run before it passed
704 with only the four assertions updated here failing.
2026-10-09 04:11:16 -07:00
CodeWhale BotandClaude Haiku 5.5 1bddf50a7e fix(tui): repair undo identity, child approvals, plan handoff, OCR test
Land the four 0.10.2 release repairs from the frozen review batch. The
source reviews passed. This commit adds local compile and focused-namespace
evidence, not hosted CI. Hosted CI on this head is the full proof.

Repairs:

- Undo (commands/contract/debug_operations.rs,
  commands/debug_mutation_host_tests.rs): refuse ambiguous, repeated,
  truncated, multiline, missing or multipart request labels instead of
  matching display snippets. Exactly one held match is required, and force
  cannot bypass identity checks. Addresses the P1 review on
  debug_operations.rs:245-251.
- Child approvals (core/engine/handle.rs, child_host.rs, tools/subagent/*):
  keep ApprovalDecider through the child Approved and Denied outcomes, so
  receipts attribute the actual decider. A timeout stays a denial,
  attributed to Host. Consumers migrated. Managed Computer Use consent
  authority is unchanged.
- Plan handoff (tui/plan_handoff.rs, tui/app.rs, tui/app/init.rs,
  tui/ui/*, docs/GUIDE.md, docs/MODES.md, docs/zh_hans/GUIDE.md):
  successful nonempty Plan prose offers handoff and queues its exact text
  once. Failed preparation rolls back only an unchanged owned seed.
  Refs #6902. Addresses the P2 review on plan_handoff.rs:48.
- OCR and CI (tools/image_ocr/host_tests.rs, .config/nextest.toml,
  .github/workflows/ci.yml): the cancellation fixture waits on an explicit
  descendant latch and observes cleanup, instead of racing a one-second
  write. OCR and PDF host tests join the max-threads-1 group. macOS test
  compilation sets CARGO_PROFILE_TEST_DEBUG=0 before cache setup.

Local evidence (macOS arm64, debug, library tests; not CI):

- cargo test -p codewhale-tui --lib --locked --no-run -j 2: exit 0,
  0 errors, one linker note.
- With RUST_MIN_STACK=8388608 (the workflow value in ci.yml):
  plan_handoff 16 passed, 0 failed; core::engine::tests::child_host
  19 passed, 0 failed.
- With the 2 MiB default test-thread stack: plan_handoff 15 of 16 and
  child_host 10 of 19 pass. The rest overflow the stack in debug builds.
  Measured stack need is 4 to 8 MiB. All nine child_host tests exist at
  HEAD and passed HEAD's CI on Linux and macOS.
- debug_mutation_host_tests 38 of 38; the approval routing test
  an_agent_approval_answer_reaches_the_agent_while_the_engine_is_busy
  1 of 1; image_ocr::host_tests 8 of 8, including
  real_host_ocr_cancellation_bounds_parser_tree_and_never_replays.
- cargo fmt -p codewhale-tui -- --check and git diff --check: clean.

Not run here: the full 19k-test suite, nextest, Windows, doctests, and
hosted macOS timing. The previous macOS job exceeded 2h45m.

Limits, as reviewed: checkpoint admission is queued acceptance, not disk
durability, and an accepted queued checkpoint cannot be recalled. Pending
Plan ownership is ephemeral. No restart recovery or permanent custody is
claimed.

Signed-off-by: CodeWhale Bot <[email protected]>
Co-Authored-By: Claude Haiku 5.5 <[email protected]>
2026-10-08 17:37:50 -07:00
CodeWhale BotandClaude Opus 5.5 6abe4d4445 wip(0.10.2): plan-handoff-regression
Applied cleanly on top of edit-approval-preview and approval-default-and-labels;
all 15 locale packs carry the same 2486 keys as en.json.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-07 15:35:19 -07:00
CodeWhale BotandClaude Opus 5.5 559442d09a wip(0.10.2): esc-esc-rewind-files
The footer change itself is already in the undo commit with the wording from
UNDO-DESIGN.md ('Files not changed; conversation rewound. /undo puts files
back'), so this patch's BACKTRACK_REWOUND_NOTICE hunk in apply.rs is dropped.
Kept: the docs and the footer-width test, rewritten to the design wording.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-07 15:35:07 -07:00
CodeWhale BotandClaude Opus 5.5 9dbc2efe1a fix: name an exhausted xAI account, keep refusal reasons readable, and make Operate the full-strength mode
- llm_client: a 403 whose body says the account is out of credits
  (xAI: "You have run out of credits or need a Grok subscription") is
  QuotaExhausted, not AuthorizationError. Out-of-credits phrases join the
  quota evidence set.
- sanitize: a key ending in an outcome word (failed, denied, rejected,
  expired, ...) is never a credential, so "Authorization failed: <reason>"
  no longer renders as "Authorization failed: [redacted]".
- Operate contract (runtime_handoff): same tools and authority as Work,
  used at full strength. Each substantive request becomes a goal via
  create_goal (the host never created one, contrary to the old text), plan
  kept in todo_write, workflows and parallel agents by default, independent
  review before done, background commands, automations offered with
  approval. Removes the old hold-back lines.
- todo_write: tells models to keep a list for multi-step work instead of
  "Optional"; deletes the test that forbade that guidance.
- Mode hint and docs/MODES.md describe Operate the same way; conformance
  goldens re-recorded; parent prompt ceiling re-measured to 89,602 B.

Tests (macOS): sanitize+config redact 37 passed; llm_client/runtime_handoff
/todo/quota 129 passed; conformance:: 33 passed after re-record;
parent_agent_surface_stays_within_measured_ceiling passes.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-05 10:32:02 -07:00
Hunter B c0fa462ad6 docs: reconcile interactive questions and Chinese session wording with runtime
Auto-Review still exposes deliberate questions in interactive hosts; omitted or zero question timeout is indefinite. Remove a stale provider-count claim and update two Chinese wording expectations to the reviewed current-session labels. Combined localization tests52/0; full npm740/0 and check:web passed. Command boundary and migration checks passed. Chinese native layout and real provider qualification remain separate.

Signed-off-by: Hunter B <[email protected]>
2026-09-29 21:17:01 -07:00
CodeWhale BotandClaude Opus 5.5 9a775fbf03 fix(exec): keep a positional - prompt literal; test the exec dispatch (#6688)
Review of #6692:

1. A lone positional `-` read stdin, which changed behavior for raw-prompt
   callers: cloud dispatch builds `codewhale exec --auto <job.prompt>`, so a
   job whose prompt is `-` would block on or fail reading stdin. Only
   `--prompt-file -` reads stdin now; a positional `-` is prompt text again.
   Help text, docs/MODES.md (+ zh_hans) and the CHANGELOG say so.
2. The tests called `resolve_exec_prompt` directly and would pass with the
   exec dispatch call site reverted. A new integration test runs the real
   `codewhale-tui exec` binary against a wiremock provider and checks the
   user message the model receives: a 200 KiB `--prompt-file` body, a
   `--prompt-file -` stdin body, and a literal `-` with stdin piped (never
   read).

Tests:
- cargo test -p codewhale-tui --lib -- exec_prompt_file read_capped_text
  exec_accepts_split exec_keeps
  test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 13795 filtered out
- cargo test -p codewhale-tui --test integration -- exec_turn_usage
  test result: ok. 9 passed; 0 failed; 0 ignored; 0 measured; 179 filtered out
- Dispatch call site reverted to `join_prompt_parts(&args.prompt)`:
  exec_prompt_reaches_the_model_from_prompt_file_and_stdin
  test result: FAILED. 0 passed; 1 failed (left: "")
- Lone positional `-` arm restored: the unit test blocked reading stdin
  (killed after 9 minutes), which is the regression itself.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_014ZwqatxgVFxHvovngywnks
2026-09-27 20:35:59 -07:00
CodeWhale BotandClaude Opus 5.5 d0b42c215d fix(exec): read the prompt from --prompt-file or stdin (#6688)
Cause: `codewhale exec` accepted its prompt only as positional argv, so a
prompt past the kernel's per-argument ceiling (131071 bytes on Linux) failed
with E2BIG before Codewhale started, with no alternative transport.

Fix: add `--prompt-file <PATH>` (`-` = stdin), mutually exclusive with the
positional prompt, which is now `required_unless_present = "prompt_file"`; a
lone positional `-` also reads stdin. `resolve_exec_prompt` produces the
effective prompt before any model call and fails loudly on a missing,
unreadable, non-UTF-8 or empty source. Reading goes through a shared
`read_capped_text` (also used by `apply`'s stdin patch reader) with a named
64 MiB byte limit. `-` is refused with `--parent-death-watch`, which owns
stdin for Fleet workers. Implicit stdin reading when no prompt is given is
not added: exec callers (Fleet) inherit pipes on stdin. An argv-side byte
guard is not possible: the kernel rejects the exec before Codewhale runs.

Tests:
- cargo test -p codewhale-tui --lib -- exec_prompt_file read_capped_text
  exec_accepts_split exec_keeps
  test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 13795 filtered out
- With resolve_exec_prompt reverted to the pre-fix argv join:
  test result: FAILED. 0 passed; 1 failed (left: "" vs the 540 KB file body)
- Built binary: 540001-byte file via --prompt-file and via `cat | exec -`
  resolve and reach provider routing; empty stdin -> "exec prompt from stdin
  is empty"; missing file -> "failed to open --prompt-file nope.txt";
  positional + --prompt-file -> clap ArgumentConflict.

Fixes #6688

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_014ZwqatxgVFxHvovngywnks
2026-09-27 20:06:47 -07:00
CodeWhale BotandClaude Opus 5.5 669c32d53f fix(approvals): keep Full Access for destructive MCP tools; doctor and dismissal edge cases
Review of the 0.10.1 addendum-remainder commits (CW-11, U7, policy rule 9).

CW-11 (b90590369):
- The destructiveHint branch set auto_approve=false under Full Access. Every
  host then got an approval request, and `codewhale exec` answers from its
  own --auto flag, so exec with approval_policy = "full-access" in config
  (and no --auto) denied every destructive-declared MCP call (all Computer
  Use input tools declare it). The TUI and runtime auto-approved it anyway,
  and a session grant still covered it. So the promised "keeps its prompt"
  never held anywhere, and one host broke. Full Access again covers these
  tools (#3866). destructiveHint still withholds the reviewed-plugin
  read-only relaxation and labels the card. docs/MODES.md now says exactly
  that.
- Preparation let a bounded worker (tool_authority) run a plugin-declared
  read-only MCP tool, but tool_execution refuses every non-built-in MCP
  tool for such a worker. So an Auto call passed preparation and failed at
  execution. Preparation now applies the execution gate's rule.

U7 (05ff7c753, d2b1430cc): first_run_ready accepts ProviderModel
NeedsAction (a failed key still reaches the wizard's ready screen), so
doctor printed "Ready: setup is complete." for a finished setup whose key
was never confirmed. The provider check now runs first.

Policy rule 9 (735fb509a): the saved dismissal list is matched and listed
case-insensitively. A hand-edited mixed-case entry could not be reset by
name and was listed twice.

No-Issue: 0.10.1 addendum review (C5/CW-11, U7, PLG-12)

Checks (targeted, local; the shared tree also held a peer's deny.toml edit):
- cargo test -p codewhale-tui --lib -- mcp_annotation_hints only_a_reviewed_plugin
  mcp_write_preparation a_fresh_home_is_not_ready finished_setup_with_an_unconfirmed_key
  plugin_dismissals fleet_run_check agent_run: 17 passed, 0 failed
- cargo test -p codewhale-tui --lib -- fleet::manager mcp::tests tool_preparation
  commands::groups::plugins runtime_api::tests::agent_run doctor: 449 passed,
  0 failed, 1 ignored
- cargo test -p codewhale-tui --lib -- core::engine::tests::mcp computer_use
  approval_cache: 33 passed, 0 failed
- cargo test -p codewhale-command-contract: 59 passed, 0 failed
- rustfmt --check on the touched files: clean

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-22 19:04:59 -07:00
CodeWhale BotandClaude Opus 5.5 b90590369a feat(approvals): honour readOnlyHint from reviewed plugins (CW-11)
Every MCP tool outside the five built-in resource helpers prepared as
Suggest, so each Chromewhale page_snapshot and Computer Use screenshot
prompted, while session auto-approve let every tool through, destructive or
not. The MCP tool annotations the servers already declare were dropped at
parse time.

- McpTool now parses the MCP `annotations` object (readOnlyHint,
  destructiveHint).
- McpPool::to_api_tools, which builds the catalog each turn, records one
  approval hint per model tool name: TrustedReadOnly only when the server is
  a reviewed plugin (reviewed_plugin provenance, catalog still authorized)
  and the tool declares readOnlyHint true without destructiveHint; the same
  claim from any other server is ignored. Destructive for any tool that
  declares destructiveHint true. A server that loses its review or a hint
  loses the relaxation on the next catalog build.
- prepare_tool_call treats a TrustedReadOnly tool like the built-in read
  helpers (Auto, read_only), and never lets session auto-approve cover a
  Destructive one. The approval card text says which applies.
- Computer Use consent and app_script gates still run first and are
  unchanged: request_access declares readOnlyHint but consent calls keep
  their own required card.

Known limitation (in mcp.rs): the hint map is process-wide, keyed by model
tool name, because call preparation has no pool handle; two pools exposing
the same model name from different servers overwrite each other. Plugin
servers carry synthesized plugin-* names, so this needs a user server named
like a plugin server.

docs/MODES.md states the rule.

No-Issue: 0.10.1 addendum C5 (CW-11)

Checks (targeted, local, shared dirty tree):
- cargo test -p codewhale-tui --lib -- only_a_reviewed_plugin mcp_annotation_hints mcp_write_preparation: 3 passed, 0 failed
- cargo test -p codewhale-tui --lib -- mcp::tests tool_preparation (within the 448-test touched-module run): 0 failed

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-22 18:40:31 -07:00
CodeWhale Bot d4e555b56d Blue ocean: agent docs describe, runtime enforces, model decides
Strip behavior laws the runtime already enforces (or never did) from
agent-facing docs, keeping every safety boundary and everything
automation parses:

- Output rituals become default shapes that compress when trivial:
  cw-slice (ladder rung, owner, slice, evidence), cw-orient (status
  block skips normal fields), cw-handoff (unordered sections),
  SUBAGENTS delegation briefs (a sentence beats the template).
- Numeric self-limits become enforcement notes: no 3-5 call law
  (docs + scout prompt), caps are for the runtime to queue/clamp,
  never a reason to pre-refuse or pre-shrink valid work.
- Singletons become guard-or-convention: only the turn loop is
  guard-tested; BASE_PROMPT/agent-tool moves go with the code plus a
  new guard, not around a prose fence.
- Roles state the enforced grant (read-only posture refuses writes;
  parent dispatches a builder) instead of personal prohibitions.
- Workflow VM denylist redirects to child workers; FLEET wizard
  drops key-level manual detail; fan-in is the default shape, not
  the only legal pattern; git conflict guidance keeps the incident
  warning with judgment restored.

Deliberately kept: authority clamp, approval routing, safety floor,
quote-N-passed, handoff done/suspected/blocked separation, exact
trailer/branch/receipt shapes, the machine-parsed five-heading
subagent output contract, CACHE/tui-contracts code invariants.

Tests: explore_prompt 2 passed; structured-briefs assertion passed.
2026-09-17 23:45:28 -07:00
CodeWhale Bot 4de9e9e281 refactor(goal): the model decides goals; the host stops guessing from verb lists
Founder clarification, 2026-09-09 (docs/design/TUI_DECONSTRUCTION.md): "the
harness should let the model decide when a goal, plan, delegation, further
investigation, or verification is useful." Operate violated that with three
conflicting authorities: `operate_goal_from_prompt` classified instructions
with work-verb and chat-opener lists, `CreateGoalTool::description` said goals
require an explicit request, and the host promoted a prompt before the model
ever ran. The verb list produced exactly the absurdity it invites: "test
respond with hello" became a persistent goal because "test" is a verb.

- `operate_goal_from_prompt` and its vocabularies are deleted (~8.6 KB with
  tests). The engine creates a goal only from an explicit user declaration —
  `/goal` and the natural-language forms `explicit_goal_directive` parses — or
  when the model calls `create_goal`. No wording is classified.
- `create_goal`'s description becomes the one model-facing contract: the model
  decides when a request is a durable objective, and is told what is not one
  (a question, a greeting, a one-shot edit, a conversational probe).
- The create-refusal report is now always the explicit one: a `/goal` that
  `GoalState::create` refuses says so instead of being swallowed.
- docs/MODES.md (Operate) updated to match; the design doc's "conflicting
  authorities" note is resolved by this change.

Tests updated to the contract, not the old behavior:
- `operate_never_promotes_wording_to_a_goal`: ordinary work prompts are
  ordinary turns in Operate and Work; an explicit declaration still creates
  the goal.
- `operate_contract_is_appended_once_and_an_existing_goal_is_never_replaced`
  seeds its goal through the explicit declaration.
- `operate_model_shell_uses_normal_approval_and_workspace_sandbox` declares its
  goal explicitly instead of relying on promotion.

Evidence: goal filter "148 passed; 0 failed"; operate filter "55 passed;
0 failed"; clippy (CI's invocation, tui lib) clean.
2026-09-17 14:37:05 -07:00
Hunter BandClaude Fable 5.1 2a34e239b8 fix(workflow): run Fleet plans through the existing Engine workers
Bind planned steps to the saved Fleet model and narrowed authority, enforce
shared budgets before child launch, and deliver dependency results and final
handbacks through the existing Engine inbox. Keep headless sessions alive
between phases and preserve cancellation and terminal journal failures.

Completion receipts include measured descendant and continuation usage. The
roster keeps supervision facts while addressed inspection retains routes,
limits and diagnostics. Align Operate and Fleet documentation with this flow.

Local verification: combined Workflow/Fleet/Engine selection 2053 passed,
0 failed, 5 ignored; final sub-agent selection 650 passed, 0 failed, 0 ignored.
The twelve-worker status test measured one page of 3945 bytes. Workspace
Clippy with the release gate allow flags, fmt and version checks exited 0.
npm test: 534 passed, 0 failed; npm run check:web exited 0.

Receipts: native-workflow-combined-tests-v7.json and
native-workflow-final-delta-v9.json. Clean final-head qualification and
exact-head hosted CI remain pending.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-09-13 04:20:12 -07:00
CodeWhale Bot 47eff23107 fix(operate): honor requests declining automatic goals
Keep the task runnable when a direct work request declines persistent goal tracking, including negated comma lists continued across lines. Preserve explicit goal directives and existing goal state.

Validation: full workspace all-feature nextest 15315 passed, 0 failed, 21 skipped; two slow tests retained. Includes real Engine turn projection and opt-out phrasing regressions. CI-flags Clippy will run on the joined final candidate; no new installed-artifact claim.
2026-09-09 03:17:48 -07:00
CodeWhale Bot ccc5dadfa2 fix(tools): expose goal controls before continuation
Keep create_goal, get_goal and update_goal in the stable initial tool set. A model must be able to settle an active goal without discovering the lifecycle tool first. Clarify that prose status is not a state change, keep parent mutation unavailable to children, and update both mode guides.

Validation: old source fails the production catalog regression (0 passed, 1 failed). Fixed scoped nextest: 156 passed, 0 failed; 12384 excluded by filter. Actual OpenAI-compatible request test verifies eager goal schemas and immediate update_goal execution. Existing 2 child-head expectations updated for read-only get_goal; LRU test still explicitly exercises a deferred fixture. No packaged/live or hosted CI claim.
2026-09-09 00:20:42 -07:00
CodeWhale Bot 45a8b088db fix: make tool paths and operate goals follow user intent
Expand home-relative file paths through existing workspace and credential guards. Raise the uncatalogued output allowance while honoring explicit route and context limits. Stop promoting conversational prompts to persistent goals by word count and make startup recovery guidance readable.

Validation: 212 selected Rust regressions passed, 0 failed, 12291 unselected; cargo fmt and git diff --check passed. Full workspace, hosted CI and packaged/live qualification remain pending.
Signed-off-by: CodeWhale Bot <[email protected]>
2026-09-08 18:19:28 -07:00
CodeWhale Bot bc4c0bd8fa feat: rename sidebar/rail to workbar, bottom default, /workbar command 2026-09-02 18:48:27 -07:00
329960fcbf feat: Codewhale 0.9.12 shell, brand, fleet, and Operate (mega) (#5826)
* feat(fleet): your fleet is the models you added, and it comes first

Design MODEL-ROUTING-CATALOG-20260901 §10, slice F1. A fleet model is a Pod
member: the selected Pod file's operator route plus every member row that
pins an exact provider + model; the roles a model fills are the member rows
that pin it. No second store.

- crate::fleet::members: fleet_models / add_fleet_model / remove_fleet_model
  / toggle_fleet_model + change_receipt; Config::fleet_members(workspace) is
  the read seam for the operator-awareness slice (F2).
- /pod models | add <provider> <model> [role…] | remove <provider> <model>
  (also via the /fleet alias). A model the configured provider does not
  serve is rejected; the first add creates and selects a user-global Pod
  named 'My fleet'.
- /model picker: ⇧F adds or removes the row's exact route; fleet models
  lead the list labelled 'fleet · <roles>', ahead of ⇧P pins and providers.
- /models prints the fleet before the provider list ('Your fleet is the
  session model only' when empty).
- PickerActionFleet message in all 15 locales; docs/FLEET.md 'Your fleet
  as models'.

Tests: scripts/dev-test.sh tui fleet::members groups::core::fleet
model_picker format_helpers — Summary 37 tests run: 37 passed, 11834
skipped.

Signed-off-by: CodeWhale Bot <[email protected]>

* fix(fleet): pass slugify by name (clippy redundant_closure)

cargo clippy -p codewhale-tui --all-targets -- -D warnings -A clippy::too_many_arguments -A clippy::uninlined_format_args -A clippy::unnecessary_map_or: no findings.

Signed-off-by: CodeWhale Bot <[email protected]>

* fix(tui): review fixes for fleet toggle and /pod add provider validation\n\n- Reject unconfigured provider ids in "/pod add" before writing, reusing\n  the existing provider_is_configured_for_active predicate and custom\n  provider table checks.\n- Add App.config snapshot so commands can consult the loaded config.\n- Update the stale DEFAULT_FLEET_NAME doc comment to mention ⇧F.\n- Sync crates/tui/CHANGELOG.md.

* style: cargo fmt

* fix(web): align react with react-dom 19.2.8 to unbreak npm ci

Dependabot #5801 bumped react-dom to 19.2.8, whose peer range requires
react 19.2.8; the lockfile still resolved react 19.2.6, so 'npm ci' in
web/ failed ERESOLVE on main and on every branch that merged it
(Lint & Type Check red). Align react to 19.2.8; install verified clean.

Signed-off-by: CodeWhale Bot <[email protected]>

* brand: trace supplied whale assets

Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Hunter Bown <[email protected]>

* brand: align icon ombre and generated tokens

Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Hunter Bown <[email protected]>

* brand: use white icon tile

Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Hunter Bown <[email protected]>

* brand: deepen ombre light stop

Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Hunter Bown <[email protected]>

* brand: wordmark takes the blue ombre

Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Hunter Bown <[email protected]>

* tui: recover from image-input rejections by non-vision routes

Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Hunter Bown <[email protected]>

* tui: localize image rejection recovery

Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Hunter Bown <[email protected]>

* chore: format 0.9.12 mega branch

Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Hunter Bown <[email protected]>

* Redesign Fleet role labels and agent cards

* feat(tui): launch hero as wordmark + small surfacing mark

Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Hunter Bown <[email protected]>

* design(tui): retune whale palette to codewhale navy / ombre sky

Field, chrome, panel, plate and raised surfaces move onto the brand navy
(#070C1D → #142352 → #1A2C63); interaction blue becomes the ombre sky
#6AA6DC, light-mode action the ombre cobalt #1535B2; ice/cyan/border/tool
tints follow. web/app/tokens.css regenerated via
scripts/export-design-tokens.py.

Co-Authored-By: Hunter Bown <[email protected]>

* test(tui): re-bless ink goldens for navy palette

Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Hunter Bown <[email protected]>

* web: Space Mono wordmark, quiet layout refresh, fleet vocabulary in site + docs

Space Mono (OFL) outlined wordmark rebuilt via scripts/build-wordmark.py,
wired as --font-display through next/font/google; body stays IBM Plex Sans,
code stays JetBrains Mono. Nav loses the issue strip, strapline, Discord badge
and second filled CTA; home loses the ticker, seals and tilt figure; docs
shell hero collapses to a one-line band; footer uses the inverted wordmark.

Public noun is fleet (/fleet, codewhale fleet, /docs/fleet canonical; /pod,
codewhale pod, /docs/pod remain compatibility aliases) across docs/, site
dictionaries, vocabulary contract and public-surface facts.

No-Issue: 0.9.12 website lane

* brand: keep the traced wordmark; drop Space Mono outline build

* web: IBM Plex Sans Condensed as display face

* brand: Plex Sans Condensed wordmark; nav mark; drop fabricated home demos; AA meta text

* feat(tui): bottom dock tabs — clickable panel switch + close

Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Hunter Bown <[email protected]>

* Fix Fleet role migration verification

* fix(tui): dock keys yield Tab to mode/permission cycles

Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Hunter Bown <[email protected]>

* web: Impeccable polish — type floors, heading outline, docs measure; add PRODUCT.md/DESIGN.md

* Resolve canonical Fleet roles to legacy members

* web: flat hero — drop cyan glow/gradients/shadow, muted eyebrows

* design: PRODUCT.md/DESIGN.md at repo root — shell direction, bottom dock, anti-slop rules, 0.9.12 tokens

* Auto-enroll used models into the Fleet

* brand: keep the founder's wordmark rasters as the source of truth

The web lane replaced brand/wordmark0901.png and brand/wordmarkinverted.png
with Plex Sans Condensed renders. The founder-supplied PNGs are the brand
source; the SVGs are re-traced from them in a following commit.

* tui(mark): the launch mark has one rung

The hero now paints the small mark over the wordmark, so the medium and
large rungs and the for_area ladder have no consumer and fail the
dead-code lint. Remove them rather than allow them.

* brand: trace the founder's wordmark to SVG

brand/wordmark.svg and wordmark-inverted.svg were an IBM Plex Sans
Condensed text render; the founder's wordmark is the rounded monoline in
brand/wordmark0901.png. scripts/brand/trace-brand.py now traces that PNG
(magick threshold 60% + trim, potrace -s --flat -t 20 -O 0.4 -a 1.2),
folds potrace's transform into one compact path in a tight 1874x264
viewBox, and writes the navy #142352 and white colourways from the same
geometry. The Plex builder scripts/build-wordmark.py is gone with it.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH

* web: derive icons and OG image from the traced mark

app/icon.svg is now the white whale on the #142352 rounded tile as on the
founder's sheet; favicon.ico (48/32/16), apple-icon.png, icon-192.png and
icon-512.png are rasterised from it by scripts/brand/trace-brand.py, and
the manifest colours are the same navy. The social card keeps the navy
ground, white mark and traced wordmark and restores the identity phrase
the page-meta contract expects.

The nav sits on the dark field on every route, so it renders the inline
Whale (white brand ink) and the inverted wordmark instead of a
prefers-color-scheme picture pair; the wordmark box uses object-fit so
the ~7.1:1 trace scales inside the compact nav instead of squashing.

Exploration rasters web/public/brand/codewhale-mark-*.png and their
web/brand/mark tile sources had no consumers and are removed;
codewhale-mark.png stays (public-auth-routes pins its hash).

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH

* web: map stray hard-coded colours to navy tokens

globals.css carried a handful of literal navy-family greys, ice hairlines,
seafoam borders and a cyan glow beside the generated --whale-* tokens.
Each now reads the token it was approximating (whale-bg/chrome/panel,
whale-ice, whale-accent-secondary, whale-action, whale-cyan,
whale-text-dim), and the docs light sheet inks the mark in the brand
navy via --whale-composer (#142352).

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH

* palette: inventory WHALE_* tokens before the one-name-per-colour collapse

Shell design §2.6 (SHELL-DESIGN-20260901) measured "58 WHALE_* symbols;
one colour under five names; 5 dead tokens". Receipt before touching
anything, generated from crates/tui/src/palette/tokens.rs. "uses" is the
whole-word count across crates/ excluding the const's own definition and
`use`/`pub use` lines (wrapper consts inside tokens.rs count).

  name                        value                       alias-of                    dead uses
  WHALE_BG_RGB                (7, 12, 29)                                                    3
  WHALE_CHROME_RGB            (12, 21, 49)                                                   1
  WHALE_PANEL_RGB             (16, 28, 64)                                                   3
  WHALE_COMPOSER_RGB          (20, 35, 82)                                                   3
  WHALE_ELEVATED_RGB          (26, 44, 99)                                                   4
  WHALE_SELECTION_RGB         (30, 60, 143)                                                  3
  WHALE_TEXT_BODY_RGB         (246, 242, 232)                                               10
  WHALE_TEXT_SOFT_RGB         (182, 192, 212)                                                4
  WHALE_TEXT_MUTED_RGB        (147, 160, 184)                                                3
  WHALE_TEXT_HINT_RGB         (138, 153, 179)                                                3
  WHALE_TEXT_DIM_RGB          (105, 119, 145)                                         yes    0
  WHALE_ACTION_RGB            (106, 166, 220)                                                6
  WHALE_COBALT_RGB            (21, 53, 178)                                           yes    0  (web: --whale-cobalt x3)
  WHALE_ICE_RGB               (221, 238, 249)                                         yes    0  (web: --whale-ice, rustRgb("WHALE_ICE"))
  WHALE_CYAN_RGB              (120, 188, 232)                                                2
  WHALE_ACCENT_SECONDARY_RGB  (79, 209, 197)                                                11
  WHALE_BRAND_ORANGE_RGB      (255, 138, 61)                                                 1
  WHALE_BRAND_MAGENTA_RGB     (240, 78, 184)                                                 1
  WHALE_HUMAN_RGB             (246, 196, 83)                                                 5
  WHALE_ACCENT_PRIMARY_RGB    = WHALE_ACTION_RGB          WHALE_ACTION_RGB                   8
  WHALE_WORKING_GREEN_RGB     (155, 214, 111)                                                5
  WHALE_ACCENT_ACTION_RGB     = WHALE_ACTION_RGB          WHALE_ACTION_RGB            yes    0
  WHALE_ERROR_RGB             (255, 134, 178)                                                9
  WHALE_ERROR_HOVER_RGB       (255, 156, 194)                                                3
  WHALE_ERROR_SURFACE_RGB     (43, 21, 34)                                                   6
  WHALE_ERROR_BORDER_RGB      = WHALE_ERROR_RGB           WHALE_ERROR_RGB                    3
  WHALE_ERROR_TEXT_RGB        (255, 219, 232)                                                3
  WHALE_WARNING_RGB           (255, 122, 89)                                                 4
  WHALE_SUCCESS_RGB           = WHALE_WORKING_GREEN_RGB   WHALE_WORKING_GREEN_RGB            9
  WHALE_INFO_RGB              = WHALE_ACTION_RGB          WHALE_ACTION_RGB                  17
  WHALE_BORDER_RGB            (42, 63, 114)                                                  1
  WHALE_REASONING_TEXT_RGB    (224, 153, 72)                                                13
  WHALE_REASONING_SURFACE_RGB (42, 34, 24)                                                   3
  WHALE_REASONING_TINT_RGB    (22, 36, 74)                                                   7
  WHALE_DIFF_ADDED_RGB        (87, 199, 133)                                                 3
  WHALE_DIFF_DELETED_RGB      = WHALE_ERROR_RGB           WHALE_ERROR_RGB             yes    0
  WHALE_DIFF_ADDED_BG_RGB     (18, 42, 34)                                                   3
  WHALE_DIFF_DELETED_BG_RGB   (52, 24, 39)                                                   3
  WHALE_MODE_AGENT_RGB        (126, 180, 232)                                                4  (via MODE_AGENT: 13)
  WHALE_MODE_YOLO_RGB         (255, 112, 160)                                                4  (via MODE_YOLO: 13)
  WHALE_MODE_PLAN_RGB         (185, 220, 236)                                                4  (via MODE_PLAN: 13)
  WHALE_MODE_OPERATE_RGB      (173, 136, 255)                                                4  (via MODE_OPERATE: 14)
  WHALE_TOOL_LIVE_RGB         = WHALE_ACCENT_SECONDARY_RGB                                   3  (via ACCENT_TOOL_LIVE: 5)
  WHALE_TOOL_ISSUE_RGB        = WHALE_ERROR_RGB                                              3  (via ACCENT_TOOL_ISSUE: 5)
  WHALE_TOOL_OUTPUT_RGB       = WHALE_TEXT_SOFT_RGB                                          3  (via TEXT_TOOL_OUTPUT: 13)
  WHALE_TOOL_SURFACE_RGB      (15, 26, 58)                                                   3  (via SURFACE_TOOL: 5)
  WHALE_TOOL_ACTIVE_RGB       (24, 44, 94)                                                   3  (via SURFACE_TOOL_ACTIVE: 9)
  WHALE_ACCENT_PRIMARY        Color(WHALE_ACCENT_PRIMARY_RGB)  -> WHALE_ACTION               9
  WHALE_ACTION                Color(WHALE_ACTION_RGB)                                       85
  WHALE_LIVE                  Color(WHALE_ACCENT_SECONDARY_RGB)                             17
  WHALE_HUMAN                 Color(WHALE_HUMAN_RGB)                                        41
  WHALE_INFO                  Color(WHALE_INFO_RGB)       -> WHALE_ACTION                  105
  WHALE_BG                    Color(WHALE_BG_RGB)                                           96
  WHALE_CHROME                Color(WHALE_CHROME_RGB)                                        5
  WHALE_PANEL                 Color(WHALE_PANEL_RGB)                                        15
  WHALE_COMPOSER              Color(WHALE_COMPOSER_RGB)                                      5
  WHALE_ERROR                 Color(WHALE_ERROR_RGB)                                        35

  57 WHALE_* consts. Pure aliases (9): ACCENT_PRIMARY_RGB, ACCENT_ACTION_RGB,
  ERROR_BORDER_RGB, SUCCESS_RGB, INFO_RGB, DIFF_DELETED_RGB, TOOL_LIVE_RGB,
  TOOL_ISSUE_RGB, TOOL_OUTPUT_RGB. #[expect(dead_code)] (5): TEXT_DIM_RGB,
  COBALT_RGB, ICE_RGB, ACCENT_ACTION_RGB, DIFF_DELETED_RGB.
  Non-WHALE aliases of the same blue in tokens.rs: STATUS_INFO (8 uses),
  ACCENT_PRIMARY (dead, 0). One colour, #6AA6DC, under seven symbols:
  WHALE_ACTION(_RGB), WHALE_INFO(_RGB), WHALE_ACCENT_PRIMARY(_RGB),
  WHALE_ACCENT_ACTION_RGB, STATUS_INFO, ACCENT_PRIMARY — 225 call sites.

Script: python3 over tokens.rs + grep -rnw crates; kept out of scripts/
(one-off receipt, the numbers live here).

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH

* palette: one name per colour — collapse WHALE_INFO / WHALE_ACCENT_PRIMARY into WHALE_ACTION

Shell design §2.6: "`WHALE_INFO`, `WHALE_ACTION`, `WHALE_ACCENT_PRIMARY`
and their `_RGB` twins are one colour. Collapse to `WHALE_ACTION`."

Mechanical rename across crates/ (word-boundary sed, no value changes):
  WHALE_INFO, WHALE_INFO_RGB           -> WHALE_ACTION, WHALE_ACTION_RGB
  WHALE_ACCENT_PRIMARY(_RGB)           -> WHALE_ACTION(_RGB)
  palette::STATUS_INFO                 -> palette::WHALE_ACTION
  WHALE_ACCENT_ACTION_RGB, ACCENT_PRIMARY (dead aliases) -> deleted
The `STATUS_INFO` static in commands/groups/config is an unrelated
CommandInfo and is untouched.

Where two names met in one predicate (adapt.rs light/solarized/community
remaps, grayscale text-soft bucket, SemanticForegroundRole::Action) the
duplicate disjuncts are dropped; `use` lists deduped; the
"primary accent aligns with action" test collapses to its one live
assertion (action blue != human gold). The Blue Stage doc comment moves
onto WHALE_ACTION_RGB. `palette::grammar` untouched: it reads UiTheme
slots, never these consts.

Evidence (CARGO_BUILD_BUILD_DIR=.../mega-tokens):
  cargo check -p codewhale-tui --all-targets      -> Finished, 0 warnings
  cargo clippy -p codewhale-tui --all-targets --all-features --locked
    -- -D warnings (CI allow-list)                -> clean
  cargo test -p codewhale-tui --lib palette::tests:: --locked -- --skip command_palette
    -> test result: ok. 59 passed; 0 failed
  RUST_MIN_STACK=67108864 cargo test -p codewhale-tui --lib startup_ink --locked
    -> test result: ok. 1 passed; 0 failed   (ink goldens unchanged)
  cargo test -p codewhale-tui --lib --locked -- menu_style cursor_accent color_compat
    -> test result: ok. 36 passed; 0 failed
Pre-existing, not from this diff (reproduced on the stashed tree):
tui::command_palette tests, feat012_ac1 and the startup_ink golden
overflow the default test-thread stack in a debug build; they pass with
RUST_MIN_STACK=64MiB.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH

* palette: delete the dead whale tokens

Shell design §2.6: "delete the five dead tokens". Two of the five went
with the alias collapse (WHALE_ACCENT_ACTION_RGB, ACCENT_PRIMARY); this
removes the rest that have no consumer in crates/ and no web consumer:

  WHALE_TEXT_DIM_RGB     (105,119,145)  0 uses, no --whale-text-dim on the site
  WHALE_DIFF_DELETED_RGB = WHALE_ERROR_RGB  0 uses, no --whale-diff-deleted
  ACCENT_SECONDARY       Color(WHALE_ACCENT_SECONDARY_RGB)  0 uses (TEXT_ACCENT/WHALE_LIVE carry it)
  STATUS_NEUTRAL         = TEXT_MUTED  0 uses

Kept, with a comment saying why the `#[expect(dead_code)]` is honest:
WHALE_COBALT_RGB and WHALE_ICE_RGB have no TUI consumer but the site
reads them through the token export (`--whale-cobalt` x3, `--whale-ice`
and `rustRgb("WHALE_ICE")` in web/lib/blue-stage-contract.test.ts).

Mode and tool-surface `_RGB` tuples stay: each is consumed through its
Color wrapper (MODE_AGENT/YOLO/PLAN/OPERATE 13-14 call sites each,
themes.rs + color_compat.rs; SURFACE_TOOL 5, SURFACE_TOOL_ACTIVE 9,
ACCENT_TOOL_LIVE 5, ACCENT_TOOL_ISSUE 5, TEXT_TOOL_OUTPUT 13). The §1
"12 tokens with zero consumers" counted the tuples, not their wrappers.

Evidence: cargo check -p codewhale-tui --all-targets -> Finished, 0 warnings;
cargo test -p codewhale-tui --lib palette::tests:: --locked -- --skip command_palette
-> test result: ok. 59 passed; 0 failed.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH

* web: regenerate tokens.css after the whale token collapse

scripts/export-design-tokens.py (never hand-edited). Ten lines gone:
--whale-accent-primary(-rgb), --whale-accent-action(-rgb),
--whale-info(-rgb), --whale-text-dim(-rgb), --whale-diff-deleted(-rgb).
No site stylesheet or component consumed any of them
(grep -rn "\-\-whale-" web/app web/components web/lib); the only
reference was the alias-chain example in web/lib/whale-tokens.ts's doc
comment, now `--whale-success` -> `--whale-working-green` -> `#9bd66f`
(the old example also quoted a hex that stopped being true a retune ago).

Evidence:
  cd web && python3 ../scripts/export-design-tokens.py --check   (CI: npm run check:tokens)
    -> design tokens up to date (1 file(s), 42 tokens)
  vitest run lib/blue-stage-contract lib/docs-theme-contract
    -> Test Files 2 passed (2) / Tests 6 passed (6)
  (vitest ran against the main checkout's node_modules via a temporary
  symlink; this worktree has none installed.)

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH

* docs(design): the status-bar grammar names the one blue token

STATUS_BAR_COLOR_GRAMMAR.md never named a collapsed token, so this is the
one sentence it needed: the Identity blue is `WHALE_ACTION`, its former
aliases (`WHALE_INFO`, `WHALE_ACCENT_PRIMARY`, `STATUS_INFO`) are gone, and
the whale theme's `info` / `accent_primary` slots both hold it. No other
document in the repo named them (grep over *.md, *.ts, *.tsx, *.css,
*.py, *.toml, *.yml, *.json outside node_modules); the root DESIGN.md
already speaks in CSS names.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH

* palette: the field follows the terminal-owned shell; `underwater` aliases deepsea

Shell design §2.0 decision 1 (founder: "We aren't supposed to be using a
blue background anymore"): ground is the terminal's; the navy field is
painted only under the opt-in deepsea column.

What was already true, verified before changing anything:
- Settings::default().theme is "terminal" (settings.rs:103).
- The whale pair (UI_THEME / LIGHT_UI_THEME) ends in
  `.with_terminal_native_shell()`: surface, panel, composer, header and
  footer are `Color::Reset`, pinned by
  `whale_pair_flat_shells_are_terminal_native_without_erasing_semantic_surfaces`.
- The ink goldens' legend reads `a reset on reset`.
- OceanTreatment::Flat is the default; Deepsea repaints Reset cells through
  OceanRamp::for_theme, which matches the whale pair by name + Reset shell.
The reviewer's citations (tokens.rs:6/:250/:465) are the token definitions
deepsea and the semantic surfaces still need, not the theme.

What was not true: ~90 direct `bg(palette::WHALE_BG)` paints in pickers,
overlays and full-screen views (provider_picker 14, views/mod.rs 11,
user_input, live_transcript, help, session/file/model pickers ...) bypass
the theme, and `adapt_bg_for_theme` only remapped them for
`theme_remap_active` presets. On the whale theme they laid navy patches
over the terminal ground. Rung 2 fix, one rule in palette/adapt.rs: the
field (`WHALE_BG` / `BACKGROUND_DARK`) always follows `ui.surface_bg` —
Reset on the whale pair, the user's `background_color` override when set,
the preset surface elsewhere. Panels, selection, elevation, error and
diff surfaces are untouched; no widget file changes.

`underwater` is now an accepted alias of `deepsea` in
settings.rs (normalize + `set`), OceanTreatment::parse and the
config_ui serde enum. Tests extended in place; the color_compat light
test now expects the Reset shell it already had for theme consumers.

DESIGN.md "Field" says the TUI ground is the terminal's own background
and the navy field is deepsea-only.

Contrast, all whale text/accent tokens on #000, #1e1e1e (VS Code),
#282c34 (One Dark), #002b36 (Solarized dark), #300a24 (Ubuntu), #0d1117
(GitHub dark), #282a36 (Dracula): body 12.5-18.8:1, soft 7.7-11.5, muted
5.3-8.0, hint 4.9-7.3 (floor 3:1), action 5.4-8.1, human 8.6-12.9, live
7.5-11.3, error 6.2-9.3, warning 5.5-8.2, green 8.2-12.2, reasoning
5.9-8.8. Only `border` (#2A3F72) is low, 1.4-2.1:1: a non-text hairline.
No token value changed.

Seen, tmux 80x24 PTY, TERM=xterm-256color COLORTERM=truecolor, hermetic
HOME, debug build, counting `48;2;R;G;B` background sequences:
  default (Terminal theme): startup, /theme picker, Help — no painted
    background before or after (picker shows only accent swatches).
  Blue Stage selected via T/Down/Enter, then F1 Help:
    before: 15 x `48;2;7;12;29` (WHALE_BG) + 1 x selection row
    after:  1 x `48;2;30;60;143` (selection row only)
  Startup stage on Blue Stage: none, before and after.

Evidence (CARGO_BUILD_BUILD_DIR=.../mega-tokens, RUST_MIN_STACK=16 MiB as CI):
  cargo check -p codewhale-tui --all-targets -> Finished, 0 warnings
  cargo test -p codewhale-tui --lib --locked -- color_compat palette::tests::
    ocean:: ocean_treatment live_transcript views::tests startup_ink
    --skip command_palette -> test result: ok. 238 passed; 0 failed
  cargo test -p codewhale-tui --lib --locked (full) ->
    test result: FAILED. 11901 passed; 7 failed; 13 ignored
    1 was this change (color_compat light test, updated above); the other 6
    are role-name / slash-list assertions from other lanes on this branch
    (scout<->explore, worker<->general, slash.impeccable) and untouched.
Ink goldens unchanged.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH

* tests(palette_audit): re-pin whale roles to the retuned palette

`whale_roles_are_pinned_and_non_colliding` still pinned the pre-navy
values (WHALE_BG (3,7,13), ACTION (106,174,242), ...) and failed on this
branch before the token slice touched anything. Pins now match tokens.rs;
no colour value changes.

cargo test -p codewhale-tui --test integration --locked palette_audit
  -> test result: ok. 3 passed; 0 failed

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH

* tui/cli/web: fleet is the public product term; /pod, codewhale pod stay aliases

Founder decision 2026-09-01: "fleet" is the customer-facing name for the
assembled model team and "Pod" is retired from product copy. `/fleet` is
the canonical slash command and `codewhale fleet` the canonical CLI verb;
`/pod`, `codewhale pod`, `loadout`, and `party` remain parser aliases.
Storage keys, the ledger file name, config tables, protocol identifiers,
and MessageId variant names keep their current spelling.

- CommandInfo name/aliases/usage, help text, and the unknown-verb error
  flip to /fleet; `/fleet fleets` (saved/manage) is the saved-fleet picker
  with `/fleet pods` kept as an alias.
- All 15 locale packs: localized values say fleet; the settings goldens
  follow. `KbCompleteCycleModes` names the modes as Plan → Work → Operate
  (Act is only a compatibility alias per docs/MODES.md).
- `scripts/check-tui-product-vocabulary.sh` now rejects `Pod` in en.json
  instead of rejecting `fleet` in every pack.
- Hotbar id `slash.fleet` is canonical; persisted `slash.pod` normalizes.
- Fleet store error prose says fleet.
- Docs: PRODUCT.md lists the current role tokens (general, explore,
  planner, reviewer, implement, test, advisor, custom) and names the old
  spellings as aliases; docs/FLEET.md uses one role vocabulary;
  web/lib/content/vocabulary.ts ADVISORY_ROLE is Advisor with consultant/
  oracle as the legacy spellings (matches fleet/profile.rs migration).

Evidence:
  sh scripts/check-tui-product-vocabulary.sh -> exit 0
  cargo test -p codewhale-config -p codewhale-lane --locked
    -> 638 passed; 0 failed / 62 passed; 0 failed
  cargo test -p codewhale-cli --locked -- fleet pod -> 3 passed; 0 failed
  cargo test -p codewhale-tui --lib --locked -- fleet::store fleet::members
    fleet::identity -> 24 passed; 0 failed
  cargo test -p codewhale-tui --lib --locked -- groups::core::fleet
    localization command_palette hotbar fleet_roster settings widgets
    fleet::control pod_workers -> 605 passed; 1 failed (the failure is
    slash_source_matches_command_palette_command_entries, which reads the
    machine's ~/.claude/skills and finds an `impeccable` skill; it fails
    identically without this change)
  cd web && npm test -- lib/content/vocabulary.test.ts -> 11 passed

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH

* chore(tui): clear the six clippy 1.98 errors the base lanes left

needless_borrow on provider_identity_for_persistence (five sites) and a
collapsible_if in the work-surface mouse path. No behaviour change.

* tui(composer): restore double-tap Enter as the send-now gesture

While a turn is running, the first bare Enter queues the message (as
before) and opens a 500 ms window (`App::DOUBLE_TAP_WINDOW`, the value
the removed code in c5c42b7d91 used). A second bare Enter inside that
window with an empty composer promotes the just-queued message to a
Steer through `attempt_steer_with_queue_fallback` — the same path
Ctrl+Enter takes, so there is one steering path. A second Enter with
new text is an ordinary queue; Ctrl+Enter still steers immediately;
outside a turn Enter is unchanged. `enter_with_double_tap` is the one
decision point again (`take_queued_for_double_tap_steer` routes through
it), and `submit_disposition_does_not_mutate_the_queue` stays true.

The posture bar advertises the gesture while the window is open
(`PostureHintEnterAgain`, next commit).

Tests (cargo test -p codewhale-tui --lib <filter> --locked):
  double_tap:          test result: ok. 3 passed; 0 failed
  enter_with:          test result: ok. 5 passed; 0 failed
  submit_disposition:  test result: ok. 6 passed; 0 failed

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH

* tui(shell): one owner per fact — posture bar, metrics line, no dead hints

Design: SHELL-DESIGN-20260901 §2.0 item 3, §2.2, §2.3, §2.3b, §2.11 and
the founder's 2026-09-02 redirect (Claude Code's grammar, less always-on
information). Under the composer there are exactly two chrome rows in
the default state, then the work surface only when it has content:

  ▶▶ ask (Shift+Tab) · work (Tab) · 2 agents · Esc to interrupt   /rc …
  deepseek-v4 · ctx 61% · $0.42 · ttft 400ms · 40 tok/s · ↓ 1.2K  Ctrl+/ help

Fact → owner, before → after (composed 80x24 / 120x32 frames, working
turn with two sub-agents; "strip" = the work-surface bottom view):

  fact              before                                        after
  context %         info line                                     metrics line
  cost              footer (+ info line when priced)              metrics line
  model             info line                                     metrics line
  provider          info line (wide)                              metrics line (wide)
  ttft / tok/s / ↓  behind /cost only                             metrics line
  repo slug         info line (+ idle empty state)                launch header / git view (not chrome)
  branch            info line (+ idle empty state)                launch header / git view (not chrome)
  mode              footer                                        posture bar
  permission        footer                                        posture bar
  phase word        footer ("sub-agents underway")                transcript active row (not chrome)
  elapsed           footer ("1m 15s")                             roster rows (per agent)
  agent count       indicator row + info "pod 2/2" + "whales 2/4" posture bar ("2 agents")
                    + dock tab + strip header                     (+ dock tab, strip header — other slice)
  task/shell count  indicator row above the composer              posture bar
  help hint         footer keys legend (F1) + info line (Ctrl+/)  metrics line (Ctrl+/), from the binding
  other key hints   footer "⌥V:output", compact "? help"          none; cycle keys next to the chip they cycle
  live hint         footer "Esc to interrupt"                     posture bar hint slot
  ≥80 % microcopy   footer right slot                             posture bar hint slot (outranks the hint)
  notice / rc       footer right slot / —                         posture bar right slot

Dead key hints removed: `F1:keys` / `fn+F1:keys` (Help binding's
`footer_chord` is now `Ctrl+/`; `info_help_hint` derives from the
binding), compact `? help`, and the `footer_action_hints` family. The
mode/permission cycle keys print only when the binding table admits
them at the current focus (no `(Tab)` on the launch stage).

Row order: composer → posture bar → metrics line → roster/to-do. The
#5286 background-work chip above the composer is gone (it repeated the
posture bar's counts); `PendingWork` stays as the counts' source.

Goldens re-blessed and read: footer_* (posture bar), infoline_startup_*,
infoline_work_* (metrics line), settings_* (the settings preview's
bottom row); infoline_settings_* deleted with the settings-path segment.

Commands run (CARGO_BUILD_BUILD_DIR=…/mega-frame, RUST_MIN_STACK=16777216):
  cargo check -p codewhale-tui --all-targets            clean
  cargo test -p codewhale-tui --lib infoline --locked   test result: ok. 11 passed; 0 failed
  cargo test -p codewhale-tui --lib tideline_tests      test result: ok. 64 passed; 0 failed
  cargo test -p codewhale-tui --lib one_owner_tests     test result: ok. 4 passed; 0 failed
  cargo test -p codewhale-tui --lib shell_key_routing   test result: ok. 13 passed; 0 failed
  cargo test -p codewhale-tui --lib localization::tests test result: ok. 49 passed; 0 failed
  cargo test -p codewhale-tui --lib --locked            test result: FAILED. 11893 passed; 8 failed
                                                        (config_panel golden re-blessed after; the other 7:
                                                        4 fail on HEAD without this change (fleet rename
                                                        in flight), tmux clipboard passes alone, none in
                                                        files this change touches)
  cargo clippy … -D warnings                            6 pre-existing errors, none in this change's hunks
                                                        (config.rs:2106/2796, apply.rs:759, event_loop.rs:464,
                                                        session_state.rs:1004, work_surface/input.rs:401)

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH

* wip(launch): checkpoint for overnight takeover — braille mark + kitty tier + Claude-Code launch header compile and pass lib tests; PTY cucumber tests still wait on the old heading

Compiles (cargo check --all-targets clean). Lib tests for mark::, underwater::,
mouse_ui::, localization:: pass: test result: ok. 120 passed; 0 failed
(needs RUST_MIN_STACK=16777216 like scripts/dev-test.sh; the rust_i18n static
overflows a 2 MiB test thread with or without this change). Startup goldens
re-blessed and read. Clippy is red only in files outside this slice
(config.rs, apply.rs, session_state.rs, work_surface/input.rs, and a
pre-existing event_loop.rs borrow).

Not done: crates/tui/tests/cucumber/{screen_mode_inline_pty,
active_composer_pointer_pty,plugin_e2e_acceptance}.rs still wait for
"What are we working on?" and press 'w'; they need the new marker
("Codewhale v") and a typed message + Enter to begin the session.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH

* wip(rail): checkpoint for overnight takeover — dock views compile, 136/137 work_surface tests pass, files/notepad/git views are stubs

Foundation for the one bottom dock (founder redirect 2026-09-02):
RailPanel is now the eight-view cycle (agents, tasks, background, files,
notepad, context, git, price; Pinned folded into tasks), an auto rule opens
agents/tasks/background while they have content, explicit picks stick until
Esc, and Ctrl+Tab / Ctrl+] (fwd) + Ctrl+Shift+Tab (back) cycle. Context and
price views render as rows; files, notepad, git are stubs in views.rs. The
classic sidebar line panels and their dead consumers are deleted.

Known: agent_rows_show_role_assignment_and_open_the_agent_transcript fails
(role_label 'worker' vs 'general'); role derivation is untouched here and
the failure is believed to predate this work — unverified.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH

* wip(operate): checkpoint for overnight takeover — auto-goal + contract land; one Operate approval test needs a goal-complete mock

Operate now turns a non-trivial prompt into the goal through the same
GoalState::create path as explicit_goal_directive, appends the Operate
contract once as a user-role runtime message (append-only history, not
the prefix), shows the Operate goal receipt, and carries the new mode copy
in all 15 locale packs plus docs/MODES.md.

Compiles. Passing: goal (134), prompts (133, incl.
every_mode_shares_one_prompt_per_host), localization (49),
runtime_handoff (14), session_peek (15), history_cells (2), both new
engine tests. Known failing:
core::engine::tests::operate_model_shell_uses_normal_approval_and_workspace_sandbox
— its mocked model never reports the auto-set goal complete, so the turn
re-prompts to max_steps (wiremock expect(1) sees 199). Six clippy
needless_borrow/collapsible_if hits pre-exist on the branch base.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH

* wip(fleet): checkpoint for overnight takeover — #5815 review findings 1-9 fixed, compiles, fleet tests green

Findings against the fleet-as-models work (verified against the current
tree, then fixed):

1. `toggle_fleet_model` decides presence by member rows, not the projected
   role list (a role-less row projects to no role, so the old
   `all(== "operator")` was vacuously true). Regression test
   `toggle_removes_a_role_less_member_row` fails on the previous commit
   ("got Unchanged { … operator route … }") and passes now.
2. `selected_or_default` loads an existing personal `My fleet` instead of
   overwriting it and never writes or selects before the add succeeds;
   `FleetModelChange::Added` carries `created_fleet` + `selected_fleet`.
3. `fleet_models` returns `Result<Vec<_>, FleetStoreError>`: a broken
   explicit selection is surfaced in `/fleet models`, `/models`, and the
   picker's ⇧F instead of reading as "session model only".
4. `add_fleet_model` dedupes roles (case-insensitive) and returns
   `Unchanged` without touching the file when every role is present
   (test compares bytes and mtime).
5. `App.config` startup snapshot removed. `/fleet add|remove` now return
   `AppAction::FleetAddModel|FleetRemoveModel`; the UI arm validates the
   provider against the live `Config` (`fleet_provider_rejection`,
   `fleet_catalog_rejection`, re-exported from `commands`).
6. ⇧F applies the same provider gate as `/fleet add`.
7. One roster path: `sync_fleet_roster` (extracted from the
   FleetStoreChanged arm) plus `App::fleet_roster_stale`, flushed once per
   event-loop iteration; `/fleet add|remove`, ⇧F, and every UI-side
   auto-enroll site set it (`auto_enroll_fleet_model` now returns bool).
8. ⇧F receipts go through `push_status_toast` (Success/Info, 6 s) and
   `set_sticky_status` (Error); no new `status_message` writes.
9. All new fleet prose is `tr(locale, MessageId::Fleet…)` (27 keys,
   translated in all 15 packs); `FleetModelError` is typed with a
   localized `message(locale)`.
10. No stale "`a` in /models" doc comment exists in the current tree.

Also re-blessed `config_panel_{80x24,120x32}` goldens (the Config tab
label says Fleet); the diff is that one label.

Evidence (this tree):
  cargo check -p codewhale-tui --all-targets --locked -> Finished
  cargo test -p codewhale-tui --lib --locked -- fleet::members
    groups::core::fleet model_picker format_helpers fleet_roster
    localization golden hotbar command_palette fleet::store
    -> 257 passed; 1 failed (slash_source_matches_command_palette_
    command_entries: reads ~/.claude/skills and finds `impeccable`;
    fails identically on main in this environment)
  cargo clippy … -D warnings (CI flags) -> the only remaining error is
    crates/tui/src/tui/work_surface/input.rs:401 collapsible_if, which
    belongs to the work_surface lane and predates this commit
  cargo fmt --all -- --check -> clean
  sh scripts/check-tui-product-vocabulary.sh -> exit 0

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH

* feat(tui): launch card, canonical role vocabulary, DashScope descriptor, test fixes

- Launch is now our own card take (founder, 2026-09-02): thin top line
  ⑂ branch  path; centred bordered card with the whale mark, Codewhale +
  version, one true announcement (no-model warning / MCP news), and the
  menu New worktree / Resume session / Changelog / Quit with real chords
  right-aligned; Enter runs the highlighted entry, Up/Down move it, and
  typing goes straight to the composer. The card dissolves on the first
  keystroke or command (≤240ms, instant under reduced motion); the
  working screen then shows ⑂ branch  path + ⋮ MCP n/m, the
  session_start receipt, and the posture bar + metrics line (hidden
  while the card is up). The composer's bottom rule carries
  model (effort) · permission — the route's one launch reading.
- Role vocabulary: fixtures and the stopship fleet/workflow now use the
  canonical tokens (explore/implement/reviewer/test); the workflow JS
  wire accepts canonical spellings with the pre-rename ones as aliases
  (AgentType serde rename+alias, serialized form is canonical).
- Alibaba Model Studio (DashScope) joins the data-driven descriptor
  table: international compatible-mode endpoint, DASHSCOPE_API_KEY,
  live /v1/models as the Qwen model authority (never a compiled id).
- Tests: role-keyed gate fixtures moved to canonical tokens; the operate
  model-shell test now seals the goal through the deferred update_goal
  tool (deferral retry included) instead of pausing blindly; the
  slash-source hotbar test isolates HOME; ⚠ and ⋮ gained ASCII
  fallbacks; launch goldens re-blessed for the card.

* feat(tui): retire Pod from copy; canonical workflow fixture; gate clean-up

- Pod literal sweep across fleet views, worker runtime, sub-agent tool,
  managed API, and command groups: user-facing copy now says Fleet
  (founder vocabulary decision; /fleet canonical, /pod and
  'codewhale pod' stay as compatibility aliases). Roster tests that
  encoded the retired Pod-public/Fleet-internal split now assert the
  public Fleet vocabulary.
- workflows/stopship + fleets/stopship use canonical role names
  (explore/implement/reviewer/test); the workflow crate's own stopship
  tests and required-roles list follow.
- Operate mode-picker hint shortened to fit 80 columns in every locale.
- Cucumber PTY launch flows: wait for the launch card, type the first
  prompt and press Enter; the live shell is proven by the launch stage's
  top line disappearing and the metrics line's ctx reading (the
  interrupt hint needs a live turn, which an offline route never
  starts). The stopship acceptance feature expects the canonical /fleet
  help copy.
- CHANGELOG receipts synced; DESIGN.md shell direction records the card,
  posture bar + metrics line, and the bottom view cycle.

* test(cucumber): launch-card PTY contract fixes

- The launch-card wait uses the menu's New worktree entry — unique to the
  card; the bare wordmark also matches onboarding copy.
- The live-shell proof is the launch stage's top line disappearing plus
  the metrics line's ctx reading; the interrupt hint needs a live turn,
  which an offline route never starts, and the help hint sheds first at
  the 40-column floor by design (SHELL-DESIGN-20260901 §2.2).
- The pointer-submit queue proof takes the offline onboarding seed into
  account: the receipt toast proves the gesture, and the queue count
  grows by exactly one.

* docs(readme): restore the canonical product screenshot the web contract pins

The brand header redesign dropped the assets/screenshot.webp embed; the
web public-surface contract pins the README and the website to one
canonical optimized screenshot (byte-identical, 1562x1256 lossless
VP8L). Re-embed it.

* test: platform-robust pointer-submit wait and cap-warning diagnostics

- The pointer queue proof accepts either the transient receipt toast or
  the queue-count increment: toast timing differs across runners, and a
  20 s wait missed a toast the queue dump proved had fired.
- The context-cap posture test dumps the drawn rows when the warning
  count misses, instead of a bare 0 != 1, so a platform-specific shed
  (the hint sheds first when the left run exceeds its budget) is
  visible in CI.

* test: fix the linux-only context-cap shed; bounded pointer-click retry

- The context-cap posture test drew at 100 columns, where a backend-less
  platform (linux CI paints 'files: workspace (unenforced)') sheds the
  cap hint first, so the warning count read 0. Draw at 140 columns,
  where the hint survives with the notice present; verified locally.
- The pointer queue proof retries the [↑] click once, re-finding the
  affordance first: under runner load a redraw can shift cells between
  the find and the click, so the first SGR gesture lands nowhere.

* fix(gates): tool-catalog budget covers the fleet rename; readme stamps; pointer baseline

- The Pod->Fleet sweep grew every mode's tool-schema surface by 58 bytes
  (+14 tokens). The receipts are re-measured and the one-way ceilings in
  scripts/runtime-contract-budget.json are raised to them as the
  explicit maintainer decision the gate asks for (the rename is the
  founder's 2026-09-01 vocabulary call).
- The README screenshot embed changed README.md; the 18 translated
  READMEs re-stamp (the embed is language-neutral HTML - no prose
  changed, so no retranslation was needed).
- The pointer queue baseline is captured while the composer is empty:
  the pending preview row hides while a draft sits in the composer, so
  the pre-click depth read None and the growth proof could not fire.

* test: re-click then keep polling until the deadline

The qa_harness Instant wrapper does not implement Div, and the retry's
single read raced the app processing the second gesture: poll to the
full deadline, re-click once at the half-way point.

* test: pointer queue diagnostics (baseline/expected/last-seen) in the failure output

* test: pointer poll keeps per-iteration state only (unused-assignment gate)

* fix: Copilot review findings — planner wire spelling and Advisor copy

- workflow::AgentType::Plan serializes as the canonical 'planner'
  ('plan'/'awaiter' stay accepted aliases), matching the FleetRole
  vocabulary the mega PR declares.
- Web: the vocabulary docs metadata, the vocabulary module header, and
  the docs-map topic description say Advisor (the public advisory term)
  instead of the retired Consultant spelling.
- Polish home dictionary: restore 'Podwodna powłoka terminala' — the
  fleet-vocabulary sweep had merged 'Fleet' into the compound word
  'Podwodna' (underwater), producing the non-word 'fleetwodna'.

* test: pointer proof accepts preview-appears when no baseline count is painted

* test: the tolerant preview-appears proof (the arm the last commit missed)

---------

Signed-off-by: CodeWhale Bot <[email protected]>
Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: CodeWhale Bot <[email protected]>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Claude Fable 5.1 <[email protected]>
2026-09-02 09:32:14 -07:00
Hunter BownandCodeWhale Bot 84f42aefc0 feat: make Pod the public roster surface (#5776)
* feat: make Pod the public roster surface

Signed-off-by: CodeWhale Bot <[email protected]>

* fix(tui): localize pod workers modal and restore fleet receipt compatibility

Review-fix follow-up for the Pod public surface:

- /pod workers modal routes all previously hardcoded English through tr()
  with 38 new MessageIds across all 15 shipped locales; a zh-Hans render
  test asserts no English leakage.
- /pod workers means current-session sub-agents and /pod status the
  durable ledger, pinned per locale by a new localization test.
- Durable receipt detail prefixes restored to the established fleet:
  spelling (lane render_detail, tui status_lines, resume detail) with
  regression tests at both layers; serde wire keys unchanged.

Local proof (RUST_MIN_STACK=33554432, --locked): localization 49/49,
fleet::control 11/11, subagents 33/33, commands fleet group 13/13,
codewhale-lane 62/62; cargo fmt --check clean; locale key-set hash
identical across all 15 packs.

Signed-off-by: CodeWhale Bot <[email protected]>

---------

Signed-off-by: CodeWhale Bot <[email protected]>
Co-authored-by: CodeWhale Bot <[email protected]>
2026-08-31 20:10:20 +00:00
Sh1ZukuandHunter Bown 806d93e826 docs(i18n): fix English doc inaccuracies and add first zh_hans translations for Tier-2 (#5613)
* docs: fix doc inaccuracies found in zh_hans review

* docs: add zh_hans translation for INSTALL

* docs: add zh_hans translation for KEYBINDINGS

* docs: add zh_hans translation for GUIDE

---------

Co-authored-by: Hunter Bown <[email protected]>
2026-08-25 04:52:50 -07:00
Hunter Bown 22bf21dbca docs: align 0.9.10 public product truth
Signed-off-by: Hunter Bown <[email protected]>
2026-08-19 23:05:31 -07:00
Hunter Bown 1a9600e7cd feat(tui): make /workflow /goal /auto one-keystroke discoverable
The engines already shipped; the remaining gap was visibility. Pin the
orchestration trio at the top of the empty / menu, name them on the idle
welcome and footer, put them in the first three Hotbar defaults, and add
/auto as a host-only Auto-Review switch with when-to-use copy (#5439).

Verified: cargo fmt --all -- --check; locale parity; command-migration
manifest; cargo nextest -p codewhale-config --lib -- hotbar (5);
codewhale-tui lib tests for empty slash pin, /auto, palette root, empty
state, footer, hotbar defaults, and locale sync (32 passed).

Signed-off-by: Hunter Bown <[email protected]>
2026-08-19 00:08:12 -07:00
CodeWhale Bot 4999092c01 docs: match Full Access hold copy to the 2026-08-10 behavior
Registered non-bypassable holds auto-approve in Full Access rather than
hard-blocking; repository-law and managed-policy holds still fail
closed. The cited regression is
non_bypassable_registered_tools_auto_approve_in_full_access.
2026-08-18 21:22:49 -07:00
Shizuku fc23323c44 docs: fix outdated A/B-tier references for v0.9.7
A-tier (contradicted the code):
- RUNTIME_API.md: document the undo/patch-undo/retry/snapshot-restore
  endpoints that shipped but were marked deferred; drop product-name
  brand residue (DeepSeek engine/client/tools -> Codewhale)
- AGENT_RUNTIME.md: rebrand shims removed in v0.9.0, file decomposition
  landed (ui.rs ~3.9k, main.rs stub), verifier contract path, v0.9.1
  release precondition met (current line v0.9.7)
- public-surface-facts.json + web test: defaultActive = the six
  DEFAULT_ACTIVE_NATIVE_TOOLS names (todo_write, not tool_search)
- MODES.md: toolbox list matches the seven model-facing names; retired
  /set removed from active slash surfaces (legacy note kept)
- KEYBINDINGS.md: Alt-P/A/Y = Plan/Work/Yolo, not Plan/Work/Operate

B-tier (clearly stale):
- ACCESSIBILITY.md: brand legacy first line; /settings set examples ->
  /config <key> <value> --save; section title
- SKILLS.md: MAX_AVAILABLE_SKILLS_CHARS 12 000 -> 2 400
- FLEET.md / WORKFLOW_AUTHORING.md: Fleet rings 5/2 -> 8/3
- TERMUX.md: self-update requests only the codewhale-android-arm64 asset
- OPERATIONS_RUNBOOK.md: RUST_LOG target deepseek_cli -> codewhale_tui
- CATALOG_REFRESH.md: broken MODEL_PROVIDER_AUDIT.md -> PROVIDERS.md
- CONFIGURATION.md: provider list 28 -> 40; /note primary path
- MCP.md: "Running DeepSeek as an MCP Server" brand -> Codewhale;
  /mcp subcommand list (import/recommendations/add recommended)
- web tools page: todo_write out of the Deferred group into its own
  schema row

ARCHITECTURE.md updates (LLM client layer, sandbox backends, github.rs
removal) that landed in the working tree are included.

Verified: facts JSON valid, no broken .md links in docs, every claim
cross-checked against code; web tests not run (node_modules absent).
2026-08-17 19:44:27 +08:00
CodeWhale Bot c43e53d284 Merge branch 'work/v098-workflows-goal-parity-20260815' into work/v098-integration-20260815
# Conflicts:
#	CHANGELOG.md
#	crates/tui/locales/ca.json
#	crates/tui/locales/de.json
#	crates/tui/locales/en.json
#	crates/tui/locales/es-419.json
#	crates/tui/locales/fr.json
#	crates/tui/locales/hi.json
#	crates/tui/locales/id.json
#	crates/tui/locales/ja.json
#	crates/tui/locales/ko.json
#	crates/tui/locales/pt-BR.json
#	crates/tui/locales/ru.json
#	crates/tui/locales/uk.json
#	crates/tui/locales/vi.json
#	crates/tui/locales/zh-Hans.json
#	crates/tui/locales/zh-Hant.json
2026-08-15 21:14:46 -07:00
Hunter Bown a98d9184e6 docs: describe host-side Workflow and Goal controls
Record the new control verbs, inferable create_goal, and the fact that
the session [workflow] table is now honored. Correct the published
auto_start_child_limit / max_children defaults (16 / 1000, matching
config.example.toml). The example header's /workflow run form is now
a real host verb; keep the CLI equivalent next to it.

The design note is the lane audit against Grok Build and DeepSeek
Harness: what shipped here, and what was left as follow-up (journal
replay resume, a named saved-workflow registry, strategist restructure).
2026-08-15 20:56:42 -07:00
CodeWhale Bot 43ffca8561 feat(tui): state a child's effective posture and document inheritance
The focused worker header now names write, network, and shell from the
runtime permission snapshot, never guessed. New AgentFocusPosture
strings are translated in every complete locale pack.

Docs and the unreleased changelog describe the session-posture gate
(Ask / Auto-Review / Full Access) and the role defaults that keep
network reads and planner probes without widening write-only roles.
2026-08-15 20:56:04 -07:00
CodeWhale Bot 16557b0705 refactor(tui): remove inert review guidance
Drop the natural-language Auto-Review knob that neither deterministic policy nor the guardian consumed. Existing configs with the retired key continue to parse, while the runtime and audit surface no longer pretend it has an effect.

Refresh the Codex comparison to the exact locally verified guardian source; Kimi and DeepSeek Harness remain correctly documented as having no LLM reviewer.

Agent assistance: Codex.
2026-08-13 14:24:50 -07:00
CodeWhale Bot 962a006c8e refactor(tui): keep guardian inputs deterministic
Remove free-form Auto-Review guidance from the model request so the guardian sees only its fixed policy, the exact held call, and deterministic observations. Document the pinned evidence boundary: Codex provides an experimental LLM-review pattern, Kimi provides unattended-mode UX without a reviewer, and DeepSeek Harness provides sandbox and escalation contracts without Auto-Review.

Agent assistance: OpenAI Codex.
2026-08-13 12:55:12 -07:00
CodeWhale Bot a75dec8b06 refactor(tui): make Auto-Review single-shot
Remove the user-intent ledger and reviewer retry loop. Review one exact held call with deterministic observations, account for that call, and fail closed on every unavailable answer.

Document the safety baseline against the pinned DeepSeek Harness 0.1.0-rc.5 sandbox and approval contracts.

Agent assistance: OpenAI Codex.
2026-08-13 12:42:11 -07:00
CodeWhale Bot 59299dff35 fix(tui): make Auto-Review risk-first
Require a typed intrinsic risk on guardian decisions, deny high and critical outcomes mechanically, and retry only malformed or incomplete answers within one deadline while preserving usage.

Keep repository-law holds fail-closed in every non-interactive posture instead of opening a hidden human approval modal.

Design informed by local source audits of Codex Guardian, Kimi Code permission policies, and DeepSeek Harness approval/sandbox behavior.

Agent assistance: OpenAI Codex performed the local comparison, implementation, and verification.
2026-08-13 10:17:44 -07:00
CodeWhale BotandLstarsky0 34c541a5af feat(tui): add a fail-closed Auto-Review guardian
Keep deterministic policy and the built-in safety floor authoritative, then consult one stateless no-tools guardian only for fallback holds in interactive Auto mode. Bind that call to exact external-input evidence, keep expanded context non-authoritative, and deny on missing authorization, timeout, cancellation, provider failure, incomplete output, malformed JSON, or oversized exact context.

The simplification removes inferred intent matchers, the reviewer toggle, remembered denial state, redundant rule actions, duplicate decision paths, and non-decision action variants.

Agent assistance was used.

Co-authored-by: Lstarsky0 <[email protected]>
2026-08-13 09:14:45 -07:00
CodeWhale Bot 037aab9cf3 docs: align the v0.9.6 public surface
Document Work and To-do as the two product concepts, synchronize every shipped locale, publish the six-tool and typed-image contracts, and keep static web generation offline while live GitHub chrome refreshes after deployment.
2026-08-11 06:16:30 -07:00
CodeWhale Bot 5798de8b39 build(release): native musl for Linux ARM64, and reconciled copy
Three v0.9.5 benchmark tasks could not launch Codewhale at all:
mteb-leaderboard, mteb-retrieve, and pytorch-model-recovery run older ARM64
images, and the aarch64-unknown-linux-gnu artifact built on ubuntu-24.04-arm
requires GLIBC_2.39.

Release and nightly now build aarch64-unknown-linux-musl on the native ARM
runner, alongside the x64 musl build that has shipped since v0.8.65. Both
gain a static check (no ELF INTERP) plus a launch smoke on the matching
native runner, so a dynamically linked or non-starting binary fails the
build rather than the user's install. docs/INSTALL.md drops the arm64 glibc
floor section and describes the v0.9.6 matrix.

Also reconciles the copy the earlier commits invalidated: setup ratification
text and all 15 locales stop attributing execution doctrine to "mode
prompts", docs/MODES.md states Auto-Review's actual deterministic
allow/deny behavior, and the source-structure, dead-code, and
runtime-contract budgets are re-measured — the last locking down 25
decreased ceilings and the new mode-agnostic prompt-stage digests.
2026-08-09 00:52:42 -07:00
Hmbown c2c414ef73 docs: correct limits, /trust, and the Ollama default that were wrong in the unsafe direction
2026-08-04 model-facing-text audit. Four user-facing claims contradicted the
code, three of them in the direction that costs the user:

- CONFIGURATION.md said max_subagents 'defaults to 20 and is clamped to
  1..=20' in four places. Code: DEFAULT_MAX_SUBAGENTS = 64, MAX_SUBAGENTS =
  128 (config/subagent_limits.rs:13,17). Out-of-box concurrency is 3.2x the
  documented figure, and a user writing max_subagents = 40 to 'raise it to
  the max' was told it would clamp to 20 when it is honored in full. Same
  shape for max_admitted: documented ceiling 200, actual
  MAX_SUBAGENT_ADMISSION = 1024.
- Usage: codewhale [OPTIONS] [PROMPT]
       codewhale [OPTIONS] <COMMAND> [ARGS]

Commands:
  run           Run interactive/non-interactive flows via the TUI binary
  doctor        Run Codewhale diagnostics
  models        List live provider API models via the TUI binary
  speech        Generate speech audio with Xiaomi MiMo TTS models via the TUI binary [aliases: tts]
  sessions      List saved TUI sessions
  resume        Resume a saved TUI session
  rc            Launch an interactive session and hand it to the Codewhale web app
  fork          Fork a saved TUI session
  init          Create a default AGENTS.md in the current directory
  setup         Bootstrap MCP config and/or skills directories
  remote-setup  Generate a remote Codewhale agent deploy bundle (cloud + chat bridge)
  exec          Run a non-interactive prompt through the TUI runtime
  fleet         Manage durable Agent Fleet runs via the TUI runtime
  workflow      Run checked-in Workflows through a Lane Runtime backend
  lane          Manage running workflow instances (Lanes) and Runtime backends (#4176)
  review        Run a Codewhale-powered code review over a git diff
  apply         Apply a patch file or stdin to the working tree
  eval          Run the offline TUI evaluation harness
  mcp           Manage TUI MCP servers
  features      Inspect TUI feature flags
  serve         Run a local TUI server
  web           Open the first-class local browser client over the canonical Runtime API
  completions   Generate shell completions for the TUI binary
  login         Configure provider credentials
  logout        Remove saved authentication state
  auth          Manage authentication credentials and provider mode
  account       Sign in to your Codewhale account and manage account-scoped provider keys [aliases: cloud]
  mcp-server    Run MCP server mode over stdio
  config        Read/write/list config values
  model         Resolve or list available models across providers
  thread        Manage thread/session metadata and resume/fork flows
  sandbox       Evaluate sandbox/approval policy decisions
  app-server    Run the canonical runtime API / control plane (HTTP/SSE, mobile, stdio)
  completion    Generate shell completions
  metrics       Print a usage rollup from the audit log and session store
  update        Check for and apply updates to the `codewhale` binary
  help          Print this message or the help of the given subcommand(s)

Arguments:
  [PROMPT]...

Options:
      --config <CONFIG>

      --profile <PROFILE>

      --provider <PROVIDER>
          Provider selector; exec/fleet also accept configured custom provider identifiers
      --model <MODEL>

      --output-mode <OUTPUT_MODE>

      --verbosity <LEVEL>
          Controls transcript and output verbosity (normal, concise)
      --log-level <LOG_LEVEL>

      --telemetry <BOOL>
          Opt in to anonymous product telemetry for this run (default off; CODEWHALE_TELEMETRY=0 always wins) [possible values: true, false]
      --approval-policy <APPROVAL_POLICY>

      --sandbox-mode <SANDBOX_MODE>

      --api-key <API_KEY>

      --base-url <BASE_URL>

  -C, --workspace <DIR>
          Workspace directory for TUI file tools
      --mouse-capture

      --no-mouse-capture

      --skip-onboarding

      --no-project-config
          Skip loading project-level config, including the workspace-specific `[workspace]`/`[projects]` overlay from user config. Must appear before the subcommand; it is forwarded to the TUI ahead of the subcommand
  -c, --continue
          Continue the most recent interactive session for this workspace
  -p, --prompt <PROMPT>

  -h, --help
          Print help
  -V, --version
          Print version said '(1-20)' while main.rs clamps to 128. Here the doc
  was right and the help was wrong; both now say 1-128, default 64.
- MODES.md gave bare  as the enable command. config.rs:2278 maps
  "" | "status" | "list" to trust_status — bare /trust only REPORTS. A user
  reads the status block, believes trust is on, and escalates to Full Access
  when the next out-of-workspace operation fails. Now documents /trust on
  and says plainly that bare /trust does not enable anything.
- CONFIGURATION.md gave  as the Ollama default; the
  string appears nowhere in crates/. provider_defaults.rs:109 is
  deepseek-v4-flash. Self-hosted is where a bad default bites hardest.

Verified: limits read from config/subagent_limits.rs, /trust dispatch read
from config.rs:2278, Ollama default from provider_defaults.rs:109; tui
builds clean. Authored with agent assistance (Claude).
2026-08-04 11:57:18 -07:00
Hmbown 8869def98a fix(exec): resume headless turns after mid-stream network drops, exit EX_TEMPFAIL on infra failure
Terminal-Bench 2.1 (89 tasks, codewhale 0.9.4, deepseek-v4-flash):
5 of 7 NonZeroAgentExitCodeError forfeits were the identical failure —
the provider stream dropped mid-response ("error decoding response
body" after partial content), the #103 policy surfaced the warning and
failed the turn, and `codewhale exec` exited 1. regex-log passed the
smoke run and crashed in the full run: a nondeterministic transport
drop, not a task failure. Pi retries the same drops (332 retries, 0
crashes).

Engine (turn_loop + streaming policy):
- New should_resume_after_network_drop policy: in headless hosts
  (exec / stream-json; terminal_chrome_enabled = false) a network-class
  stream error after partial content now schedules a full request
  re-issue, bounded by MAX_STREAM_RETRIES, exactly like the #2990
  sleep-resume. The partial fragment was never committed and no tool
  from the incomplete response executed, so replaying from the last
  committed boundary cannot duplicate side effects. Interactive TUI
  keeps the #103 surface-the-warning behavior. No error event is
  emitted for attempts that will be retried; the budget-exhausted final
  attempt still reports the real error.

Exec exit semantics (main.rs):
- Terminal failures with error_category network/timeout now exit 75
  (EX_TEMPFAIL) instead of 1, so harnesses can distinguish retryable
  infra failures from genuine task failures (still exit 1). No error is
  masked: the stream-json error event, terminal metadata status=failed,
  and error_category are unchanged.
- Recoverable mid-turn error events (e.g. stream-stall warnings) no
  longer poison the exec run summary; the terminal TurnComplete carries
  the authoritative outcome. Previously any recoverable warning forced
  a non-zero exit even when the turn later completed.

Regression coverage:
- Pure policy tests for the headless/network/budget/cancel matrix.
- Engine-level tests with a flaky mock client: mid-stream drop recovers
  (2 requests, completed, fragment discarded); budget exhaustion fails
  with the real error and exactly one error event.
- Process-level acceptance (tests/exec_stream_drop_acceptance.rs): raw
  TCP server truncates the SSE body mid-content-length, reproducing the
  production decode error against the real binary — exit 0 after
  recovery, exit 75 with error-channel reporting after exhaustion.

Gates: cargo fmt --all --check; cargo check -p codewhale-tui; targeted
tests 18/18 + acceptance 2/2; full codewhale-tui suite 10141 passed,
21 failed — all in the known pre-existing env-key/qa_pty set
(provider-catalog API-key panics + PTY visual matrix), none in the
touched paths.
2026-08-03 10:07:10 -07:00