- macOS 26+ or iOS/iPadOS 26+
- Apple Intelligence enabled
- Apple Silicon device
Private Cloud Compute additionally requires macOS/iOS/iPadOS 27+, a network
connection, and Apple's managed
com.apple.developer.private-cloud-compute
entitlement. The crate still targets 26.0; 27-only Swift APIs are selected by
the build SDK and guarded at runtime.
[dependencies]
fm-rs = "0.2"Enable the derive macro if you want compile-time schema generation:
[dependencies]
fm-rs = { version = "0.2", features = ["derive"] }use fm_rs::{GenerationOptions, Session, SystemLanguageModel};
fn main() -> Result<(), fm_rs::Error> {
let model = SystemLanguageModel::new()?;
model.ensure_available()?;
let session = Session::with_instructions(&model, "You are a helpful assistant.")?;
let options = GenerationOptions::builder()
.temperature(0.7)
.max_response_tokens(500)
.build();
let response = session.respond("What is the capital of France?", &options)?;
println!("{}", response.content());
Ok(())
}- Blocking and streaming responses
- Tool calling with JSON argument schemas and tool-calling modes
- Structured JSON output (explicit schemas or derive macro)
- Transcript persistence, restoration, replacement, and error policy
- Context usage estimates and compaction/rollover helpers
- Model-reported context sizes and exact session token usage (27+)
- Multimodal image attachments and built-in OCR/barcode/Spotlight tools (27+)
- Typed Foundation Models error taxonomy on blocking and streaming paths
- Prewarming and timeout-aware respond APIs
- Private Cloud Compute sessions on macOS/iOS/iPadOS 27+
Private Cloud Compute support is intentionally excluded from the default build. Per Apple's eligibility requirements, PCC access requires:
- Enrollment in the App Store Small Business Program
- Fewer than two million first-time downloads across your apps
- The managed entitlement assigned to your account and enabled for the App ID
Enable the private-cloud-compute feature only for applications whose
App ID has Apple's managed entitlement:
[dependencies]
fm-rs = { version = "0.2", features = ["private-cloud-compute"] }use fm_rs::{
GenerationOptions, PrivateCloudComputeLanguageModel, ReasoningLevel, Session,
};
fn main() -> Result<(), fm_rs::Error> {
let model = PrivateCloudComputeLanguageModel::new()?;
model.ensure_available()?;
// PCC has a daily, per-user quota; check it to decide when to fall
// back to the on-device SystemLanguageModel.
if model.quota_usage()?.is_limit_reached() {
return Err(fm_rs::Error::QuotaLimitReached("daily quota".into()));
}
let session = Session::new(&model)?;
let response = session.respond_with_reasoning(
"Compare these approaches and explain the tradeoffs.",
&GenerationOptions::default(),
// Start with Moderate; use Deep only when the added latency and
// context consumption are justified.
ReasoningLevel::Moderate,
)?;
println!("{}", response.content());
Ok(())
}On an older SDK or runtime, construction returns
Error::UnsupportedPlatform. Availability can also report
PrivateCloudComputeSystemNotReady when PCC cannot currently serve requests.
PCC request failures surface as typed errors — Error::NetworkFailure,
Error::QuotaLimitReached, and Error::ServiceUnavailable — so applications
can retry or fall back to the on-device model. quota_usage() reports the
current quota status and reset date, and context_size() reports the PCC
context window.
Running the example needs the managed
com.apple.developer.private-cloud-compute entitlement, which Apple assigns
per developer account and App ID; without it, signing fails with a
provisioning-profile error.
PCC is a managed capability: Apple must assign the entitlement to your App ID,
and its provisioning profile must authorize the final executable's signature.
An ad-hoc signature is rejected by macOS because this is a restricted
entitlement. A standalone executable cannot embed the required profile, so the
example runner wraps the executable in a minimal app bundle before signing it.
The repository includes the required Boolean entitlement in
crates/fm-rs/examples/private_cloud_compute.entitlements.
To build, automatically provision, sign, and run the repository example:
brew install xcodegen
just example-pccThe runner passes the existing DEVELOPMENT_TEAM environment variable to an
Xcode-managed macOS app target. With an Apple account configured in Xcode,
xcodebuild -allowProvisioningUpdates creates or selects the profile and embeds
it in the signed app automatically. On the first build, Xcode may also register
the Mac with the developer account so it can be included in the development
profile. Set PCC_BUNDLE_IDENTIFIER only if the PCC capability is enabled for
an App ID other than the default
com.blacktop.fm-rs.pcc-example.
The profile's App ID must have the PCC managed capability enabled. A library
build.rs cannot provision or sign the final consuming application, so
applications should perform this step in their own app build or distribution
pipeline.
These APIs work with the on-device model — no PCC entitlement needed. They
require building with the macOS/iOS 27 SDK. On older SDKs or runtimes, session
APIs return Error::UnsupportedPlatform; ToolCallingMode is ignored and the
framework keeps its default allowed behavior.
On the observed 8,192-token on-device context window, enable one built-in system tool at a time. Combined tool schemas can exhaust the context window before the prompt is processed.
For vision tools, give each image attachment a meaningful .with_label(...)
and refer to that same label in the prompt. The example below uses receipt in
both places.
use fm_rs::{
Attachment, ContextLimit, GenerationOptions, Session, SystemLanguageModel, SystemTool,
ToolCallingMode,
};
fn main() -> Result<(), fm_rs::Error> {
let model = SystemLanguageModel::new()?;
model.ensure_available()?;
// Model-reported context window (falls back to 4096 on older SDKs).
let limit = ContextLimit::for_model(&model)?;
println!("context window: {} tokens", limit.max_tokens);
// Built-in system tools run inside the framework.
let session = Session::builder(&model)
.instructions("Describe images and read any text in them.")
.system_tool(SystemTool::Ocr)
.build()?;
// Multimodal prompting with image attachments.
let options = GenerationOptions::builder()
.tool_calling_mode(ToolCallingMode::Allowed)
.build();
let response = session.respond_with_attachments(
"What does this receipt say?",
&[Attachment::file("receipt.png").with_label("receipt")],
&options,
)?;
println!("{}", response.content());
// Exact token usage (input, cached, output, reasoning).
let usage = session.usage()?;
println!("input tokens: {}", usage.input_tokens);
Ok(())
}Failures surface as typed errors on both blocking and streaming paths:
ContextSizeExceeded, RateLimited, GuardrailViolation, Refusal,
UnsupportedCapability, UnsupportedTranscriptContent,
UnsupportedGenerationGuide, UnsupportedLanguageOrLocale,
AssetsUnavailable, ConcurrentRequests, and Timeout. Sessions also
support transcript replacement (Session::set_transcript) and
TranscriptErrorHandlingPolicy.
Legend: ✅ Implemented · 🟡 Partial · ⏳ Deferred · ➖ Automatic · ❌ Out of scope
| Foundation Models 27 API | Status |
|---|---|
| Private Cloud Compute model, quota, availability | ✅ Implemented (private-cloud-compute feature) |
Extended reasoning via ContextOptions |
✅ Implemented (respond_with_reasoning, _timeout) |
Typed error taxonomy (LanguageModelError, PCC, session, model errors) |
✅ Implemented, blocking + streaming |
26-era GenerationError bridging (macOS/iOS 26 runtimes) |
✅ Implemented — same typed errors on all runtimes |
SystemLanguageModel.contextSize / PCC contextSize |
✅ Implemented (context_size, ContextLimit::for_model) |
| Exact session token usage | ✅ Implemented (Session::usage, SessionUsage::delta_since) |
Per-Response usage property |
🟡 Partial — implemented for blocking respond paths, including respond_json_with_timeout |
| Python bindings parity | 🟡 Partial — typed errors, context size, usage, tool modes, attachments, system tools, and transcript controls are implemented; PCC remains Rust-only |
| Tool-calling modes (allowed/required/disallowed) | ✅ Implemented (ToolCallingMode) |
| Multimodal image attachments | 🟡 Partial — blocking responds implemented; streaming/structured variants deferred |
| Built-in tools: Vision OCR, barcode, Spotlight search | ✅ Implemented with Apple's default configurations |
| Built-in tool configuration (sources, guides, delegates) | ⏳ Deferred — Swift delegate/closure hooks do not cross the C FFI |
| Transcript replacement and error policy | ✅ Implemented |
| Dynamic Profiles | ⏳ Deferred — Swift result-builder DSL maps poorly onto a C FFI |
Custom LanguageModel providers / executors, including Core AI and MLX adapters |
⏳ Deferred — requires Rust-side executor callbacks; architectural |
| Foundation Models framework utilities | ⏳ Deferred with Dynamic Profiles; this is a separate Swift package |
| Foundation Models Instruments updates | ➖ Automatic for profiled consumers; no crate API required |
Apple fm CLI, Python SDK, and Evaluations framework |
❌ Out of scope — separate Apple tooling, not reimplemented by this Rust binding |
| New on-device base model | ➖ Automatic via SystemLanguageModel |
- FFI calls are synchronous. Use
spawn_blockingin async runtimes. - macOS 27 built-in-tool schema overflows are classified as
ContextSizeExceededon blocking and streaming paths, including the runtime's private bridged error. - If you see
libswift_Concurrency.dylibload errors, add Swift rpaths in your binary crate’sbuild.rs.
use std::process::Command;
fn main() {
println!("cargo:rustc-link-arg=-Wl,-rpath,/usr/lib/swift");
if let Ok(output) = Command::new("xcrun")
.args(["--toolchain", "default", "--find", "swift"])
.output()
{
let swift_path = String::from_utf8_lossy(&output.stdout).trim().to_string();
if let Some(toolchain) = std::path::Path::new(&swift_path).parent().and_then(|p| p.parent()) {
let lib_path = toolchain.join("lib/swift/macosx");
if lib_path.exists() {
println!("cargo:rustc-link-arg=-Wl,-rpath,{}", lib_path.display());
}
}
}
}For best results on-device:
- Keep prompts focused and explicit about length and style.
- Prefer instructions for stable behavior across prompts.
- Use small examples when you need consistent formatting.
- Break complex tasks into smaller steps.
- Use structured output when you need reliable parsing.
See Apple’s guidance for more detail:
- https://developer.apple.com/documentation/foundationmodels/prompting-an-on-device-foundation-model
- https://developer.apple.com/documentation/technotes/tn3193-managing-the-on-device-foundation-model-s-context-window
- https://developer.apple.com/videos/play/wwdc2024/10150/
- https://developer.apple.com/videos/play/wwdc2024/10163/
This crate tracks Apple FoundationModels updates from:
Current coverage includes context-window management helpers aligned with TN3193:
Session::context_usage(...)compact_transcript(...)compact_session_if_needed(...)session_from_summary(...)
cargo run --example basic
cargo run --example streaming
cargo run --example tools
cargo run --example structured
cargo run --example context_compaction
just example-pccSee API details and advanced usage in the crate docs (docs.rs).
MIT License - see LICENSE for details.