christopherkarani/swarm
Install
Default link is lean: core Swarm + on-device Foundation Models. Graph/memory/web/Hive paths are trait-gated (off by default) and are not linked into Swarm unless you enable Integrations.
HiveCore, Membrane, and ContextCore are native in-tree Sources/ targets (internal modules — not separate library products). Enabling Integrations links those modules plus Wax (still remote) and SwiftSoup; omitting the trait does not link them into Swarm. Lean resolve never pulls Hive/Membrane/ContextCore/Conduit package identities, and (with trait-gated product edges) also does not pin Wax, MetalANNS→GRDB, swift-crypto, swift-mutex, or SwiftSoup. Always-on remotes remain (swift-syntax, swift-log, MCP sdk, OTel, plus NIO transitives — including swift-collections via NIO). SWARM_CORE_ONLY=1 drops the integration package block entirely. ContextCore / full Membrane session stack require Apple platforms (Metal/CoreML); Linux Integrations still builds Hive + MembraneCore + web helpers. DefaultAgentMemory uses a CoreML embedding model that is not bundled — without minilm-l6-v2.mlpackage, ContextCore falls back to deterministic pseudo-embeddings.
Root-package note: bare swift build / swift test on this repo compile every registered target, so integration modules need either --traits Integrations or the lean CI helper (scripts/ci/lean-build-test.sh). App consumers only build reachable targets and stay lean without that helper.
// Lean default link (recommended for most apps)
.package(url: "https://github.com/christopherkarani/Swarm.git", from: "0.6.0")
// Full integrations: durable Hive workflows, ContextCore+Wax default memory,
// Membrane adapters, and web helpers
.package(
url: "https://github.com/christopherkarani/Swarm.git",
from: "0.6.0",
traits: ["Integrations"]
)From a checkout of this package:
swift build --product Swarm --product SwarmMCP --product SwarmOpenTelemetry \
--product SwarmMembrane --product SwarmCapabilityShowcase
# Full graph
swift build --traits Integrations
swift test --no-parallel --traits Integrations
swift run --traits Integrations SwarmCapabilityShowcase matrixQuick Start
import Swarm
// The @Tool macro generates the JSON schema 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" }
}
// Create an agent with unlabeled instructions first and tools in the trailing @ToolBuilder closure
// Built-in backend: Apple Foundation Models (no API key on supported devices)
let agent = try Agent("Answer finance questions using real data.",
configuration: .default.name("Analyst"),
inferenceProvider: .foundationModels()) {
PriceTool()
CalculatorTool()
}
let result = try await agent.run("What is AAPL trading at?")
print(result.output) // "Apple (AAPL) is currently trading at $182.50."That is a working agent with type-safe tool calling. Swarm also supports AGENTS.md and SKILL.md for declarative agent specs and reusable skills — see the Getting Started guide for the full workspace layout.
Why Swarm
- Swift concurrency is part of the surface. Swift 6.2
StrictConcurrencyis enabled across the package. - Tools stay type-safe. The
@Toolmacro generates JSON schemas from Swift structs. - Workflows can survive crashes. Durable workflow checkpointing lets you resume from an explicit checkpoint ID.
- Built-in inference is on-device Foundation Models. Inject any
InferenceProviderfor custom backends; the agent loop stays the same. - It is written in Swift all the way down.
AsyncThrowingStream, actors, result builders, and macros are first-class here.
Examples
Capability matrix showcase
Swarm now ships with an in-repo capability showcase that exercises the stable surface area in one deterministic matrix:
- agents and tools
- streaming
- conversation plus session persistence
- sequential, parallel, routed, and repeat-until workflows
- handoffs
- memory
- on-device workspace loading
- guardrails
- resilience helpers
- durable checkpoint and resume
- observability
- MCP discovery and tool bridging
- provider selection
Run it locally:
# Capability showcase matrix covers durable workflows; enable Integrations
swift run --traits Integrations SwarmCapabilityShowcase list
swift run --traits Integrations SwarmCapabilityShowcase matrix
swift run --traits Integrations SwarmCapabilityShowcase run handoff
swift run --traits Integrations SwarmCapabilityShowcase smokeThe deterministic matrix is CI-safe. Live-provider smoke coverage is opt-in through environment variables. See docs/guide/capability-showcase.md for the scenario catalog and smoke-mode details.
End-to-end example apps
Two minimal, buildable apps under Examples/ stress the public API:
| Example | What it proves | | --- | --- | | Examples/OnDeviceChat | Foundation Models chat with @Tool, streaming, and multi-turn Conversation (zero API keys; --demo for CI) | | Examples/MultiAgentPipeline | Sequential + parallel workflows and durable checkpoint/resume (--demo for CI) | | Examples/CodeReviewer | Lightweight CLI that links Swarm and prints a deterministic review plan |
cd Examples/OnDeviceChat && swift run OnDeviceChat --demo
cd Examples/MultiAgentPipeline && swift run MultiAgentPipeline --demoOptional demos
Package-root demo executables are opt-in so the default library graph stays focused on the framework products:
SWARM_INCLUDE_DEMO=1 swift build
SWARM_INCLUDE_DEMO=1 swift run SwarmDemo
SWARM_INCLUDE_DEMO=1 swift run SwarmMCPServerDemoFoundation Models First
For Apple platforms, use the built-in on-device path — no API keys:
import Swarm
// Requires macOS/iOS 26+ and Apple Intelligence available on the device.
let agent = try Agent(
"You are a private on-device assistant.",
inferenceProvider: .foundationModels()
) {
// @Tool structs or FunctionTool values
}
let result = try await agent.run("Summarize my notes.")Notes that matter in production:
- Availability: use
FoundationModelsInferenceProvider.ifAvailable()or checkFoundationModelsInferenceProvider.isAvailablebefore assuming the system model is ready. - Tool calling: Swarm bridges
@Tool/ToolSchemato Apple'sFoundationModels.Tooland executes tools in the agent loop with guardrails intact. - Streaming tool calls: not advertised; streaming is text deltas, tools complete as capture-then-execute turns.
- Dynamic profiles:
.foundationModels(profile:)re-resolves instructions/tools/history every turn (WWDC 2026–aligned Swarm API). - Linux / CI: Foundation Models is compile-time gated; inject a mock or custom
InferenceProvider, or use the deterministic--demomodes inExamples/.
Multi-agent pipeline
let researcher = try Agent("Research the topic and extract key facts.",
inferenceProvider: .foundationModels()) {
WebSearchTool()
}
let writer = try Agent("Write a concise summary from the research.",
inferenceProvider: .foundationModels())
let result = try await Workflow()
.step(researcher)
.step(writer)
.run("Latest advances in on-device ML")Each agent resolves its own provider. Pass inferenceProvider: per agent (as above), or call await Swarm.configure(provider: myProvider) once at app startup to share a default across every agent that doesn't specify one.
Parallel fan-out
let result = try await Workflow()
.parallel([bullAgent, bearAgent, analystAgent], merge: .structured)
.run("Evaluate Apple's Q4 earnings.")
// Three perspectives, merged into one output.Dynamic routing
let result = try await Workflow()
.route { input in
if input.contains("$") { return mathAgent }
if input.contains("weather") { return weatherAgent }
return generalAgent
}
.run("What is 15% of $240?")Streaming
for try await event in agent.stream("Summarize the changelog.") {
switch event {
case .output(.token(let t)): print(t, terminator: "")
case .tool(.completed(let call, _)): print("\n[tool: \(call.toolName)]")
case .lifecycle(.completed(let r)): print("\nDone in \(r.duration)")
case .lifecycle(.failed(let error)): print("\nError: \(error)")
default: break // Other events include .output(.thinking(...)), .handoff(...), .observation(...), and .lifecycle(.iterationStarted(...)).
}
}<details> <summary><strong>More examples</strong></summary>
Semantic memory
let agent = try Agent("You remember past conversations.",
memory: .vector(embeddingProvider: myEmbedder, similarityThreshold: 0.75),
inferenceProvider: .foundationModels()) {
// tools
}Guardrails
let agent = try Agent("You are a helpful assistant.",
inputGuardrails: [InputGuard.maxLength(5000), InputGuard.notEmpty()],
outputGuardrails: [OutputGuard.maxLength(2000)])Closure tools
let reverse = FunctionTool(
name: "reverse",
description: "Reverses a string",
parameters: [ToolParameter(name: "text", description: "Text to reverse", type: .string, isRequired: true)]
) { args in
let text = try args.require("text", as: String.self)
return .string(String(text.reversed()))
}
let agent = try Agent("Text utilities.", tools: [reverse])Crash-resumable workflows
let workflow = Workflow()
.step(monitor)
.durable.checkpoint(id: "monitor-v1", policy: .everyStep)
.durable.checkpointing(.fileSystem(directory: checkpointsURL))
let resumed = try await workflow.durable.execute("watch", resumeFrom: "monitor-v1")Provider selection
// Built-in: on-device Foundation Models (no API key)
let local = try Agent("Be helpful.", inferenceProvider: .foundationModels())
// Custom backend: any type conforming to InferenceProvider
let custom = try Agent("Be helpful.", inferenceProvider: myCustomProvider)
// Or swap at runtime via environment
let modified = agent.environment(\.inferenceProvider, myCustomProvider)Conversation
let conversation = Conversation(with: agent)
let response1 = try await conversation.send("What's the weather?")
let response2 = try await conversation.send("And tomorrow?") // Context preserved
for message in await conversation.messages {
print("\(message.role): \(message.text)")
}</details>
How Swarm Compares
| | Swarm | LangChain | AutoGen | |---|---|---|---| | Language | Swift 6.2 | Python | Python | | Data race safety | Compile-time | Runtime | Runtime | | On-device LLM | Foundation Models | n/a | n/a | | Execution model | Typed Workflow graph | Loop-based | Loop-based | | Crash recovery | Checkpoints | n/a | Partial | | Type-safe tools | @Tool macro (compile-time) | Decorators (runtime) | Runtime | | Streaming | AsyncThrowingStream | Callbacks | Callbacks | | iOS / macOS native | First-class | n/a | n/a |
What's Included
| | | |---|---| | Agents | Agent struct with @ToolBuilder trailing closure, AgentRuntime protocol | | Workflows | Workflow: .step(), .parallel(), .route(), .repeatUntil(), .timeout() | | Tools | @Tool macro, FunctionTool, @ToolBuilder, parallel execution | | Memory | .conversation(maxMessages:), .vector(embeddingProvider:similarityThreshold:maxResults:), .slidingWindow(maxTokens:), .summary(configuration:summarizer:), .hybrid(configuration:summarizer:) | | Guardrails | InputGuard.maxLength(), InputGuard.notEmpty(), InputGuard.custom(), OutputGuard.maxLength(), OutputGuard.custom() | | Conversation | Conversation actor for stateful multi-turn dialogue | | Resilience | 7 backoff strategies, circuit breaker, fallback chains, rate limiting | | Observability | AgentObserver, Tracer, SwiftLogTracer, per-agent token metrics | | MCP | Model Context Protocol client and server support | | Providers | Built-in Apple Foundation Models (on-device); inject any InferenceProvider for custom backends | | Macros | @Tool, @Parameter, @Traceable, #Prompt |
Architecture
┌─────────────────────────────────────────────────────────────┐
│ Your Application │
│ iOS 26+ · macOS 26+ · Linux (Ubuntu 22.04+) │
├─────────────────────────────────────────────────────────────┤
│ Workflow · Conversation · .run() · .stream() │
├─────────────────────────────────────────────────────────────┤
│ Agents Memory Tools │
│ Agent (struct) Memory factories @Tool macro │
│ AgentRuntime Conversation FunctionTool │
│ (dot-syntax) @ToolBuilder │
├─────────────────────────────────────────────────────────────┤
│ InputGuard · OutputGuard · Resilience · Observability · MCP│
├─────────────────────────────────────────────────────────────┤
│ Durable Graph Runtime (internal) │
│ Workflow Graph · Checkpointing · Deterministic retry │
├─────────────────────────────────────────────────────────────┤
│ InferenceProvider (pluggable) │
│ Foundation Models (built-in) · custom InferenceProvider │
└─────────────────────────────────────────────────────────────┘Requirements
| Platform | Minimum | |----------|---------| | Swift | 6.2+ | | iOS | 26.0+ | | macOS | 26.0+ | | tvOS | 26.0+ | | Linux | Ubuntu 22.04+ with Swift 6.2 |
The default Swarm graph is CI-tested on Ubuntu with Swift 6.2. Apple-only features such as Foundation Models, SwiftData, OSLog, and some built-in tool behavior are unavailable or different on Linux; inject a mock or custom InferenceProvider there.
Documentation
| | | |---|---| | Getting Started | Installation, first agent, workflows | | OpenTelemetry Tracing | Export agent and LLM spans, with optional trace header injection for provider HTTP requests | | API Reference | Every type, protocol, and API | | Front-Facing API | Public API surface | | Why Swarm? | Design philosophy and architecture |
Contributing
- Fork → branch →
swift test→ PR - All public types must be
Sendable; the compiler enforces it - Format with
swiftformat Sources Tests --lint --config .swiftformat
Bug reports and feature requests: GitHub Issues
Community
GitHub Issues · Discussions · @ckarani7
If Swarm saves you time, a star helps others find it.
License
Released under the MIT License.
Package Metadata
Repository: christopherkarani/swarm
Default branch: main
README: README.md