FoundationModels has no Private Cloud Compute API
TL;DR —
FoundationModelsin iOS 26 is on-device only. There is no public API to route a request to Private Cloud Compute —SystemLanguageModel.defaultis the on-device model and that’s the whole surface. Also: every symbol in the framework is iOS 26.0+, not iOS 18.1+. If you’re planning a hybrid on-device/cloud design around this framework, read the swiftinterface before you build it.
Checked against the iOS 26.5 SDK.
What I was building
VoiceKit removes filler words from recordings, generates subtitles, and summarizes what was said. Everything runs on device — WhisperKit for transcription, Apple’s foundation model for the summary.
The summary step had an obvious problem. Meeting recordings are long, on-device models have a small context window, and a one-hour transcript does not fit. So I designed around it: short inputs summarize locally, long inputs go to Private Cloud Compute where the bigger model lives. A settings toggle would let the user choose, with an indicator when a request left the device.
It’s a clean design. It’s also built entirely on an API that doesn’t exist.
Where the assumption came from
Two things led me here, and I suspect they lead other people here too.
Apple’s Private Cloud Compute messaging. PCC is real, it’s well documented, and Apple talks about it as the tier the system reaches for when a request needs more than the device can offer. That’s an accurate description of how Apple’s own features work. It is not a description of what third-party apps can call.
The version number. I had iOS 18.1+ written in my planning notes for the whole summarization feature, because that’s when Apple Intelligence shipped. It felt right. It’s wrong — the FoundationModels framework is iOS 26.0+, and so is every symbol in it. Apple Intelligence launching in 18.1 and the framework being available to developers are two separate events, about a year apart.
Neither assumption is unreasonable. Both are the kind you only catch by looking at the actual interface.
How I checked
Swift frameworks in the SDK ship a .swiftinterface — the module’s public surface as text. It’s the ground truth for what you can call, and it’s greppable.
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/
Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/
FoundationModels.framework/Modules/FoundationModels.swiftmodule/
I grepped the interface for every word a cloud-routing API would plausibly contain: cloud, PCC, server, remote.
Zero hits. Not a deprecated symbol, not an SPI-looking thing behind an underscore, not a stray doc comment. The concept simply isn’t in the public surface.
While I was in there I also checked the availability annotations, which is where the iOS 18.1 assumption died. Everything is iOS 26.0.
This took about two minutes. I had been designing against the imagined API for considerably longer than two minutes.
What’s actually there
SystemLanguageModel.default
LanguageModelSession(instructions:).respond(to:) -> Response<String>
That’s the shape of it. SystemLanguageModel.default is the on-device foundation model. There is no sibling that means “the big one.” There’s no options struct with a routing preference, no .cloud case, nothing to opt into.
Availability comes from SystemLanguageModel.default.availability, and the failure cases are about the device, not about a network:
enum SummaryCapability {
case available
case unavailableOS // below iOS 26 — framework not present
case deviceNotEligible // pre-iPhone 15 Pro
case appleIntelligenceOff // user hasn't enabled it
case modelNotReady // model still downloading
}
Every one of those is a local condition. That’s the tell: an API that could reach a server would have failure modes that mention one.
What I changed
The toggle is gone. I’d sketched a settings screen where the user picks on-device or cloud. Since there is no cloud, shipping that switch would mean shipping a control that does nothing — a fake choice dressed up as a privacy feature. The screen now states a fact instead:
Summarization
On-device only
Summaries are generated entirely on this device.
Nothing is sent anywhere.
The PCC entitlement came out. I’d requested Private Cloud Compute entitlements early, back when the hybrid design was real. Nothing in the app uses them now. Leaving an unused cloud-related entitlement on a build whose entire pitch is “nothing leaves your device” is a bad look at review time and a worse one if anyone inspects it.
The privacy claim got stronger, not weaker. This surprised me. I’d been planning a consent flow, a “request left the device” indicator, and App Privacy declarations that admitted data leaves in some cases. All of that disappeared. “No data collected” is now unconditionally true rather than true-with-an-asterisk — which is a better position than the one I was designing toward.
Weak linking, because the deployment target is lower. The app supports iOS 17, the framework is iOS 26. So it’s linked weakly and every call sits under #available(iOS 26.0, *):
sdk: FoundationModels.framework
weak: true
Without this you crash on launch on anything below 26.
The problem PCC was supposed to solve
It didn’t go away. A one-hour transcript still doesn’t fit in the context window. It just has to be solved locally now.
The approach that worked is map/reduce. Chunk the transcript, summarize each chunk, then summarize the summaries. When a single chunk still overflows, the framework tells you precisely:
LanguageModelSession.GenerationError.exceededContextWindowSize
Catch that, split the chunk in half, recurse. It bottoms out.
Two details that mattered more than I expected:
Build a fresh LanguageModelSession for every chunk. A session accumulates conversational context, and that context eats the same window you’re trying to conserve. Reusing one session across chunks means each chunk has less room than the last, and you’ll hit exceededContextWindowSize on material that would have fit on its own.
tokenCount(for:) is iOS 26.4+, not 26.0. If you want to size chunks before sending rather than catching the overflow after, note that the measuring API arrived later than the rest of the framework. On 26.0–26.3 you’re catching and splitting.
Takeaway
When a framework is new, the swiftinterface is the documentation. Not the announcement, not the platform’s marketing story, not the version number you remember from a keynote. The interface file is generated from what actually shipped, it’s on your disk already, and it’s grep-able.
I built a design on top of an API that was never announced as existing — I’d just filled in the gap between “Apple has PCC” and “Apple shipped a model framework” with an assumption. Two minutes of grep would have caught it before any of the design work.
The check is cheap enough that there’s no reason not to make it the first step whenever a plan depends on a framework you haven’t used yet.
I'm Kou (日々野 考), an indie iOS developer in Japan building on-device ML apps under kouworks. I write up the things that cost me days, so they cost you minutes.
Apps:
- VoiceKit — filler-word removal, subtitles, and summarization, entirely on-device.
- KidsMask — automatic face mosaic for photos and video; no face data ever leaves the device.
- VlogMask — real-time face mosaic camera for vlogging.
- VertiCut — turns horizontal video into vertical 9:16, following a person automatically.