CLAUDE.md
packages/ios/CLAUDE.mdCLAUDE.md
Quality
82/100
Scores the file, not the repository.Length
843 words
14 headings · 4 code blocksRepository
1.4k
— · pushed 0 days agoLast changed
3 days ago
First indexed 3 days ago.1# iOS Package (Native iOS App)23This package contains the native SwiftUI iOS/iPadOS app for Nimbalyst. It provides a mobile interface for viewing and interacting with AI sessions synced from the desktop Electron app via end-to-end encrypted WebSocket sync.45The app is **pure Swift/SwiftUI** with no Capacitor or web framework dependency. The only web view is `TranscriptWebView` (WKWebView) which renders the rich chat transcript using the same React components as the desktop app.67## Package Structure89```10packages/ios/11 NimbalystNative/ # Swift Package - all business logic and UI12 Sources/13 App/ # AppState (root observable), ContentView, navigation14 Auth/ # AuthManager (Stytch OAuth via ASWebAuthenticationSession)15 Crypto/ # CryptoManager (AES-256-GCM, PBKDF2), KeychainManager16 Database/ # DatabaseManager (GRDB migrations, queries)17 Models/ # GRDB record types: Project, Session, Message, QueuedPrompt, SyncState18 Notifications/ # NotificationManager (push notification registration)19 Sync/ # SyncManager, WebSocketClient, SyncProtocol types20 Utils/ # RelativeTimestamp, NimbalystColors21 Views/ # All SwiftUI views22 Tests/ # Unit and integration tests (68 tests)23 Package.swift # Swift Package Manager manifest (GRDB dependency)2425 NimbalystApp/ # Xcode app target26 Sources/ # App entry point (@main), DebugMenu27 Resources/ # Assets.xcassets (AppIcon, Splash), transcript-dist bundle28 project.yml # XcodeGen project definition2930 CryptoCompatibility/ # CommonCrypto bridging header for PBKDF2 key derivation3132 src/transcript/ # React transcript web bundle (loaded in WKWebView)33 main.tsx # Entry point with Swift <-> JS bridge34 styles.css # Styles with bundled Material Symbols font35 fonts/ # Locally bundled Material Symbols TTF3637 vite.config.transcript.ts # Vite config for transcript bundle (IIFE format for file://)38 transcript.html # HTML entry point for Vite build39 dist-transcript/ # Build output (not committed)40```4142## Key Architecture Decisions4344### Authentication Flow451. QR pairing stores encryption seed + server URL in Keychain462. Stytch OAuth stores JWT + user ID in Keychain473. When both paired AND authenticated, managers initialize484. Encryption key derived from seed + user ID via PBKDF24950### Data Flow51- **Sync**: WebSocket connection to CollabV3 Durable Object (same server as desktop)52- **Encryption**: All session data encrypted with AES-256-GCM before transmission53- **Storage**: GRDB (SQLite) with reactive `ValueObservation` for live UI updates54- **Transcript**: WKWebView loads bundled React app, communicates via `webkit.messageHandlers.bridge`5556### iPad Support57- `NavigationSplitView` for regular size class (sidebar + detail)58- `NavigationStack` for compact size class (iPhone)5960## Development6162### Prerequisites63- Xcode 16+64- Node.js 20+ (for transcript bundle)65- XcodeGen (`brew install xcodegen`)6667### Commands68```bash69# From monorepo root:70npm run ios:test:swift # Run all 68 Swift tests71npm run ios:build:transcript # Build transcript web bundle7273# From packages/ios/:74cd NimbalystNative && swift test # Run tests directly75cd NimbalystApp && xcodegen generate # Regenerate .xcodeproj76open NimbalystApp/NimbalystApp.xcodeproj # Open in Xcode77```7879### Transcript Bundle80The Xcode pre-build script in `project.yml` automatically builds the transcript with Vite and copies it to `Resources/transcript-dist/`. You can also build manually:8182```bash83npm run ios:build:transcript84```8586Output: `dist-transcript/transcript.html` + `dist-transcript/assets/` (JS bundle + Material Symbols font).8788After building, copy the output to Xcode resources:89```bash90rm -f NimbalystApp/Resources/transcript-dist/assets/transcript-*.js91cp dist-transcript/transcript.html NimbalystApp/Resources/transcript-dist/transcript.html92cp dist-transcript/assets/* NimbalystApp/Resources/transcript-dist/assets/93```9495**CRITICAL: React hooks rules in `src/transcript/main.tsx`**9697The transcript React app runs inside WKWebView where errors are invisible (cross-origin `window.onerror` reports "Script error." with no details). This makes hooks violations especially dangerous -- the screen goes blank with no diagnostic information.9899Rules for editing `TranscriptApp` in `main.tsx`:100- **All hooks (`useState`, `useRef`, `useCallback`, `useMemo`, `useEffect`) must come BEFORE any early returns.** React requires the same hooks to run in the same order on every render. An early `return` before a hook means that hook runs on some renders but not others, crashing React with "Rendered more hooks than during the previous render."101- **The `TranscriptErrorBoundary` wraps the app** to catch render errors and display them on screen + report to the native bridge. Do not remove it.102- **The `postErrorToNative` helper** sends error details through `webkit.messageHandlers.bridge` so they appear in Xcode console logs with full stack traces. Use it in any new try-catch blocks.103- **Test after any change**: Always rebuild the transcript (`npm run ios:build:transcript`), copy to Xcode resources, and rebuild in Xcode. Vite build success does NOT mean React will render correctly at runtime.104105## Key Files106107| File | Purpose |108|------|---------|109| `Sources/App/AppState.swift` | Root observable object; owns database, crypto, and sync managers |110| `Sources/Sync/SyncManager.swift` | WebSocket sync with CollabV3; processes index responses and broadcasts |111| `Sources/Sync/SyncProtocol.swift` | All wire protocol types (Codable structs with CodingKeys) |112| `Sources/Database/DatabaseManager.swift` | GRDB schema migrations, queries, and project stats refresh |113| `Sources/Crypto/CryptoManager.swift` | AES-256-GCM encrypt/decrypt, deterministic project ID encryption |114| `Sources/Views/TranscriptWebView.swift` | WKWebView + Coordinator with JS bridge, TranscriptController |115| `Sources/Views/SessionDetailView.swift` | Session detail with transcript, scroll-to-top, jump-to-prompt |116| `Sources/Views/SessionListView.swift` | Time-grouped session list with search and swipe-to-delete |117| `Sources/Views/ProjectListView.swift` | Project list sorted by last activity with desktop connection indicator |118| `src/transcript/main.tsx` | React transcript app with `scrollToTop`, `scrollToMessage`, `getPromptList` JS bridge |119120## Testing121- 68 Swift tests covering database, crypto, sync integration, and web view122- See [TESTING.md](./TESTING.md) for CI/CD pipeline details123- Tests run on both macOS (via Swift Package Manager) and iOS simulator (via Xcode)124
Also in nimbalyst/nimbalyst
Diff this repo’s formatsOne repository carrying more than one format is the comparison this product exists for: does anyone actually write different content in each file, or is one a copy of the other?
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| nimbalyst/nimbalystCLAUDE.md · 1.4k | CLAUDE.md | setupbuildteststyle+11 | 84/100 | today | |
| nimbalyst/nimbalystpackages/android/CLAUDE.md · 1.4k | CLAUDE.md | setupbuildstylearch+2 | 100/100 | 3 days ago | |
| nimbalyst/nimbalystpackages/electron/CLAUDE.md · 1.4k | CLAUDE.md | buildtestgitapi+2 | 83/100 | 3 days ago | |
| nimbalyst/nimbalystpackages/runtime/CLAUDE.md · 1.4k | CLAUDE.md | agent-behaviour | 44/100 | 3 days ago |
Similar configs
Same format, overlapping stack, ranked by quality.
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| Adit-Jain-srm/NightmareNetCLAUDE.md · 45 | CLAUDE.md | buildtestlint-formatstyle+6 | 100/100 | 3 days ago | |
| nimbalyst/nimbalystpackages/android/CLAUDE.md · 1.4k | CLAUDE.md | setupbuildstylearch+2 | 100/100 | 3 days ago | |
| dotCMS/corecore-web/CLAUDE.md · 949 | CLAUDE.md | teststylearchtesting-strategy+3 | 100/100 | 3 days ago | |
| microsoft/playwrightCLAUDE.md · 94k | CLAUDE.md | buildtestlint-formatstyle+7 | 100/100 | 3 days ago | |
| filamentphp/filamentCLAUDE.md · 32k | CLAUDE.md | buildtestlint-formatstyle+7 | 100/100 | 3 days ago | |
| bagisto/bagistoCLAUDE.md · 28k | CLAUDE.md | setupbuildteststyle+5 | 100/100 | 3 days ago | |
| dotCMS/coreCLAUDE.md · 949 | CLAUDE.md | setupbuildteststyle+7 | 99/100 | today | |
| lollipopkit/flutter_server_boxCLAUDE.md · 8.3k | CLAUDE.md | buildteststylearch+2 | 98/100 | 3 days ago |
