--- name: implement-feature description: | Guide for implementing features in ClaudeBar following architecture-first design, TDD, rich domain models, and Swift 6.2 patterns. Use this skill when: (1) Adding new functionality to the app (2) Creating domain models that follow user's mental model (3) Building SwiftUI views that consume domain models directly (4) User asks "how do I implement X" or "add feature Y" (5) Implementing any feature that spans modules (DataSources, Providers, Quotas) and the App --- # Implement Feature in ClaudeBar Implement features using architecture-first design, TDD, rich domain models, and Swift 6.2 patterns. ## Workflow Overview ``` ┌─────────────────────────────────────────────────────────────┐ │ 1. ARCHITECTURE DESIGN (Required - User Approval Needed) │ ├─────────────────────────────────────────────────────────────┤ │ • Read the design docs — they are the source of truth │ │ • Place the feature: owner, capability, extension point │ │ • Write the design change into the docs first │ │ • Analyze requirements │ │ • Create component diagram │ │ • Show data flow and interactions │ │ • Present to user for review │ │ • Wait for approval before proceeding │ └─────────────────────────────────────────────────────────────┘ │ ▼ (User Approves) ┌─────────────────────────────────────────────────────────────┐ │ 2. TDD IMPLEMENTATION │ ├─────────────────────────────────────────────────────────────┤ │ • Model tests → models (Quotas / Providers / Domain) │ │ • Module tests → generic rules and workers (DataSources) │ │ • Views, reading the domain directly │ └─────────────────────────────────────────────────────────────┘ ``` ## Phase 0: Architecture Design (MANDATORY) Before writing any code, design it **in the docs** and get user approval. The design docs are the source of truth ([AGENTS.md → Design docs are the source of truth](../../../AGENTS.md#design-docs-are-the-source-of-truth)). ### Step 0: Read the design docs, and place the feature in them Read the design in order ([ARCHITECTURE.md](../../../docs/architecture/ARCHITECTURE.md) maps it): [USER_JOURNEYS.md](../../../docs/architecture/USER_JOURNEYS.md) (the person and the moment), [CANONICAL_MODEL.md](../../../docs/architecture/CANONICAL_MODEL.md) (the tree, the words, each law and its owner, *owned* vs *offered*), [TARGET_ARCHITECTURE.md](../../../docs/architecture/TARGET_ARCHITECTURE.md) (the pieces and their one job, the flows), then any `docs/features//design.md` it touches. Then answer: | Question | If yes | |---|---| | Does it answer *another question* than the product's lifecycle? | it is a **capability** (CANONICAL §2.1): declared in the definition, its own types, reached through a handle that is `nil` when not declared — never a flag on `Provider`, never chosen by a provider's name. A runner outside the modules is supplied by the `Engine` (TARGET_ARCHITECTURE §10) | | Does a provider need something the definition can't say? | a **generic rule or worker** in `DataSources` (ENGINE_DESIGN), then a line of JSON — never a Swift line that names the provider | | Does it react to a refresh, a selection, a setting? | it observes an **extension point** (e.g. `QuotaMonitor.onRefreshed`) — the Monitor is not edited for it | | Does it notify? | its own port in Alerting — not a new method on an existing alerter | | Is a law missing, or owned twice? | add it to CANONICAL §5 with **one** owner | When the docs don't cover it, write the change into them first (tree lines, laws with owners, a pieces table, a TARGET section) — that doc change is the architecture you present in Step 4. Code that disagrees with the docs is behind; don't bend the design to it. ### Step 1: Analyze Requirements Identify: - What new models/types are needed - Which existing components will be modified - Data flow between components - External dependencies (CLI, API, etc.) ### Step 2: Create Architecture Diagram Use ASCII diagram showing all components and their interactions: ``` Example: Codex accounts (#326) — a definition change plus generic pieces ┌──────────────────────────────────────────────────────────────────────┐ │ ARCHITECTURE │ ├──────────────────────────────────────────────────────────────────────┤ │ Resources (data) Modules (Swift, no vendor names) App │ │ │ │ ┌──────────────┐ ┌─────────────────────────────┐ ┌───────────┐ │ │ │ codex.json │──▶│ Providers │──▶│ Accounts │ │ │ │ accounts: │ │ ProviderCatalog.detect() │ │ card │ │ │ │ folder, ids │ │ ProviderDefinition.Accounts│ └───────────┘ │ │ │ dataSources │ │ Provider owns its Accounts │ │ │ └──────────────┘ └──────────────┬──────────────┘ │ │ │ │ │ ┌──────────────▼──────────────┐ │ │ │ DataSources │ │ │ │ identity, requiresFiles, │ │ │ │ JSON-RPC `then`, env │ │ │ └──────────────┬──────────────┘ │ │ ▼ │ │ ┌─────────────────────────────┐ │ │ │ Quotas (UsageSnapshot …) │ │ │ └─────────────────────────────┘ │ └──────────────────────────────────────────────────────────────────────┘ ``` ### Step 3: Document Component Interactions List each component with: - **Purpose**: What it does - **Inputs**: What it receives - **Outputs**: What it produces - **Dependencies**: What it needs ``` Example: | Component | Purpose | Inputs | Outputs | Dependencies | |----------------|------------------------|-----------------|----------------|-----------------| | AddedAccounts | Validate a login folder| folder path | account config | DataSources | | identity rule | Fail closed on swaps | credential | UsageError | — | ``` ### Step 4: Present for User Approval **IMPORTANT**: Always ask user to confirm the design is correct before implementing — the doc change (tree, laws and owners, pieces), the diagram, and for UI a mockup in `design-concept//` on mock data. Use AskUserQuestion tool with options: - "Approve - proceed with implementation" - "Modify - I have feedback on the design" Do NOT proceed to Phase 1 until user explicitly approves. --- ## Core Principles ### 1. Rich Domain Models (User's Mental Model) Domain models encapsulate behavior, not just data: ```swift // Rich domain model with behavior public struct UsageQuota: Sendable, Equatable { public let percentRemaining: Double // Domain behavior - computed from state public var status: QuotaStatus { QuotaStatus.from(percentRemaining: percentRemaining) } public var isDepleted: Bool { percentRemaining <= 0 } public var needsAttention: Bool { status.needsAttention } } ``` ### 2. Swift 6.2 Patterns (No ViewModel/AppState Layer) Views consume domain models directly from `QuotaMonitor`: ```swift // QuotaMonitor is the single source of truth @MainActor @Observable public final class QuotaMonitor { // The providers you keep: add, delete, order, the derived lineup public let providers: Providers public var logins: [Account] // every login public var lineup: [Account] // the lineup public func login(id: String) -> Account? // Selection state public var selectedProviderId: String public var selectedLogin: Account? public var selectedProviderStatus: QuotaStatus } // Views consume domain directly - NO AppState layer struct MenuContentView: View { let monitor: QuotaMonitor // Injected from app var body: some View { // Use delegation methods, not monitor.providers.enabled ForEach(monitor.lineup, id: \.id) { login in ProviderPill(provider: login) } } } ``` ### 3. Protocol-Based DI with @Mockable Ports for what lies outside the app live at a module's root and are `@Mockable`; their implementations are `internal` in `Internal/`: ```swift @Mockable public protocol NetworkClient: Sendable { func request(_ request: URLRequest) async throws -> (Data, URLResponse) } ``` ## Architecture > **Reference:** [MODULAR_DESIGN.md](../../../docs/architecture/MODULAR_DESIGN.md) (modules) · > [TARGET_ARCHITECTURE.md](../../../docs/architecture/TARGET_ARCHITECTURE.md) (how a provider runs) · > [ARCHITECTURE.md](../../../docs/architecture/ARCHITECTURE.md) (the app layers) The code is mid-migration from three layers to modules. Find which side the behaviour lives on before you change it: | Where | Holds | Tests | |---|---|---| | `Modules/Providers/Resources/Providers/.json` (+ `.js`) | every built-in provider: where the key is, how to fetch, how to read | `Modules/Providers/Tests/` (golden tests over `StubbedProvider` / `ClaudeHarness`) | | `Modules/Providers/Sources` | `ProviderCatalog` (finds every definition), `Engine` (the shared ports), `Provider` (the one lifecycle: refresh, fallback chain, accounts), `ProviderDefinition`, settings and account contracts, the capabilities (`UsageHistory`, `GuestPasses`, `InUse`) | `Modules/Providers/Tests/` | | `Modules/DataSources/Sources` | `DataSource` and its workers: credential lookups (environment, login shell, files, Keychain, browser cookies and storage, SQLite) and refreshes; HTTP, steps, JSON-RPC, terminal, command, file, directory, SQLite, local-server and CloudWatch fetches; JSON / text / script mapping; `UsageLog` and its log readers; the process runners | `Modules/DataSources/Tests/` | | `Modules/Quotas/Sources` | the usage model: `UsageSnapshot`, `UsageQuota`, `UsageError`, plans, costs, `DailyUsageStat` / `DailyUsageReport` (interim shapes, see each type's `- Note:`) | `Tests/DomainTests/` and the tests of the module that uses it | | `Modules/AWSClients` | the AWS SDK behind DataSources' `CloudWatchClient` and `PriceCatalog` ports | `Modules/AWSClients/Tests/` | | `Sources/Domain` | `QuotaMonitor`, Notify!, sessions, In use's `NewSessions` | `Tests/DomainTests/` | | `Sources/Infrastructure` | storage, notifications, hooks, the shell environment, Claude's guest-pass runner | `Tests/InfrastructureTests/` | | `Sources/App` | SwiftUI views reading the domain directly; `ClaudeBarApp.init`, the composition root, which builds the `Engine` and names no provider | `Tests/AppTests/`, `Tests/AcceptanceTests/` | A bug in a migrated provider is fixed in its JSON, or generically in `DataSources`, never with vendor-named Swift. Modules never `import Domain`. **Key patterns:** - **Modules by context** — the domain at a module's root, its implementation in `Internal/`, one factory enum per module (`DataSources.make`, `ProviderFactory.make`) - **Providers are data** — a feature a provider needs becomes a generic rule or worker, then a line of JSON - **Protocol-based DI** — `@Mockable` ports; Chicago-school tests assert on state - **No ViewModel layer** — views read `QuotaMonitor` and `Provider` directly - **Settings** — generic per-provider values (`dataSourceKind`, `isOn`) before a new sub-protocol ## TDD Workflow (Chicago School) Name each test `should [when ]`, in the person's words, never a method, type or mechanism verb → [Naming tests](references/tdd-patterns.md#naming-tests). We follow **Chicago school TDD** (state-based testing): - Test **state changes** and **return values**, not interactions - Focus on the "what" (observable outcomes), not the "how" (method calls) - Mocks stub dependencies to return data, not to verify calls - Design emerges from tests (emergent design) ### Phase 1: Domain Model Tests Test state and computed properties: ```swift @Suite struct FeatureModelTests { @Test func `should be normal when half is left`() { // Given - set up initial state let model = FeatureModel(value: 50) // When/Then - verify state/return value #expect(model.status == .normal) } @Test func `should have 70 left and stay healthy after using 30 of 100`() { // Given var model = FeatureModel(value: 100) // When - perform action model.consume(30) // Then - verify new state #expect(model.value == 70) #expect(model.status == .healthy) } } ``` ### Phase 2: Module Tests (DataSources / Providers) Stub dependencies to return data, assert on resulting state: ```swift @Suite struct FeatureServiceTests { @Test func `should load three items when the service answers`() async throws { // Given - stub dependency to return data (not verify calls) let mockClient = MockNetworkClient() given(mockClient).fetch(any()).willReturn(validResponseData) let service = FeatureService(client: mockClient) // When let result = try await service.fetch() // Then - verify returned state, not interactions #expect(result.items.count == 3) #expect(result.status == .loaded) } } ``` ### Phase 3: Integration Create the views. `ClaudeBarApp.init` is the composition root: it builds the `Engine` (the ports every provider shares) and calls `ProviderCatalog().detect()`. A provider is never wired there; a new **port** is a new `Engine` field, built once in `init` (keep startup work there, never in `ClaudeBarMain`). Acceptance specs in `Tests/AcceptanceTests/` compose real modules with stubbed ports. ```bash tuist test Providers # one module's tests while working (schemes: Providers, DataSources, Domain, Infrastructure, AppTests, AcceptanceTests) # tuist caches results; the final check, and a forced re-run of one suite, use xcodebuild: xcodebuild test -workspace ClaudeBar.xcworkspace -scheme ClaudeBar-Workspace -destination 'platform=macOS,arch=arm64' xcodebuild test -workspace ClaudeBar.xcworkspace -scheme ClaudeBar-Workspace \ -destination 'platform=macOS,arch=arm64' -only-testing:ProvidersTests/ClaudeAPITests ``` ## References - [Architecture diagram patterns](references/architecture-diagrams.md) - ASCII diagram examples for different scenarios - [Swift 6.2 @Observable patterns](references/swift-observable.md) - [Rich domain model patterns](references/domain-models.md) - [TDD test patterns](references/tdd-patterns.md) ## Checklist ### Architecture Design (Phase 0) - [ ] Read CANONICAL_MODEL, TARGET_ARCHITECTURE and the feature's design.md - [ ] Place it: owner, capability (handle `nil` when not declared), extension point - [ ] Write the design change into the docs first - [ ] Analyze requirements and identify components - [ ] Create ASCII architecture diagram with component interactions - [ ] Document component table (purpose, inputs, outputs, dependencies) - [ ] **Get user approval before proceeding** ### Implementation (Phases 1-3) - Chicago School TDD - [ ] Write failing test asserting expected STATE (Red) - [ ] Write minimal code to pass the test (Green) - [ ] Refactor while keeping tests green - [ ] Put each type in the module MODULAR_DESIGN.md names (never a vendor-named type in a module) - [ ] Test state changes and return values (not interactions) - [ ] Define protocols with `@Mockable` for external dependencies - [ ] Stub mocks to return data, assert on resulting state - [ ] Implement ports in the module's `Internal/` - [ ] Create views consuming domain models directly - [ ] Views render and tell only — no comparing, counting or reading quotas to decide - [ ] Docs updated in the same change (status, build truth, laws) - [ ] Real UI screenshots on mock data (`scripts/demo-screenshots.sh`) for UI changes - [ ] Full `xcodebuild test` green (`tuist test` skips cached targets)