Stream React (web) - scaffold + enhance + audit + migrate
Read first (every session): Read
(React/Next.js non-negotiables) and the cross-cutting
. Where the two files state the same rule differently (e.g. Strict mode protection, Package manager),
this pack's wins for React work. Glob
; if empty, install with
.
CLI: CLI usage (onboarding, credentials, auth, every
call) lives in the root skill - its "Stream CLI" section in
, with CLI safety in
. Glob
; install silently if missing (
).
This skill builds, enhances, audits, and migrates Stream Chat, Video, and Feeds in React / Next.js web apps - the default pack for all web React work. It covers five tracks:
- Track A - Scaffold a new app: Steps 0-7 below. Use when the cwd is empty / new and the user said "build me a ... app".
- Track E - Enhance an existing app: see . Skips scaffold + theme; reuses the same SDK wiring and component blueprints.
- Track F - Audit an existing integration (read-only): for "audit/review my video integration", "check my app against best practices", "is my video app production-ready?", "what am I missing before launch?". Video only: load the Integration best-practices audit section in and follow its protocol - it has a Video-specific checklist + output contract. If the user asks to audit Chat or Feeds, say up front there is no dedicated best-practices checklist for those yet, then do a general docs-based review (fetch the relevant pages from and check the app against them) rather than applying the Video checklist. Skip onboarding, auth, the CLI, and all build steps - this track only reads the app and reports findings. Fix issues only if the user then asks.
- Track M - Migrate / upgrade an SDK version: see . For "upgrade stream-chat-react to v14", "migrate to the new SDK", "bump my Stream version". Docs-driven: detect the installed version, fetch the matching release guide, apply it. Never migrate from memory.
- Track S - Migrate from Sendbird: see . For "migrate my app from Sendbird to Stream", "replace @sendbird/uikit-react with Stream", "we're switching off Sendbird". Detects the existing Sendbird integration shape, swaps packages + init, re-implements each touchpoint (UI composition, channels, messages, events/pagination, moderation, theming) against the grounded Sendbird<->Stream mapping the file carries, then offers the separate data migration.
Flow dispatch - choose exactly one
- Track A: run to onboard (authenticate + select/create org + app + write credentials), then continue to Start and execute Steps 0-7.
- Track E: run to onboard (authenticate + select/create org + app + write credentials), then Read and execute . Do not enter Start or any scaffold task.
- Track F: skip onboarding and go directly to the audit in . Do not enter Start or any build step.
- Track M: skip onboarding and Read first; it fetches the live release guide before any edit. Do not enter Start or any scaffold task.
- Track S: skip onboarding and Read first; it detects the integration shape before any edit. Do not enter Start or any scaffold task.
Styling-depth flag (orthogonal to the track). If the request carries a
target appearance - an attached screenshot, a Figma frame, or "make it look like WhatsApp / Slack / <app>" - route through
references/design-matching.md
: a reference design is a
checklist of regions, not a color tweak. Its pipeline is
Classify -> Design analysis -> Route -> Ground -> Build -> Verify, run as a coordinator-agent orchestration (parallel subagents where the harness dispatches them; inline serially where not): classify the fidelity tier + viewport, produce a fine-grained design analysis at
.design-verify/design-analysis.md
that
names the Stream concept behind every visual signal via per-product identification checklists (chat / video / feeds), route each region to a component + mechanism (theming / injection -> the
completion contract / bespoke), ground the names against the live docs, build batched, and close with
an empirical verify loop - screenshot + computed-style checks via session browser tooling or a Playwright fallback - iterated until the spec table passes. This composes with the track:
Track A scaffolds first, then matches before Step 4's build;
Track E matches within E3. Load it
before writing UI.
Docs-first triggers (consult docs before building)
For any feature that matches a UI component, cookbook, or advanced-guide topic, fetch the matching Stream docs page BEFORE writing code. The live docs are the source of truth for the current API and the recommended pattern; the bundled
references/*-blueprints.md
cover the prebuilt common path only. Full keyword -> page map with exact URLs:
- it opens with the
docs convention (the
-twin rule + per-product live index) so any unmapped page is still reachable: never guess a path, fetch the index. Enforced by
> Docs-first for cookbook / advanced features.
This skill is
prebuilt-component-first: build the common path with the SDK's prebuilt React components and customize via the documented hooks/props - see
> Reference authority. The docs-first protocol covers both the
component reference pages and the
cookbook / advanced recipes:
- UI Cookbook (customization / theming): typing indicator, custom message UI, message actions, reactions customization, message composer / input UI, channel header, channel list preview, emoji picker, autocomplete / suggestion list, link previews, pin indicator, thread header, search, collapsible sidebar, system message / banner, mentions actions, attachment actions, hide channel history, localization / i18n; Video: replacing call controls, custom layouts, lobby preview, PiP, network quality, livestream watching, ringing.
- Advanced Guides: AI integrations (LangChain, AI SDK), advanced search, multiple lists, infinite scroll, read state, online status, location sharing, blocking, message reminders, notifications / web push, attachment previews, audio playback, date formatting, SDK state management, dialog management, TypeScript custom data, chat + video integration, recording, broadcasting, video filters.
When a request hits one of these:
match -> the page's URL from -> implement to match. On fetch failure, hand to the
skill; if neither resolves the API,
stop and ask the user - never build from memory.
Start
Track A only. Tracks E, F, and M branch in Flow dispatch above and never enter this section.
Once
has onboarded (authenticated + selected/created org + app + written credentials), announce the network plan once, then
immediately start executing Steps 0-7 - do not ask permission to begin (the user has authorized the build by asking for it). The only pause for input is the theme + app pick (Step 1b).
Trust readout (announce, then continue on the same turn - do not wait)
Before the first network command, print this verbatim to the user, then proceed straight into Step 0 without stopping for a reply:
Scaffolding now. Network calls you'll see:
- (Vercel) - scaffold + UI components from npm.
npm install <stream-packages> --legacy-peer-deps
- Stream SDKs from npm (, @stream-io/video-react-sdk
, etc.).
- - local CLI, no network; writes (gitignored by the Next.js scaffold's default; Task B verifies).
Interrupt me at any point if something looks wrong. I'll pause once for your input: the theme + Stream-app pick (Step 1b).
Full per-command audit (publisher, why unpinned, what each writes): section Install trust & integrity below. The user's continued silence after the readout is implicit consent for this scaffold; an objection or stop instruction aborts the run.
Shadcn/ui is always installed during Step 3.
stream-react does not install third-party frontend skills - the build uses Stream references + Shadcn.
If frontend skill packs (
,
vercel-react-best-practices
,
) are already available in the session, use them for generic React / UI polish only; Stream references remain authoritative for SDK wiring.
Install trust & integrity
This builder runs three classes of network-touching commands. Each is listed here so a reviewer can audit before approving. CLI install instructions live in the root skill's "Stream CLI" section in
.
| Command | Publisher | Why unpinned | What it writes |
|---|
npx shadcn@latest init ...
(Task A) | Vercel - | Scaffolder; is the maintainer's documented usage. Pinning ships outdated scaffolds. | Project files in cwd. Next.js scaffold's ignores by default. |
npx shadcn@latest add ...
(Task A.1) | Vercel - same source as above | Same scaffolder; component sync depends on registry parity. | Component files under . |
npm install <stream-packages> --legacy-peer-deps
(Task C) | GetStream (npm) for and ; transitive deps via standard npm trust | Latest published versions of GetStream's own SDKs - same trust model as the CLI itself. | Modules under . Runtime SDKs + transitive deps. |
| (Task B) | GetStream - install instructions in the root skill's "Stream CLI" section in | n/a (local CLI, no network at this step) | in the project root with NEXT_PUBLIC_STREAM_API_KEY
+ . Task B verifies covers before writing (Next.js scaffold's default already does). The agent never reads (RULES.md > Secrets). |
Playwright into a self-contained harness (npm install --prefix .design-verify -D playwright
+ browser install) - design-matching verify-loop fallback only | Microsoft - | Latest published; runs only when a design match needs a capture and no in-session browser tooling exists (may never run), announced inline at point of use. | Everything under (its own + , gitignored) - the app's / lockfile are untouched - plus ~120MB Chromium in the shared Playwright cache. Deleted wholesale at loop exit; nothing lands in the app manifest. |
Reviewer checklist:
- All invocations resolve to the publishers listed above; substitute a different publisher and the install fails.
- is written by the Stream CLI directly, not by the agent, and is not transmitted into the conversation.
- If the user wants to pin a specific shadcn version, replace with in Tasks A and A.1.
- The Playwright row is a design-matching verify-loop fallback, not part of the scaffold: it is announced inline if and when it runs (it may never run), installs only into a self-contained harness (never the app root), and does not appear in the Start trust readout above.
Builder Steps
Execute phases
in order (later steps depend on earlier ones). Do
not run independent phases in parallel.
One exception: when
references/design-matching.md
is active, its Orchestration section governs scheduling - the design-analysis agent runs concurrently with the Steps 0-3 setup work, and builds / verifies fan out per its role table; everything else here stays sequential. Shell discipline (one
per phase, no
,
standalone) lives in
> Shell discipline.
Two-call exception: If you must Read JSON from a
call and then choose IDs, use one call for the read, one batched call for all creates.
Step 0: Package manager
Always use
. Never use bun. (
> Package manager.)
Step 1: Auth
Authentication is handled by
(Step 2) - it opens the browser as its
own invocation if you're not signed in (
> Provisioning;
> Shell discipline). There is
no separate auth probe - CLI v1.0.0 removed the pre-1.0
probe, and
subcommands are now product-namespaced (e.g.
). Continue to Step 1b.
Step 1b: Theme + app pick
Ask both setup questions in
one message before doing anything else - a single pause, the same "ask exactly once, then act" pattern the other platform packs use for credentials. Build the app options from what is already in context: the org/app already configured in this project by a prior
, if any. If none is configured yet,
lists your orgs/apps when it runs (Step 2) - interactively with a TTY; in a non-interactive shell it writes a
command file to uncomment instead (
> Provisioning documents the exact headless sequence). Don't try to enumerate them with a raw
call.
Quick setup - two questions:
- Theme: I can use a random shadcn theme, or you can design your own at ui.shadcn.com/create and share the value (e.g. ). Random, or do you have a preset? (If you already shared a screenshot or Figma, I'll match that instead - skip this.)
- Stream app: (an app is already configured) Use the currently configured app (default), or pick/create a different one? / (no app configured yet) will list your orgs and apps when it runs - use an existing one, or create a fresh org + app?
STOP here and wait for the user's answer. Do not continue with any other step until the user responds. Asking a question and continuing to work in parallel is confusing - the user misses the question as output scrolls past.
- Theme - preset provided -> store it for Task A scaffold command. Random / doesn't care -> pick a random preset from , , , , , .
- Theme - a reference design (screenshot / Figma) was provided -> the design dictates the theme: skip question 1, pick the shadcn preset closest to the sampled palette, ask only question 2 (the Stream app), and match the design via
references/design-matching.md
.
- App - named choice, "default", or "don't care" -> Step 2 applies it (the configured app wins whenever one exists). Create new -> Step 2 runs the create flow.
- Account has no orgs at all -> drop question 2, announce that a fresh org + app will be created, and ask only the theme.
Step 2: Pick org + app
Run
Provisioning in
:
handles auth and org/app selection-or-creation (including the Feeds v3 region choice). Let
drive it - interactively or via its command file; don't provision with raw
calls.
Step 3: Scaffold + .env + SDKs + Configure - SEQUENTIALLY
Scaffold order
Order:
- Steps 1-1b: Auth + theme/app pick (wait for answer).
- Step 2: Apply the org/app choice (select existing or create).
- Task A: Scaffold with Shadcn + Next.js using the chosen preset.
- Task A.1: Add base Shadcn components.
- Continue with Task B (.env), Task C (SDKs), Task D (CLI config).
Task A: Scaffold - scaffolds Next.js + Tailwind + Shadcn/ui (Base UI) into the current directory. Use the theme preset chosen in Step 1b.
The scaffold command creates a new directory, so we scaffold into a temporary
subdirectory and move everything up. The
flag also lands in the generated
as
, which npm/pnpm/yarn reject (a package name can't start with
), so the final step rewrites
to a valid slug derived from the project directory:
bash
npx shadcn@latest init -t next -b base -n .scaffold --no-monorepo -p <random-preset> && mv .scaffold/* .scaffold/.* . 2>/dev/null; rm -rf .scaffold && node -e "const fs=require('fs'),path=require('path'),j=require('./package.json');j.name=path.basename(process.cwd()).toLowerCase().replace(/[^a-z0-9._-]+/g,'-').replace(/^[._-]+/,'')||'app';fs.writeFileSync('package.json',JSON.stringify(j,null,2)+'\n')"
Task A.1: Add base Shadcn components:
bash
npx shadcn@latest add button input textarea card avatar badge separator
Add more components as the use case requires (e.g.
,
,
,
).
Do
not modify
or
after scaffold - use Shadcn's defaults as-is (RULES.md > Theme).
Task B: .env - run AFTER scaffold so the
lands inside the project directory.
First, verify is gitignored (
> Secrets). The Next.js scaffold's default already includes it; this is a safety net for projects whose
was hand-edited or doesn't yet exist. Use the
file tools (no shell) so no broad
permission is needed:
- for in (or it). If it already ignores , do nothing.
- If exists but has no entry, it to append a line .
- If does not exist, a new containing .
(Inspecting/editing
is fine;
never Read or Edit
itself -
> Secrets.)
Then write secrets:
detects the Next.js project and writes
NEXT_PUBLIC_STREAM_API_KEY
+
to
. The secret is server-side only - used by
to mint tokens, never in the client bundle. The public API key may be read client-side from
NEXT_PUBLIC_STREAM_API_KEY
or returned via
. The agent never reads
(
> Env vars).
Task C: Install Stream SDKs + verify icons - Only what the use case needs:
bash
# Chat: stream-chat stream-chat-react
# Video: @stream-io/video-react-sdk
# Feeds: @stream-io/feeds-react-sdk
# Server: @stream-io/node-sdk
npm install <packages> --legacy-peer-deps
After installing SDKs, note the resolved
Stream Chat React major: the bundled blueprints assume
v14 (
,
stream-chat-react/css/index.css
).
is v14 today; if a future install resolves a
newer major, fetch that major's component reference from
(Version note) before writing the provider tree - don't apply v14 names from memory.
Also verify an icon package is available. Some Shadcn presets bundle one, others don't:
bash
node -e "const p=['lucide-react','@phosphor-icons/react','@hugeicons/react'];console.log(p.some(m=>{try{require.resolve(m);return true}catch{return false}})?'ICONS_OK':'NO_ICONS')"
If
, install
:
npm install lucide-react --legacy-peer-deps
. If an icon package is already present, use that one throughout the app - do not install a second.
Task D: Configure Stream - run the CLI commands from the relevant
(App Integration -> Setup) for each product the use case needs.
Step 4: Generate code and UI
Prebuilt-component-first. Build the common path with the SDK's prebuilt React components and customize via the documented hooks/props (
> Reference authority). Writing your own component for a region (custom message row, composer, channel preview/header, call layout) - not just passing props - loads
(the completion contract) first; see
> Reference authority.
Docs-first: before implementing any component, cookbook, or advanced feature (typing indicator, custom message UI, reactions, AI integrations, read state, notifications, call layouts, ...), follow the
Docs-first triggers section above -
the matching
page first, then build to match.
Load and (cross-cutting SDK wiring: token route, instantiation, CSS imports), plus
only the relevant
header +
references/<Product>-blueprints.md
(the prebuilt provider tree + props) for the product(s) you are implementing - not every reference file. For any customization, fetch the matching live page from
first (and if you are writing your own component for a region, load
first per Step 4's rule above /
> Reference authority). Pull
Use Case Matching and
Page Flow from
to choose products and navigation structure.
For multi-product apps (Chat + Video, Chat + Feeds, Video + Feeds, etc.), also load references/CROSS-PRODUCT.md
before writing AppShell - it has the canonical multi-client provider hierarchy and an error -> cause -> fix table.
Step 5: Verify
Type-check first (reports ALL errors at once, ~3s):
Fix all type errors. Then run the full build:
Fix any remaining errors. Do NOT skip
- it catches every type error in one pass, while
stops at the first error per file and requires multiple rebuild cycles.
Step 6: Start dev server
Pick a random 5-digit port (10000-65535). Run the server using
:
bash
PORT=$((RANDOM % 55536 + 10000))
npx next dev -p $PORT
Important: The dev server is a long-running process. When run in the background it will eventually emit a "completed" notification - this does not mean the server stopped. The server is still running and serving requests. Do not respond to the background-task completion notification by telling the user the server has stopped. If you receive that notification after Step 7, ignore it silently - do not output anything.
Step 6b: Smoke-check the render (required)
A green
+
(Step 5) says nothing about what the user sees - it compiles, it does not render. Before the summary,
capture at least one screenshot of the logged-in main screen and actually look at it, using the tool ladder in
references/design-matching.md
> 6b (in-session browser tooling first, else the Playwright fallback; the
and capture gotchas in 6c apply). You are checking for gross breakage the build cannot catch: a blank / splash-stuck screen, unstyled or collapsed layout, a region not filling its pane, or console errors. Fix what you see and re-capture.
If the request carried any target appearance - an attached screenshot, a Figma frame, or "make it look like <app>" - this smoke check is
not enough: you must run the full
references/design-matching.md
Step 6 verify loop (a per-region spec table diffed against a this-round capture). A referenced build that skipped that loop is unfinished, not merely unpolished - catching it here is the backstop if the styling-depth flag was missed at Start.
Step 7: Summary
Show the org/app used (created or selected), plus resources and files created. Include the local URL. Do NOT say "you can now start the dev server" - it's already running.
End with:
Open
, enter a username, and start testing. Open a second tab with a different username to test multi-user interactions.
Use Case Matching and Page Flow
Both live in
(Use Case Matching, Page Flow). Match the user's words to a use case there, then build only the products that use case needs and follow the hub-first navigation it describes.
Moderation is configured via CLI during setup only -
never build moderation review UI (
> Moderation is Dashboard-only).
Cross-Product Integration
When building apps that combine multiple products, read each relevant
App Integration section. Key patterns:
- Combined token route: returns tokens for each product (
{ chatToken, videoToken, feedToken, apiKey }
). Upsert only the requesting user - never seed demo users ( > No auto-seeding).
- Video + Feeds (Livestreaming): Feed hub separates activities as prominent live cards. "Go Live" posts a live activity via . "End Stream" removes it.
- Video + Chat (Livestreaming): Chat alongside video on the watch screen. Use channel type - one channel per stream, keyed by call ID. Create the chat channel in the route.
- Moderation (all use cases): Run Moderation CLI setup commands from (App Integration -> Setup), adjusting channel type name. Never build moderation review UI ( > Moderation is Dashboard-only).
For multi-product provider nesting, load
references/CROSS-PRODUCT.md
.
Reference file paths
Blueprint files live in the
directory
next to this SKILL.md. Resolve them relative to this skill's own directory, wherever the pack is installed (e.g.
<skill-dir>/references/FEEDS.md
). Do not hardcode machine-specific absolute paths or assume a repo-checkout layout.