Three related problems in the app's UI surfaces, found while reviewing the interface against the Phase 1 design contract.
1. No signal when an agent is waiting on you
A tab gives no indication when an agent in one of its panes is blocked awaiting a user response. If the pane is in a background tab, the agent can sit unanswered indefinitely — nothing in the tab bar changes, and the pane header carries no marker either.
The blocked state has two independent sources that both need checking: a plugin-backed CLI agent session, and the Oz conversation. Checking only the conversation is insufficient, because selected_conversation_status_for_display returns None for a conversation that is blocked but empty.
Expected: the tab bar shows that a pane needs a response, and the pane header says which pane.
2. The bundled theme catalog is too large
The app ships 24 built-in themes, including ten background-image themes, three gradients, and two referral-reward themes that are unreachable in an OSS build (there is no referral program to unlock them). The theme chooser is long enough that the good defaults are hard to find, and several entries do not fit a dark-first, editor-grade product.
Expected: a small curated set. Retiring a theme must not break existing settings — a user already on a retired theme should keep a sensible appearance rather than getting an error or a jarring lightness flip.
3. Colors hard-coded to one background lightness
Several render sites hard-code a color that only works against either a light or a dark background, so they degrade or disappear on the other themes. These are correctness bugs, not styling preferences:
- Settings → working directory input draws
ColorU::black() text on a surface_2() background. On every dark theme this is black-on-dark and effectively invisible.
- Tab bar icons (maximize indicator and both tab-kind icons) fall back to
ColorU::white() when the tab style carries no font color — white-on-light in the Light theme. The ambient agent icon a few lines away already does this correctly.
- Account avatar uses black initials on the
#7c3aed accent fill, which fails contrast.
- Shared-block overflow icon uses a fixed
#b3bab8, low contrast on light backgrounds.
Related: the primary_foreground token is defined in castcodes_ui_tokens but nothing reads it, and active_highlighted_text_color() — the natural accessor for "text on the accent color" — has no callers.
Underlying cause: colors are properly tokenized via theme accessors, but radius, spacing and type have no code representation at all. The contract lives only in prose in AGENTS.md, so every call site writes a bare literal and there is nothing for review to check against. 48 radii across 37 files currently sit outside the documented 4/6/8px scale.
Three related problems in the app's UI surfaces, found while reviewing the interface against the Phase 1 design contract.
1. No signal when an agent is waiting on you
A tab gives no indication when an agent in one of its panes is blocked awaiting a user response. If the pane is in a background tab, the agent can sit unanswered indefinitely — nothing in the tab bar changes, and the pane header carries no marker either.
The blocked state has two independent sources that both need checking: a plugin-backed CLI agent session, and the Oz conversation. Checking only the conversation is insufficient, because
selected_conversation_status_for_displayreturnsNonefor a conversation that is blocked but empty.Expected: the tab bar shows that a pane needs a response, and the pane header says which pane.
2. The bundled theme catalog is too large
The app ships 24 built-in themes, including ten background-image themes, three gradients, and two referral-reward themes that are unreachable in an OSS build (there is no referral program to unlock them). The theme chooser is long enough that the good defaults are hard to find, and several entries do not fit a dark-first, editor-grade product.
Expected: a small curated set. Retiring a theme must not break existing settings — a user already on a retired theme should keep a sensible appearance rather than getting an error or a jarring lightness flip.
3. Colors hard-coded to one background lightness
Several render sites hard-code a color that only works against either a light or a dark background, so they degrade or disappear on the other themes. These are correctness bugs, not styling preferences:
ColorU::black()text on asurface_2()background. On every dark theme this is black-on-dark and effectively invisible.ColorU::white()when the tab style carries no font color — white-on-light in the Light theme. The ambient agent icon a few lines away already does this correctly.#7c3aedaccent fill, which fails contrast.#b3bab8, low contrast on light backgrounds.Related: the
primary_foregroundtoken is defined incastcodes_ui_tokensbut nothing reads it, andactive_highlighted_text_color()— the natural accessor for "text on the accent color" — has no callers.Underlying cause: colors are properly tokenized via theme accessors, but radius, spacing and type have no code representation at all. The contract lives only in prose in
AGENTS.md, so every call site writes a bare literal and there is nothing for review to check against. 48 radii across 37 files currently sit outside the documented 4/6/8px scale.