|
| 1 | +# AGENTS.md |
| 2 | + |
| 3 | +This file provides guidance to AI agents like Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +This file is symlinked for cross-agents compatibility to the following paths: |
| 6 | +- `CLAUDE.md` |
| 7 | + |
| 8 | +## Project Overview |
| 9 | + |
| 10 | +Bitkit iOS is a native Swift implementation of a Bitcoin and Lightning Network wallet. This is a work-in-progress repository that is **NOT** the live production app. The production app uses React Native and is at github.com/synonymdev/bitkit. |
| 11 | + |
| 12 | +This app integrates with: |
| 13 | +- **LDK Node** (Lightning Development Kit) for Lightning Network functionality |
| 14 | +- **BitkitCore** (Rust-based core library) for Bitcoin operations |
| 15 | +- **Electrum/Esplora** for blockchain data |
| 16 | +- **Blocktank** for Lightning channel services |
| 17 | + |
| 18 | +## Build & Development Commands |
| 19 | + |
| 20 | +### Building |
| 21 | +```bash |
| 22 | +# Standard build - Open Bitkit.xcodeproj in Xcode and build |
| 23 | + |
| 24 | +# E2E test build (uses local Electrum backend) |
| 25 | +xcodebuild -workspace Bitkit.xcodeproj/project.xcworkspace \ |
| 26 | + -scheme Bitkit \ |
| 27 | + -configuration Debug \ |
| 28 | + SWIFT_ACTIVE_COMPILATION_CONDITIONS='$(inherited) E2E_BUILD' \ |
| 29 | + build |
| 30 | +``` |
| 31 | + |
| 32 | +### Code Formatting |
| 33 | +```bash |
| 34 | +# Install SwiftFormat |
| 35 | +brew install swiftformat |
| 36 | + |
| 37 | +# Format all Swift code |
| 38 | +swiftformat . |
| 39 | + |
| 40 | +# Setup git hooks for automatic formatting on commits |
| 41 | +npm install -g git-format-staged |
| 42 | +./scripts/setup-hooks.sh |
| 43 | +``` |
| 44 | + |
| 45 | +### Localization |
| 46 | +```bash |
| 47 | +# Validate translations (checks for missing translations and validates translation keys) |
| 48 | +node scripts/validate-translations.js |
| 49 | +``` |
| 50 | + |
| 51 | +**Note:** Localization files are synced from Transifex using [bitkit-transifex-sync](https://github.com/synonymdev/bitkit-transifex-sync). |
| 52 | + |
| 53 | +### Testing |
| 54 | +```bash |
| 55 | +# Run tests via Xcode Test Navigator or: |
| 56 | +# Cmd+U in Xcode |
| 57 | +``` |
| 58 | + |
| 59 | +## Architecture |
| 60 | + |
| 61 | +### SwiftUI Patterns (CRITICAL) |
| 62 | + |
| 63 | +This project follows **modern SwiftUI patterns** and explicitly **AVOIDS traditional MVVM with ViewModels**. The architecture uses: |
| 64 | + |
| 65 | +1. **@Observable Objects for Business Logic** |
| 66 | + - Use `@Observable class` for shared business logic instead of ViewModels |
| 67 | + - Inject via `.environment(businessLogic)` |
| 68 | + - Retrieve with `@Environment(BusinessLogic.self)` |
| 69 | + - Example: `@Observable class UserManager { var users: [User] = []; func loadUsers() async { } }` |
| 70 | + |
| 71 | +2. **Native SwiftUI Data Flow** |
| 72 | + - `@State` for local view state only |
| 73 | + - `@Binding` for two-way data flow between parent/child views |
| 74 | + - `@Observable` for shared business logic objects |
| 75 | + - All state mutations must happen on `@MainActor` |
| 76 | + |
| 77 | +3. **Lifecycle Management** |
| 78 | + - Use `.task` modifier for async operations (NOT `.onAppear`) |
| 79 | + - `.task` automatically cancels when view disappears |
| 80 | + - Async operations should delegate to `@Observable` business logic objects |
| 81 | + |
| 82 | +4. **Component Design** |
| 83 | + - Decompose views into small, focused, single-purpose components |
| 84 | + - Use descriptive names (e.g., `UserProfileCard` not `Card`) |
| 85 | + - Prefer composition over deep view hierarchies |
| 86 | + - Components should be independent and reusable with generic data types |
| 87 | + |
| 88 | +### Core Architecture Layers |
| 89 | + |
| 90 | +``` |
| 91 | +┌─────────────────────────────────────────────────┐ |
| 92 | +│ Views (SwiftUI) │ |
| 93 | +│ - MainNavView, Activity, Wallet, Settings │ |
| 94 | +│ - Small, focused components │ |
| 95 | +└─────────────────┬───────────────────────────────┘ |
| 96 | + │ |
| 97 | +┌─────────────────▼───────────────────────────────┐ |
| 98 | +│ @Observable Business Logic │ |
| 99 | +│ - AppViewModel, WalletViewModel, etc. │ |
| 100 | +│ - Injected via .environment() │ |
| 101 | +└─────────────────┬───────────────────────────────┘ |
| 102 | + │ |
| 103 | +┌─────────────────▼───────────────────────────────┐ |
| 104 | +│ Services │ |
| 105 | +│ - CoreService (BitkitCore bridge) │ |
| 106 | +│ - LightningService (LDK Node) │ |
| 107 | +│ - TransferService, CurrencyService │ |
| 108 | +└─────────────────┬───────────────────────────────┘ |
| 109 | + │ |
| 110 | +┌─────────────────▼───────────────────────────────┐ |
| 111 | +│ External Dependencies │ |
| 112 | +│ - BitkitCore (Rust): Bitcoin operations │ |
| 113 | +│ - LDKNode: Lightning Network operations │ |
| 114 | +│ - Electrum/Esplora: Blockchain data │ |
| 115 | +└─────────────────────────────────────────────────┘ |
| 116 | +``` |
| 117 | + |
| 118 | +### Key Components |
| 119 | + |
| 120 | +**App Entry Point:** |
| 121 | +- `BitkitApp.swift`: Main app entry, handles AppDelegate setup, push notifications, quick actions |
| 122 | +- `AppScene.swift`: Root scene coordinator, manages app-wide ViewModels and lifecycle |
| 123 | +- `ContentView.swift`: Root content view |
| 124 | + |
| 125 | +**Services Layer:** |
| 126 | +- `CoreService`: Bridge to BitkitCore (Rust), handles Bitcoin operations and activity storage |
| 127 | +- `LightningService`: Manages LDK Node lifecycle, Lightning operations, channel management |
| 128 | +- `TransferService`: Orchestrates Bitcoin/Lightning transfers (send/receive) |
| 129 | +- `TransferStorage`: Persists pending transfer state |
| 130 | +- `CurrencyService`: Currency conversion and exchange rates |
| 131 | +- `ElectrumConfigService`, `RgsConfigService`: Backend configuration |
| 132 | +- `ServiceQueue`: Queue system for background operations (`.core`, `.ldk` queues) |
| 133 | + |
| 134 | +**Managers:** |
| 135 | +- `SessionManager`: User session state |
| 136 | +- `PushNotificationManager`: Push notification handling for incoming payments |
| 137 | +- `ScannerManager`: QR code scanning for payments |
| 138 | +- `ToastWindowManager`: App-wide toast notifications |
| 139 | +- `TransferTrackingManager`: Tracks pending transfers (new feature) |
| 140 | +- `TimedSheets/`: Timed sheet management (backup reminders, high balance warnings) |
| 141 | +- `SuggestionsManager`, `TagManager`, `LanguageManager`, `NetworkMonitor` |
| 142 | + |
| 143 | +**ViewModels (Legacy):** |
| 144 | +While the project is transitioning away from traditional ViewModels, these still exist but should follow `@Observable` patterns: |
| 145 | +- `AppViewModel`: App-wide state (toasts, errors) |
| 146 | +- `WalletViewModel`: Wallet state, balance, node lifecycle |
| 147 | +- `ActivityListViewModel`: Transaction/payment history |
| 148 | +- `TransferViewModel`: Transfer flows (send/receive) |
| 149 | +- `NavigationViewModel`, `SheetViewModel`: UI navigation state |
| 150 | +- `BlocktankViewModel`: Lightning channel ordering via Blocktank |
| 151 | + |
| 152 | +**Key Directories:** |
| 153 | +- `Components/`: Reusable UI components (buttons, sliders, widgets) |
| 154 | +- `Views/`: Feature-specific views (Onboarding, Backup, Security, Wallets, Settings, Transfer) |
| 155 | +- `Extensions/`: Swift extensions for utilities and mock data |
| 156 | +- `Utilities/`: Helper utilities (Logger, Keychain, Crypto, Haptics, StateLocker) |
| 157 | +- `Models/`: Data models (Toast, ElectrumServer, NodeLifecycleState, etc.) |
| 158 | +- `Styles/`: Fonts and sheet styles |
| 159 | + |
| 160 | +### Service Queue Pattern |
| 161 | + |
| 162 | +Operations that interact with `CoreService` or `LightningService` must use `ServiceQueue`: |
| 163 | + |
| 164 | +```swift |
| 165 | +// For BitkitCore operations |
| 166 | +try await ServiceQueue.background(.core) { |
| 167 | + // Core operations here |
| 168 | +} |
| 169 | + |
| 170 | +// For LDK Node operations |
| 171 | +try await ServiceQueue.background(.ldk) { |
| 172 | + // Lightning operations here |
| 173 | +} |
| 174 | +``` |
| 175 | + |
| 176 | +### State Management Patterns |
| 177 | + |
| 178 | +**Node Lifecycle:** |
| 179 | +The Lightning node has distinct lifecycle states tracked via `NodeLifecycleState`: |
| 180 | +- `.notStarted` → `.initializing` → `.running` → `.stopped` |
| 181 | +- Error states: `.errorStarting(String)` |
| 182 | + |
| 183 | +**Transfer Tracking:** |
| 184 | +New feature (`TransferTrackingManager`) tracks pending transfers to handle edge cases where transfers are initiated but not completed. |
| 185 | + |
| 186 | +## Important Development Notes |
| 187 | + |
| 188 | +### Security & Bitcoin/Lightning |
| 189 | + |
| 190 | +- Use proper Bitcoin/Lightning terminology in code and naming |
| 191 | +- All Bitcoin/Lightning operations belong in the service layer, never in views |
| 192 | +- The app uses `StateLocker` to prevent concurrent Lightning operations (`.lightning` lock) |
| 193 | +- Keychain is used for sensitive data (mnemonics, passphrases) |
| 194 | + |
| 195 | +### Network Configuration |
| 196 | + |
| 197 | +- The app currently runs on **regtest only** (see `LightningService.swift:92` guard) |
| 198 | +- VSS (Versioned Storage Service) authentication is not yet implemented |
| 199 | +- Electrum/Esplora server URLs are configurable via `Env` |
| 200 | +- E2E builds use local Electrum backend via `E2E_BUILD` compilation flag |
| 201 | + |
| 202 | +### Error Handling |
| 203 | + |
| 204 | +- Use `do-catch` blocks for async operations |
| 205 | +- Provide user feedback via toasts: `app.toast(type: .error, title: "...", description: "...")` |
| 206 | +- Handle loading, error, and empty states comprehensively |
| 207 | +- Consider using `enum LoadingState<T> { case idle, loading, loaded(T), error(Error) }` |
| 208 | + |
| 209 | +### iOS Version Compatibility |
| 210 | + |
| 211 | +- Xcode previews only work with iOS 17 and below (due to Rust dependencies) |
| 212 | +- Use availability checks for iOS 18/26 features: |
| 213 | + ```swift |
| 214 | + if #available(iOS 18.0, *) { |
| 215 | + // Use iOS 18+ features |
| 216 | + } else { |
| 217 | + // Fallback |
| 218 | + } |
| 219 | + ``` |
| 220 | + |
| 221 | +### Performance |
| 222 | + |
| 223 | +- Avoid expensive operations in view body |
| 224 | +- Move heavy computations to `@Observable` objects |
| 225 | +- Use proper state granularity to minimize view updates |
| 226 | +- Use `@ViewBuilder` for repetitive view code |
| 227 | + |
| 228 | +### Accessibility |
| 229 | + |
| 230 | +Ensure accessibility modifiers and labels are added to custom components. |
| 231 | + |
| 232 | +## Code Style & Conventions |
| 233 | + |
| 234 | +- **SwiftFormat** configuration in `.swiftformat` |
| 235 | +- Max line width: 150 characters |
| 236 | +- Swift version: 5.10 |
| 237 | +- Use descriptive names: `isLoadingUsers` not `loading` |
| 238 | +- Follow Apple's SwiftUI best practices |
| 239 | + |
| 240 | +## Common Workflows |
| 241 | + |
| 242 | +### Adding a New Feature |
| 243 | + |
| 244 | +1. Identify if business logic should live in an `@Observable` object or existing ViewModel |
| 245 | +2. Create UI components in `Components/` or feature-specific views in `Views/` |
| 246 | +3. Wire up via `.environment()` injection in `AppScene.swift` |
| 247 | +4. Use `.task` for async initialization |
| 248 | +5. Add error handling and user feedback (toasts) |
| 249 | + |
| 250 | +### Working with Lightning |
| 251 | + |
| 252 | +1. All Lightning operations go through `LightningService.shared` |
| 253 | +2. Lock the Lightning state with `StateLocker.lock(.lightning)` for critical operations |
| 254 | +3. Listen to LDK events via `wallet.addOnEvent(id:)` pattern |
| 255 | +4. Sync activity list after Lightning events |
| 256 | + |
| 257 | +### Working with Bitcoin |
| 258 | + |
| 259 | +1. Use `CoreService` for Bitcoin operations |
| 260 | +2. Activity tracking handles both on-chain and Lightning payments |
| 261 | +3. RBF (Replace-By-Fee) is tracked via `ActivityService.replacementTransactions` |
| 262 | + |
| 263 | +### Localization Changes |
| 264 | + |
| 265 | +1. Update translation keys in code |
| 266 | +2. Run `node scripts/validate-translations.js` to check for issues |
| 267 | +3. Sync with Transifex using `bitkit-transifex-sync` tool |
0 commit comments