Conduit — type-safe LLM inference for Swift.
One API. Every provider. Compile-time schemas. Native SwiftUI.
- Compile-time validated schemas — Define the shape of LLM output with
@Generableand catch mismatches before you ship. - One API for every provider — Claude, GPT-5.5, Gemini, Ollama, MLX, CoreML, llama.cpp. Swap providers without rewriting your app.
- Native tool calling — Expose Swift functions to models with strongly-typed arguments. The tool loop is handled for you.
- Streaming + SwiftUI ready —
AsyncSequencestreaming and an@ObservableChatSessionthat drops into aView. - Fast local inference — First-class MLX support tuned for Apple Silicon.
swift package add --url https://github.com/christopherkarani/Conduit --from 0.3.14Or add it in Xcode: File → Add Package Dependencies → https://github.com/christopherkarani/Conduit
Conduit uses Swift 6 package traits to keep compile times fast and binaries small. You must enable the traits for the providers you want to use.
// Package.swift
.package(
url: "https://github.com/christopherkarani/Conduit",
from: "0.3.0",
traits: ["Anthropic", "OpenAI", "MLX"] // ← pick your providers
)Available traits: Anthropic, OpenAI, OpenRouter, Gemini, Kimi, MiniMax, MLX, CoreML, Ollama, Llama, HuggingFaceHub
Linux or server-side? Skip
MLX. Cloud providers work out of the box. For local inference on Linux, use theOllamatrait.
import Conduit
let provider = AnthropicProvider(apiKey: "sk-ant-...")
let response = try await provider.generate(
"Explain the benefits of Swift Actors",
model: .claudeSonnet45,
config: .default.maxTokens(300)
)
print(response)This is Conduit's superpower. Define a Swift struct, attach @Generable, and the LLM returns a validated instance.
import Conduit
@Generable
struct MovieReview {
let title: String
let rating: Int
@Guide("One-paragraph summary")
let summary: String
let pros: [String]
let cons: [String]
}
let provider = AnthropicProvider(apiKey: "sk-ant-...")
let result = try await provider.generate(
messages: Messages { Message.user("Review the movie Inception") },
model: .claudeSonnet45,
config: .default.responseFormat(.jsonSchema(MovieReview.generationSchema))
)
let review = try MovieReview(GeneratedContent(json: result.text))
print(review.rating) // 9@Generable
struct WeatherArgs {
@Guide("City name") let city: String
@Guide("Unit", .anyOf(["celsius", "fahrenheit"])) let unit: String
}
struct WeatherTool: Tool {
let name = "get_weather"
let description = "Get current weather"
func call(arguments: WeatherArgs) async throws -> String {
return "72°F and sunny in \(arguments.city)"
}
}
let result = try await provider.generate(
messages: Messages { Message.user("What's the weather in Tokyo?") },
model: .claudeSonnet45,
config: .default.tools([WeatherTool()])
)// Cloud
let anthropic = AnthropicProvider(apiKey: "sk-ant-...")
// Local Apple Silicon (MLX)
let mlx = MLXProvider()
// Local via Ollama
let ollama = OpenAIProvider(ollamaHost: "localhost", port: 11434)
// Same generate() API on every provider.import SwiftUI
import Conduit
struct ChatView: View {
@State private var session = ChatSession(
provider: AnthropicProvider(apiKey: "sk-ant-..."),
model: .claudeSonnet45
)
@State private var input = ""
var body: some View {
VStack {
ScrollView { /* messages */ }
HStack {
TextField("Message", text: $input)
Button("Send") {
Task {
let reply = try await session.send(input)
input = ""
// append reply to UI
}
}
}
}
}
}- Getting Started — Installation, traits, and your first generation.
- Structured Output —
@Generable,@Guide, and compile-time schemas. - Tool Calling — Native Swift tools with automatic tool loops.
- Streaming — Real-time
AsyncSequencestreaming. - Chat Session —
ChatSession, history, and SwiftUI integration. - Architecture — How Conduit is put together.
Conduit is tuned for Apple Silicon and local model throughput.
| Hardware | Model | Quantization | Tokens/sec |
|---|---|---|---|
| M3 Max | Llama 3.1 8B | 4-bit | ~85 |
| M2 Max | Llama 3.1 8B | 4-bit | ~62 |
| M1 Pro | Llama 3.2 1B | 4-bit | ~120 |
Conduit is released under the MIT License. See LICENSE.