Native Swift SDK for building autonomous AI agents with Apple's FoundationModels design philosophy
SwiftAgent simplifies AI agent development by providing a clean, intuitive API that handles all the complexity of agent loops, tool execution, and adapter communication. Inspired by Apple's FoundationModels framework, it brings the same elegant, declarative approach to cross-platform AI agent development.
These are the defaults and conventions that keep changes consistent and easy to review.
- After code changes: build the app to make sure it still compiles.
- After test changes: run the relevant unit/UI tests (and the suite when appropriate).
- Text & localization: use the repo’s SwiftUI localization approach (String Catalog with plain
Text/LocalizedStringKey). - Style bias: readability beats cleverness; keep types and files small where possible.
- Commits: only commit when you’re explicitly asked to.
- Always build the project for all supported platforms (and run tests if your changes touch them or could reasonably affect them).
- If you changed Swift files, always run:
swiftformat --config ".swiftformat" {files}
- If you touch it, give it solid doc strings.
- For anything non-trivial, leave a comment explaining the "what" and “why”.
- Prefer descriptive, English-like names (skip abbreviations unless they’re truly standard).
- If a file is getting large or multi-purpose, feel free to split it into reusable components when that improves clarity.
- In view types, declare properties as
var(notlet). - Use
#Preview(traits: .tesseraDesigner)for previews. - For state-driven animation, prefer
.animation(.default, value: ...)over scatteredwithAnimation.- Put
.animationas high in the hierarchy as you can so containers/scroll views animate naturally.
- Put
- Prefer
$-derived bindings ($state,$binding,@Bindableprojections).- Avoid manual
Binding(get:set:)unless it genuinely simplifies an adaptation (optional defaults, type bridging, etc.). If you do use it, leave a short note explaining why.
- Avoid manual
- Prefer
.onChange(of: value) { ... }with no closure arguments; readvalueinside the closure. - Push
@Stateas deep as possible, but keep it as high as necessary. Don’t default to hoisting everything to the root.
- Use
Layout.SpacingandLayout.Paddingtokens fromDesignSystem/Layout.swift. - Use the
HStack/VStackcustom initializers that accept spacing tokens. - Use the
.padding(_:)extension that takesLayout.Padding. - For consistent visuals, reach for
Card,CollapsibleCard, andcardStyle(material backgrounds + borders).
ControlViewis the standard wrapper for label/subtitle + content + trailing accessory.- Use
Divider()between grouped control rows; when needed, pad dividers so they align with card edges.
- Use string literals in
TextandLocalizedStringKey(String Catalog). - Use
String(localized:)outside SwiftUI or when aLocalizedStringKeyinitializer isn’t available. - Use
.help(...)for macOS tooltips when it adds value (it’s cross-platform, but only displays on macOS).
- Build SDK
xcodebuild -workspace SwiftAgent.xcworkspace -scheme ExampleApp -destination "platform=iOS Simulator,name=iPhone 17 Pro,OS=latest" build -quiet
- Build AgentRecorder (CLI)
xcodebuild -workspace SwiftAgent.xcworkspace -scheme AgentRecorder -destination "platform=macOS" build -quiet
- Build Tests
xcodebuild -workspace SwiftAgent.xcworkspace -scheme SwiftAgentTests build -quiet
- Run Tests
xcodebuild -workspace SwiftAgent.xcworkspace -scheme SwiftAgentTests -testPlan SwiftAgentTests test -quiet
- Always pass
-quiettoxcodebuildto keep logs readable. If something fails and you need more logs, drop it temporarily.
- Output is printed to stdout (Xcode: Debug console).
- Project skill:
.codex/skills/agent-recorder-fixtures/SKILL.md(workflow for updating test fixtures). - Keys: set
OPENAI_API_KEY/ANTHROPIC_API_KEYor pointAGENT_RECORDER_SECRETS_PLISTat a localSecrets.plistcontainingOpenAI_API_Key_Debug/Anthropic_API_Key_Debug.
For example:
# Apple Silicon: add `arch=arm64` to avoid “multiple matching destinations” warnings.
xcodebuild -workspace SwiftAgent.xcworkspace -scheme AgentRecorder -destination "platform=macOS,arch=arm64" -derivedDataPath .tmp/DerivedData build -quiet
./.tmp/DerivedData/Build/Products/Debug/AgentRecorder --list-scenarios
./.tmp/DerivedData/Build/Products/Debug/AgentRecorder --secrets-plist Secrets.plist --provider openai --scenario openai/streaming-tool-calls/weather --no-include-headers