|
| 1 | +# ChatWithSkills |
| 2 | + |
| 3 | +A SwiftUI iOS chat app built end-to-end with the [Stream Swift Agent Skill](https://www.skills.sh/getstream/agent-skills/stream-swift). This repo is both a working Stream Chat sample and a demonstration of how the `stream-swift` skill scaffolds, wires, and verifies Stream-powered Swift apps from a single prompt. |
| 4 | + |
| 5 | +--- |
| 6 | + |
| 7 | +## What is the Stream Swift Agent Skill? |
| 8 | + |
| 9 | +`stream-swift` is an open-source [Agent Skill](https://www.skills.sh) published by [GetStream](https://getstream.io) that teaches your coding agent (Cursor, Claude Code, Codex, Windsurf, etc.) how to build and integrate Stream **Chat**, **Video**, and **Feeds** in Swift apps. |
| 10 | + |
| 11 | +It is not a library you import. It is a structured bundle of instructions, rules, and reference blueprints that the agent reads on demand so that when you ask "build me a SwiftUI chat app" or "add video calls to this Xcode project," it follows a deterministic, Stream-blessed flow instead of guessing. |
| 12 | + |
| 13 | +The skill lives at: |
| 14 | + |
| 15 | +```text |
| 16 | +~/.agents/skills/stream-swift/ |
| 17 | +├── SKILL.md # router + intent classifier (entrypoint) |
| 18 | +├── RULES.md # non-negotiable Stream/Swift rules |
| 19 | +├── builder.md # build & integration flow |
| 20 | +├── sdk.md # shared lifecycle/auth/state patterns |
| 21 | +└── references/ |
| 22 | + ├── CHAT-SWIFTUI.md # Chat + SwiftUI setup + gotchas |
| 23 | + ├── CHAT-SWIFTUI-blueprints.md # Chat + SwiftUI view blueprints |
| 24 | + ├── CHAT-UIKIT.md # Chat + UIKit setup + gotchas |
| 25 | + ├── CHAT-UIKIT-blueprints.md # Chat + UIKit view controller blueprints |
| 26 | + ├── VIDEO-SWIFTUI.md # Video + SwiftUI setup |
| 27 | + ├── VIDEO-SWIFTUI-blueprints.md |
| 28 | + ├── VIDEO-UIKIT.md |
| 29 | + ├── VIDEO-UIKIT-blueprints.md |
| 30 | + ├── LIVESTREAM-SWIFTUI.md # creator/viewer, goLive/stopLive, HLS |
| 31 | + ├── LIVESTREAM-SWIFTUI-blueprints.md |
| 32 | + ├── FEEDS-SWIFTUI.md # Feeds SDK patterns (SwiftUI + UIKit) |
| 33 | + ├── FEEDS-SWIFTUI-blueprints.md |
| 34 | + └── COMBINED-CHAT-VIDEO.md # name-collision + file isolation guide |
| 35 | +``` |
| 36 | + |
| 37 | +--- |
| 38 | + |
| 39 | +## What it does and can do |
| 40 | + |
| 41 | +The skill gives an agent the ability to: |
| 42 | + |
| 43 | +### Build new Stream apps from scratch |
| 44 | + |
| 45 | +- Scaffold a SwiftUI **or** UIKit iOS app wired to Stream Chat, Video, Feeds, or a combination. |
| 46 | +- Build a **livestream** experience with creator/viewer modes, `goLive` / `stopLive`, backstage, and HLS playback. |
| 47 | +- Set up a **combined Chat + Video** app with the proper file-isolation pattern so the colliding SDK type names (`User`/`UserInfo`, `Token`/`UserToken`, `ViewFactory`) don't collide at compile time. |
| 48 | + |
| 49 | +### Integrate Stream into an existing app |
| 50 | + |
| 51 | +- Detect whether you have a `.xcodeproj`, `.xcworkspace`, `Package.swift`, or `Podfile`, and preserve your existing package manager. |
| 52 | +- Preserve your existing UI layer (no forced SwiftUI ↔ UIKit conversions) and navigation/DI architecture. |
| 53 | +- Add the minimum composition points needed for the requested Stream surface. |
| 54 | + |
| 55 | +### Bootstrap credentials and seed data automatically |
| 56 | + |
| 57 | +- Use the [Stream CLI](https://github.com/GetStream/stream-cli) to read your app's API key (`stream config get-app`) and generate a real user token (`stream token <user_id>` or `stream token <user_id> --ttl 1h`). |
| 58 | +- Optionally seed 3–5 realistic channels with random usernames so the app shows real data on first launch — no placeholder strings in your code. |
| 59 | +- Keep the API **secret** out of your app entirely (CLI/server-side only). |
| 60 | + |
| 61 | +### Answer reference questions |
| 62 | + |
| 63 | +- Look up how a specific Stream SwiftUI/UIKit type, modifier, or hook works. |
| 64 | +- Map a feature request ("custom message composer," "thread list," "permissions for backstage") to the correct blueprint file without dumping unrelated documentation. |
| 65 | + |
| 66 | +### Enforce Stream-blessed rules |
| 67 | + |
| 68 | +The skill ships a [`RULES.md`](file:///Users/amosgyamfi/.agents/skills/stream-swift/RULES.md) the agent reads once per session. The most important ones: |
| 69 | + |
| 70 | +- **No wrapper/bridge abstractions.** Use `StreamVideo`, `StreamChat`, `CallViewModel`, `ChatClient` directly — never `CallManager`, `VideoCallBridge`, `StreamWrapper`, etc. |
| 71 | +- **Client lifetime is owned.** SDK clients are created once in `App.init()`, `AppDelegate`, or an app-scoped service — never in a `View` body or computed property. |
| 72 | +- **Secrets stay server-side.** The API secret never enters app code, `Info.plist`, or chat. |
| 73 | +- **Main-actor discipline.** UI state changes hop back to the main actor. |
| 74 | +- **Project ownership.** Don't convert UIKit ↔ SwiftUI, don't replace CocoaPods with SPM, don't flatten existing coordinators — unless asked. |
| 75 | + |
| 76 | +### Operate on a deterministic 4-track flow |
| 77 | + |
| 78 | +Every request is routed into one of four tracks before the agent touches a tool: |
| 79 | + |
| 80 | +| Track | When | What happens | |
| 81 | +|---|---|---| |
| 82 | +| **A — New app** | "Build me a SwiftUI chat app" | Full scaffold: detect → choose lane → install → wire → verify | |
| 83 | +| **B — Existing app** | "Add Stream Video to this project" | Detect → preserve architecture → integrate → verify | |
| 84 | +| **C — Reference lookup** | "How does `ChannelList` work in Chat SwiftUI?" | Load only the matching reference file(s) | |
| 85 | +| **D — Bootstrap / setup** | "Just install Stream and wire auth" | Detect → install → auth wiring → stop | |
| 86 | + |
| 87 | +--- |
| 88 | + |
| 89 | +## This repo |
| 90 | + |
| 91 | +`ChatWithSkills` is the output of running the skill against an empty SwiftUI iOS project with the prompt _"build me a SwiftUI chat app using Stream"_. The relevant files: |
| 92 | + |
| 93 | +```text |
| 94 | +ChatWithSkills/ |
| 95 | +├── ChatWithSkillsApp.swift # App entrypoint — owns the ChatClient lifetime |
| 96 | +├── RootView.swift # Auth-aware root (Login ↔ ChannelList) |
| 97 | +├── LoginView.swift # Token + user-id entry / CLI-generated token flow |
| 98 | +├── ChannelListScreen.swift # Stream Chat SwiftUI ChannelList |
| 99 | +└── StreamConfig.swift # API key + token wiring (no secret) |
| 100 | +``` |
| 101 | + |
| 102 | +It follows every rule above: no wrappers, client owned at app launch, secret never present, channels seeded via the Stream CLI rather than hardcoded. |
| 103 | + |
| 104 | +--- |
| 105 | + |
| 106 | +## How to use the skill |
| 107 | + |
| 108 | +### 1. Install it |
| 109 | + |
| 110 | +The skill is already installed at `~/.agents/skills/stream-swift/`. To install it on another machine: |
| 111 | + |
| 112 | +```bash |
| 113 | +npx skills add https://github.com/getstream/agent-skills --skill stream-swift |
| 114 | +``` |
| 115 | + |
| 116 | +Or clone manually: |
| 117 | + |
| 118 | +```bash |
| 119 | +git clone https://github.com/getstream/agent-skills.git |
| 120 | +cp -R agent-skills/skills/stream-swift ~/.agents/skills/ |
| 121 | +``` |
| 122 | + |
| 123 | +Agents that respect `~/.agents/skills/` (Cursor, Claude Code, Codex, etc.) will pick it up automatically on their next session. |
| 124 | + |
| 125 | +### 2. Install prerequisites |
| 126 | + |
| 127 | +- **Xcode 15+** (the skill won't scaffold an `.xcodeproj` for you — create the empty app first). |
| 128 | +- **[Stream CLI](https://github.com/GetStream/stream-cli)** — needed for credential fetching and token generation: |
| 129 | + |
| 130 | +```bash |
| 131 | +brew install GetStream/stream-cli/stream-cli |
| 132 | +stream config new # log in with your Stream API key + secret once |
| 133 | +``` |
| 134 | + |
| 135 | +- A **Stream account** with at least one app — sign up at [getstream.io](https://getstream.io). |
| 136 | + |
| 137 | +### 3. Invoke the skill |
| 138 | + |
| 139 | +Just describe what you want. The skill's intent classifier matches keywords and routes the work automatically. Sample prompts: |
| 140 | + |
| 141 | +**Build a new app** |
| 142 | + |
| 143 | +> Build me a SwiftUI chat app using Stream. Seed a few channels so I can see data on first launch. |
| 144 | +
|
| 145 | +> Create a SwiftUI livestream app with creator and viewer modes. |
| 146 | +
|
| 147 | +> Scaffold a UIKit chat app and wire it to Stream. |
| 148 | +
|
| 149 | +**Integrate into an existing app** |
| 150 | + |
| 151 | +> Add Stream Video calls to this Xcode project. Keep the existing UIKit navigation. |
| 152 | +
|
| 153 | +> Wire Stream Chat into my SwiftUI app — the package manager is SPM, don't switch to Cocoapods. |
| 154 | +
|
| 155 | +> Integrate Feeds into this app and build a basic timeline screen. |
| 156 | +
|
| 157 | +**Bootstrap / setup only** |
| 158 | + |
| 159 | +> Just install the Stream Chat SwiftUI package and wire auth — I'll build the UI myself. |
| 160 | +
|
| 161 | +**Reference lookup** |
| 162 | + |
| 163 | +> How does `CallViewModel` handle incoming-call state in Video SwiftUI? |
| 164 | +
|
| 165 | +> Show me the Chat SwiftUI blueprint for a custom message composer. |
| 166 | +
|
| 167 | +> What's the right way to handle name collisions in a combined Chat + Video app? |
| 168 | +
|
| 169 | +### 4. Answer the one upfront question |
| 170 | + |
| 171 | +For Tracks A, B, and D, the agent will ask **one** consolidated question about credentials, token expiry, and (for Chat) channel seeding. Answer it once and the agent executes the rest of the CLI sequence — `stream config get-app`, `stream token <user_id>`, `stream chat channel create ...` — without pausing for further confirmation. |
| 172 | + |
| 173 | +If you'd rather paste credentials yourself, say so in your reply and the agent will skip the CLI calls. |
| 174 | + |
| 175 | +### 5. Verify |
| 176 | + |
| 177 | +When the agent stops, it will report a short verification checklist. For this repo that meant: |
| 178 | + |
| 179 | +- Stream Chat SwiftUI package resolves in `ChatWithSkills.xcodeproj`. |
| 180 | +- `ChatClient` is initialized in `ChatWithSkillsApp` once, before any view renders. |
| 181 | +- `LoginView` connects the seeded user with the CLI-generated token. |
| 182 | +- `ChannelListScreen` renders the seeded channels on first launch. |
| 183 | +- Logging out cleanly disconnects the current user. |
| 184 | + |
| 185 | +--- |
| 186 | + |
| 187 | +## Running this repo |
| 188 | + |
| 189 | +```bash |
| 190 | +git clone <this-repo> |
| 191 | +cd ChatWithSkills |
| 192 | +open ChatWithSkills.xcodeproj |
| 193 | +``` |
| 194 | + |
| 195 | +1. In Xcode, let Swift Package Manager resolve `stream-chat-swiftui`. |
| 196 | +2. Open `StreamConfig.swift` and paste your **API key** and a **user token** (generate one with `stream token <user_id>`). |
| 197 | +3. Build & run on an iOS 17+ simulator or device. |
| 198 | +4. The login flow uses the user id whose token you generated; the channels seeded via the CLI will appear immediately. |
| 199 | + |
| 200 | +> **Never** commit your API secret. Only the API key and user token belong in `StreamConfig.swift`. |
| 201 | +
|
| 202 | +--- |
| 203 | + |
| 204 | +## Related resources |
| 205 | + |
| 206 | +- Skill page: <https://www.skills.sh/getstream/agent-skills/stream-swift> |
| 207 | +- Source repo: <https://github.com/getstream/agent-skills> |
| 208 | +- Stream Chat SwiftUI SDK: <https://github.com/GetStream/stream-chat-swiftui> |
| 209 | +- Stream Video iOS SDK: <https://github.com/GetStream/stream-video-swift> |
| 210 | +- Stream Feeds Swift SDK: <https://github.com/GetStream/stream-feeds-swift> |
| 211 | +- Stream CLI: <https://github.com/GetStream/stream-cli> |
| 212 | +- Stream Swift docs: <https://getstream.io/chat/docs/sdk/ios/> |
| 213 | + |
| 214 | +--- |
| 215 | + |
| 216 | +## License |
| 217 | + |
| 218 | +This sample app is provided under the same license as the Stream Swift agent skill — see the [LICENSE](https://github.com/getstream/agent-skills/blob/main/LICENSE) in the `agent-skills` repository. |
0 commit comments