SDK 1.0.0-betaLocalLMLabSDKCore keeps a macOS 26 deployment floor; one build serves macOS 26 and 27, with Private Cloud Compute, Claude, and open-weight (MLX) models registered behind #available(macOS 27, *). Consuming it needs the Xcode 27 beta (the xcframeworks are built with the macOS 27 SDK). The 0.8.x SDK series (MCP client and connectors, no model layer) continues separately. 1.0.0-beta.N makes no API-stability promise — signatures can move between betas.

The model layer

New in 1.0 — offer more than one model, without creating your own provider abstraction

The 0.8 SDK gives your native macOS app a real MCP client, the Calendar / Reminders / Contacts / Location connectors, ready-made Tools, and Keychain-backed OAuth — all still here, all unchanged. 1.0 adds the piece you reach for when which model becomes a real question in your app.

And the MCP client is no longer Apple-only. The same tool-calling loop runs on top of whichever provider you route to, so a session backed by Claude or a downloaded open-weight model discovers and calls your MCP servers — Slack, GitHub, Notion, Linear, and the rest — exactly the way an Apple on-device session does.

Start from working code

Every API on this page is exercised by a small, runnable example you can clone and build — use the closest one as a starting reference rather than writing from scratch. For the model layer, three of them, smallest to fullest:

ExampleStart here if you want…
repo-qa-local the smallest "download and run an open-weight model" — one file, a CLI that answers questions about a GitHub repo through an MCP server. About 20 lines different from the Apple-model version next to it.
code-buddy the full pattern: a CLI coding agent with .heavy / .light routes to two local models (one kept warm), Core's Workspace tools, an MCP docs server, streamed output, and two host-owned Process tools the SDK deliberately doesn't ship. Runs one task and stops, or drops into an interactive >> loop over one persistent session (Ctrl-C cancels the current turn; a second press quits). Every API below has a "→ code-buddy uses this" pointer in the guide.
workspace-buddy-local a sandboxed GUI app running a downloaded model — the Mac App Store shape. Folder picker + security-scoped bookmark, the model edits files, and the model download works inside the App Sandbox container.

Each folder has a README with copy-paste setup and a real "verified live" transcript. All examples → — the MCP-client and connector ones (repo-qa, plate-today, components-demo) need no model download. annotated-examples.md walks every one line by line.

Four providers, one protocol

ProviderBacksShips inmacOS
SystemModelProviderApple's on-device modelCore26+
PCCModelProviderApple Private Cloud Compute — not functional in this beta, see beta notesCore27
ClaudeModelProviderClaude (your API key or auth)LocalLMLabSDKClaude27
MLXModelProviderOpen-weight models you download and run locallyInference27

On macOS 26 the 27-only providers are simply not registered; lab.models.availability(for:) reports their schemes as .requiresOS("macOS 27") and ModelPickerView shows them as disabled rows.

Register the providers you want on a LocalLMLab instance (the optional front door that also bundles the MCP manager and the connector facades), name models with routes, and make a session. Adoption is small — this is repo-qa-local's entire change over the Apple-model repo-qa next to it; the rest of the two files is identical:

let mlx = MLXModelProvider(residentModelLimit: 1)
let lab = LocalLMLab(configuration: .init(providers: [mlx, SystemModelProvider()]))
let modelID = ModelID(scheme: "mlx", rest: "mlx-community/Qwen3-8B-4bit")!
lab.models.route(.local, to: modelID)

if case .notDownloaded = lab.models.availability(for: modelID) {
    _ = try await mlx.validate(modelID.rest)                // fits this Mac's RAM? MLX format?
    for try await event in mlx.download(modelID.rest) { … }  // stream progress %
}

let session = try lab.makeSession(route: .local, tools: tools, instructions: instructions)
for try await partial in session.languageModelSession.streamResponse(to: task) { … }

makeSession merges your tools with the enabled MCP tools whatever the route — your own Tools, the connectors, and the MCP client attach to Apple on-device, Claude, and MLX sessions alike; .events is a side-channel for tool-call and context-compaction progress; contextBudget and retryOnContextOverflow carry a long session.

The memory story

MLXModelProvider isn't "load and go" on a constrained Mac: validate preflights a model (MLX format? architecture supported? weights vs. this Mac's RAM?) with no download; download streams progress; capabilityProbe is the authoritative check of whether a downloaded model can actually tool-call. residentModelLimit caps how many models stay in RAM — switching routes evicts the other — and residencyEventStream reports it. For a starting shortlist of which open-weight models tool-call and which don't, see tested-models.md.

Three binaries

LocalLMLabSDKCore is the engine — link it always (macOS 26 floor). LocalLMLabSDKInference is the MLX runtime (~49 MB, the whole stack statically linked) — link it only if you use MLXModelProvider. LocalLMLabSDKClaude holds ClaudeModelProvider — link it only if you offer Claude, and note that its dependency is macOS-27-pinned, so it forces a macOS 27 deployment target on whatever links it. All three are binaryTargets on the same GitHub release, all Developer-ID signed and notarized. See code-buddy's Package.swift for the multi-binary manifest shape.

Migrating from 0.8.x

Docs

Contact

Building something on this, or hit a rough edge? neuron@thisbrain.ai or the Discord.