| 1 | # Whale Teams in the TUI |
| 2 | |
| 3 | Codewhale Cloud's **Whale Teams / Signal Cut** identity (CWC, 2026-08-15) |
| 4 | gives every agent role a species-led whale and every whale one of six runtime |
| 5 | states. This document is the contract for how that identity appears in the |
| 6 | Codewhale terminal UI. The implementation is `crates/tui/src/tui/whales.rs`. |
| 7 | |
| 8 | > **Status — runtime badges current; portrait reference retired.** The |
| 9 | > canonical Codewhale product mark is a raster asset outside this terminal-art |
| 10 | > vocabulary. Neither the old hand-drawn crown/fluke treatment nor an |
| 11 | > approximate block-glyph silhouette is a current product mark, and neither |
| 12 | > renders in `underwater.rs`. |
| 13 | |
| 14 | The source artwork (six species × six states × four colorways of 384×192 |
| 15 | rasters, plus concept boards and the visual brief) lives in the CWC repository. |
| 16 | No CWC file is copied here: the terminal whales are authored fresh as glyph |
| 17 | art, using the same state grammar and the same palette tokens. |
| 18 | |
| 19 | ## Role → species (single table) |
| 20 | |
| 21 | | Codewhale role id / `FleetRole` | Whale | Species | Job | |
| 22 | | --- | --- | --- | --- | |
| 23 | | `scout` | Scout | beaked whale | research | |
| 24 | | `builder` | Patch | harbor porpoise | coding | |
| 25 | | `manager`, `planner` | Harbor | humpback whale | coordination | |
| 26 | | `consultant`, `synthesizer` | Echo | pilot whale | communications | |
| 27 | | `verifier` | Keel | sperm whale | operations | |
| 28 | | `reviewer` | Lantern | orca | review | |
| 29 | | `worker`, `general`, `custom`, unknown | *(plain Codewhale whale)* | whale | general work | |
| 30 | |
| 31 | `WhaleSpecies::for_role_id` is the only place this mapping exists. Roles the |
| 32 | table does not name render the plain Codewhale whale — the mapping never |
| 33 | guesses from keywords. |
| 34 | |
| 35 | The roster resolves species from the profile id first (built-in ids are role |
| 36 | names), then from the resolved worker agent type. Worker rows resolve from the |
| 37 | advisory `assignment.role` when it names a species, otherwise from the runtime |
| 38 | `FleetRole`. |
| 39 | |
| 40 | ## State grammar and evidence |
| 41 | |
| 42 | | State | Word | Cue (portrait) | Cue (badge) | Evidence required | |
| 43 | | --- | --- | --- | --- | --- | |
| 44 | | Resting | Resting | level float, no wake | *(none)* | completed child; idle/done session | |
| 45 | | Thinking | Thinking | two cyan ticks above the head | `˚` | worker `Queued`/`Starting`/`ModelWait`; session typing | |
| 46 | | Working | Working | bounded cyan wake under the tail | `·`/`˚` loop | worker `Running`/`RunningTool`, or durable status `Running`; session working/verifying | |
| 47 | | Waiting for you | Waiting for you | Signal Gold ring around the head | `◆` | pending question for the parent, worker `WaitingForUser`/`Interrupted`, durable `Interrupted`; session waiting/approval | |
| 48 | | Blocked | Blocked | still, nose against a vertical ink bar | `▌` | worker `Failed`; durable `Failed`/`BudgetExhausted`; session failed | |
| 49 | | Offline | Offline | open outline, fill drained, no wake | `░` | worker/durable `Cancelled` | |
| 50 | |
| 51 | Rules: |
| 52 | |
| 53 | - **State is evidence, never decoration.** `WhaleState::for_subagent` reads |
| 54 | only the child's real status fields; `WhaleState::for_shell_phase` reads the |
| 55 | session `ShellPhase`. Working is never inferred from elapsed time or a |
| 56 | timestamp. |
| 57 | - **A portrait without a state claims nothing.** The `/fleet` roster renders |
| 58 | members as identity only (no state cue, no state word, no caption) because |
| 59 | a profile is not a runtime. |
| 60 | - **Glyph + word, always.** Every state pairs a cue glyph with a localized word |
| 61 | (`WhaleState::word`), so state never depends on color alone — the same rule |
| 62 | `menu_style::StatusMark` enforces. |
| 63 | - **Priority** when several facts apply mirrors CWC: waiting 60 > blocked 50 > |
| 64 | working 40 > thinking 30 > offline 20 > resting 10. |
| 65 | |
| 66 | ## Motion |
| 67 | |
| 68 | The Working wake is a four-frame loop over 720 ms (180 ms per frame), the same |
| 69 | timing as the CWC GIFs. `whales::working_frame(now_ms, mode)` returns frame 0 |
| 70 | (the poster) for `MotionMode::Reduced` and `MotionMode::Still`; only |
| 71 | `MotionMode::Full` animates. Surfaces that cannot see the motion policy hold |
| 72 | the poster. |
| 73 | |
| 74 | ## Colors |
| 75 | |
| 76 | All inks resolve through the live `UiTheme` (`WhaleInk::from_theme`) and are |
| 77 | contrast-enforced to the secondary-chrome floor (3:1) against the theme |
| 78 | surface. Only the **signal-classic** colorway is represented. |
| 79 | |
| 80 | | Ink | Token | |
| 81 | | --- | --- | |
| 82 | | Body | `accent_action` (Signal Gold `#F6C453` on Blue Stage; `#7A5500` on Blue Stage Light) — the idle mark's body | |
| 83 | | Lantern (orca) body | `text_muted`, with a Signal Gold saddle patch | |
| 84 | | Eye / fluke centre | `text_body` | |
| 85 | | Thinking ticks, working wake, Scout research lens | `WHALE_CYAN_RGB` `#48D7FF` (bounded accent) | |
| 86 | | Waiting ring | `accent_action` (Signal Gold, the human-attention role) | |
| 87 | | Blocked bar | `text_muted` | |
| 88 | | Offline | `text_dim` | |
| 89 | | Patch bracket | `accent_secondary` (seafoam `#4FD1C5`) | |
| 90 | | Harbor mooring loop | `WHALE_BRAND_ORANGE_RGB` `#FF8A3D` | |
| 91 | | Echo sonar ticks | `WHALE_BRAND_MAGENTA_RGB` `#F04EB8` | |
| 92 | | Keel stripe | `warning` (coral `#FF7A59`) | |
| 93 | | Lantern review lens | `mode_operate` (violet `#AD88FF`) | |
| 94 | |
| 95 | `WHALE_BRAND_ORANGE_RGB` and `WHALE_BRAND_MAGENTA_RGB` are the two CWC brand |
| 96 | palette entries the TUI palette did not already carry. They are identity |
| 97 | accents only and must never be used for status, mode, or permission. |
| 98 | |
| 99 | ## Art |
| 100 | |
| 101 | The current startup intentionally uses direct copy rather than translating the |
| 102 | canonical raster into terminal glyph art. [`WHALE_TEAMS_TUI_ART.md`](WHALE_TEAMS_TUI_ART.md), |
| 103 | its text preview, and its generator are retained as an **archived portrait |
| 104 | reference** for removed artwork; they must not be used as a product-mark source. |
| 105 | |
| 106 | The live runtime uses two-cell badges: a species feature glyph in the role |
| 107 | accent plus a body cell. With `CODEWHALE_ASCII_SAFE=1` the seven badges stay |
| 108 | distinct: `<#` `#]` `#\` `:#` `#-` `*#` `.#`. |
| 109 | |
| 110 | ## Surfaces |
| 111 | |
| 112 | - `/fleet` roster: species badge on every member row, with the |
| 113 | `badge Name · species · job` line — no retired portrait is rendered. |
| 114 | - `/fleet` workers (`SubAgentsView`): badge on every worker row, plus a |
| 115 | second line with the badge and the state cue and word — nothing else. |
| 116 | - `whales::badge` is public for other surfaces (the Fleet setup role pane is |
| 117 | the intended next consumer). |
| 118 | |
| 119 | Not represented: the deep-current, reef-shift, and night-signal colorways; the |
| 120 | legacy WhalePet atlas and Rive companion contracts (which have no artwork in |
| 121 | either repository); any GIF/raster asset. |
| 122 |