https://github.com/christopherkarani/swarm
π¦βπ₯ A Lightweight Agent Orchestration Framework written in pure Swift 6.2
https://github.com/christopherkarani/swarm
agent agentic-ai agentic-systems agents ai ai-agents foundation-models ios langchain machine-learning macos memory offline-first server-side swift swift-agents swift-library swiftui watchos
Last synced: 24 days ago
JSON representation
π¦βπ₯ A Lightweight Agent Orchestration Framework written in pure Swift 6.2
- Host: GitHub
- URL: https://github.com/christopherkarani/swarm
- Owner: christopherkarani
- License: mit
- Created: 2025-12-12T09:01:41.000Z (4 months ago)
- Default Branch: main
- Last Pushed: 2026-02-20T06:12:50.000Z (2 months ago)
- Last Synced: 2026-02-20T16:20:36.851Z (2 months ago)
- Topics: agent, agentic-ai, agentic-systems, agents, ai, ai-agents, foundation-models, ios, langchain, machine-learning, macos, memory, offline-first, server-side, swift, swift-agents, swift-library, swiftui, watchos
- Language: Swift
- Homepage:
- Size: 2.45 MB
- Stars: 366
- Watchers: 8
- Forks: 21
- Open Issues: 4
-
Metadata Files:
- Readme: README.md
- License: LICENSE
- Agents: AGENTS.md
Awesome Lists containing this project
README

[](https://swift.org)
[](https://swift.org)
[](LICENSE)
[](https://swift.org/package-manager/)
> β If Swarm is useful to you, a star helps others find it.
# Swarm
**Multi-agent orchestration for Swift β built for production, not demos.**
```swift
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.
---
## Why Swarm
Most agent frameworks are Python-first, stringly-typed, and assume every workflow completes in one shot. Swarm makes three different bets.
### 1. Data races are compile errors
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.
```swift
// β Compile error under Swarm's StrictConcurrency β caught before it ships
struct BrokenAgent: AgentRuntime {
var cache: NSCache
// error: stored property 'cache' of 'Sendable'-conforming struct
// has non-Sendable type 'NSCache'
}
// β 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] }
}
```
### 2. Workflows survive crashes
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.
```swift
// 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": "..." }
```
### 3. Orchestration is a DSL, not a switch statement
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.
```swift
// Sequential chain
fetchAgent --> analyzeAgent --> writerAgent
// Type-safe pipeline (compiler enforces Input/Output types at each stage)
let pipeline = Pipeline { $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
```
---
## How Swarm Compares
| | 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+ | β | β |
---
## Quick Start
```swift
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)
```
---
## Features
| 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](https://github.com/christopherkarani/Conduit) |
| **Concurrency** | All public types `Sendable`; actors for all shared state; `StrictConcurrency` on every target |
---
## Architecture
```
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β 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 β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
```
---
## More Examples
### Parallel Fan-Out
Run multiple agents on the same input concurrently. Each agent's metadata is automatically namespaced as `"agentName.key"` β no key collisions across concurrent results.
```swift
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.")
```
### Semantic Memory (On-Device SIMD)
`VectorMemory` uses Accelerate's `vDSP_dotpr` for cosine similarity β no network call, no cloud embedding API.
```swift
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)
```
### Supervisor Routing
```swift
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 mathAgent
```
### Resilience
```swift
let 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))
```
### Streaming
```swift
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
}
}
```
### Session Continuity
```swift
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
```
---
## Installation
### Swift Package Manager
```swift
// Package.swift
dependencies: [
.package(url: "https://github.com/christopherkarani/Swarm.git", from: "0.3.1")
],
targets: [
.target(name: "YourApp", dependencies: ["Swarm"])
]
```
### Xcode
**File β Add Package Dependencies β** `https://github.com/christopherkarani/Swarm.git`
---
## Documentation
| Topic | Description |
|---|---|
| [Agents](docs/agents.md) | Agent types, configuration, `@AgentActor` macro |
| [Tools](docs/tools.md) | `@Tool` macro, `FunctionTool`, `AnyJSONTool` ABI, runtime toggling |
| [Memory](docs/memory.md) | Conversation, Vector (SIMD), Summary, Hybrid, SwiftData backends |
| [Sessions](docs/sessions.md) | In-memory and persistent session management |
| [Orchestration](docs/orchestration.md) | DAG, parallel, chains, handoffs, human-in-the-loop |
| [Streaming](docs/streaming.md) | `AgentEvent` streaming and SwiftUI integration |
| [Observability](docs/observability.md) | Span-based tracing, `OSLogTracer`, `SwiftLogTracer`, metrics |
| [Resilience](docs/resilience.md) | Retry, circuit breakers, fallback agents, timeouts |
| [Guardrails](docs/guardrails.md) | Input/output validation, tripwires, audit trails |
| [MCP](docs/mcp.md) | Model Context Protocol client and server |
| [Providers](docs/providers.md) | Configuring inference providers |
---
## Requirements
| | 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.
---
## Contributing
1. Fork and create a branch: `git checkout -b feature/my-feature`
2. All public types must be `Sendable` β `StrictConcurrency` will reject violations at build time
3. Write tests first: `swift test`
4. Format: `swift package plugin --allow-writing-to-package-directory swiftformat`
5. Open a Pull Request β describe what changed and why it matters
See [CONTRIBUTING.md](CONTRIBUTING.md) for agent registry conventions and TDD workflow.
---
## Support
- **Issues** β [GitHub Issues](https://github.com/christopherkarani/Swarm/issues)
- **Discussions** β [GitHub Discussions](https://github.com/christopherkarani/Swarm/discussions)
- **X** β [@ckarani7](https://x.com/ckarani7)
---
## License
MIT β see [LICENSE](LICENSE) for details.
---
*Built in Swift for Apple platforms and Linux.*