JavaScript and TypeScript bindings for Apple's Foundation Models framework, providing access to the on-device foundation model at the core of Apple Intelligence on macOS.
This SDK is a near 1-to-1 translation of Apple's Python Foundation Models SDK, adapted for modern JS runtimes (Bun and Node.js).
- TypeScript is first-class (source is
.ts, published types indist/). - JavaScript consumers import the same package from npm (compiled ESM in
dist/). - Node without a prior
tscbuild: run TypeScript sources directly with tsx (bun run start:node,bun run example:node). - Bun is the primary dev toolchain for install, test, and native builds.
The SDK provides a typed, async interface to Apple's Foundation Models framework from JavaScript or TypeScript.
You can:
- Evaluate Swift Foundation Models app features by running batch inference and analyzing results from JS/TS
- Perform on-device inference with the system foundation model
- Stream real-time text generation responses
- Use guided generation with structured output schemas and Zod constraints
- Get type-safe responses in TypeScript by defining generation schemas with Zod (plain JS works too—you just won't get compile-time types)
- Configure custom model settings for different model options and generation parameters
- Define tools the model can call during a conversation
- Process transcripts exported from Swift apps for quality analysis
Keep in mind that it's your responsibility to design AI experiences with care. To learn about practical strategies you can implement in code, check out: Improving the safety of generative model output and Apple's Human Interface Guidelines on Generative AI.
Higher-level tools that depend on javascript-apple-fm-sdk for in-process on-device inference:
- fm-server — OpenAI-compatible HTTP server and CLI for Apple Intelligence. The system backend uses this SDK in-process (N-API / Foundation Models); the pcc backend pairs with
fm-access-pcc. - fm-acp — Agent Client Protocol stdio adapter for Apple Foundation Models (routes through
fm serve/ related backends).
These are not replacements for this library; they are commonly combined with it in the same stack:
- fm-access-pcc — TypeScript library/REST access to Foundation Models including Private Cloud Compute (PCC) paths; used with
fm-serverwhen you need PCC in addition to the on-device system model this SDK drives. - Foundation-Models-Framework-CLI (
afm) — Swift CLI withafm serve, schema/tool helpers, and workbench; useful next to this SDK for CLI workflows or an alternate local OpenAI-compatible endpoint. - FoundationModelsKit — Swift kit underlying much of the
afmtooling stack.
For broader ecosystem links (upstream Python SDK, prior TS experiments, etc.), see Reference & Inspiration.
- macOS 26.0+
- Download Xcode 26.0+ and agree to the Xcode and Apple SDKs agreement in the Xcode app (needed to build native artifacts from source).
- Bun 1.0+ or Node.js 18+ (with tsx if you want to run
.tssources without compiling) - Apple Intelligence turned on for a compatible Mac
npm install javascript-apple-fm-sdk
# or
pnpm add javascript-apple-fm-sdk
# or
bun add javascript-apple-fm-sdkThe published package ships prebuilt native artifacts for macOS arm64 (build/libFoundationModels.dylib and build/apple_fm_sdk_napi.node) plus compiled JS and .d.ts types under dist/. No postinstall build step is required on supported platforms.
Platform support: macOS 26+ on Apple Silicon only. The package declares
os: ["darwin"]andcpu: ["arm64"]so npm will warn on unsupported platforms.
| Use case | How |
|---|---|
| App / library dependency (JS or TS) | import fm from 'javascript-apple-fm-sdk' — uses published dist/ |
| Bun (dev or prod) | Same import; Bun runs the package natively |
| Node + published package | Same import under Node 18+ (loads the N-API .node addon) |
Node + local TypeScript sources (no tsc) |
npx tsx path/to/file.ts or repo scripts bun run start:node / bun run example:node |
| Bun + local TypeScript sources | bun run src/... or bun run start / bun run example |
To install from source or contribute, see Development Installation below.
This release targets Apple’s python-apple-fm-sdk v0.2.1 plus commit e868e60811aa0706feb2ccb33cfe7e27626287b7 (composed_prompt cleanup, PR #18). The C ABI comes from the vendored submodule at reference/python-apple-fm-sdk/foundation-models-c. See reference/UPSTREAM.md.
- Python SDK documentation (the JS/TS API follows the same structure)
- Python code examples (concepts translate directly to JavaScript/TypeScript)
Examples below are written in TypeScript. They run as-is under Bun or Node+tsx, and the same API is available from plain JavaScript via the published package.
import fm from 'javascript-apple-fm-sdk';
async function main() {
// Get the default system foundation model
const model = new fm.SystemLanguageModel();
// Check if the model is available
const [isAvailable, reason] = model.isAvailable();
if (isAvailable) {
// Create a session
const session = new fm.LanguageModelSession();
// Generate a response
const response = await session.respond("Hello, how are you?");
console.log(`Model response: ${response}`);
} else {
console.log(`Foundation Models not available: ${reason}`);
}
}
await main();Note:
streamResponseyields cumulative snapshots (the full response generated so far), not deltas. To print incrementally, slice off the portion you have already seen.
import fm from 'javascript-apple-fm-sdk';
const model = new fm.SystemLanguageModel();
const [isAvailable] = model.isAvailable();
if (isAvailable) {
const session = new fm.LanguageModelSession();
let previous = "";
for await (const snapshot of session.streamResponse("Tell me a short story about a cat")) {
const delta = snapshot.slice(previous.length);
process.stdout.write(delta);
previous = snapshot;
}
}The SDK uses Zod schemas and the guide() helper to define generation constraints. This is equivalent to the Python SDK's @generable decorator and fm.guide(). In TypeScript you get inferred types from Zod; in JavaScript you use the same runtime API without static types.
import fm from 'javascript-apple-fm-sdk';
import z from "zod";
const Cat = fm.generable(
z.object({
name: z.string(),
age: fm.guide(z.number().int(), { description: "Age in years", range: [0, 20] }),
}),
"Cat",
);
async function generateCat() {
const model = new fm.SystemLanguageModel();
const [isAvailable, reason] = model.isAvailable();
if (isAvailable) {
const session = new fm.LanguageModelSession();
// Generate a response typed as Cat
const cat = await session.respond("Generate an adorable rescue cat", {
generating: Cat.generationSchema(),
});
// The response is a GeneratedContent instance; parse it with the schema
const parsed = Cat.parse(cat);
console.log(`Name: ${parsed.name}, Age: ${parsed.age}`);
} else {
console.log(`Foundation Models not available: ${reason}`);
}
}
await generateCat();Define tools by extending the Tool class. The model can invoke them during a conversation.
import fm from 'javascript-apple-fm-sdk';
import z from "zod";
const WeatherParams = fm.generable(
z.object({
location: z.string(),
}),
"Weather parameters",
);
class WeatherTool extends fm.Tool {
name = "WeatherTool";
description = "Gets the current weather for a location.";
get argumentsSchema() {
return WeatherParams.generationSchema();
}
async call(args: fm.GeneratedContent) {
const location = args.value<string>("location");
return `72°F in ${location}`;
}
}
const model = new fm.SystemLanguageModel();
const [isAvailable] = model.isAvailable();
if (isAvailable) {
const session = new fm.LanguageModelSession({
instructions: "You can use the WeatherTool to check the weather.",
tools: [new WeatherTool()],
});
const response = await session.respond("What is the weather in Taipei?");
console.log(response);
}import fm from 'javascript-apple-fm-sdk';
const options = new fm.GenerationOptions({
temperature: 0.7,
sampling: fm.SamplingMode.random({ top: 50, seed: 42 }),
maximumResponseTokens: 200,
});
const session = new fm.LanguageModelSession();
const response = await session.respond("Write a haiku.", { options });Export a session's conversation history and restore it later.
const session = new fm.LanguageModelSession();
await session.respond("My name is Alice.");
await session.respond("What is my name?");
const transcript = new fm.Transcript(session.ptr);
const dict = await transcript.toDict();
// Restore the conversation from the transcript
const restored = await fm.Transcript.fromDict(dict);const model = new fm.SystemLanguageModel({
useCase: fm.SystemLanguageModelUseCase.CONTENT_TAGGING,
guardrails: fm.SystemLanguageModelGuardrails.PERMISSIVE_CONTENT_TRANSFORMATIONS,
});
console.log(`Context size: ${model.getContextSize()}`);If you need to modify the SDK or install from source:
- Get the code
git clone https://github.com/tariqwest/javascript-apple-fm-sdk
cd javascript-apple-fm-sdk- Initialize the upstream submodule, install dependencies, and build native bits
git submodule update --init --recursive
bun install
bun run verify:headers
bun run build:allThis compiles the Swift foundation-models-c dylib, the Rust N-API addon, and (via tsc) the published dist/ JS + types. You do not need tsc just to try the SDK from this repo—see step 5.
- Run the test suite (Bun’s built-in test runner)
bun run testTo run tests that exercise the native FFI layer (requires a macOS 26+ machine with Apple Intelligence enabled):
FM_NATIVE=1 bun run test- Type-check the project
bun run check- Run TypeScript sources without compiling
Bun executes .ts directly. On Node, use tsx (devDependency) the same way—no dist/ emit required:
bun run start # Bun → src/entry.ts
bun run start:node # Node + tsx → src/entry.ts
bun run example # Bun → examples/simple-inference.ts
bun run example:node # Node + tsx → examples/simple-inference.ts
# or ad hoc:
npx tsx examples/streaming.ts
npx tsx src/entry.ts- Optional: emit
dist/for a local Node consumer that imports the package like npm would
bun run build # tsc only (native artifacts already built above)
node --input-type=module -e "import fm from './dist/index.js'; console.log(fm.isNativeAvailable())"Toolchain summary: Bun is primary for install, test, and native builds. Node is fully supported at runtime via the N-API addon. For day-to-day JS/TS development against this repo, prefer Bun or Node + tsx so you are not blocked on tsc.
- Runtime: Runs on both Bun and Node.js via the Rust N-API addon in
native/(built withbun run build:napi). Both load the same.nodeartifact through theNativeBindingsabstraction. Local TypeScript can be executed with Bun or Node+tsx without a separate compile step. - Language: Implemented in TypeScript; published as ESM JavaScript + declaration files. Plain JavaScript projects consume the npm package normally.
- Generables: Python uses a
@fm.generableclass decorator; JS/TS uses afm.generable(zodSchema)factory function. - Schema constraints: Python uses
fm.guide("description", range=(0, 20)); JS/TS usesfm.guide(z.number(), { description: "Age in years", range: [0, 20] }). - Tool return values: Tools in both SDKs return strings that are passed back to the model.
This project is not yet taking contributions. Stay tuned!
Projects and docs that informed this SDK (API parity, native ABI, tooling, or adjacent ecosystem):
- apple/python-apple-fm-sdk — primary API source of truth (vendored as
reference/python-apple-fm-sdk) - foundation-models-c — C bindings / dylib ABI used by this package’s N-API layer
- Apple Foundation Models documentation — system framework docs
- Improving the safety of generative model output
- HIG: Generative AI
- rudrankriyam/Foundation-Models-Framework-CLI (
afm) — Swift CLI, OpenAI-compatibleafm serve, schema/tool helpers, workbench - rryam/FoundationModelsKit — Swift kit used by the
afmCLI stack - meridius-labs/apple-on-device-ai — prior Bun/Node bindings and Vercel AI SDK-oriented patterns
- anthropics/ClaudeForFoundationModels — Claude on Apple Foundation Models infrastructure (adjacent product)
Pin details for the Python SDK / foundation-models-c revision we track: reference/UPSTREAM.md.
Maintainers can prepare a release tarball with:
bun run build:release # headers + native + tsc + package verify
npm pack --dry-run --ignore-scripts # preview the tarballTo publish (requires GitHub CLI via gh auth login and npm login):
./scripts/release.sh current --yes # first publish of package.json version
./scripts/release.sh patch --yes # bump patch, npm publish, tag, GitHub releaseThis publishes to npm (unless --github-only), pushes the git tag, and creates a GitHub Release with the npm tarball attached.
MIT — see LICENSE.