β If Swarm is useful to you, a star helps others find it.
Multi-agent orchestration for Swift β built for production, not demos.
let result = try await (fetchAgent --> reasonAgent --> writerAgent)
.run("Summarize the WWDC session on Swift concurrency.")
print(result.output)Three agents. One line. Crash-resumable, data-race-safe, compiled to a DAG.
Most agent frameworks are Python-first, stringly-typed, and assume every workflow completes in one shot. Swarm makes three different bets.
Swift 6.2's StrictConcurrency is enabled across every Swarm target β agents, memory systems, orchestrators, macros, and tests. Non-Sendable types crossing actor boundaries is a build failure, not a 3 AM incident.
// β Compile error under Swarm's StrictConcurrency β caught before it ships
struct BrokenAgent: AgentRuntime {
var cache: NSCache<NSString, NSString>
// error: stored property 'cache' of 'Sendable'-conforming struct
// has non-Sendable type 'NSCache<NSString, NSString>'
}
// β Actor isolation makes shared state safe by construction
actor ResponseCache {
private var store: [String: String] = [:]
func set(_ value: String, for key: String) { store[key] = value }
func get(_ key: String) -> String? { store[key] }
}Swarm ships a WorkflowCheckpointStore protocol with two built-in implementations: InMemoryWorkflowCheckpointStore for tests and FileSystemWorkflowCheckpointStore for production. Each step boundary writes a snapshot. A pipeline that crashes on step 7 of 10 resumes from step 7 β not from the beginning.
// Crash-recovery checkpoint store β survives process restarts
let store = FileSystemWorkflowCheckpointStore(
directory: .applicationSupportDirectory.appending(path: "workflow-checkpoints")
)
// Snapshots are serialised JSON β human-readable, diff-friendly
// { "workflowID": "run-42", "stepIndex": 3, "intermediateOutput": "...", "timestamp": "..." }Eleven composable step types in a SwiftUI-style @resultBuilder. Sequential chains use -->. Type-safe pipelines use >>>. Dependency DAGs use .dependsOn(). Human review gates use a three-way response.
// Sequential chain
fetchAgent --> analyzeAgent --> writerAgent
// Type-safe pipeline (compiler enforces Input/Output types at each stage)
let pipeline = Pipeline<String, [String]> { $0.components(separatedBy: "\n") }
>>> Pipeline<[String], String> { $0.filter { !$0.isEmpty }.joined(separator: "β’ ") }
// Dependency DAG β nodes run as soon as their dependencies complete
DAGWorkflow(nodes: [
DAGNode("fetch", agent: fetchAgent),
DAGNode("refs", agent: refsAgent),
DAGNode("analyze", agent: analyzeAgent).dependsOn("fetch", "refs"),
DAGNode("write", agent: writerAgent).dependsOn("analyze"),
])
// Human-in-the-loop: three-way response
HumanApproval("Approve before publishing?", handler: reviewerUI)
// .approved β workflow continues with current output
// .rejected(reason) β workflow throws OrchestrationError.humanApprovalRejected
// .modified(newInput) β corrected value flows forward, replacing the agent's output| Swarm | LangChain (Python) | AutoGen | |
|---|---|---|---|
| Language | Swift 6.2 | Python | Python |
| Data race safety | Compile-time β | Runtime | Runtime |
| On-device LLM | Foundation Models β | β | β |
| DAG execution engine | Hive (compiled) β | Loop-based | Loop-based |
| Crash-resumable workflows | β FileSystemCheckpointStore |
β | Partial |
| Type-safe tool parameters | β @Tool macro |
Decorators (runtime) | Runtime |
| Streaming | AsyncThrowingStream β |
Callbacks | Callbacks |
| iOS support | β iOS 26+ | β | β |
import Swarm
// 1. Define a tool
@Tool("Returns the current price of a stock")
struct StockPriceTool {
@Parameter("Ticker symbol, e.g. AAPL")
var ticker: String
func execute() async throws -> String {
// call your price API here
return "182.50"
}
}
// 2. Define an agent blueprint
struct FinanceAgent: AgentBlueprint {
let analyst = Agent(
name: "Analyst",
tools: [StockPriceTool()],
instructions: "Answer finance questions concisely using real data."
)
@OrchestrationBuilder var body: some OrchestrationStep {
Guard(.input) {
InputGuard("no_pii") { input in
input.contains("SSN") ? .tripwire(message: "PII detected") : .passed()
}
}
analyst
}
}
// 3. Run it
let result = try await FinanceAgent()
.environment(\.inferenceProvider, .anthropic(key: "YOUR_API_KEY"))
.run("What is the current price of AAPL?")
print(result.output)| Capability | Detail |
|---|---|
| Agents | Agent (tool-calling), ReActAgent (thoughtβactionβobservation), PlanAndExecuteAgent (planβexecuteβreplan) |
| DSL | @OrchestrationBuilder, --> sequential chain, >>> typed pipeline, .dependsOn() DAG |
| Step types | Sequential, Parallel, DAGWorkflow, Router, RepeatWhile, Branch, Guard, Transform, Pipeline, SequentialChain, ParallelGroup |
| Memory | Conversation (rolling buffer), VectorMemory (SIMD cosine via Accelerate), SummaryMemory (LLM-compressed), HybridMemory |
| Hive runtime | Compiled DAG execution, channel checkpointing, deterministic retry (jitter stripped by RetryPolicyBridge) |
| Macros | @Tool β full AnyJSONTool conformance + JSON schema; @AgentActor β boilerplate-free agent actors |
| Guardrails | Input, output, tool-input, tool-output validators; tripwire and warning modes |
| Resilience | Configurable retry backoff, circuit breaker, fallback agents, per-step timeouts |
| Observability | SwiftLogTracer, OSLogTracer, span-based tracing, per-agent token metrics |
| MCP | Model Context Protocol client + HTTP server |
| Providers | Foundation Models (on-device), Anthropic, OpenAI, Ollama, Gemini, MLX via Conduit |
| Concurrency | All public types Sendable; actors for all shared state; StrictConcurrency on every target |
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Your Application β
β iOS 26+ Β· macOS 26+ Β· Linux (Ubuntu 22.04+) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β AgentBlueprint Β· Runner.run() Β· .stream() β
ββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββ€
β Orchestration DSL β Step Types β
β @resultBuilder β Sequential Β· Parallel Β· DAGWorkflow β
β --> Β· >>> β Router Β· RepeatWhile Β· Branch β
β .dependsOn() β Guard Β· Transform Β· HumanApproval β
ββββββββββββββββββββββββ΄βββββββββββββββββββββββββββββββββββββββ€
β Agents Memory Tools β
β Agent (tool-call) Conversation @Tool macro β
β ReActAgent VectorMemory FunctionTool β
β PlanAndExecute SummaryMemory AnyJSONTool ABI β
β HiveBackedAgent HybridMemory Runtime toggling β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Guardrails Β· Resilience Β· Observability Β· MCP β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Hive Runtime (HiveCore) β
β Compiled DAG Β· Channel checkpointing Β· Tool approval β
β Deterministic retry Β· RetryPolicyBridge (jitter-free) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β InferenceProvider (pluggable) β
β Foundation Models Β· Anthropic Β· OpenAI Β· Ollama Β· MLX β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Run multiple agents on the same input concurrently. Each agent's metadata is automatically namespaced as "agentName.key" β no key collisions across concurrent results.
let group = ParallelGroup(
agents: [
(name: "primary", agent: primaryAgent),
(name: "backup", agent: backupAgent),
(name: "expert", agent: expertAgent),
],
mergeStrategy: MergeStrategies.Concatenate(
separator: "\n\n---\n\n",
shouldIncludeAgentNames: true
),
maxConcurrency: 3
)
let result = try await group.run("Analyze the Swift concurrency model.")VectorMemory uses Accelerate's vDSP_dotpr for cosine similarity β no network call, no cloud embedding API.
let memory = VectorMemory(
embeddingProvider: myEmbedder,
similarityThreshold: 0.75,
maxResults: 8
)
await memory.add(.user("The project deadline is March 15."))
await memory.add(.assistant("Noted. I will prioritise accordingly."))
// Semantically retrieves the deadline entry despite different phrasing
let context = await memory.context(for: "When is this due?", tokenLimit: 1_200)let supervisor = SupervisorAgent(
agents: [
(name: "math", agent: mathAgent, description: mathDesc),
(name: "weather", agent: weatherAgent, description: weatherDesc),
(name: "code", agent: codeAgent, description: codeDesc),
],
routingStrategy: LLMRoutingStrategy(inferenceProvider: provider),
fallbackAgent: Agent(instructions: "I am a general assistant.")
)
let result = try await supervisor.run("What is 15% of $240?")
// Routes to mathAgentlet agent = FinanceAgent()
.environment(\.inferenceProvider, provider)
.withRetry(.exponentialBackoff(maxAttempts: 3, baseDelay: .seconds(1)))
.withCircuitBreaker(threshold: 5, resetTimeout: .seconds(60))
.withFallback(Agent(instructions: "Service temporarily unavailable."))
.withTimeout(.seconds(30))for try await event in (fetchAgent --> writerAgent).stream("Summarise the changelog.") {
switch event {
case .outputToken(let token): print(token, terminator: "")
case .toolCalling(let call): print("\n[tool: \(call.toolName)]")
case .completed(let result): print("\n\nDone in \(result.duration)")
case .failed(let error): print("\nError: \(error)")
default: break
}
}let session = InMemorySession(sessionId: "user-42")
try await agent.run("My portfolio has 100 AAPL shares.", session: session)
let result = try await agent.run("What is my total value?", session: session)
// Agent recalls the earlier context// Package.swift
dependencies: [
.package(url: "https://github.com/christopherkarani/Swarm.git", from: "0.3.1")
],
targets: [
.target(name: "YourApp", dependencies: ["Swarm"])
]File β Add Package Dependencies β https://github.com/christopherkarani/Swarm.git
| Topic | Description |
|---|---|
| Agents | Agent types, configuration, @AgentActor macro |
| Tools | @Tool macro, FunctionTool, AnyJSONTool ABI, runtime toggling |
| Memory | Conversation, Vector (SIMD), Summary, Hybrid, SwiftData backends |
| Sessions | In-memory and persistent session management |
| Orchestration | DAG, parallel, chains, handoffs, human-in-the-loop |
| Streaming | AgentEvent streaming and SwiftUI integration |
| Observability | Span-based tracing, OSLogTracer, SwiftLogTracer, metrics |
| Resilience | Retry, circuit breakers, fallback agents, timeouts |
| Guardrails | Input/output validation, tripwires, audit trails |
| MCP | Model Context Protocol client and server |
| Providers | Configuring inference providers |
| Minimum | |
|---|---|
| Swift | 6.2 |
| iOS | 26.0 |
| macOS | 26.0 |
| Linux | Ubuntu 22.04 + Swift 6.2 |
iOS 26 / macOS 26 are required for Apple's on-device Foundation Models. External providers (Anthropic, OpenAI, Ollama) work on any Swift 6.2 platform including Linux.
- Fork and create a branch:
git checkout -b feature/my-feature - All public types must be
SendableβStrictConcurrencywill reject violations at build time - Write tests first:
swift test - Format:
swift package plugin --allow-writing-to-package-directory swiftformat - Open a Pull Request β describe what changed and why it matters
See CONTRIBUTING.md for agent registry conventions and TDD workflow.
- Issues β GitHub Issues
- Discussions β GitHub Discussions
- X β @ckarani7
MIT β see LICENSE for details.
Built in Swift for Apple platforms and Linux.