Using Apple Intelligence’s Default System Model To Build a Chat Command Line Tool

Here we create a simple command line chat tool. The LLM specific code can also be used in iOS, iPadOS, and macOS applications. This chat tool will use the local system LLM for simple queries and will transparently call a more capable model on Apple’s servers in a secure and privacy preserving sandbox.

The following Swift package manifest defines an executable command-line program named chattool designed to run on macOS. The tool relies on Apple’s swift-argument-parser package to process command-line arguments.

Package.swift:

 1 // swift-tools-version: 6.2
 2 import PackageDescription
 3 
 4 let package = Package(
 5     name: "ChatTool",
 6     platforms: [.macOS(.v26)],   // macOS 15/16 is fine too
 7     products: [
 8         .executable(name: "chattool", targets: ["ChatTool"])
 9     ],
10     dependencies: [
11         // ⬇︎ Apple’s official argument-parsing package
12         .package(url: "https://github.com/apple/swift-argument-parser.git",
13                  from: "1.3.0")
14     ],
15     targets: [
16         .executableTarget(
17             name: "ChatTool",
18             // expose the ArgumentParser product to the target
19             dependencies: [
20                 .product(name: "ArgumentParser", package: "swift-argument-parser")
21                 // FoundationModels is an Apple framework, no SPM entry needed
22             ],
23             path: "Sources/ChatTool"          // adjust if your path differs
24         )
25     ]
26 )

ChatTool.swift:

This Swift code implements a command-line chat interface that interacts directly with Apple’s native FoundationModels framework. Upon launch, it verifies the system’s default language model is available, initializes a LanguageModelSession with a hard-coded system prompt and temperature, and then enters a read-evaluate-print loop. The program continuously accepts user input from the console and sends it to the language model for processing until the user quits.

The core of the implementation leverages modern Swift concurrency (async/await) to handle the model’s output as an asynchronous stream. For each user prompt, it iterates through the text fragments as they are generated by session.streamResponse, writing only the new characters to standard output to create a real-time, typewriter-like effect. To enhance usability, it uses a DispatchSource to set up a signal handler for SIGINT (Ctrl+C), allowing a user to cancel the current in-progress stream from the model without terminating the entire chat application.

 1 import Foundation
 2 import FoundationModels
 3 import Dispatch
 4 
 5 @main
 6 struct ChatCLI {
 7     static func main() async throws {
 8         // Hard-coded defaults
 9         let temperature  = 0.2
10         let sysPrompt    = "You are a helpful assistant."
11 
12         // Verify model
13         let model = SystemLanguageModel.default
14         guard model.isAvailable else {
15             throw RuntimeError("Model unavailable: \(model.availability)")
16         }
17 
18         let session = LanguageModelSession(instructions: sysPrompt)
19         print("Temperature: \(temperature)")
20         print("System Prompt: \(sysPrompt)")
21         let options = GenerationOptions(temperature: temperature)
22 
23         print("Apple-Intelligence chat (streaming, T=0.2). Type /quit to exit.\n")
24 
25         while true {
26             print("Enter your message: ", terminator: "")
27             guard let prompt = readLine(strippingNewline: true) else { break }
28             if prompt.isEmpty || prompt == "/quit" { break }
29 
30             var previous = ""       // text already printed
31 
32             let task = Task {
33                 for try await part in session.streamResponse(to: prompt, options: op\
34 tions) {
35                     let delta = part.dropFirst(previous.count) // new characters only
36                     if !delta.isEmpty {
37                         FileHandle.standardOutput.write(Data(delta.utf8))
38                         fflush(stdout)
39                         previous = part
40                     }
41                 }
42                 print() // newline when complete
43             }
44 
45             // ^C cancels the streaming task
46             signal(SIGINT, SIG_IGN)
47             let sigSrc = DispatchSource.makeSignalSource(signal: SIGINT, queue: .mai\
48 n)
49             sigSrc.setEventHandler { task.cancel() }
50             sigSrc.resume()
51             defer { sigSrc.cancel() }
52 
53             _ = try await task.value
54         }
55     }
56 }
57 
58 /// Simple error wrapper
59 struct RuntimeError: Error, CustomStringConvertible {
60     let description: String
61     init(_ msg: String) { description = msg }
62 }

Here are the first few lines of output given the prompt Describe the math for calculating the orbit of Jupiter, then write a very short design for a Python script:

 1 $ swift run
 2 [1/1] Planning build
 3 Building for debugging...
 4 [1/1] Write swift-version-39B54973F684ADAB.txt
 5 Build of product 'chattool' complete! (0.16s)
 6 Temperature: 0.2
 7 System Prompt: You are a helpful assistant.
 8 Apple-Intelligence chat (streaming, T=0.2). Type /quit to exit.
 9 
10 Enter your message: Describe the math for calculating the orbit of Jupiter, then wri\
11 te a very short design for a Python script
12 Calculating the orbit of Jupiter involves solving Kepler's laws of planetary motion,\
13  which describe the elliptical orbits of planets around the Sun. The key equations i\
14 nvolve gravitational forces and conservation laws. Here's a brief overview of the ma\
15 th involved:
16 
17  ### Key Concepts:
18 
19 1. **Kepler's Laws:**
20    - **First Law (Law of Ellipses):** Planets move along ellipses with the Sun at on\
21 e focus.
22    - **Second Law (Law of Equal Areas):** A line segment joining a planet and the Su\
23 n sweeps out equal areas during equal intervals of time.
24    - **Third Law (Law of Harmonies):** The square of the orbital period (\(T\)) is p\
25 roportional to the cube of the semi-major axis (\(a\)): \(T^2 = \frac{4\pi^2}{GM}a^3\
26 \).
27 
28 2. **Gravitational Force:**
29    - The gravitational force between two masses (\(m_1\) and \(m_2\)) is given by Ne\
30 wton's law: \(F = G \frac{m_1 m_2}{r^2}\), where \(G\) is the gravitational constant\
31  and \(r\) is the distance between centers.
32 
33 3. **Centripetal Force:**
34    - For circular orbits, centripetal force equals gravitational force: \(F = \frac{\
35 mv^2}{r}\).