> ## Documentation Index
> Fetch the complete documentation index at: https://docs.synheart.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Swift

> syni-swift — iOS / macOS SDK for Syni's adaptive on-device LLM inference with hybrid local/cloud chat.

## Overview

`syni-swift` is the **iOS / macOS consumer SDK** for Syni. Same agent surface as the [Flutter sibling](/syni/flutter) and the [Kotlin sibling](/syni/kotlin), idiomatic for Swift (`async`/`await`, `AsyncThrowingStream<SyniChatEvent, Error>` for streaming, Combine `AnyPublisher<SyniInstallState, Never>` for the install lifecycle).

## Platform support

* iOS 16.0+ · macOS 13.0+
* Swift 5.9+ · Xcode 15+
* Native runtime delivered by the `synheart` CLI as `SyniRuntime.xcframework` (see install steps below)

## Installation

### Swift Package Manager

```swift theme={null}
// Package.swift
dependencies: [
    .package(url: "https://github.com/synheart-ai/syni-swift.git", from: "0.0.4"),
],
targets: [
    .target(
        name: "YourApp",
        dependencies: [
            .product(name: "Syni", package: "syni-swift"),
        ]
    ),
]
```

### CocoaPods

```ruby theme={null}
# Podfile
pod 'Syni', '~> 0.0.4'
```

### Native runtime

Both install paths ship Swift sources only. Install the native runtime
once with the `synheart` CLI:

```bash theme={null}
curl -fsSL https://synheart.sh/install | sh
synheart install runtime syni
```

This writes `SyniRuntime.xcframework` to `<your-project>/synheart/vendor/syni-runtime/`.
Add the framework to your Xcode target under **General → Frameworks, Libraries, and Embedded Content**.
The Swift package resolves all C symbols at runtime via `dlsym(RTLD_DEFAULT)`,
so the package compiles standalone — calls into the runtime fail with a
clear error if the install step hasn't been run.

## Basic usage

```swift theme={null}
import Syni

let agent = SyniAgent()

// Load a persona by id from bundled spec assets.
let persona = try await SyniSpecPersona.load("focus.coach.v1")

// First-run install: download + verify the model, load the engine,
// bind the persona. Emits lifecycle events on agent.installState.
try await agent.install(
    persona: persona,
    model: SyniModels.qwen25_15bInstructQ4
)

// Single-turn chat.
let response = try await agent.chat("How can I focus right now?")
print(response.displayText)
```

## Streaming

`chatStream` returns an `AsyncThrowingStream<SyniChatEvent, Error>` — token-level `.delta` events followed by exactly one `.final` carrying the structured response.

```swift theme={null}
for try await event in agent.chatStream("hello") {
    switch event {
    case let .delta(text):
        print(text, terminator: "")
    case let .final(response):
        print("\n[\(response.displayText.count) chars]")
    }
}
```

## Hybrid local / cloud

```swift theme={null}
let agent = SyniAgent(
    cloudConfig: SyniCloudConfig(
        baseUrl: "https://api.synheart.ai",
        authToken: { "<bearer-token>" },
        tenantId: "<tenant>",
        userId: "<user>"
    )
)

let response = try await agent.chat(
    "how was my recent session?",
    mode: .cloudFirst // try cloud, fall back to local
)
```

`SyniExecutionMode` cases: `.localFirst` (default), `.cloudFirst`, `.localOnly`, `.cloudOnly`.

## Install lifecycle

Wire `installState` into SwiftUI to surface progress:

```swift theme={null}
@Observable
final class InstallVM {
    var state: SyniInstallState = .notInstalled
    private var cancellable: AnyCancellable?

    func observe(_ agent: SyniAgent) {
        cancellable = agent.installState.sink { [weak self] in self?.state = $0 }
    }
}

// In your view
switch vm.state {
case .notInstalled:               Button("Install model") { /* trigger install */ }
case let .installing(stage, p):   ProgressView("\(stage)", value: p)
case .installed:                  ChatView()
case let .failed(reason, _):      Text("Install failed: \(reason)")
}
```

Stages: `.downloadingModel` → `.verifyingModel` → `.loadingEngine` → `.bindingPersona`.

## Where this fits

`syni-swift` is the **agent layer** — inference, install lifecycle, persona binding, chat orchestration. It does NOT own:

* HSI signal collection (the [synheart-core](/synheart-core/swift) SDK does), or
* the four-authority gate (consent + capability + activation + session; also a host concern).

Synheart-ecosystem apps typically depend on `SynheartCore` and use `SyniModule`, which wraps this SDK with those layers. Standalone use of `Syni` is fully supported when you don't need the wider Synheart contract.

## Models

Out-of-the-box GGUF models exposed under `SyniModels`:

* `qwen25_15bInstructQ4` (default, \~1.5 GB)
* `qwen2_05bInstructQ4` (\~500 MB)
* `gemma3_1bInstructQ4`

Pinned SHA-256 per model; verified at install time. Bring your own GGUF via a custom `SyniModelSpec`. Swift also supports Apple Foundation Models as an execution target where available (`.appleFoundationModels` in `RoutingPolicy.preferredEngines`).

## API reference

| Surface                                                           | Notes                                                                                                                        |
| ----------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `SyniAgent`                                                       | Constructed with optional `installer` / `cloudConfig`. Exposes `installState` / `currentState` / `isInstalled` / `hasCloud`. |
| `SyniAgent.install / restoreInstallIfReady / uninstall / dispose` | `async` / `throws`; emit install-state transitions.                                                                          |
| `SyniAgent.chat / chatStream`                                     | `async throws` / `AsyncThrowingStream<SyniChatEvent, Error>`.                                                                |
| `SyniInstallState`                                                | Enum: `.notInstalled`, `.installing(stage:progress:)`, `.installed(...)`, `.failed(reason:cause:)`.                          |
| `SyniChatResponse`                                                | `displayText`, `message`, `suggestions`, `kind` (`.chat` / `.coach` / `.suggestions` / `.unknown`).                          |
| `SyniSpecPersona`                                                 | `load(id)` — bundled persona JSON.                                                                                           |
| `SyniModelCatalog`                                                | List local + cloud model options; bundled defaults under `SyniModelCatalog.bundled`.                                         |
| `SyniCloudConfig`                                                 | `baseUrl`, `authToken: () -> String?`, `tenantId`, `userId`.                                                                 |
| `SyniExecutionMode`                                               | `.localFirst`, `.cloudFirst`, `.localOnly`, `.cloudOnly`.                                                                    |

## Related

* [Syni overview](/syni/overview)
* [Syni spec](/syni-spec/overview)
* [synheart-core/swift](/synheart-core/swift) — host SDK with `SyniModule` consent gate
