Skip to main content
The Moss Swift SDK brings semantic search to iOS. It wraps the native libmoss runtime and exposes an idiomatic async/await API. Documents are embedded and queried on-device, with optional cloud sync.

Requirements

  • iOS 15+
  • Xcode 15+
  • Apple Silicon for the simulator (the SDK ships arm64 device + simulator slices)

Install

Add the package in Xcode via File ▸ Add Package Dependencies… and enter https://github.com/usemoss/moss, or declare it in Package.swift:
dependencies: [
  .package(url: "https://github.com/usemoss/moss", from: "0.3.0"),
],
targets: [
  .target(name: "YourTarget", dependencies: [
    .product(name: "Moss", package: "moss"),
  ]),
]
On first build, Xcode downloads the precompiled Moss.xcframework from the GitHub release and verifies its checksum. The Swift SDK exposes two entry points:
  • MossClient - the entry point. Construct it with your credentials, open sessions, and track push jobs.
  • MossSession - an on-device index. Embed and query documents locally with no network calls, persist to disk, and sync to the cloud with pushIndex / loadIndex.

Indexing & sync

Indexes are created locally: open a session, call addDocs, and the documents are embedded and stored on-device - no network required. To share an index across devices or back it up, sync it through the cloud: The cloud is the source of truth, so an index built on one device can be pulled and queried on another. By default loadIndex is a one-time pull, so re-pull to pick up later changes; continuous auto-sync - keeping a loaded index current automatically - is also available if you’d rather not re-pull by hand.

Quick start

Build an index on-device, push it to the cloud, then load it back:
import Moss

let client = try MossClient(projectId: "your_project_id", projectKey: "your_project_key")
defer { client.close() }

// 1. Build an index on-device. Documents are embedded locally and can carry
//    metadata you filter on later.
let session = try await client.session("products")
try await session.addDocs([
  .init(id: "p1", text: "Running shoes with breathable mesh.",
        metadata: ["category": "shoes", "brand": "swiftfit", "price": "79", "city": "new-york"]),
  .init(id: "p2", text: "Lightweight city backpack.",
        metadata: ["category": "bags", "brand": "urbanpack", "price": "95", "city": "seattle"]),
])

// 2. Query locally. Tune `alpha` and add metadata filters - see the Querying guide.
let hits = try await session.query("something to run in", options: .init(topK: 3))
hits.docs.forEach { print($0.score, $0.id) }

// 3. Push it to the cloud and wait for the job to finish.
let push = try await session.pushIndex()
session.close()
while try await client.getJobStatus(push.jobId).status != "ready" {
  try await Task.sleep(nanoseconds: 1_000_000_000)
}

// 4. Load it back into a new session and query - still on-device.
let restored = try await client.session(push.indexName)
defer { restored.close() }
_ = try await restored.loadIndex(push.indexName)
let results = try await restored.query("something to run in", options: .init(topK: 3))
print(results.docs.map(\.id))

Models

The on-device embedding model defaults to moss-litelm on iOS. Pass "custom" as the session modelId to supply your own pre-computed embeddings via DocumentInfo.embedding.

Preparing documents

A few guidelines for the best retrieval quality and a compact index:
  • Document size - aim for roughly 100-250 tokens of text per document. Split long content (a chapter, a transcript) into focused chunks rather than one large document.
  • Metadata - metadata is free-form [String: String]. Put anything you’ll filter on (category, ids, coordinates) here - see the Querying guide.

Cross-platform

All Moss SDKs - Swift (iOS), Python, and JavaScript - are interoperable and read the same indexes. An index built or pushed from one SDK can be loaded and queried from another.

Reference

Example app

A complete SwiftUI sample app is in examples/ios.