Apple Put a Local LLM in macOS 27. The Dangerous Part Is the JSON.
I tested the fm CLI on summaries, extraction, code, math, context limits, and its local API.
Your Mac can now summarize a document, classify a folder, extract fields into valid JSON, and expose the result through a local Chat Completions API without installing a model runner or creating an API key.
That convenience creates a new failure mode because a weak answer can arrive inside production-shaped JSON.
I tested Apple's new fm command on macOS 27.0.1 with an Apple M5 Mac.
The summary was accurate, the first structured extraction chose the wrong number, the coding tests traded 1 violation for another, and a simple time calculation went completely off the rails before a sharper prompt fixed it.
The useful question is whether a small on-device model becomes safe automation merely because Apple gives it a CLI, schemas, and a local API.

The Viral Post Got the Interface Right
A post from Alvaro Cintas described fm as a free local LLM that was already available in the macOS 27 Terminal.
It showed the core commands, file piping, structured output, saved sessions, and fm serve as a local OpenAI-compatible endpoint.

The source post described the right product, but some limits and commands did not match the release build that I tested.
The basic setup took less than a minute because the model was already downloaded on my Mac.
fm license --status
fm available
fm respond "Explain why HTTP 200 does not always mean business success."
My machine returned System model available.
The executable lived at /usr/bin/fm, so I did not install a package, download model weights manually, or configure a provider.
Apple says the CLI ships with macOS 27, and Apple Intelligence supports Macs with M1 or later.
The exact experience still depends on the OS build, language, region, downloaded model, and hardware.
The screenshot in the post also showed token-count, quota-usage, and a pcc model.
My macOS 27.0.1 help listed count-tokens instead of token-count, and it listed only the on-device system model.
Apple demonstrated Private Cloud Compute during WWDC26, but it was not available in the CLI help on the build that I tested.
The interface had already changed between the screenshot and my release build.
That matters when a shell script depends on a flag, model name, or assumed context limit.
FM Summarized the Incident Correctly
I started with a short incident report that contained several numbers and 1 easy trap.
A content pipeline processed 240 product descriptions.
A partner API exhausted its quota but continued returning HTTP 200 responses with an error inside the JSON body.
The worker saved blank descriptions for 37 products in staging.
Production did not change because publication required a separate approval.
The incident lasted 3 hours and 28 minutes, while direct recovery took 42 minutes.
The prompt contained 203 tokens.
I asked fm to produce exactly 3 concise bullets, preserve every number, and avoid inventing a cause.
It returned an accurate summary in 2.62 seconds on my M5 Mac.
It kept 240, 37, 03:12, 06:40, 3 hours and 28 minutes, and 42 minutes in the right roles.
That result fits the model's natural territory.
The input was short, the task was a transformation, and every important detail could be checked against the source.
The JSON Looked Safer Than It Was
I then asked for structured output from the same incident.
fm schema object \
--name Incident \
--string root_cause \
--integer affected_items \
--string production_impact \
--integer recovery_minutes \
> incident-schema.json
fm respond \
--schema incident-schema.json \
--text "$(cat incident.txt)" \
"Extract the incident facts."
The response was valid JSON.
The field names were correct, the types were correct, and every required property was present.
The value of affected_items was wrong.
{
"affected_items": 240,
"recovery_minutes": 42,
"production_impact": "No production page changed...",
"root_cause": "Transport success did not mean business success..."
}
The report said that 240 products were processed and 37 products received blank copy.
The model selected 240 for affected_items.

The structured response passed a parser while it failed the business meaning of 1 field.
That is the dangerous part of guided generation.
A schema can guarantee the shape of an answer, but it cannot guarantee that the model understood the meaning of each property.
Plain prose often looks uncertain, so a human reads it carefully.
Valid JSON looks contractual, so software tends to trust it.
A wrong paragraph can confuse a reader.
A wrong integer can move files, reject records, update a database, or trigger another agent.
A Better Contract Fixed the Number
The first schema used a name that felt obvious to me and remained ambiguous to the model.
affected_items could describe every item touched by the pipeline or only the items damaged by the incident.
I added a description to the schema and narrowed the prompt.
--integer affected_items \
--description "Number of products that ended with blank copy in staging"
I also told the model to use affected_items for products with blank copy, not for all products processed.
With greedy sampling, it returned 37.
The fix did not require a larger model.
It required a better contract.
This follows the same rule I use when I run small models locally instead of calling an API: the input stays bounded, the output stays bounded, and the result remains objectively checkable.
Structured output works when the schema carries domain meaning instead of merely declaring JSON types.
A field named count gives the model almost nothing.
A field described as Number of staging products whose description became blank gives it a decision boundary.
Even then, the application must validate the value.
In this example, the code could reject any affected_items value above the total number of records known to have failed, compare the extracted number with a deterministic parser, or require human approval before applying a mutation.
The schema reduces parsing uncertainty.
The validator reduces business risk.
Those jobs are different.
Code and Math Exposed the Model
The source post recommended skipping code and math.
My tests support that caution, although the failures were more useful than a generic warning.
I asked for a strict TypeScript function that returned true only when an unknown input was an object whose ok property was exactly true and whose error property was absent.
I also prohibited any.
The first answer avoided any, but it tested !obj.error.
That logic accepts an object whose error property exists with an empty string, null, or undefined value.
The prompt required the property to be absent.
I sharpened the requirement and enabled greedy sampling.
The second answer correctly used an ownership check, but it introduced this line:
const obj = input as any;
The prompt explicitly prohibited any.
Across 2 attempts, the model satisfied the property logic or the typing constraint, but it did not satisfy both at once.
The math test failed more visibly.
I wrote that an incident began at 03:12 and recovered at 06:40, while direct recovery work occupied 42 minutes inside that interval.
The first response invented an end time of 11:18 and reported a total duration of 11 hours and 18 minutes.
A more constrained prompt told it not to add time after 06:40.
The second response correctly calculated 208 minutes and 20.29%.

The model improved when the prompt removed interpretive freedom, but the first answers were still plausible enough to pass a casual glance.
These tests do not prove that fm always fails at code or math.
They prove that short, verifiable tasks can still require explicit constraints and external checks.
A local model removes network latency and token billing.
It does not remove review.
The Token Limit Had Already Changed
The source post stated that each session had a 4,096-token limit shared by the prompt, instructions, history, and answer.
That number did not match my build.
I generated 2 synthetic prompts and measured them with the current fm count-tokens command.
The first prompt counted 8,108 tokens and returned OK in 9.24 seconds.
The second counted 8,308 tokens and failed with this message:
Error: The session's transcript exceeded the model's context size.
An independent practical guide tested an 8,192-token context on an earlier macOS 27 build.
My result fits that neighborhood, but I would not hardcode 8,192 as a permanent product contract.
The reliable statement is narrower.
The build that I tested accepted 8,108 tokens and rejected 8,308 tokens on October 24, 2026.
This feature is changing fast enough that screenshots, blog posts, and even remembered flags can become stale between beta and release builds.
A production script should call fm count-tokens, test the installed CLI, and fail clearly when the local capability changes.
FM Serve Turns It Into Infrastructure
The most consequential command is not fm chat.
It is fm serve.
fm serve --host 127.0.0.1 --port 1976
That single command exposed 3 endpoints on my Mac:
GET /health
GET /v1/models
POST /v1/chat/completions
The health check reported that the system model was available.
A non-streaming Chat Completions request returned a normal response object with token usage and assistant content.
This means an existing tool that supports an OpenAI-style base URL can potentially use Apple's local model without a custom Swift integration.
The CLI matters because agents work better when apps expose a command surface that they can call, inspect, and test.
The server also accepted my request without authentication.
That behavior is convenient on localhost and dangerous on a network interface.
I would keep it bound to 127.0.0.1 or use the supported Unix socket mode.
The help output allows --host 0.0.0.0, but exposing an unauthenticated language model endpoint to the network is a bad default.
Any remote use needs an authenticated proxy, network restrictions, timeouts, request limits, and logging that does not leak prompt content.
The local license text on my Mac added another limit.
It restricted programmatic access to cases that Apple has "expressly permitted."
Apple documents scripting and ships fm serve, but the CLI terms did not define the full boundary of permitted programmatic use.
I would read those terms before a commercial integration and avoid treating an unofficial proxy as legal clearance.
The local API makes integration easy.
It also makes over-trust easy.
Builders Already Added the Missing Layers
Several projects around Apple's local model are not waiting for it to become smarter.
They are adding the layers that turn a model into something people can actually use.
Familiar Local wraps the Foundation Models framework in a lightweight chat application.
It binds its server to 127.0.0.1, keeps chat history in browser storage, and gives non-developers a normal window instead of a Swift project.
pi-apple-fm connects fm serve to the Pi coding agent as a model provider.
It can start the local server, check health, and expose Apple models in Pi's model picker.
Its README also describes beta behavior that no longer matches my 27.0.1 build, including a smaller context and the pcc model, which shows how quickly integrations can drift.
fm-proxy sits between ordinary OpenAI clients and Apple's server.
The project reports that some valid client requests need translation, automatic tool calling can fail silently, and a recursive schema can hang fm serve until restart.
It also raises the same programmatic-access concern found in the local license text.
apple-fm-audit adds a local web interface and SQLite logs for requests and responses.
That makes debugging possible, although storing full prompts creates a new local data-retention problem that the operator must manage.
The most interesting example is systemANE.
It uses a small calibrated classifier for fast, high-confidence decisions and sends only uncertain cases to fm serve.
The model becomes a second tier instead of the first and only authority.
That architecture fits the test results better than a general chatbot does.
Cheap deterministic logic handles what it can prove, the local model handles bounded ambiguity, and the workflow refuses or escalates the rest.
These projects are unofficial, target different macOS builds, and do not prove that every integration is safe or permitted.
They do show where the practical work is happening: interfaces, compatibility, observability, routing, and refusal paths.
Safe Uses Stay Bounded and Verifiable
fm already has a useful operating zone.
That zone is narrower than a general assistant and larger than a toy demo.
I would use it when all 5 conditions hold:
- The input stays short and bounded.
- The expected output stays narrow and preferably structured.
- A deterministic rule or a human can verify the answer.
- A wrong answer cannot immediately create an expensive or irreversible effect.
- The workflow has a safe fallback when the model or command is unavailable.
That includes local note summaries, content tagging, filename triage, metadata extraction, rewriting, intent classification, and draft suggestions.
Apple's WWDC demo used fm to classify draft and final files before a script copied or moved them.
I would keep the idea and add a dry run, an allowlist, a backup, validation of every returned path, and a separate confirmation before deletion.
I would not let this model approve payments, publish content, delete files, modify production data, or execute generated code without another control.
The same rule applies to a cloud model, but a built-in local command can feel safer than it is because privacy and correctness are separate properties.
On-device inference can protect data from a cloud round trip.
It cannot make the answer true.
The Limits Matter More Than the Price
The lack of a token bill is real, but the tool still has costs and constraints.
The on-device model showed brittle instruction following in my code test and brittle reasoning in my first math test.
The context remained small enough that long documents needed chunking or another model.
Private Cloud Compute appeared in Apple's WWDC presentation but did not appear in my release build's help.
My timing came from an M5 Mac, so it says nothing reliable about latency on an M1.
Apple supports M1 and later Macs, but supported does not mean equally fast.
Apple also says its intelligence models can require up to 8 GB of storage on many supported devices and up to 14 GB on newer hardware configurations.
The model has no per-token invoice, but it still consumes disk space, memory, battery, and compute.
Availability can also depend on language, region, and whether the model finished downloading.
A script must handle fm available returning something other than success.
The biggest limitation remains conceptual.
The CLI makes the model look like a deterministic Unix program, while the output still comes from a probabilistic model.
The CLI Changes More Than the Model
fm did not replace a frontier model on my Mac.
It became useful when I narrowed the task, described the schema, and kept a verifier outside the model.
It became dangerous when I treated valid JSON as validated truth.
Apple has still changed the baseline for Mac automation.
A compatible machine now ships with a local language model, a shell interface, structured generation, saved sessions, image inputs, and a Chat Completions server.
Developers no longer need to install a model runtime before trying a private local classification or extraction step.
The partial answer is enough.
Apple did not put a reliable agent in /usr/bin.
It put an LLM primitive there, and the next bug will come from the shell script that assumes those are the same thing.
Sources
- Alvaro Cintas, X post about the macOS 27 fm CLI
- Apple Developer, Foundation Models framework
- Apple WWDC26, Build AI-powered scripts with the fm CLI and Python SDK
- Apple Support, Get started with the next generation of Apple Intelligence
- FM(1) command manual
- fm-guide, independent tests and practical limitations
- The local
fm license --showoutput was captured on macOS 27.0.1 on October 24, 2026. - Familiar Local, a local chat interface for Foundation Models
- pi-apple-fm, an Apple Foundation Models provider for Pi
- fm-proxy, a compatibility layer for fm serve
- apple-fm-audit, a local proxy with SQLite request logs
- systemANE, a calibrated decision cascade that escalates to fm serve
Apple's
fmCLI lets you pipe files into structured JSON without installing anything, but valid JSON from a weak model can slip straight into production. The demo vs product checklist in the welcome kit shows you the 8 criteria that separate a convenient tool from something you can actually ship.
This post may contain affiliate links. If you click them, I might earn a small commission — costs you nothing, and helps me keep shipping quality articles every day for your reading pleasure.