Files
DeepSeek-TUI/docs/zh_hans/GUIDE.md
Hunter Bown 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 <bot@codewhale.net>

* 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 <bot@codewhale.net>

* 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 <bot@codewhale.net>

* brand: trace supplied whale assets

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

* 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 <hmbown@gmail.com>

* brand: use white icon tile

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

* brand: deepen ombre light stop

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

* 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 <hmbown@gmail.com>

* 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 <hmbown@gmail.com>

* tui: localize image rejection recovery

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

* 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 <hmbown@gmail.com>

* 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 <hmbown@gmail.com>

* 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 <hmbown@gmail.com>

* 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 <hmbown@gmail.com>

* 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 <hmbown@gmail.com>

* 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 <hmbown@gmail.com>

* 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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
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 <bot@codewhale.net>
Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: CodeWhale Bot <bot@codewhale.net>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 09:32:14 -07:00

26 KiB
Raw Permalink Blame History

Codewhale 用户指南

本文翻译自英文版 GUIDE.md,与英文修订 3c36303962026-08-19同步。

本指南面向你使用 Codewhale 的第一个小时。它涵盖了主要工作流程、重要安全控制,以及当你需要完整参考时接下来该看什么。

Codewhale 有更深入的参考文档涵盖安装、配置、提供商provider、模式、快捷键、工具和运维。请将本页当作引导式走查需要每个选项时再顺着"下一步"链接往下看。

1. 欢迎使用 Codewhale

Codewhale 是一个终端编码智能体agent。你从某个工作区运行它交给它一个任务它就能用结构化工具检查文件、运行命令、编辑代码并带回证据汇报结果。

与普通聊天模型的重要区别在于Codewhale 是围绕 “驾驭框架”harness 构建的:

  • 它让活动工作区和会话保持可见。
  • 它把每一轮都路由到明确的模式与审批规则。
  • 它在对话记录中展示工具调用,而不是把工作藏起来。
  • 它可以保存会话、分叉对话,并在之后继续。
  • 它可以运行子智能体来执行专注的后台工作。

你可以用 Codewhale 回答小问题:

解释此仓库中的身份验证流程。

也可以用它做多步工作:

找到失败的验证路径,提出修复方案,等我批准了再编辑文件。

对于新仓库,请从保守的方式开始。在要求 Codewhale 修改文件之前,先让它探索和规划。这样会为您提供可审查的路径,并更容易及早发现错误的假设。

下一步:ARCHITECTURE.md 讲解内部 harness 与运行时模型。

2. 首次启动

用适合你机器的路径安装 Codewhale。发布安装器在 codewhalecodew 两个命令名下提供同一运行时;每条受支持的安装路径都提供 codewhale 调度器,codewhale-tui 运行时已内置。

# npm
npm install -g codewhale

# Cargo
cargo install codewhale-cli --locked
# Cargo 安装后可选的短命令名:
ln -s "$(command -v codewhale)" "$(dirname "$(command -v codewhale)")/codew"

# Homebrew
brew tap Hmbown/deepseek-tui
brew install codewhale

当你想要隔离的运行时,也可以用 Docker

docker volume create codewhale-home
docker run --rm -it \
  -e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \
  -v codewhale-home:/home/codewhale/.codewhale \
  -v "$PWD:/workspace" \
  -w /workspace \
  ghcr.io/hmbown/codewhale:latest

从你希望它工作的仓库或目录启动 Codewhale

codewhale

首次启动时Codewhale 只询问本次安装仍然需要的决定:无法推断语言时询问语言,未配置可用路由时询问提供商,文件夹需要决定时询问工作区信任。提供商步骤包含明确的离线路由。就绪界面随后打开真正的编辑器,保留命令行中提供的任务,或为当前文件夹建议第一个任务。

此后所有可选内容都保持可用。用 /setup 打开渐进式设置与修复指南,用 /settings 打开完整键入式编辑器,想自定义内置工作约定时用 /constitution。本地化遥测选择只在工作区就绪后出现,不会阻塞编辑器。

DeepSeek 是默认提供商。如果你想在首次启动之前或之后配置它的 key最直接的设置路径是

codewhale auth set --provider deepseek

你也可以通过环境变量提供 key

export DEEPSEEK_API_KEY="your-key"
codewhale

新的 Codewhale 配置存放在 ~/.codewhale/config.toml。旧的 ~/.deepseek/config.toml 文件仍受支持,供从旧名称迁移的用户使用。

/constitution 查看或更改常驻指引。设置完成后,运行一次 doctor 检查:

codewhale doctor

当你需要机器可读的报告用于提交 issue 时,用 JSON 形式:

codewhale doctor --json

两种形式默认都是离线的。 它们报告结构配置和字面上的未知/未探测凭证状态,不会加载工作区的 .env 凭据、打开 secret/OAuth 文件、探测密钥串、联系提供商或启动 MCP 服务器。只有有意需要该实时边界时,才使用 --check-updates--probe-api--probe-local--probe-mcp。JSON 保持离线,不接受实时标志。

JSON 把凭据的 source(来源)与字面的 availability可用性分开报告。配置的环境、外部认证、OAuth、consent 和 secret-store 来源仍为 not_probed;它们的声明本身并不会让 Setup 或 fleet 就绪。只有结构上存在的字面配置值或一条不需要凭据的路由才能证明离线就绪。对于无法使用共享存储的路由上的旧版密钥存储哨兵secret-store sentinel会单独报告为 secret_store_unavailable/unavailable,而不是简单的"符合条件"或"未知"。

doctordoctor --json 都还包含一项会话恢复诊断,它把旧会话文件名与当前存储对比,不读取会话内容,并报告以下之一: isolatedno_legacy_sessionsmigration_pendingmigration_incompletemigration_completescan_failed 。 使用 migration_pendingmigration_incomplete 作为提示,完成把会话从 ~/.deepseek 迁移到 ~/.codewhale 的工作——就是上面提到的旧路径迁移。显式设置 CODEWHALE_HOME 会抑制此环境检查。

下一步:INSTALL.md 涵盖各平台的安装路径,CONFIGURATION.md 涵盖配置解析,PROVIDERS.md 涵盖提供商 ID 与凭据。

3. 你的第一个任务

从一个真实工作区里的只读任务开始:

映射仓库结构,并告诉我 CLI 入口点在哪里。

然后要一份有重点的计划:

我想为空的配置值添加一个小型验证。
检查相关代码,并在编辑任何内容之前提出最小的安全更改。

当你准备好做编辑时,把验收标准说具体:

实施你提出的验证。
将更改范围限制在配置解析内,添加或更新最窄的测试,并运行相关的检查。

好的首批提示词prompt包含四个要素

  • 你想要的结果。
  • 你关心的文件、功能或行为。
  • 哪些不在范围内。
  • 什么算"验证通过"。

例如:

修复配置加载器中损坏的提供程序错误消息。
不要更改提供程序注册表。添加回归测试,并且只运行 config 包的测试。

如果你不确定 bug 在哪,直说:

调查为什么 `codewhale doctor` 报告了错误的提供程序。
暂时不要编辑文件。返回可能的原因、证据和提议的补丁计划。

面对不熟悉的代码,让调查和实现分步进行时 Codewhale 表现最好。对于很小且充分理解的改动,一个单独的实现请求就够了。

下一步:MODES.md 讲解何时使用 Plan、Act 和 Operate。

4. 了解界面

交互式 TUI 有几个稳定的区域:

  • 头部Header当前会话、活动模型、模式和总体状态。
  • 转录区对话记录Transcript对话、工具调用、命令输出摘要和模型回复。
  • 输入区Composer你在这里输入提示、斜杠命令和文件提及。
  • 工作栏Work bar转录区上方的一条或可选的侧栏承载活动目标、待办列表和子智能体。行会保持整个会话——已完成的工作显示为"已完成"而不是消失——点击某一行(或对它按 Enter)会打开它的详情。
  • 状态与底部区域:实时活动、排队的后续动作和简短命令提示。

底部状态行可配置。运行 /statusline 选择哪些底部的片区可见,或在 config.toml 里设置 [tui].status_items 同时控制选择和顺序。 当前支持的键包括 modemodelcostbalance(仅 DeepSeek / DeepSeekCNstatusagentsreasoning_replayprefix_stabilitycachecontext_percentgit_branchlast_tool_elapsed(保留)、rate_limit(保留)、tokenssession_metrics。 省略 status_items 以保持内置默认顺序;把它设为 [] 以隐藏可配置的片区。

session_metrics(默认开启)在阶段行上绘制会话指标条带: 4 turns · 108 steps │ LLM 11m46s · Tool call 1m52s │ TTFT avg 1.5s · 120 tok/s │ Cache hit 99% │ Input 9.3M Turns 是用户回合steps 是模型调用加工具调用;LLM 是模型调用墙钟时间的总和,Tool call 是工具墙钟时间的总和;TTFT avg 是到首个流式 token 的平均时间;tok/s 是提供商报告的输出 token 除以流式秒数;Cache hitInput 是提供商报告的 token 类别。提供商或运行时证据尚未到达的单元格会被省略而不是估算,在窄行上,指标条会丢弃价值最低的组(先是 steps 和工具时间然后是延迟、turns、LLM 时间),而不是截断某个数字。/status 打印未裁剪的完整行。

转录区(对话记录)就是审计轨迹。当 Codewhale 读文件、跑命令或改代码时,动作会出现在那里。如果某条命令失败,把可见的失败输出作为你下一条指令的一部分,而不是从头再来。

输入区接受普通提示和斜杠命令。输入 / 可以发现可用命令。想让模型专注于某个特定文件或目录而不是广泛搜索时,使用文件提及。

当一个回合跨越多个步骤时,工作栏很有用。它让目标、待办列表和智能体状态保持可见,同时转录区继续增长——包括在工作落定之后,这样你仍然可以打开看看发生了什么。

键盘快捷键因上下文、终端和平台而异。本指南不重复完整的快捷键目录,以免与 TUI 脱节。

下一步:KEYBINDINGS.md 是完整的快捷键参考。

5. 模式

Codewhale 有三种可见的 TUI 模式:

模式 用于 默认姿态
Plan 改动前的探索、设计与审查 只读调查
Act 常规的多步编码工作 带审批门禁的工具使用
Operate 直接工作,外加并行或后台协调 工具遵循活动姿态;需要时委派

从 TUI 里用模式选择器切换模式:

/mode

或直接切换:

/mode plan
/mode act
/mode operate

Plan 模式是在陌生仓库里开始的最安全位置。它用于检查和决策不做文件编辑。对于非平凡的工作Plan 模式的确认提示可以显示有依据的计划工件PlanArtifact目标、上下文、使用的来源、关键文件、约束、方法、验证计划、风险和交接说明。 当智能体agent使用富工件形态时空章节也是可见的所以你可以要求修订而不是接受一份说明不足的计划。

Act 模式是大多数贡献工作的默认模式。它允许 Codewhale 读文件、跑检查、编辑文件,同时把有风险的动作留在审批门禁之后。

Operate 保持直接的工具面及其审批、沙箱、shell、ask 规则和仓库保护。它的区别在于编排重点Codewhale 优先把独立、并行、后台或长时间运行的工作交给 fleet worker而小型或紧密耦合的工作可以留在父进程中。

对于你信任的工作区,如果你确实希望动作不经审批提示就继续,可以用 Shift+Tab 选择 Full Access 权限姿态。不要在你不信任的仓库里使用 Full Access。

模式与模型路由是分开的。输入区空闲时 Tab 循环切换可见模式,而 /model auto 控制回合的模型与思考选择。

你也可以在 /config 里通过编辑审批模式来改变审批行为。只有当你理解它会如何改变工具执行时才使用它。

下一步:MODES.md 有完整的模式、审批和信任模式参考。

6. 斜杠命令

斜杠命令在输入区里输入。当你想要直接改变 Codewhale 状态,而不是用自然语言让模型去做时,它们很有用。

对首次用户常用的命令:

命令 用途
/mode 打开模式选择器,或用 /mode agent 切换
/model 选择模型,或用 /model auto
/provider 选择活动的 API 提供商
/fleet 打开当前所选 fleet 的成员花名册
/fleet saved 选择或切换已命名保存的 fleet
/goal 设置一个智能体跨回合持续追求的持久目标;裸 /goal 显示进度
/workflow 把当前工作编排为 Workflowstatuscancelsettings 无需模型回合即可回答
/workflows 打开实时 Workflow 运行仪表盘:该工作区日志记录的每一次运行,含阶段、子项、进度和主机侧取消
/config 编辑运行时与提供商设置
/statusline 选择哪些底部状态芯片可见
/compact 压缩长上下文以回收 token 预算
/review 请求结构化的审查工作流
/memory 启用时检查或管理记忆
/mcp 配置或检查 MCP 服务器集成
/plugin 审查和管理默认禁用的本地插件包
/rc 把此确切会话交给已登录的 Codewhale 网页应用

工具箱命令直接输入即可搜索:/models 拉取实时端点 ID/modeldb 打开内置模型参考,/rlm 把文件或一段文本加载进工作上下文,在会话剩余时间里保持可用。

想切离默认的 DeepSeek 路由时用 /provider。Provider ID、环境变量、模型默认值和能力说明都保留在提供商注册表文档里。

软自动多智能体工作:AUTOMATIC_WORKFLOWS.md

面向持久多 worker 工作的下一步:FLEET_WORKFLOW_TUTORIAL.md 带你走一遍 fleet 任务规格、监控和 Workflow 编写。

想让 Codewhale 每回合自己选模型和思考级别时,用 /model auto。当 DeepSeek 路由模型可用时Auto 可以在脱敏清单中选取任何可运行的 provider/模型组合。该分类会把最新请求(上限 4,000 字符)加上最多六条最近上下文行的有界摘要(每条 900 字符)发送到 DeepSeek / deepseek-v4-flash。凭据、端点和提供商错误文本不会包含在清单里。没有该路由器时Auto 使用本地的、感知提供商的启发式方法不发送任何路由请求。如果分类尝试未通过验证或出错Auto 回退到该启发式方法,同时把尝试过的分类器数据路径保留在回合回执中。

/model 选择器会说明哪条数据路径可用,并显示最后解析的路由。Ctrl+O 打开所选或当前回合的推理详情;Ctrl+Alt+O(或 /turn inspect打开整回合的回合检查器Turn Inspector其模型路由区记录具体的 provider/模型、strong/fast 配对、所选层级、选择范围、路由原因,以及分类器是否收到了路由上下文。当你需要可重复的比较、严格的提供商边界或完全不要分类请求时,使用固定模型。

会话变长、模型开始承载太多历史记录时,用 /compact。压缩会用简洁的工作摘要换取原始转录细节。

本指南有意不列出每条命令。命令面比上手流程变化更频繁你在会话里时TUI 命令面板才是事实来源。

下一步:CONFIGURATION.md 涵盖运行时设置,MCP.md 涵盖模型上下文协议MCPModel Context Protocol集成。PLUGIN_BUNDLES.md 涵盖默认禁用的包清单、能力审查和带命名空间的 Skill/MCP 激活边界。

7. 使用工具

Codewhale 的工具是结构化操作。模型不只是产出文字,还能调用工具来检查和改变工作区。

工具支撑的工作示例包括:

  • 解释文件之前先读它。
  • 提出重构之前先搜索调用点。
  • 运行一条有重点的测试命令。
  • 应用一个小补丁。
  • 为并行调查打开一个子智能体。

工具使用由模式、审批和沙箱策略约束。确切行为取决于当前模式和配置,但基本规则很简单:只读探索用 Plan 开始,常规改动用 ActFull Access 留给受信任的自动化。

工作区边界很重要。Codewhale 应该在你启动它的目录或你配置的工作区里工作。当任务应该留在仓库内时要说清楚:

就检查并编辑此仓库下的文件。别触父目录和全局配置。

当命令需要网络、在工作区外写入或有风险的 shell 操作时,除非你配置了更宽松的行为,否则期待一个审批提示。

好的工具指令是具体的:

运行覆盖此解析器更改的最窄测试。
如果失败,报告失败并在扩大测试范围之前停止。

避免在专注修复期间要求广泛的清理。较小的工具范围使对话记录更易于审查,最终的差异更易于合并。

下一步:TOOL_SURFACE.md 列出工具面,SANDBOX.md 讲解沙箱行为。

8. 子智能体与并行工作

子智能体是后台子代理。父会话给子代理一个专注的任务,收到一个 agent id然后可以在子代理运行时继续工作。

主要的编排工具是:

  • agent:带任务和角色启动一个专注的子代理。子代理在后台运行,返回一份紧凑回执加转录句柄。

你通常不需要直接调用这些工具。用自然语言请求并行工作:

为 config 包打开一个只读探索器,为 TUI 提供商选择器打开另一个。让两者在规划修复之前返回文件引用和风险。

有用的角色包括:

角色 适合
general 多步任务;未指定角色时的默认值
explore 只读代码梳理
plan 设计与迁移规划
review 对已有改动的 bug 聚焦审查
implementer 规格明确的编辑
verifier 运行检查并报告通过/失败证据

子智能体在可以干净切分工作的时候最有用。不要为微小编辑使用它们,也不要让多个智能体同时写入相同文件。

长时间工作如何保持连贯

跨越多个回合的工作不依赖无限增长的聊天转录。这是普通 Agent 行为——不需要打开任何东西,也没有单独的工作流要学:

  • 工作上下文在整个会话中保持加载。大段源材料和持久转录作为数据保存,智能体可以搜索和切片,有用的变量与导入跨回合存活。
  • Workflow 组合独立的 task(...) 调用和并行扇出。
  • agent 消息与后续动作直接协调活动的子代理。
  • 目标Goals在工作期间保留持久目标。

/rlm <file-or-text> 把工作上下文指向一个特定文件或一段文本。历史上一度存在的动作形态 rlm 工具仍然注册着,只为了让旧会话能回放,并且刻意不教给新的模型回合。

Codewhale 还可以在 .codewhale/harness/state.json 维护一个小型项目级账本:有证据支撑的提示备注、可复用的子代理简报和 skill 路由提示。之后的回合会把它当作不受信任的补充指导接收,绝不是权威或可执行指令。读取它是自动的;添加或删除条目要走正常的审批回执。它和个人记忆是分开的,绝不能保存密钥、草稿转录或未经证实的说法。

下一步:SUBAGENTS.md 涵盖角色、生命周期、并发和输出契约。

9. 技能Skills

技能是可复用的指令包。一个技能通常是 SKILL.md 文件,教 Codewhale 如何执行某个重复工作流、使用某类工具,或遵循某项项目约定。

当任务有可重复的流程时使用技能:

  • 审查某一类 PR。
  • 处理某种文档或电子表格格式。
  • 遵循团队发布检查清单。
  • 使用项目特定的记忆或 wiki 工作流。

在 TUI 里,/skill <name> 在可用时激活技能,裸 /skills 打开技能管理器(仅限自有清单,无网络)。用 /skills <prefix>/skills inspect/skills --remote/skills suggest <task>/skills sync 走文本/注册表路径。建议会对远程目录排序,但绝不安装或激活任何东西。命令面板也能把技能条目和普通斜杠命令一起展示。

知识贵广,技能贵精。它们应该告诉模型遵循什么工作流、收集什么证据、避免什么。它们不应该隐藏凭据或取代正常的仓库文档。

如果仓库有自己的指令,把请将其当作活动工作的一部分。编辑前先读本地指南,并让你的贡献保持在仓库约定之内。

下一步:见 SKILLS.md 了解管理器、所有权和来源规则;CLAUDE_PLUGIN_COMPAT.md 了解 Claude Code 技能/插件兼容性;CONFIGURATION.md 了解配置路径与项目权威。

10. 获取帮助

从 doctor 输出开始:

codewhale doctor

提交详细 issue 时用 JSON

codewhale doctor --json

对于认证问题用结构化的来源状态确认声明了什么。Doctor 刻意不检查环境、secret-store、钥匙串或 OAuth token 的值。当实时检查合适时,用 codewhale doctor --probe-api 选择加入(本地端点用 --probe-local)。

对于提供商问题,确认活动的提供商和模型:

/provider
/model

会话又长又乱时,用 /compact 减轻上下文压力,或在同一工作区开一个新会话并总结你需要的东西。

报告 issue 时,请包含:

  • Codewhale 版本。
  • 安装方式。
  • 操作系统和终端。
  • 提供商和模型。
  • 确切的命令或提示。
  • 相关的 doctor 输出。
  • 问题是否在新工作区里也出现。

不要把 API key、私有源码或密钥粘贴进公开 issue。

下一步:OPERATIONS_RUNBOOK.md 有运维分诊与恢复步骤。

常见问题FAQ

Codewhale 只支持 DeepSeek 吗?

DeepSeek 是默认且一等的路由,但 Codewhale 也支持其他托管和本地的 OpenAI 兼容供应商。用 /providercodewhale --provider <id> 选择供应商。配置非默认路由时,请打开提供商注册表参考。

我应该先用哪个模式?

陌生代码用 Plan常规实现用 Act只有在你信任、可以接受自动执行的仓库里才用 Full Access。

为什么 Codewhale 运行命令前要问我?

审批是安全模型的一部分。Shell 命令、付费工具、写入以及预期工作区之外的动作都可能产生副作用。审批提示让你在让模型做有用工作的同时保持控制。

我如何在 macOS 上运行一个 Python 文件?

在包含该文件的文件夹里打开终端并运行:

python3 your_file.py

如果 macOS 提示 python3 缺失,从 python.org 或 Homebrew 安装 Python

brew install python

在 Codewhale 里,让智能体检查文件并用 python3 your_file.py 运行它。如果脚本需要包,先在虚拟环境里安装:

python3 -m venv .venv
source .venv/bin/activate
python3 -m pip install -r requirements.txt
python3 your_file.py

我的配置存放在哪里?

新的 Codewhale 配置使用 ~/.codewhale/config.toml。旧的 ~/.deepseek/config.toml 为兼容性仍然受支持。当工作区配置存在时,项目覆盖也可能影响行为。

如何让成本可预测?

/model auto 做路由,需要严格配置时选择固定模型,并压缩长会话。对更大的任务,让 Codewhale 先规划再实现,这样你就不会把 token 花在错误的路线上。

如何继续之前的工作?

Codewhale 会保存会话。用 README 和模式指南里讲到的会话选择器或 resume/continue CLI 路径。对于有风险的实验在改变方向前先分叉fork会话。

/sessions 选择器以当前工作区为范围启动,这样恢复会保持挂在打开的项目上。在选择器里按 a 显示所有工作区的会话,或在恢复某个特定 id 之前运行 codewhale sessions 列出所有已保存会话及其最后更新时间。

要从网页应用继续当前正在运行的会话,输入 /rc 或用 codewhale rc 启动。在系统浏览器里批准一次性代码。租赁期生效期间,浏览器拥有新的提示和审批,终端是可读的安全面。连接后,横幅和一条转录备注会显示实时会话链接(https://app.codewhale.net/session?run=…/rc open 在浏览器里打开它,/rc link 打印它。/rc status 显示归属,/rc stop 把它交回终端interrupt 仍然可用。断开的连接会保持本地输入锁定,直到最后一个网页租赁过期,这样两个控制器永远不会竞争。从一个终端登记的每个文件夹共享同一个稳定的设备 id因此网页应用每台机器列出一台电脑而不是每个会话一台。

模型糊涂了,我该怎么办?

停下来,重新陈述目标、约束和当前证据。如果转录很长,用 /compact,或带简短交接开一个新会话。如果是运维问题,运行 codewhale doctor 并检查报告的配置与提供商状态。

项目规则应该放在提示里还是文件里?

持久性的项目规则用仓库文件,回合特定的意图用提示。如果某个工作流跨项目重复出现,考虑把它做成技能。

Codewhale 能编辑当前仓库之外的文件吗?

这取决于工作区边界、沙箱设置、信任模式和审批策略。做贡献工作时,让指令保持在当前仓库范围内,除非你确实需要别的。

学完本指南后我该去哪?

读与你正在改动的东西相关的重点参考。对大多数用户,接下来的页面是安装、配置、提供商、模式、快捷键、工具和子智能体。

下一步:INSTALL.mdCONFIGURATION.mdPROVIDERS.mdMODES.mdTOOL_SURFACE.md