How to use the Apple Foundation Model from AppleScript
July 2, 2026 · View on GitHub
Call Apple's on-device Foundation Model from AppleScript via do shell script + curl. 100% on-device - perfect for Shortcuts, Automator, and macOS system automation.
Runnable scripts + tests: Arthur-Ficial/apfel-guides-lab/scripts/applescript.
Prerequisites
- macOS 26+ Tahoe, Apple Silicon, Apple Intelligence enabled
brew install apfel jqapfel --serverunning (port11434)- AppleScript (ships with macOS)
AppleScript has no native HTTP client; the idiomatic pattern is do shell script "curl ...".
1. One-shot
set payload to "{\"model\":\"apple-foundationmodel\",\"messages\":[{\"role\":\"user\",\"content\":\"In one sentence, what is the Swift programming language?\"}],\"max_tokens\":80}"
set response to do shell script "curl -sS http://localhost:11434/v1/chat/completions -H 'Content-Type: application/json' -d " & quoted form of payload & " | jq -r '.choices[0].message.content'"
return response
Real output:
Swift is a modern, open-source programming language developed by Apple for developing iOS, macOS, watchOS, and tvOS applications.
Lab script: 01_oneshot.applescript.
2. Streaming
AppleScript doesn't stream natively - do shell script returns the final string only. Streaming happens inside the shell pipeline:
set shellCmd to "curl -sS -N http://localhost:11434/v1/chat/completions " & ¬
"-H 'Content-Type: application/json' " & ¬
"-d '{\"model\":\"apple-foundationmodel\",\"messages\":[{\"role\":\"user\",\"content\":\"List three Apple silicon chips, one per line.\"}],\"max_tokens\":80,\"stream\":true}' " & ¬
"| while IFS= read -r line; do " & ¬
" line=\"${line#data: }\"; " & ¬
" [ -z \"$line\" ] || [ \"$line\" = \"[DONE]\" ] && continue; " & ¬
" content=$(printf '%s' \"$line\" | jq -r '.choices[0].delta.content // empty' 2>/dev/null || true); " & ¬
" [ -n \"$content\" ] && printf '%s' \"$content\"; " & ¬
" done; echo"
return do shell script shellCmd
Real output:
Apple M1
Apple M1 Pro
Apple M1 Max
Lab script: 02_stream.applescript.
3. JSON mode
set payload to "{\"model\":\"apple-foundationmodel\",\"messages\":[{\"role\":\"user\",\"content\":\"Return JSON with fields chip, year, cores. Describe the Apple M1 chip. Return ONLY JSON.\"}],\"response_format\":{\"type\":\"json_object\"},\"max_tokens\":120}"
set cmd to "curl -sS http://localhost:11434/v1/chat/completions -H 'Content-Type: application/json' -d " & quoted form of payload & " | jq -r '.choices[0].message.content' | sed -E 's/^```(json)?//; s/```$//' | tr -d '\\r' | jq '.'"
return do shell script cmd
Real output (note AppleScript collapses newlines when returning from do shell script):
{ "chip": "Apple M1", "year": 2020, "cores": 8}
Lab script: 03_json.applescript.
4. Error handling
set cmd to "tmp=$(mktemp); status=$(curl -sS -o \"$tmp\" -w '%{http_code}' http://localhost:11434/v1/embeddings -H 'Content-Type: application/json' -d '{\"model\":\"apple-foundationmodel\",\"input\":\"apfel runs 100% on-device.\"}'); if [ \"$status\" -ge 400 ]; then msg=$(jq -r '.error.message // empty' \"$tmp\" 2>/dev/null || true); echo \"Got expected error: HTTP $status - ${msg:-see response}\"; else echo \"unexpected success: HTTP $status\"; cat \"$tmp\"; fi; rm -f \"$tmp\""
return do shell script cmd
Real output:
Got expected error: HTTP 501 - Embeddings not supported by Apple's on-device model.
Lab script: 04_errors.applescript.
5. Tool calling (delegate to Bash)
Tool calling from pure AppleScript is not idiomatic - the required JSON escaping becomes unreadable fast. The correct AppleScript pattern is to delegate complex shell work to a script file. Reuse the Bash tool-calling script:
set scriptPath to POSIX path of ((path to me as text) & "::") & "../bash-curl/05_tools.sh"
return do shell script "bash " & quoted form of scriptPath
Real output:
The current temperature in Vienna is 14 degrees Celsius.
Lab script: 05_tools.applescript. For production tool-calling, use python.md or nodejs.md.
6. Real example - summarize a file
AppleScript cannot read stdin inside do shell script, so pass a file path on argv:
on run argv
if (count of argv) < 1 then error "usage: osascript 06_example.applescript <path-to-file>"
set filePath to item 1 of argv
set cmd to "text=$(cat " & quoted form of filePath & "); " & ¬
"payload=$(jq -n --arg text \"$text\" '{model:\"apple-foundationmodel\", messages:[{role:\"system\",content:\"You are a concise summarizer. Reply with one short paragraph.\"},{role:\"user\",content:(\"Summarize:\\n\\n\" + $text)}], max_tokens:150}'); " & ¬
"curl -sS http://localhost:11434/v1/chat/completions -H 'Content-Type: application/json' -d \"$payload\" | jq -r '.choices[0].message.content'"
return do shell script cmd
end run
Usage: osascript 06_example.applescript /path/to/file.txt
Real output:
In November 2020, Apple released the M1 chip, the first ARM-based system-on-a-chip for Mac computers. The chip features an 8-core CPU with four performance and four efficiency cores, an integrated GPU with up to 8 cores, and a unified CPU, GPU, memory, and neural engine on a single die. The M1 chip offers significant performance-per-watt improvements over the Intel chips it replaced.
Lab script: 06_example.applescript.
Shortcuts integration
Paste any of these into a Run AppleScript action in Shortcuts. Combine with Get Contents of Clipboard to summarize whatever you just copied - all on-device, no network call.
Troubleshooting
- Collapsed newlines -
do shell scriptreturns a single AppleScript string with all newlines folded. That's a Classic macOS quirk, not an apfel issue. - Stdin not flowing - AppleScript cannot pipe its own stdin into
do shell script. Pass file paths viaon run argvinstead. - Escaping - always use
quoted form offor any user-supplied string before embedding in a shell command.
Tested with
- apfel v1.0.3 / macOS 26.3.1 Apple Silicon (original capture; the CLI and HTTP surfaces used here are release-gated by apfel's test suite on every version)
- osascript / AppleScript (system) / jq 1.7
- Date: 2026-04-16
Runnable tests: tests/test_applescript.py.