stream-swift

Build, integrate, migrate to, and answer how-to questions for Stream Chat, Video, and Feeds in Swift / SwiftUI / UIKit / iOS apps. Routes each request to the exact official iOS docs page, fetches it live, and applies it - with a curated setup flow, a Sendbird -> Stream Chat migration runbook, and iO

By getstream · 426 installs

npx skills add getstream/agent-skills --skill stream-swift

Source repository · Upstream listing

Stream Swift docs orchestrator for iOS This skill is small on purpose . It does not bundle SDK reference dumps the official iOS docs are the source of truth and they cover the entire surface (Chat, Video, Feeds; SwiftUI and UIKit; polls, drafts, voice, AI, push, screen share, CallKit, SIP, transcriptions, moderation, and more). Your job is to orchestrate : classify the request, point to the exact docs page, fetch it live, and apply it inside the user's project while obeying the curated rules and pitfalls that the docs do not shout about. Rules (read once per session): [ RULES.md ](RULES.md) non negotiable rules + iOS pitfalls. Read before writing any code. The docs convention (the core mechanism) Every Stream docs page has a Markdown twin that coding agents can read directly: take the page URL, drop the trailing / , add .md . Always fetch the .md variant it is clean Markdown with verbatim code, no page chrome. Per product index pages list every doc page with its .md URL. Fetch these to discover or confirm a page: Product Live index (always current) Page URL shape Chat (iOS SDK: UI + State Layer) https://getstream.io/cli/docs/chat sdk ios.md https://getstream.io/chat/docs/sdk/ios/...md Chat (low level client API reference) https://getstream.io/cli/docs/chat ios swift.md https://getstream.io/chat/docs/ios swift/...md Video https://getstream.io/cli/docs/video ios.md https://getstream.io/video/docs/ios/...md Feeds https://getstream.io/cli/docs/activity feeds ios.md https://getstream.io/activity feeds/docs/ios/...md URL grounding: only fetch a page URL that you got from [ docs map.md ](docs map.md) or from a live index fetch in this conversation. Do not invent doc paths from memory many look guessable but are wrong. If a page is not in the map, fetch the live index and pick from it. Step 0: Classify the request (always first) From the user's words alone, resolve three things: 1. Product Chat, Video, Feeds, or a combination. 2. Framework SwiftUI, UIKit, or mixed (default to SwiftUI when the user is starting fresh and has not said). 3. Mode one of: How to / reference ("how do I add reactions?", "what does CallViewModel do?", "theming") go straight to Docs lookup . No setup, no credentials. Integrate ("add Chat to my app", "wire Video into this project") run Setup ([ setup.md ](setup.md)) then Docs lookup for the feature. New app ("build a livestream app", "new SwiftUI chat app") Setup then Docs lookup , scoped to the requested screens. Migrate from Sendbird ("migrate my app from Sendbird to Stream", "replace the Sendbird Chat SDK with Stream", "we're switching off Sendbird / SendbirdUIKit / SendbirdSwiftUI") run [ sendbird migration.md ](sendbird migration.md): detect the existing Sendbird integration shape, swap packages + init, re implement each touchpoint against Stream while changing as little app code as possible, then re apply theming and verify design + functional fidelity per screen against the Sendbird original. It reuses Setup's CLI credential flow ([ setup.md ](setup.md)) and the region by region rigor of [ design matching.md ](design matching.md). The runbook covers the code/SDK migration; when it's done and verified, it asks whether to also migrate the Sendbird data (users, channels, message history, reactions) and, if so, hands off to the shared language agnostic data migration runbook [ ../stream/sendbird data migration.md ](../stream/sendbird data migration.md) (§10). AI assistant / LLM / agent ("build a ChatGPT style app", "add an AI assistant / support bot / copilot", "stream the LLM response", "thinking indicator", "stop generating", "render markdown from the model", "show the agent's reasoning / tool calls", "ask before the agent acts", "let the agent call tools on the device", MCP, "show the voice agent's transcript", "chat view of what was said to the voice agent") run [ ai integration.md ](ai integration.md): it first settles which StreamChatAI to use (a product of stream chat swift from 5.13.0 suggest the version update; the standalone stream chat swift ai package is the fallback), classifies the shape (AI first app vs a bot inside an existing messenger vs an agent that shows its steps and asks first vs device side tools vs a voice agent's transcript), keeps the model on a backend agent (never an LLM key in the app), and shows the conversation with AIConversationView , the primary way, wiring in the other StreamChatAI components ( AIComposerView , AIMessagePartsView , AIToolApprovalView , AIClientToolRunner , SuggestionsView ). The alternative is the pre built StreamChatSwiftUI message list with those components plugged in: for a conversation that needs messenger features, or an assistant inside an existing messenger. A voice agent on a Video call whose transcript the app shows as a chat also lands here (shape E): when one person talks to one agent, the transcript renders with AIConversationView (5.15.0), not a hand built list of bubbles. Runs Setup first for integrate / new app. A pure how to about one AI component goes to Docs lookup ([ docs map.md ](docs map.md) "Chat AI integrations"). For Vision Agents core on Swift ( VisionAgentsCore ), look at the accelerate branch of GetStream/Vision Agents for now [ ai integration.md ](ai integration.md) has the details. Push setup ("add push notifications for chat", "ringing should wake the app on a call", VoIP, CallKit) run [ push.md ](push.md): create the Stream push provider(s) via the CLI and wire the client capabilities + code. Uses the Stream CLI like Setup. There is also a styling depth flag, orthogonal to the mode above: if the request carries a target appearance an attached screenshot, a Figma link, or "make it look like WhatsApp / iMessage / Telegram / Slack / <app " then before Docs lookup, reproduce it region by region. For Chat, first run the strategy decision below (components vs custom): if it lands on components, run [ design matching.md ](design matching.md); if it lands on custom (livestream/overlay/bespoke), run [ custom ui.md ](custom ui.md) instead same region by region rigor, different mechanism. The rest of this paragraph is the components case (the common one). A reference design is a checklist of regions (header, composer buttons, where the timestamp + read receipts sit, bubble shape/tail, date separators, attachments...), and most of them differ from Stream's defaults structurally , not just by color. Do not stop at the wallpaper and bubble color that is the known failure mode. Decompose every region first (capturing its dimensions , not just colors), then route each to one of three axes theming token ( Appearance ), Styles modifier ( factory.styles , for padding/insets/corner radius/chrome), or ViewFactory slot (structure). Routing padding to theming, or structure to a color, is the core failure. Recurring traps the doc guards against: (1) overriding a composite slot ( makeMessageItemView , the header, the composer, makeComposerInputTrailingView ) silently drops the sub features the default rendered the incoming message avatar, grouping, reactions, replies, status, or the send/voice/edit/slow mode button unless you read the default's body and reproduce them; (2) the channel header modifier is applied to a divider above the composer , so a header rendered there via safeAreaInset / VStack lands at the bottom use .toolbar placements instead, and never fake the header in the app root for one channel; (3) the composer send/voice button lives inside the field ( makeComposerInputTrailingView ), so moving buttons to the right of the field needs a relayout, not just makeTrailingComposerView ; (4) bubble/collage padding is Styles ( makeMessageAttachmentsViewModifier ), not theming. The match is not done until you build, run, seed data that triggers every region, compare region by region against the reference on the real navigation path, and iterate ([ design matching.md ](design matching.md) Step 5), reverting any throwaway verification scaffold the UI must be as close to the reference as possible, not approximately like it. Implement every region, the composer included never deliver a partial match with the rest labelled "known cosmetic gaps"; a region left at the SDK default is a FAIL, not a footnote. And work in batches to stay fast : ground the pinned SDK version + checkout once, read all the source you need in one pass, implement all regions, then build once on a persistent derivedDataPath against one pinned simulator don't rebuild and screenshot after every small edit (see [ design matching.md ](design matching.md) "Work in batches"). If product and framework are explicit, do not probe proceed. If genuinely ambiguous between "wire it in" and "just explain", ask one short question: Want me to wire this into the project, or just map the docs page and pattern? Chat only: pick the UI strategy first (before any code) Stream Chat ships two layers , and choosing between them is an architecture decision that dwarfs any styling choice getting it wrong wastes a day either way. So decide deliberately, and default to the pre built components : Strategy Use when the design is... Mechanism Runbook Pre built UI components ( StreamChatSwiftUI / StreamChatUI ) — the default A messenger: bubbles, or a channel list → conversation, or per message avatar/timestamp/receipts/reactions/attachments. Social, marketplace, workplace, support, DMs. "Make it look like WhatsApp / iMessage / Telegram / Slack." Customize via theming + ViewFactory + Styles [ design matching.md ](design matching.md) Custom UI on the low level client + State Layer — the exception Not a messenger: a flat bubble less author inline feed, an overlay/ticker on video, high volume ephemeral livestream chat (Twitch / YouTube / Kalshi), live shopping. Every message rendered identically; bespoke app chrome around it. Build SwiftUI directly on StreamChat (+ optional StreamChatCommonUI ); no StreamChatSwiftUI [ custom ui.md ](custom ui.md) Lean hard toward components. They're built to be customized , and the litmus test is: if theming + a few ViewFactory slots + Styles could get there, it's a components job even strong reskins like WhatsApp. Pick custom only when matching the design would mean replacing the message row, composer, header, AND list all at once i.e. you'd be using the SDK purely as a data source, not for any of its views. Over choosing custom (rebuilding a worse messenger by hand, losing avatars/grouping/reactions/threads/attachments/typing/receipts/pickers) is the common, expensive mistake; over choosing components costs a few hours of fighting layout. When unsure, build the components version first it's faster to confirm or reject. The full signal rubric + litmus test is in [ custom ui.md ](custom ui.md) Step 0. Workplace / Slack style hybrid is a components job too and usually a Liquid Glass one. A Slack/Teams/Discord surface is a channel list + message list + composer, so it stays on the pre built components but two things differ from a messenger and must be matched, not punted: (1) the message row is flat and left aligned (avatar top rounded square, an author·custom status·timestamp header line, body, bottom reaction pills , and a thread reply summary ), with no incoming/outgoing bubble split reproduce it by overriding makeMessageItemView (composite slot reproduce its sub features); (2) the header and chrome are custom and typically glassy recommend the SDK's ready made Liquid Glass look ( factory.styles = LiquidGlassStyles() , the Styles axis baseline for translucent/floating composer designs; renders on iOS 26+/Swift 6.2+)