◉ — ◉ — ◉
| | | SwiftSynapse
◉ — ◉ — ◉ connected intelligence, native Swift
| | |
◉ — ◉ — ◉
SwiftSynapse is an open-source framework for building smart, autonomous AI agents natively in Swift — with no Python bridges, no heavy external runtimes, and no compromises on type safety or platform integration. Every agent is observable, background-capable, and macro-powered: reasoning steps, tool calls, and streaming output surface directly in SwiftUI with zero Combine plumbing.
Agents delegate to SwiftOpenResponsesDSL's Agent actor for LLM communication, tool dispatch, and conversation continuity — so building a new agent is ~30 lines of domain logic. Drop-in SwiftUI components from SwiftSynapseUI give you a complete chat interface, and App Intents integration enables Siri and Shortcuts support. On iOS 26+ / macOS 26+, agents run on-device first via Apple's Foundation Models framework with transparent cloud fallback.
This project follows a strict spec-driven development (SDD) workflow: every .swift file is a generated artifact. Human authors write and refine Markdown specifications; Claude Code produces all implementation code from those specs. Generated files are never edited manually — to change behavior, update the spec and regenerate.
- Agent Delegation — agents are thin wrappers (~30-60 lines) over
SwiftOpenResponsesDSL.Agent, which handles tool dispatch loops, parallel execution, conversation continuity, and transcript management - SwiftUI Components —
TranscriptView,AgentStatusView,StreamingTextView,ToolCallDetailView, andAgentChatViewprovide drop-in agent UIs viaSwiftSynapseUI - Spec-Driven Development — every agent is defined by a
SPEC.md; all Swift code is generated from it, never hand-written - Observable Agents —
@Observablestate exposes live transcript, tool calls, and reasoning steps directly to SwiftUI views viaObservableTranscript - On-Device Priority — Apple Foundation Models framework used first on iOS 26+ / macOS 26+ for full privacy; transparent cloud fallback via
HybridLLMClient - Skills Integration — agentskills.io standard supported natively via
SkillStore,SkillsAgent, andactivate_skilltool - Type-Safe Tools —
@LLMToolmacros generate JSON schemas at compile time; no stringly-typed dispatch, no runtime schema errors - App Intents —
AgentAppIntentprotocol exposes agents to Siri and Shortcuts with a single conformance - Pure Swift — zero external runtimes, no Python bridges; only Foundation and the SwiftSynapse libraries
- Apple-Native — SwiftUI interfaces,
actor-based agents, strict Swift 6.2+ concurrency throughout
1. Clone the repository
git clone https://github.com/RichNasz/SwiftSynapse.git
cd SwiftSynapse2. Open in Xcode
open Package.swift3. Configure your LLM endpoint (once)
export SWIFTSYNAPSE_SERVER_URL=http://127.0.0.1:1234/v1/responses
export SWIFTSYNAPSE_MODEL=llama3
# export SWIFTSYNAPSE_API_KEY=sk-... # if needed4. Run the AgentDashboard app
Select the AgentDashboard scheme in Xcode and run. Pick an agent from the sidebar, type a goal, and watch the transcript live.
5. Or run an agent from the CLI
# Minimal echo agent (no LLM needed)
swift run simple-echo "Hello, SwiftSynapse!"
# Plain LLM reply
swift run llm-chat "What is the capital of France?"
# Persona-rewritten reply (prints original + persona version)
swift run llm-chat-personas "Explain black holes." --persona pirate
# Streaming response (token-by-token)
swift run streaming-chat-agent "Tell me a joke."
# LLM with retry on transient failures
swift run retrying-llm-chat-agent "Hello!" --max-retries 5
# Tool-using agent (math + unit conversion)
swift run tool-using-agent "Convert 100 miles to kilometers"
# Skills-enabled agent (discovers agentskills.io skills)
swift run skills-enabled-agent "Help me with my task"All CLI options (--server-url, --model, --api-key) are optional when environment variables are set.
6. Or invoke an agent in code
import SwiftSynapseHarness
import LLMChatAgent
// Configure once — validated at construction time
let config = try AgentConfiguration(
serverURL: "http://127.0.0.1:1234/v1/responses",
modelName: "llama3"
)
// Or resolve from environment variables
let config = try AgentConfiguration.fromEnvironment()
// Instantiate and run
let agent = try LLMChat(configuration: config)
let reply = try await agent.execute(goal: "Summarize the Swift 6.2 release notes.")
print(reply)
// Observe — transcript and status are @Observable; bind directly in SwiftUI
let transcript = await agent.transcript // ObservableTranscript
let status = await agent.status // AgentStatus7. Or use SwiftSynapseUI for a complete chat interface
import SwiftSynapseUI
struct ContentView: View {
let agent: some ObservableAgent
var body: some View {
AgentChatView(agent: agent)
}
}SwiftSynapse ships 7 runnable agents today. Every agent is fully spec-driven — no hand-written implementation code.
| Agent | Description | Key Patterns Demonstrated |
|---|---|---|
| SimpleEcho | Echoes a goal string back with a prefix — the minimal @SpecDrivenAgent reference |
@SpecDrivenAgent macro, transcript, status lifecycle |
| LLMChat | Forwards a prompt to any Open Responses API-compatible endpoint and returns the reply | Agent delegation, retryWithBackoff, transcript sync |
| LLMChatPersonas | Two-step pipeline: plain LLM response followed by an optional persona rewrite | Agent conversation continuity via lastResponseId, two-call pipeline |
| RetryingLLMChatAgent | LLM chat with exponential-backoff retry on transient failures | Shared retryWithBackoff, Agent delegation |
| StreamingChatAgent | Streams LLM responses token-by-token with real-time transcript updates | Agent.stream(), ToolSessionEvent, setStreaming/appendDelta lifecycle |
| ToolUsingAgent | Dispatches LLM-chosen tool calls for math and unit conversion | AgentTool registration, Agent handles tool dispatch loop |
| SkillsEnabledAgent | Discovers and activates agentskills.io skills from the filesystem | SkillStore, SkillsAgent, activate_skill tool, ~30 lines of domain logic |
| Agent | Description | Key Patterns Demonstrated |
|---|---|---|
| PRReviewer | Analyzes GitHub PRs for style, performance, and security issues | Tool calling, structured patches, multi-phase review |
| TaskPlanner | Multi-phase productivity agent with sub-task tracking | Planning, verification, sub-agent orchestration |
| ResearchAssistant | Long-running research agent with session persistence | Memory, web tools, RAG, background continuation |
New agents are bootstrapped from Agents/TemplateAgent/specs/SPEC.md. Copy it, fill in the spec, and run the generator.
Every agent is a thin wrapper over SwiftOpenResponsesDSL.Agent:
import SwiftSynapseHarness
@SpecDrivenAgent
public actor MyAgent {
private let config: AgentConfiguration
public init(configuration: AgentConfiguration) throws {
self.config = configuration
_ = try configuration.buildLLMClient() // fail-fast validation
}
public func execute(goal: String) async throws -> String {
guard !goal.isEmpty else { throw MyAgentError.emptyGoal }
_status = .running
_transcript.reset()
let client = try config.buildLLMClient()
let agent = Agent(client: client, model: config.modelName)
let result = try await agent.send(goal)
_transcript.sync(from: await agent.transcript)
_status = .completed(result)
return result
}
}let agent = try Agent(client: client, model: config.modelName) {
AgentTool(tool: calculateDef) { args in try calculate(args) }
AgentTool(tool: convertDef) { args in try convert(args) }
}
let result = try await agent.send(goal)
// Agent handles the entire tool dispatch loop internallylet store = SkillStore()
try await store.load()
let agent = try await SkillsAgent(client: client, model: config.modelName) {
Skills(store: store)
}
let result = try await agent.send(goal)| Type | Purpose |
|---|---|
AgentConfiguration |
Centralized config — validates URLs, model names, timeouts, retry counts. fromEnvironment() reads SWIFTSYNAPSE_* env vars. |
retryWithBackoff |
Free async function — exponential backoff with isTransportRetryable predicate and onRetry callback |
AgentLLMClient |
Protocol — send(_:) / stream(_:) with CloudLLMClient and HybridLLMClient (on-device + cloud fallback) implementations |
AgentSession |
Codable struct — session persistence with CodableTranscriptEntry bridge |
The SwiftSynapseHarness package provides a complete agent harness — everything between run(goal:) and your domain logic:
| Capability | Key Types |
|---|---|
| Typed Tools | AgentToolProtocol, ToolRegistry, AgentToolLoop — JSON-schema tools with batch dispatch |
| Hooks | AgentHookPipeline, ClosureHook — 15 event types with block/modify/proceed semantics |
| Permissions | PermissionGate, ToolListPolicy — policy-driven tool access with human-in-the-loop |
| Recovery | RecoveryChain — self-healing from context overflow and output truncation |
| Streaming | StreamingToolExecutor — dispatch tools as they stream from the LLM |
| Subagents | SubagentRunner — child agents with shared or independent lifecycles |
| Session Persistence | FileSessionStore — pause/resume workflows across app launches |
| Guardrails | GuardrailPipeline, ContentFilter — PII/secret detection, compliance checks |
| MCP | MCPManager — connect to Model Context Protocol servers (databases, CRMs, APIs) |
| Coordination | CoordinationRunner — dependency-aware multi-agent workflows |
| Plugins | PluginManager — modular extension mechanism for hooks, tools, guardrails |
| Caching | ToolResultCache — LRU/FIFO with TTL for identical tool calls |
| Compression | CompositeCompressor — advanced context window management |
| Config Hierarchy | ConfigurationResolver — 7-level priority (CLI > local > project > user > MDM > remote > env) |
| Telemetry | TelemetrySink — structured events to OSLog, in-memory, or custom backends |
| View | Purpose |
|---|---|
AgentChatView |
Complete drop-in chat UI: text input + transcript + status |
TranscriptView |
Chat-style message list with auto-scroll and streaming support |
AgentStatusView |
Status icon + label (idle/running/completed/error) |
StreamingTextView |
Typing cursor animation during token-by-token streaming |
ToolCallDetailView |
Expandable tool call row with JSON arguments, result, and duration |
| Protocol | Purpose |
|---|---|
ObservableAgent |
Common interface for all agents: status, transcript, execute(goal:) |
AgentAppIntent |
Exposes any ObservableAgent as a Siri Shortcut / Shortcuts action |
SwiftSynapse is fully AI-first: no human writes implementation code. Every .swift file is a generated artifact produced by Claude Code reading a Markdown specification.
+---------------------------------------------+
| 1. Write or refine a spec |
| VISION.md / CodeGenSpecs/ / SPEC.md |
+--------------------+------------------------+
|
v
+---------------------------------------------+
| 2. Run the generator |
| Claude Code reads spec -> writes Swift |
+--------------------+------------------------+
|
v
+---------------------------------------------+
| 3. Review generated output |
| Compile, test, iterate on spec if wrong |
+--------------------+------------------------+
|
v
+---------------------------------------------+
| 4. Commit spec + generated artifacts |
| Never edit generated .swift files |
+---------------------------------------------+
| Path | What it contains | Who authors it |
|---|---|---|
VISION.md |
Project vision, goals, non-negotiables | Human |
CodeGenSpecs/ |
Shared generation rules for all agents | Human |
Agents/<Name>/specs/SPEC.md |
Per-agent goal, inputs, tasks, tools, outputs | Human |
Agents/<Name>/specs/Overview.md |
Agent-specific generation guidance | Human |
Agents/<Name>/Sources/ |
Generated Swift implementation | AI (never edit) |
Apps/AgentDashboard/ |
Example SwiftUI app | AI (never edit) |
README.md |
This file | AI (never edit) |
SwiftSynapse agents depend on the macro libraries. Add them to your Swift package:
// Package.swift
dependencies: [
.package(url: "https://github.com/RichNasz/SwiftSynapseHarness", branch: "main"),
],
targets: [
.target(
name: "YourAgent",
dependencies: [
.product(name: "SwiftSynapseHarness", package: "SwiftSynapseHarness"),
]
)
]For SwiftUI views and App Intents:
.target(
name: "YourApp",
dependencies: [
.product(name: "SwiftSynapseUI", package: "SwiftSynapseHarness"),
]
)
SwiftSynapseHarnessre-exportsSwiftOpenResponsesDSL,SwiftLLMToolMacros, andSwiftOpenSkills, so a single import is all most agent files need.
Platform requirement: On-device Foundation Models inference requires iOS 26+, macOS 26+, or visionOS 2.4+ with Apple Intelligence enabled. For broader compatibility, point
AgentConfigurationat any OpenAI-compatible cloud endpoint.
We welcome contributions — especially new agent specs, improvements to shared CodeGenSpecs, and infrastructure feedback.
Read the Creating Agent Specs guide for a detailed walkthrough of every section in SPEC.md and Overview.md, the traits system, tool design, and the pre-generation checklist.
Quick steps:
- Copy
Agents/TemplateAgent/->Agents/<YourAgentName>/ - Fill in
Agents/<YourAgentName>/specs/SPEC.md - Customize
Agents/<YourAgentName>/specs/Overview.md— delegate toAgentfrom SwiftOpenResponsesDSL, useAgentConfigurationandretryWithBackoff - Run the generator (Claude Code) to produce
Sources/,CLI/, andTests/Swift files - Build and run
swift testto verify all tests pass - Open a pull request containing spec files and generated output together
- PRs must not contain manually edited
.swiftfiles inSources/,CLI/, orTests/ - Spec changes and their generated output belong in the same commit
- Describe what the spec change achieves and how you verified the generated output
This project is released under the MIT License — use it, fork it, build on it.
| Library | Purpose |
|---|---|
| SwiftSynapseHarness | Unified agent harness — re-exports all dependencies; provides @SpecDrivenAgent, typed tools, hooks, permissions, recovery, streaming, MCP, guardrails, multi-agent coordination, session persistence, caching, plugins, telemetry, cost tracking, context management, SwiftSynapseUI |
| SwiftOpenResponsesDSL | Base LLM communication layer — Agent, ResponseRequest, LLMClient, AgentTool, ToolSession |
| SwiftLLMToolMacros | Tool definition macros — @LLMTool / @LLMToolArguments generate FunctionToolParam schemas |
| SwiftOpenSkills | agentskills.io standard in Swift — SkillStore, SkillsAgent, skill discovery and activation |
Follow along: @naszcyniec on X
