Show HN: I Built LangGraph for Swift
🐦🔥 Swarm: LangGraph for the Swift Ecosystem
Overview: Swarm is a powerful Swift framework designed for the creation of AI agents and complex multi-agent workflows. It brings the stateful, graph-based orchestration of LangGraph natively to Apple and Linux platforms.
🚀 Getting Started
To integrate Swarm into your project, add the following dependency via the Swift Package Manager:
package(url: "https://github.com/christopherkarani/Swarm.git", from: "0.6.0")
Basic Implementation
Swarm leverages modern Swift features like macros, result builders, and actors to ensure type safety and concurrency.
import Swarm
// The @Tool macro handles JSON schema generation at compile time
@Tool("Looks up the current stock price")
struct PriceTool {
@Parameter("Ticker symbol")
var ticker: String
func execute() async throws -> String {
"182.50"
}
}
// Initialize an agent with instructions and tools
let agent = try Agent("Answer finance questions using real data.", provider: .anthropic(key: "{ENV}")) {
PriceTool()
CalculatorTool()
}
let result = try await agent.output("What is Apple's current price?")
// Output: "Apple (AAPL) is currently trading at $182.50."
🛠 Core Capabilities
Swarm isn't just about single prompts; it's about stateful orchestration.
1. Multi-Agent Pipelines
You can chain agents together into a Directed Acyclic Graph (DAG). This allows for specialized roles (e.g., a Researcher and a Writer) to collaborate.
let researcher = try Agent("Research the topic and extract key facts.") { WebSearchTool() }
let writer = try Agent("Write a concise summary from the research.")
// Execute a pipeline
let finalResult = try await Workflow()
.sequence([researcher, writer])
.run("Latest advances in on-device ML")
2. Durable State & Resilience
Forget losing your agent's progress on a crash. Swarm implements durable workflow checkpointing, allowing you to resume execution from a specific ID.
let workflow = Workflow().checkpointing(.fileSystem(directory: checkpointsURL))
let resumed = try await workflow.execute("watch", resumeFrom: "monitor-v1")
3. Advanced Agent Features
- Semantic Memory: Utilize vector embeddings to remember past interactions.
- Logic:
let agent = try Agent(..., memory: .vector(embeddingProvider: myEmbedder, similarityThreshold: 0.75))
- Guardrails: Enforce constraints like
maxLength(2000)to control output. - Closure-based Tools: Define tools on the fly using
FunctionToolwithout needing a full struct. - Declarative Specs: Support for
AGENTS.mdandSKILL.mdfor structured workspace management.
📊 Provider & Compatibility Matrix
Swarm is provider-agnostic. You can set a global provider via Swarm.configure(provider:) or define them per agent.
| Provider | Type | Note |
|---|---|---|
| Foundation Models | On-Device | Private, no API key required |
| Anthropic / OpenAI | Cloud | High-reasoning capabilities |
| Ollama / MLX | Local | Self-hosted LLMs |
| Gemini / MiniMax | Cloud | Alternative API ecosystems |
| OpenRouter | Aggregator | Unified access to multiple models |
Capability Showcase
The framework includes a deterministic matrix to verify stability. You can run these locally:
-
swift run SwarmCapabilityShowcase list(View all) -
swift run SwarmCapabilityShowcase matrix(Run matrix) -
swift run SwarmCapabilityShowcase run handoff(Test agent handoffs) -
swift run SwarmCapabilityShowcase smoke(Smoke tests)
Note: Live-provider tests require environment variables to be set.
⚖️ Swarm vs. The Competition
| Feature | Swarm | LangChain | AutoGen |
|---|---|---|---|
| Language | Swift 6.2 | Python | Python |
| Safety | Compile-time | Runtime | Runtime |
| Data Race Safety | Native (Actors) | N/A | N/A |
| On-Device LLM | Foundation Models | Limited | Limited |
🧪 Optional Demos & Testing
To keep the core library lean, demos are opt-in. Use the following flags to build and run them:
# Build with demos included
SWARM_INCLUDE_DEMO=1 swift build
# Run the general demo
SWARM_INCLUDE_DEMO=1 swift run SwarmDemo
# Run the MCP Server demo
SWARM_INCLUDE_DEMO=1 swift run SwarmMCPServerDemo
Event Handling Example
Swarm uses AsyncThrowingStream to provide real-time observability into the agent's thought process:
for try await event in agent.stream("Hello!") {
switch event {
case .output(.thinking(let thought)): print("Thinking: \(thought)")
case .handoff(let nextAgent): print("Handoff to \(nextAgent)")
case .failed(let error): print("Error: \(error)")
default: break
}
}