Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions skills/stream-android/RULES.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,39 @@ Default token model:

---

## Matching a reference design

When the request carries a **target appearance** (a screenshot, a Figma frame, or "make it look like
\<app\>"), run [`design-matching.md`](design-matching.md) and decompose **every** region before writing
code - setting the accent color and the wallpaper and stopping is the known failure.

- **There are TWO axes on Android, not three.** **Theming** (`StreamDesign.Colors` / `Typography`:
colors and fonts) and **Structure** (`ChatComponentFactory` slots: which Composables render and how
they are arranged). There is **no `Styles` axis** and no public shapes/dimens - **padding,
corner-radius, bubble shape, and composer layout are STRUCTURE** (override the slot), never a theme
token. Routing a structural difference to a color (or vice versa) is the core failure mode.
- **The chat bubble colors are DERIVED, not settable.** `chatBgOutgoing` / `chatTextOutgoing` /
`chatBorder*` are computed `internal val`s on `StreamDesign.Colors` (from `brand` / `accentPrimary` /
`chrome`) - not constructor params. Recolor a bubble via the full `brand` `ColorScale` (cascades to all
accent surfaces) or by overriding `MessageBubble` + `MessageContent`. Sample the accent **exactly** and
set the full `brand` scale, not just `accentPrimary`, or the theme reads washed-out.
- **Overriding a composite slot drops every sub-feature it drew.** `MessageContainer`, `ChannelHeader`,
and `MessageComposer` render many children; reproduce them (read the default `@Composable` body first)
or consciously drop and say so. Prefer the **narrowest** slot.
- **The three most-missed regions** (decompose each as carefully as the message bubble): the
**message-header trailing slot defaults to a channel avatar/facepile** - override it for action icons;
the **composer** differs by row count, input-field shape, and vertical alignment more than by icon set
(the default row is bottom-aligned; the field is a bordered pill baked into `MessageInput`); and
**channel-list rows** carry type-dependent leading (public `#`, private lock, DM = member avatar -
never `#` a DM), read-state weight, previews, and trailing badges.
- **A match is unverified until you build, seed data that triggers every region, open the real message
screen on the real navigation path, compare region-by-region, and iterate.** Implement every region,
the composer included; a region left at the SDK default is a FAIL, not a "known cosmetic gap." A region
the seed data cannot populate is **data-limited / unverified**, not a pass. Full procedure + the region
-> slot map are in [`design-matching.md`](design-matching.md).

---

## Project ownership

Preserve the app's existing architecture:
Expand Down
10 changes: 9 additions & 1 deletion skills/stream-android/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ Before any tool call, decide the **track** from the user's input alone - no prob
| "Build me a new Android app", "create a Compose app", "new Android app" + Stream product | **A - New app** |
| "Add/integrate Stream into this app", "wire Chat/Video/Feeds into my Android project" | **B - Existing app** |
| "Install Stream packages", "set up Stream in Android Studio", "wire auth/token flow" with no broader feature request | **D - Bootstrap / setup** |
| Request carries a **target appearance** - a screenshot, a Figma frame, or "make the chat look like WhatsApp / Telegram / Slack / \<app\>" | **B (or A)** + the **styling-depth flag** below -> [`design-matching.md`](design-matching.md) |
| Bare `/stream-android` with no args | List the tracks briefly and wait |

### Disambiguation flow
Expand All @@ -58,6 +59,10 @@ If the request is ambiguous between **build/integrate** and **reference lookup**
- **Tracks A, B, D** -> run **Step 0.5 (credentials)** first, **then Project signals** once per session, then continue in [`builder.md`](builder.md) and [`sdk.md`](sdk.md). Do not probe the project before credentials.
- **Track C** -> skip both steps if the product + UI layer are explicit. Only run Project signals on demand if the SDK or UI layer is ambiguous.

### Styling-depth flag (orthogonal to the track)

If the request carries a **target appearance** - an attached screenshot, a Figma frame, or "make the chat look like WhatsApp / Telegram / Slack / \<app\>" - run [`design-matching.md`](design-matching.md) **before** writing UI code. It sits on top of the Track A/B work (it is *how* you build the requested UI), not instead of it. A reference is a **checklist of regions** (header, composer, where the timestamp + read receipts sit, bubble shape/tail, channel-list rows, date separators, attachments...), and most differ from Stream's Compose defaults **structurally**, not just by color - setting the accent + wallpaper and stopping is the known failure. Classify each screenshot to its screen (channel list vs message vs thread - Step 0), decompose every region capturing **dimensions** not just colors, then route each difference to one of the **two axes**: a theming token (`StreamDesign.Colors`/`Typography`) or a `ChatComponentFactory` slot (structure - padding / corner-radius / bubble-shape / composer layout live here; Android has **no `Styles` axis**, so those are structure, not theming). Recurring traps the doc guards against: overriding a **composite slot** (`MessageContainer`, the header, `MessageComposer`) silently drops the sub-features the default drew (incoming avatar, grouping, reactions, replies, status, send/voice) unless you reproduce them; the **message-header trailing slot defaults to a channel avatar** (override it for action icons); the **composer** differs by row count / field shape / alignment far more than by icon set; **DMs must not be prefixed with `#`** in the list or titled "Channel" in the header. The match is **not done** until you build, seed data that triggers every region, compare region-by-region on the real navigation path, and iterate - implement **every** region, the composer included; a region left at the SDK default is a FAIL, not a footnote.

---

## Step 0.5: Credentials, token, and seed data (tracks A, B, D only)
Expand Down Expand Up @@ -106,7 +111,10 @@ Use the result to produce a **one-line status**, for example:

## Reference layout

Shared Android/Kotlin patterns live in **[`sdk.md`](sdk.md)**.
Shared Android/Kotlin patterns live in **[`sdk.md`](sdk.md)**. The curated procedure for reproducing a
**reference design** with the pre-built Compose components (the region -> `ChatComponentFactory`-slot map
and the build/verify loop) lives in **[`design-matching.md`](design-matching.md)** - loaded via the
styling-depth flag above, on top of whichever track applies.

Product and UI-layer specifics live under **`references/`** using a flat naming scheme that can grow with the full Stream Android surface:

Expand Down
Loading