BYOKit 2.0 turns the provider list into a compact command center: the active route, secure-key posture, and add-provider action are visible before the first row. The underlying components remain independently reusable and the base package remains dependency-free.
A Swift Package that gives any iOS / iPadOS / macOS app a production-grade BYOK (Bring Your Own Key) LLM configuration experience — in one line.
import BYOKit
BYOKSettingsView()
.environmentObject(store) // a ConfigurationStore
.byokClient(DefaultLLMClient()) // or your own LLMClientThe hard part of supporting multiple LLM providers isn't calling them — there are many good libraries for that (AnyLanguageModel, SwiftOpenAI, …). It's the configuration UX: per-provider onboarding with deep links, key validation, one-tap connection testing, custom base URLs, and multi-key management. Every app rebuilds it by hand. BYOKit ships it.
- One-line settings center — list, add, edit, reorder, delete, choose the active provider.
- Per-provider onboarding — structured "get a key" guide with steps, notes, and deep links (console / sign-up / docs / pricing).
- Secure by default — keys go to the Keychain; the UI masks them; "Test Connection" uses a minimal request.
- Data-driven catalog — add a provider by editing
providers.json; no UI code. Ships built-in, optionally overridden by a remote OTA JSON. - Swappable engine —
DefaultLLMClient(URLSession, zero deps) speaks OpenAI, Anthropic, Gemini, and Ollama, with streaming built in. Conform toLLMClientto use anything else. - Adaptive & themeable — looks right on iPhone, iPad, and Mac; matches your app's style.
- Localized — UI, validation hints, and error messages in English + Simplified Chinese, following the host app's language.
OpenAI · Anthropic · Google Gemini · DeepSeek · OpenRouter · Groq · Mistral · xAI (Grok) · Ollama (local) · Custom (any OpenAI-compatible endpoint).
Each ships with brand styling, key validation, model presets, and a full onboarding guide.
Xcode → File ▸ Add Package Dependencies… → paste
https://github.com/everettjf/BYOKit → choose Up to Next Major Version
(Xcode fills in the latest release for you).
Package.swift
.package(url: "https://github.com/everettjf/BYOKit", from: "2.0.0")
from: "2.0.0"is a floor, not a pin — SwiftPM always resolves the newest compatible release, so this line never needs editing when a new version ships.
Add the BYOKit product (umbrella). For just the data layer, depend on
BYOKitCore; for just the UI, BYOKitUI.
Requirements: iOS 17 / iPadOS 17 / macOS 14, Swift 6.1 toolchain.
@main
struct MyApp: App {
@StateObject private var store = ConfigurationStore() // Keychain + UserDefaults
var body: some Scene {
WindowGroup {
BYOKSettingsView()
.environmentObject(store)
.byokClient(DefaultLLMClient())
}
}
}Send a request with the active configuration:
if let config = store.activeConfiguration,
let provider = await ProviderRegistry.shared.provider(config.providerID) {
let resolved = ResolvedConfiguration(
provider: provider,
configuration: config,
apiKey: store.apiKey(for: config.id)
)
let response = try await DefaultLLMClient()
.complete(.text("Hello"), with: resolved)
print(response.text)
}Every LLMClient can stream incremental text. DefaultLLMClient parses the
provider's wire stream (OpenAI/Anthropic/Gemini SSE, Ollama NDJSON); other
clients fall back to a single complete call automatically.
for try await delta in client.streamComplete(.text("Write a haiku"), with: resolved) {
print(delta, terminator: "") // each chunk is a delta — concatenate for the full text
}UI chrome, key-validation hints, and connection/error messages ship in English and Simplified Chinese (zh-Hans), resolved from the package's own bundle. The host app's language selection drives which is shown — no setup required.
BYOKSettingsView()
.byokProviders(.only(.openAI, .anthropic, .ollama)) // limit providers
.byokTheme(BYOKTheme(accent: .pink, cornerRadius: 16))
.byokShowsOnboarding(true)
.byokClient(myCustomClient)ProviderPickerView, ProviderConfigForm, OnboardingGuideView,
ConnectionTestButton, KeyField, and ProviderBadge are all public and usable
on their own.
The optional BYOKitClientAnyLanguageModel product adds on-device Apple
Foundation Models via AnyLanguageModel,
delegating every cloud/HTTP provider to a wrapped fallback (so custom BYOK
endpoints keep working through DefaultLLMClient):
import BYOKitClientAnyLanguageModel
let builtins = await ProviderRegistry.shared.all()
BYOKSettingsView()
.byokClient(AnyLanguageModelClient()) // adds on-device support
.byokProviders(builtins + [.appleFoundationModels]) // expose the Apple providerOnly depend on this product if you want local models — the base BYOKit library
stays dependency-free.
The adapter also services on-device MLX (Apple Silicon) and llama.cpp / GGUF models — gated behind BYOKit traits so the heavy backends are only pulled in when you ask for them:
.package(url: "https://github.com/everettjf/BYOKit", from: "1.0.0",
traits: ["MLX", "Llama"]) // enable the backends you wantBYOKSettingsView()
.byokClient(AnyLanguageModelClient())
.byokProviders(builtins + [.appleFoundationModels, .mlx, .llama]).mlx— the selected model id is a Hugging Face MLX repo (e.g.mlx-community/Qwen3-0.6B-4bit), downloaded on first use..llama— point themodelPathfield at a local.gguffile.
With neither trait enabled (the default), these providers report that the backend isn't compiled in, and nothing heavy is added to your graph.
| Target | Role | Dependencies |
|---|---|---|
BYOKitCore |
Models, provider registry, onboarding metadata, providers.json |
none |
BYOKitStore |
Keychain credential store + configuration persistence | Core |
BYOKitClient |
LLMClient protocol + DefaultLLMClient (URLSession) |
Core |
BYOKitUI |
SwiftUI components | Core, Store, Client |
BYOKit |
Umbrella re-export | all |
BYOKitClientAnyLanguageModel |
Optional — on-device Apple Foundation Models (+ MLX / llama.cpp via traits) | Core, Client, AnyLanguageModel |
BYOKitCore has zero third-party dependencies, and the base BYOKit library
pulls in nothing third-party. Only the optional adapter above adds a dependency.
Example/ contains a multi-platform SwiftUI demo.
cd Example
xcodegen generate # needs `brew install xcodegen`
open BYOKitDemo.xcodeprojswift testThe test suite covers the registry, key validation, Keychain round-trips, the
store, all four API formats (via a stubbed URLProtocol), streaming, and the
AnyLanguageModel adapter's delegation. Set ROCKY_OPENAI_APIKEY to also run two
live OpenAI smoke tests (skipped otherwise). The package is build-verified on
macOS and the iOS/iPadOS simulator SDKs.
- M1/M2 — Core models, Keychain store, URLSession client, full SwiftUI configuration UI.
- M3 — Optional
AnyLanguageModeladapter (on-device Apple Foundation Models) behindLLMClient. - MLX / llama.cpp local models via opt-in BYOKit traits.
- M4 — Streaming completions + English / Simplified Chinese localization.
- Usage / quota hints.
- DocC API reference on the docs site.
Issues and PRs welcome. Adding a provider is usually just an entry in
Sources/BYOKitCore/Resources/providers.json —
no code required.
MIT © Everett. See LICENSE.