Apple's Python SDK is an FFI bridge to a Swift framework
Python bindings for access to the on-device model at the core of Apple Intelligence through the Foundation Models framework
At a glance
- What is it?
- python-apple-fm-sdk exposes the on-device foundation model behind Apple Intelligence to Python, and the package ships prebuilt static libraries and dylibs inside the wheel, which tells you it reaches the Swift framework through a native bridge rather than a service call. It is macOS only, alpha, and closed to contributions.
- Who is it for?
- Adopt apple-fm-sdk if you are evaluating the on-device Apple Intelligence model from Python, running batch inference on a Mac with Apple Intelligence enabled. Do not adopt it for anything that must ship on other platforms, since the classifiers declare macOS only, or for production workloads, since the project declares Development Status:: 3 - Alpha and is not taking contributions.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 16 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What the API looks like
The surface is small and reads like the Swift API it mirrors.
You get the default system model with `fm.SystemLanguageModel()`, then check whether it is usable with `model.is_available()`, which returns both a boolean and a reason. That pairing matters: on a Mac without Apple Intelligence enabled, the SDK tells you why rather than failing at the first request.
A session is created with `fm.LanguageModelSession()` and text comes back from an awaited `session.respond()` call:
import apple_fm_sdk as fm
import asyncio
async def main():
model = fm.SystemLanguageModel()
is_available, reason = model.is_available()
if is_available:
session = fm.LanguageModelSession()
response = await session.respond("Hello, how are you?")
print(f"Model response: {response}")
else:
print(f"Foundation Models not available: {reason}")
asyncio.run(main())The list of uses the README gives is worth reading for who this is for. Batch inference for evaluating Swift app features from Python, on-device inference, streaming real-time text generation, guided generation with structured output schemas and constraints, type-safe responses through decorators, custom model settings, and processing transcripts exported from Swift apps for quality analysis.
That last one and the evaluation framing tell you the intended use. This is a research and evaluation tool sitting next to a Swift application, not a general-purpose AI client library.
The three examples in `examples/` match that reading: `simple_inference.py`, `streaming_example.py` and `transcript_processing.py`.
Guided generation through a decorator
The typed-response feature is the part most worth understanding, because it is where a schema-constrained generation library earns its keep.
You mark a class with `@fm.generable`, which signals that the type should be produced by the model, and you constrain individual fields with `fm.guide`:
import apple_fm_sdk as fm
@fm.generable
class Cat:
name: str
age:int = fm.guide("Age in years", range=(0, 20))The class is an ordinary Python type with ordinary annotations, and the constraint is expressed as a default value. `age` is then generated as an integer between 0 and 20 rather than parsed out of prose afterwards, and the request passes the class itself:
cat = await session.respond("Generate an adorable rescue cat", generating=Cat)The practical difference from asking for JSON is that the constraint travels with the type definition rather than being duplicated in a prompt and a parser. When a model returns this, you already have a `Cat`, and the failure mode of a malformed response is largely designed out.
The range syntax in `fm.guide` is one constraint of an options surface the README does not enumerate, so the full vocabulary of constraints needs the documentation site.
Version history shows this area moving: v0.2.0 on 2026-06-08 added images for prompts with an Attachment type, and v0.1.1 on 2026-03-08 added GenerationOptions and transcript loading.
The wheel carries native code
The packaging is where the architecture becomes visible.
`package-data` in pyproject.toml lists `lib/*.a` and `lib/*.dylib` for the `apple_fm_sdk` package, which means the published wheel contains static libraries and a dynamic library. A pure Python client would have none of that. So the SDK is a native bridge: it links against Apple's Foundation Models framework and the model runs on the device.
Two more directories support that reading. `foundation-models-c/` at the repository root suggests a C shim layer, and `bin/` is consistent with shipping build outputs. In the dev dependency group, `ctypesgen` appears alongside `psutil`, which is a generator for Python ctypes bindings from C headers.
The build is also custom. pyproject.toml sets `build-backend = "build_backend"` with `backend-path = ["."]` and `requires = ["setuptools"]`, pointing at the `build_backend.py` at the repository root. The usual setuptools build backend is not enough here, because something has to compile or fetch the native artefacts and place them in the wheel.
The result is a package that is much less portable than its Python syntax suggests. The classifiers list only `Operating System:: MacOS`, there is no CPU architecture or Windows or Linux classifier, and the requirements list macOS 26.0 or newer, Xcode 26.0 or newer with the Xcode and Apple SDKs agreement accepted, Python 3.10 or newer, and Apple Intelligence turned on for a compatible Mac.
Every one of those is a hard gate.
Development install and the tooling
The development path uses uv, and the README treats the virtual environment as optional but recommended.
uv venv
source .venv/bin/activateThen sync and install in editable mode:
uv sync
uv pip install -e .
pytestThe README is specific that after making any change you must rebuild the project again and test, which follows from the native artefacts: editing Python alone will not pick up a change in the underlying C or Swift side.
The test configuration is unusually thorough for a small SDK. `[tool.pytest.ini_options]` sets `testpaths = ["tests"]`, restricts discovery to `test_*.py` files, `Test*` classes and `test_*` functions, and sets `asyncio_mode = "auto"` with a function-scoped default event loop. The development group includes `pytest-asyncio`, and the test configuration sets `asyncio_mode = "auto"`.
The development group also includes `pytest-timeout`.
The other dev tools are conventional: ruff for linting, `twine` for publishing, and a docs group built on Sphinx with the book theme, autodoc type hints, sphinx-copybutton and myst-parser, which is the documentation published at apple.github.io/python-apple-fm-sdk.
Status, licensing and what not to build on
The package version is 0.2.1, released on 2026-06-29 as improvements to the API and the build process. The last push was on 2026-10-07 and the repository is not archived, so the work is continuing even though no release has shipped since June.
The declared development status is `Development Status:: 3 - Alpha`, which is an explicit statement by the author about what this is.
The contribution position is stated just as plainly: this project is not yet taking contributions, with a stay tuned. The explicit alpha status is a clear signal about the intended relationship with the code. You can read it, evaluate the model, and file bugs; you are not being invited to change it.
The licensing is Apache-2.0 in pyproject.toml, with a LICENSE.md at the root, and the README carries the copyright line for Apple Inc.
One more thing the README does that more SDKs skip. It tells you to keep in mind that it is your responsibility to design AI experiences with care, and links two specific Apple resources: guidance on improving the safety of generative model output, and the Human Interface Guidelines on generative AI. For a library whose main use is generating text on a user's device, that framing is part of the API's intended contract rather than boilerplate, and an integrator who ignores it is building something the platform documentation warns against.
The honest summary is that this is a supported way to drive an on-device Apple model from Python for evaluation and prototyping, on one operating system, at an alpha maturity level, with no path to becoming something else.
Editorial conclusion
Adopt apple-fm-sdk if you are evaluating the on-device Apple Intelligence model from Python, running batch inference on a Mac with Apple Intelligence enabled. Do not adopt it for anything that must ship on other platforms, since the classifiers declare macOS only, or for production workloads, since the project declares Development Status:: 3 - Alpha and is not taking contributions. Verify first that you are on macOS 26.0 or newer with Xcode 26.0 or newer installed and the SDK agreement accepted, and check that your compatible Mac has Apple Intelligence turned on before writing code around it.
Frequently asked questions
What are the requirements for apple-fm-sdk?
macOS 26.0 or newer, Xcode 26.0 or newer with the Xcode and Apple SDKs agreement accepted, Python 3.10 or newer, and Apple Intelligence turned on for a compatible Mac. The package classifiers list macOS only.
How do I install apple-fm-sdk?
With `pip install apple-fm-sdk`, or from source with uv using `uv venv`, `uv sync`, `uv pip install -e .` and then `pytest`. The README notes the package must be rebuilt after a change before testing.
What does is_available() return?
A boolean and a reason, as shown by `is_available, reason = model.is_available()`. When the model is unavailable the reason explains why, rather than the first request failing.
How does guided generation work in apple-fm-sdk?
You mark a Python class with the `@fm.generable` decorator and constrain fields with `fm.guide`, for example `age: int = fm.guide("Age in years", range=(0, 20))`, then pass the class to `session.respond(prompt, generating=Cat)` to get an instance of it back.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/apple-python-apple-fm-sdk)Was this useful?