AD

add-provider

Assists developers in building new AI providers by structuring architecture and test-driven implementation logic.

Install

mkdir -p .claude/skills/add-provider && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/7648" && unzip -o skill.zip -d .claude/skills/add-provider && rm skill.zip

Installs to .claude/skills/add-provider

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Guide for adding new AI providers to ClaudeBar using TDD patterns. Use this skill when:
(1) Adding a new AI assistant provider (like Antigravity, Cursor, etc.)
(2) Creating a usage probe for a CLI tool or local API
(3) Following TDD to implement provider integration
(4) User asks "how do I add a new provider" or "create a provider for X"
339 chars · catalog description✓ has a “when” triggerlonger than Claude Code's old 250-char listing cap (fine on current versions)
Advanced

Key capabilities

  • Implements new AI provider integrations using TDD
  • Creates usage probes for CLI tools and local APIs
  • Registers providers in the ClaudeBar application
  • Defines visual identity for new providers

How it works

The skill guides the developer through a five-phase TDD process, from parsing tests to registration and visual identity setup.

Inputs & outputs

You give it
Request to add a new AI provider
You get back
Implementation code, test suites, and registration logic

When to use add-provider

  • Integrate new AI service providers
  • Create usage probes for CLI tools
  • Implement provider integration using TDD

About this skill

Add Provider to ClaudeBar

Add new AI providers following established TDD patterns and architecture.

Architecture Overview

Full architecture: docs/ARCHITECTURE.md

ComponentLocationPurpose
AIProviderSources/Domain/Provider/Rich domain model with isEnabled state
UsageProbeSources/Infrastructure/CLI/Fetches quota from CLI/API
TestsTests/InfrastructureTests/CLI/Parsing + behavior tests

TDD Workflow

Phase 1: Parsing Tests (Red → Green)

Create Tests/InfrastructureTests/CLI/{Provider}UsageProbeParsingTests.swift:

import Testing
import Foundation
@testable import Infrastructure
@testable import Domain

@Suite
struct {Provider}UsageProbeParsingTests {

    static let sampleResponse = """
                                { /* sample API/CLI response */ }
                                """

    @Test func `parses quota into UsageQuota`() throws {
        let data = Data(Self.sampleResponse.utf8)
        let snapshot = try {Provider}UsageProbe.parseResponse(data, providerId: "{provider-id}")
        #expect(snapshot.quotas.count > 0)
    }

    @Test func `maps percentage correctly`() throws { /* ... */ }
    @Test func `parses reset time`() throws { /* ... */ }
    @Test func `extracts account email`() throws { /* ... */ }
    @Test func `handles missing data gracefully`() throws { /* ... */ }
}

Phase 2: Probe Behavior Tests (Red → Green)

Create Tests/InfrastructureTests/CLI/{Provider}UsageProbeTests.swift:

import Testing
import Foundation
import Mockable
@testable import Infrastructure
@testable import Domain

@Suite
struct {Provider}UsageProbeTests {

    @Test func `isAvailable returns false when not detected`() async {
        let mockExecutor = MockCLIExecutor()
        given(mockExecutor).execute(...).willReturn(CLIResult(output: "", exitCode: 1))
        let probe = {Provider}UsageProbe(cliExecutor: mockExecutor)
        #expect(await probe.isAvailable() == false)
    }

    @Test func `isAvailable returns true when detected`() async { /* ... */ }
    @Test func `probe throws appropriate error when unavailable`() async { /* ... */ }
    @Test func `probe returns UsageSnapshot on success`() async { /* ... */ }
}

Phase 3: Implement Probe

Create Sources/Infrastructure/CLI/{Provider}UsageProbe.swift:

import Foundation
import Domain

public struct {Provider}UsageProbe: UsageProbe {
    private let cliExecutor: any CLIExecutor
    private let networkClient: any NetworkClient
    private let timeout: TimeInterval

    public init(
        cliExecutor: (any CLIExecutor)? = nil,
        networkClient: (any NetworkClient)? = nil,
        timeout: TimeInterval = 8.0
    ) {
        self.cliExecutor = cliExecutor ?? DefaultCLIExecutor()
        self.networkClient = networkClient ?? URLSession.shared
        self.timeout = timeout
    }

    public func isAvailable() async -> Bool {
        // Detect if provider is available (binary exists, process running, etc.)
    }

    public func probe() async throws -> UsageSnapshot {
        // 1. Detect/authenticate
        // 2. Fetch quota data
        // 3. Parse and return UsageSnapshot
    }

    // Static parsing for testability
    static func parseResponse(_ data: Data, providerId: String) throws -> UsageSnapshot {
        // Parse response into domain models
    }
}

Phase 4: Create Provider

Choose Repository Type (ISP):

  • Simple provider (no special config) → Use base ProviderSettingsRepository
  • Provider with config → Create sub-protocol extending base (see ISP section below)

Create Sources/Domain/Provider/{Provider}Provider.swift:

import Foundation
import Observation

@Observable
public final class {Provider}Provider: AIProvider, @unchecked Sendable {
    public let id: String = "{provider-id}"
    public let name: String = "{Provider Name}"
    public let cliCommand: String = "{cli-command}"

    public var dashboardURL: URL? { URL(string: "https://...") }
    public var statusPageURL: URL? { nil }

    /// Whether the provider is enabled (persisted via settingsRepository)
    public var isEnabled: Bool {
        didSet {
            settingsRepository.setEnabled(isEnabled, forProvider: id)
        }
    }

    public private(set) var isSyncing: Bool = false
    public private(set) var snapshot: UsageSnapshot?
    public private(set) var lastError: Error?

    private let probe: any UsageProbe
    private let settingsRepository: any ProviderSettingsRepository  // Or your sub-protocol

    public init(probe: any UsageProbe, settingsRepository: any ProviderSettingsRepository) {
        self.probe = probe
        self.settingsRepository = settingsRepository
        // Default to enabled for most providers (set defaultValue: false for opt-in providers)
        self.isEnabled = settingsRepository.isEnabled(forProvider: "{provider-id}")
    }

    public func isAvailable() async -> Bool {
        await probe.isAvailable()
    }

    @discardableResult
    public func refresh() async throws -> UsageSnapshot {
        isSyncing = true
        defer { isSyncing = false }
        do {
            let newSnapshot = try await probe.probe()
            snapshot = newSnapshot
            lastError = nil
            return newSnapshot
        } catch {
            lastError = error
            throw error
        }
    }
}

Phase 5: Register Provider

Add to Sources/App/ClaudeBarApp.swift:

let settingsRepository = JSONSettingsRepository.shared

let repository = AIProviders(providers: [
    ClaudeProvider(probe: ClaudeUsageProbe(), settingsRepository: settingsRepository),
    // ... existing providers
    {Provider}Provider(probe: {Provider}UsageProbe(), settingsRepository: settingsRepository),
])

For providers with special settings (ISP pattern):

// ZaiProvider uses ZaiSettingsRepository (sub-protocol)
ZaiProvider(
    probe: ZaiUsageProbe(settingsRepository: settingsRepository),
    settingsRepository: settingsRepository  // Same instance, casted to ZaiSettingsRepository
)

// CopilotProvider uses CopilotSettingsRepository (sub-protocol with credentials)
CopilotProvider(
    probe: CopilotUsageProbe(settingsRepository: settingsRepository),
    settingsRepository: settingsRepository  // Same instance, casted to CopilotSettingsRepository
)

Add visual identity in Sources/App/Views/Theme.swift:

// In AppTheme.providerColor(for:scheme:)
case "{provider-id}": return /* your color */

// In AppTheme.providerName(for:)
case "{provider-id}": return "{Provider Name}"

// In AppTheme.providerSymbolIcon(for:)
case "{provider-id}": return "/* SF Symbol name */"

// In AppTheme.providerIconAssetName(for:)
case "{provider-id}": return "{Provider}Icon"

Domain Model Mapping

Map provider responses to existing domain models:

Source DataDomain Model
Quota percentageUsageQuota.percentRemaining (0-100)
Model/tier nameQuotaType.modelSpecific("name")
Reset timeUsageQuota.resetsAt (Date)
Account emailUsageSnapshot.accountEmail

Error Handling

Use existing ProbeError enum:

ProbeError.cliNotFound("{Provider}")      // Binary/process not found
ProbeError.authenticationRequired          // Auth token missing/expired
ProbeError.executionFailed("message")      // Runtime errors
ProbeError.parseFailed("message")          // Parse errors

ISP: Creating Provider-Specific Repository Sub-Protocols

If your provider needs special configuration or credentials, create a sub-protocol following ISP:

Step 1: Define Sub-Protocol in Domain

Add to Sources/Domain/Provider/ProviderSettingsRepository.swift:

/// {Provider}-specific settings repository, extending base ProviderSettingsRepository.
public protocol {Provider}SettingsRepository: ProviderSettingsRepository {
    // Configuration
    func {provider}ConfigPath() -> String
    func set{Provider}ConfigPath(_ path: String)

    // Credentials (if needed)
    func save{Provider}Token(_ token: String)
    func get{Provider}Token() -> String?
    func has{Provider}Token() -> Bool
}

Step 2: Implement in Infrastructure

Add to Sources/Infrastructure/Storage/JSONSettingsRepository.swift:

// MARK: - {Provider}SettingsRepository

extension JSONSettingsRepository: {Provider}SettingsRepository {
    public func {provider}ConfigPath() -> String {
        store.read(key: "{provider}.configPath") ?? ""
    }

    public func set{Provider}ConfigPath(_ path: String) {
        store.write(value: path, key: "{provider}.configPath")
    }
}

Step 3: Update Provider and Probe

// Provider
private let settingsRepository: any {Provider}SettingsRepository

// Probe (if needs settings)
public init(settingsRepository: any {Provider}SettingsRepository) {
    self.settingsRepository = settingsRepository
}

Existing Examples:

  • ZaiSettingsRepository - config path + env var
  • CopilotSettingsRepository - env var + GitHub credentials

Reference Implementation

See references/antigravity-example.md for a complete working example showing:

  • Full parsing test suite
  • Probe behavior tests with mocking
  • Probe implementation with process detection
  • Provider class pattern

Provider Icon

See references/provider-icon-guide.md for creating provider icons:

  • SVG template with rounded rectangle background
  • PNG generation at 1x/2x/3x sizes
  • Asset catalog setup
  • ProviderVisualIdentity extension

Checklist

  • Parsing tests created and passing
  • Probe behavior tests created and passing
  • Probe implementation complete
  • Provider class created
  • Provider registered in ClaudeBarApp
  • Visual identity added to Theme.swift (color, name, icons)
  • Provider ico

Content truncated.

When not to use it

  • When not following the established TDD architecture

Limitations

  • Requires adherence to specific repository patterns
  • Requires manual creation of icon assets

How it compares

It enforces a strict TDD workflow and architectural pattern, ensuring new providers are testable and consistent with existing ones.

Compared to similar skills

add-provider side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
add-provider (this skill)15moNo flagsAdvanced
implement-feature17moReviewAdvanced
new-api-support16moReviewIntermediate
api-test-generator19moReviewIntermediate

Try saying

Example prompts that trigger this skill in your AI assistant.

You might also like

implement-feature

tddworks

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 Domain, Infrastructure, and App layers

16

new-api-support

nalexn

Add introspection support for a SwiftUI API (view type, modifier, or View extension function). Use when the user wants to add support for a new SwiftUI entity to ViewInspector.

10

api-test-generator

mikopbx

Генерация полных Python pytest тестов для REST API эндпоинтов с валидацией схемы. Использовать при создании тестов для новых эндпоинтов, добавлении покрытия для CRUD операций или валидации соответствия API с OpenAPI схемами.

16

ios-simulator-skill

conorluddy

21 production-ready scripts for iOS app testing, building, and automation. Provides semantic UI navigation, build automation, accessibility testing, and simulator lifecycle management. Optimized for AI agents with minimal token output.

27181

build-iphone-apps

glittercowboy

Build professional native iPhone apps in Swift with SwiftUI and UIKit. Full lifecycle - build, debug, test, optimize, ship. CLI-only, no Xcode. Targets iOS 26 with iOS 18 compatibility.

1483

xcodebuildmcp

cameroncooke

Official skill for XcodeBuildMCP. Use when doing iOS/macOS/watchOS/tvOS/visionOS work (build, test, run, debug, log, UI automation).

2447

Search skills

Search the agent skills registry