stream-builder
Stream Builder - scaffold + enhance
Read first (every session): Glob
../stream/SKILL.md. If the path is empty, install withnpx skills add GetStream/agent-skills --s stream -y(no confirmation, just run). Then Read../stream/RULES.md- it includes a Peer skills table for installing/invoking any other pack skills on demand.
This skill covers two flows:
- 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
enhance.md. Skips scaffold + theme; reuses the same SDK wiring and component blueprints.
Start
Once preflight has reported OK Stream CLI vN.N.N | ..., announce the network plan once, then immediately start executing Steps 0-7 - no interactive prompts at the start (the user has authorized the build by asking for it).
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:
npx shadcn@latest ...(Vercel) - scaffold + UI components from npm.npm install <stream-packages> --legacy-peer-deps- Stream SDKs from npm (stream-chat-react,@stream-io/video-react-sdk, etc.).stream env- local CLI, no network; writes.env(gitignored by the Next.js scaffold's default; Task B verifies).Interrupt me at any point if something looks wrong. The only step that pauses for explicit consent is the optional third-party skill packs in Task A.2.
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. Third-party frontend skills (vercel-react-best-practices, web-design-guidelines, frontend-design) are installed only with explicit user consent - see Task A.2 for the disclosure script. If the user declines, Step 4 proceeds using Stream references only. Precedence (when the skills are present): Stream references win for SDK wiring; frontend skills guide generic React / UI polish.
Install trust & integrity
The builder runs three classes of network-touching commands. Each is listed here so a reviewer can audit before approving. The full CLI installer audit (SHA-256 verification, TTY confirmation, scoped platform) lives in the stream-cli skill's bootstrap.md.
| Command | Publisher | Why unpinned | What it writes |
|---|---|---|---|
npx shadcn@latest init ... (Task A) |
Vercel - shadcn-ui/ui |
Scaffolder; @latest is the maintainer's documented usage. Pinning ships outdated scaffolds. |
Project files in cwd. Next.js scaffold's .gitignore ignores .env* 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 components/ui/. |
npm install <stream-packages> --legacy-peer-deps (Task C) |
GetStream (npm) for @stream-io/* and stream-chat-react; transitive deps via standard npm trust |
Latest published versions of GetStream's own SDKs - same trust model as the CLI itself. | Modules under node_modules/. Runtime SDKs + transitive deps. |
npx skills add <github> (Task A.2) |
vercel-labs/agent-skills and anthropics/skills |
Optional. Markdown-only skill packs; npx skills add is the published install path. |
Markdown files in the user's skills directory. Gated by explicit user consent in Task A.2 - never runs without an affirmative answer. |
stream env (Task B) |
GetStream - installed via the stream-cli skill's bootstrap.md (SHA-256 verified) |
n/a (local CLI, no network at this step) | .env in the project root with STREAM_API_KEY + STREAM_API_SECRET. Task B verifies .gitignore covers .env* before writing (Next.js scaffold's default already does). The agent never reads .env (RULES.md > Secrets). |
Reviewer checklist:
- All
npxinvocations resolve to the publishers listed above; substitute a different publisher and the install fails. npx skills addruns only after the disclosure prompt in Task A.2 and an explicit user "yes.".envis 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
@latestwith@<version>in Tasks A and A.1.
Builder Steps
Execute phases in order (later steps depend on earlier ones). Do not run independent phases in parallel. Shell discipline (one bash -c per phase, no bash -ce, stream auth login standalone) lives in the stream skill's RULES.md > Shell discipline.
Two-call exception: If you must Read JSON (e.g. OrganizationRead) and then choose IDs, use one call for the read, one batched call for all creates + stream config set.
Step 0: Package manager
Always use npm. Never use bun.
Step 1: Auth
Test auth first, then act - don't skip this and don't wait until Step 2 surfaces an error. Run stream api OrganizationRead as a probe:
- Exit 0 -> already authenticated, continue to Step 1b.
- Exit 2 / "not authenticated" -> immediately run
stream auth loginas its own Bash invocation. This is a hard constraint:- Browser PKCE requires an unwrapped
stream auth logincall - never chain with&&, embed in a heredoc, or bundle with other commands. - Do not ask the user first; just run it. Give it up to ~3 minutes for the browser flow.
- Browser PKCE requires an unwrapped
- Login hangs past ~60s, or the user reports the browser is stuck -> run
stream auth logoutto clear any stale session state, then retrystream auth loginonce. If the second attempt also hangs, stop and ask the user to run! stream auth loginthemselves (the!prefix runs it in-session so you see the result).
Step 1b: Theme pick
Ask the user which Shadcn theme they'd like before doing anything else:
Quick theme pick: I can use a random shadcn theme, or you can design your own at ui.shadcn.com/create and share the
--presetvalue (e.g.--preset b1Gdi7z7r). Want a random one or do you have a preset?
STOP here and wait for the user's answer. Do not continue with org/app creation or any other steps until the user responds. Asking a question and continuing to work in parallel is confusing - the user misses the question as output scrolls past.
- User provides a preset -> store it for Task A scaffold command.
- User says random / doesn't care / wants to move on -> pick a random preset from
nova,vega,maia,lyra,mira,luma.
Step 2: Create org + app
First, check existing orgs with stream api OrganizationRead. If there are already 10 orgs, do NOT create a new one - pick an existing builder-* org and create a new app inside it.
App names are globally unique. Always use app-<hash> where hash = openssl rand -hex 4.
# Check existing orgs first:
stream api OrganizationRead
# If under 10 orgs, create new:
HASH=$(openssl rand -hex 4)
stream api OrganizationCreate name=builder-$HASH slug=builder-$HASH
# Create app with Feeds v3 + US East (region_id=1):
stream api AppCreate name=app-$HASH org_id=<org_id> is_development=true region_id=1 feeds_version=v3
# Set defaults:
stream config set org <org_id> && stream config set app <app_id>
Never use the auto-created app from OrganizationCreate - it uses Feeds v2 and US Ohio.
Fallback (org limit / 429): Use OrganizationRead to list existing builder orgs, pick one, create a new app in it.
Step 3: Scaffold + .env + SDKs + Configure - SEQUENTIALLY
Scaffold order
Order:
- Steps 1-1b: Auth + theme pick (wait for answer).
- Step 2: Create org/app.
- Task A: Scaffold with Shadcn + Next.js using the chosen preset.
- Task A.1: Add base Shadcn components.
- Task A.2: Disclose + ask about third-party frontend skill installs; install only with user consent.
- 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 .scaffold subdirectory and move everything up:
npx shadcn@latest init -t next -b base -n .scaffold --no-monorepo -p <random-preset> && mv .scaffold/* .scaffold/.* . 2>/dev/null; rm -rf .scaffold
Task A.1: Add base Shadcn components:
npx shadcn@latest add button input textarea card avatar badge separator
Add more components as the use case requires (e.g. dialog, dropdown-menu, tabs, popover).
Task A.2: Frontend skills - third-party skill packs. You must disclose and ask before installing. Do NOT construct your own command variant.
Print this disclosure verbatim, then stop and wait for the user's answer:
I'd like to install three third-party skill packs that improve generic UI quality:
vercel-react-best-practices- fromvercel-labs/agent-skillsweb-design-guidelines- fromvercel-labs/agent-skillsfrontend-design- fromanthropics/skillsThe packs are markdown only - no scripts execute. If you say yes, I'll run
npx skills add ... -yonce per pack from those GitHub repos at their currentmainbranch (-yskips the installer's own confirmation since you've consented here). These aren't required - Stream reference files cover SDK wiring either way. Install them?
- User agrees -> run:
npx skills add https://github.com/vercel-labs/agent-skills --skill vercel-react-best-practices -y && npx skills add https://github.com/vercel-labs/agent-skills --skill web-design-guidelines -y && npx skills add https://github.com/anthropics/skills --skill frontend-design -y - User declines -> skip silently and continue to Task B. Do not retry, do not bring it up again this session.
- Install fails -> continue with Stream reference files only; mention the failure briefly.
Do not modify layout.tsx or globals.css after scaffold - use Shadcn's defaults as-is (RULES.md > Theme).
Task B: .env - run AFTER scaffold so the .env lands inside the project directory.
First, verify .env* is gitignored (the stream skill's RULES.md > Secrets). The Next.js scaffold's default already includes it; this is a safety net for projects whose .gitignore was hand-edited or doesn't yet exist:
bash -c 'test -f .gitignore && grep -qE "^\.env" .gitignore || echo ".env*" >> .gitignore'
Then write secrets:
stream env
stream env writes STREAM_API_KEY and STREAM_API_SECRET - both server-side. The client never reads env vars directly; it gets apiKey, userId, and its token from the /api/token response and holds them in React state. No NEXT_PUBLIC_* duplication, no .env gymnastics.
Task C: Install Stream SDKs + verify icons - Only what the use case needs:
# 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, verify an icon package is available. Some Shadcn presets bundle one, others don't:
node -e "try{require.resolve('lucide-react');console.log('ICONS_OK')}catch{try{require.resolve('@phosphor-icons/react');console.log('ICONS_OK')}catch{console.log('NO_ICONS')}}"
If NO_ICONS, install lucide-react: 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 references/<Product>.md (App Integration -> Setup) for each product the use case needs.
Step 4: Generate code and UI
Load builder-ui.md and only the relevant references/<Product>.md header + references/<Product>-blueprints.md for the sections you are implementing - not every reference file. 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):
npx tsc --noEmit
Fix all type errors. Then run the full build:
npx next build
Fix any remaining errors. Do NOT skip tsc --noEmit - it catches every type error in one pass, while next build 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 run_in_background:
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 7: Summary
Show what was created: org, app, resources, files. Include the local URL. Do NOT say "you can now start the dev server" - it's already running.
End with:
Open
http://localhost:<PORT>, enter a username, and start testing. Open a second tab with a different username to test multi-user interactions.
Use Case Matching
Only build with the products the user explicitly mentions. If unclear, ask.
| User says | Use case | Products |
|---|---|---|
| "Twitch", "YouTube Live", "Kick", "livestream" | Livestreaming | Video + Chat + Feeds |
| "Zoom", "Google Meet", "video call", "meeting" | Video Conferencing | Video [+ Chat] |
| "Slack", "Discord", "team chat", "channels" | Team Messaging | Chat |
| "WhatsApp", "iMessage", "DM", "messaging" | Direct Messaging | Chat [+ Video] |
| "Instagram", "Twitter", "social feed", "Reddit" | Social Feed | Feeds + Chat |
Moderation is configured via CLI during setup only. Never build moderation review UI in the app (RULES.md > Moderation is Dashboard-only) - review happens in the Stream Dashboard.
Page Flow
Every app needs a clear navigation structure. Users should always understand where they are and what they can do. Never drop a user into a camera/mic prompt, an empty state, or a feature-heavy screen without context.
Principle: Hub-first
After login, land on a hub - a home screen that shows what's happening and lets the user choose their path. The hub is the anchor; everything else is a destination the user navigates to intentionally.
Flow by use case
Livestreaming (Twitch, YouTube Live, Kick):
Login -> Feed hub (live streams + posts) -> Watch a stream (viewer: video + chat, no camera)
-> Go Live (explicit action -> then camera/mic setup -> streaming)
- The feed hub shows live streams (if any) as prominent cards, plus regular posts below
- Clicking a live card opens the watch view - video player + chat as a viewer. No camera permissions.
- "Go Live" is a deliberate action (button in header or dedicated screen). Only THEN prompt for camera/mic. The streamer sees a setup/preview before going live.
- Viewers and streamers are the same user type - the difference is the action they take, not the page they land on.
Video Conferencing (Zoom, Google Meet):
Login -> Lobby (list of calls or "start a call") -> Join call (camera/mic preview -> join)
- Land on a lobby or call list - not directly in a call.
- Joining a call shows a preview screen (camera/mic toggles) before connecting. The user opts in.
Team Messaging (Slack, Discord):
Login -> Channel list + active channel -> Browse/search channels
- Land on the channel list with the most recent channel open (or a welcome state if no channels).
Direct Messaging (WhatsApp, iMessage):
Login -> Conversation list -> Open a conversation -> Start new conversation
Social Feed (Instagram, Twitter):
Login -> Feed hub (follow users + composer + tabs: Timeline | My Posts) -> Comments -> User profiles
- The user posts to their own
user:<userId>feed and reads fromtimeline:<userId>(aggregates followed users' posts) - Feed hub tabs: Use a
Tabscomponent with two views:- Timeline (default) - shows
timeline:<userId>(posts from followed users) - My Posts - shows
user:<userId>(the current user's own posts)
- Timeline (default) - shows
- Refresh button: Place a refresh/reload button next to the tabs. On click, re-call
feed.getOrCreate({ watch: true })on the active feed to re-fetch the latest activities. This gives users an explicit way to refresh after follows or if real-time events are missed. - A Follow User input (username + follow button) must be visible so users can populate their timeline
- Without following, the timeline is permanently empty - this component is not optional
- Follow wiring: The Follow component must receive the timeline feed instance and call
timelineFeed.follow('user:targetId')- notclient.follow(). Using the feed instance keepsuseFeedActivities()in sync so the timeline updates immediately after following.
Key rules
- Camera/mic: opt-in only. Never request permissions on page load. Only when the user takes an explicit action (Go Live, Join Call).
- No empty ambiguity. If there's no content yet, show a clear empty state that tells the user what to do ("No live streams yet - be the first to Go Live").
- Navigation is visible. The user should always be able to get back to the hub. Use the App Header or a sidebar for navigation.
- One primary action per screen. The hub's primary action is browsing/discovering. The watch screen's primary action is viewing. The Go Live screen's primary action is streaming. Don't mix them.
Cross-Product Integration
When building apps that combine multiple products, read each relevant references/<Product>.md App Integration section. Key patterns:
- Combined token route:
/api/tokenreturns tokens for each product ({ chatToken, videoToken, feedToken, apiKey }). Upsert only the requesting user - never seed demo users. - Video + Feeds (Livestreaming): Feed hub separates
type === "live"activities as prominent live cards. "Go Live" posts a live activity via/api/feed/live. "End Stream" removes it. - Video + Chat (Livestreaming): Chat alongside video on the watch screen. Use
livestreamchannel type - one channel per stream, keyed by call ID. Create the chat channel in the/api/tokenroute. - Moderation (all use cases): Run Moderation CLI setup commands from
references/MODERATION.md(App Integration -> Setup), adjusting channel type name. Never build moderation review UI (RULES.md > Moderation is Dashboard-only) - review happens in the Stream Dashboard.
Authentication
If not authenticated:
- Has account ->
stream auth login - No account -> Open
https://getstream.io/try-for-free/, thenstream auth loginafter signup
Reference file paths
Blueprint files live under agent-skills/skills/stream-builder/references/ inside the Stream skill pack. Reference them as agent-skills/skills/stream-builder/references/FEEDS.md from the root of this repository. Do not use machine-specific absolute paths.
More from getstream/agent-skills
stream
Stream router for Chat, Video, Feeds, and Moderation. Use when the user wants to build a new app with Stream, scaffold a project, add Chat/Video/Feeds/Moderation to an existing app, integrate Stream, build for Swift/SwiftUI/UIKit/iOS/Xcode, query Stream data, list channels, list calls, show flagged messages, find users, run stream api / stream config / stream auth commands, install the Stream CLI, set up Stream, search Stream SDK documentation, look up Stream React/iOS/Android/Node/Flutter/Unity SDK methods, ask how-to questions about Stream hooks/components/methods, configure moderation blocklists or automod, set up webhooks, or anything tagged Chat React, Video iOS, Feeds Node, Moderation, etc. Routes to the right sub-skill based on the task.
137stream-docs
Search live Stream SDK documentation for Chat, Video, Feeds, and Moderation. Look up how a Stream React/iOS/Android/Node/Flutter/Unity/Angular hook, component, or method works. Answer how-to questions about any Stream SDK across every framework and version. Triggers on 'docs', 'documentation', explicit SDK tokens (Chat React, Video iOS, Feeds Node, Moderation), and 'how do I ... in <framework>' phrasing. Answers come verbatim from getstream.io with citations - no CLI required.
34stream-cli
Query Stream data and run CLI operations against Chat, Video, Feeds, and Moderation: list channels, list calls, show flagged messages, find users, query any Stream resource. Run stream api / stream config / stream auth commands. Install the Stream CLI binary. Use when the user gives operational verbs ('list', 'show', 'find', 'check', 'query') with Stream nouns, or invokes the CLI literally.
24stream-swift
Build and integrate Stream Chat, Video, and Feeds in Swift apps. Use for SwiftUI, UIKit, Xcode, and iOS project work with Stream package setup, auth wiring, and view blueprints.
13stream-react-native
Create, build, and integrate Stream Chat React Native apps in React Native Community CLI and Expo. Use for new RN/Expo Chat apps from scratch, existing app integration, Stream Chat RN, stream-chat-react-native, stream-chat-expo, migration/setup, channel list, message list, MessageComposer, attachment picker, image/file attachments, media picker, camera upload, audio messages, threads, thread list, React Navigation, Expo Router, theming, offline support, push notifications, and Chat customization. Chat only in v1; not for Stream Video, Feeds, or Moderation UI.
2