A lightweight, open-source Swift CLI for running Apple Foundation Models and MLX models on your Mac.
- macOS 26+ (Tahoe)
- Apple Silicon (M1 or later)
- Xcode 26+
- Swift 6.0+
Foundation Models requires Apple Intelligence to be enabled. MLX mode works on any Apple Silicon Mac.
brew install techopolis/tap/perspectiveThe quickest way to install without Homebrew:
curl -fsSL https://raw.githubusercontent.com/techopolis/PerspectiveCLI/main/scripts/remote-install.sh | bashDownload the latest release archive from Releases, then:
tar xzf perspective-cli-*.tar.gz
cd perspective-cli-*
sudo ./install.shThis installs to /usr/local/bin (requires sudo because the directory is owned by root on macOS). If /usr/local/bin isn't on your PATH, the script will tell you how to add it.
To uninstall:
sudo ./install.sh --uninstallgit clone https://github.com/your-username/PerspectiveCLI.git
cd PerspectiveCLI
./build.sh
swift run PerspectiveCLITo create a release archive:
./build.sh distRun with --prompt for one-shot mode (no REPL, clean output for piping):
perspective --fm --prompt "What is Swift?"
perspective --mlx --prompt "Hello"
perspective --mlx --mlx-model mlx-community/gemma-3-4b-it-4bit --prompt "Hi"
perspective --temperature 0.5 --system "Be brief" --prompt "Explain recursion"| Argument | Short | Value | Description |
|---|---|---|---|
--fm |
Use Foundation Models backend | ||
--mlx |
Use MLX backend | ||
--model |
-m |
<model-id> |
Set MLX model |
--prompt |
-p |
<text> |
Send prompt and exit (one-shot mode) |
--temperature |
-t |
<float> |
Set temperature (FM: 0.0-1.0, MLX: 0.0-2.0) |
--stream |
-s |
Enable streaming output (FM) | |
--system |
<text> |
Set a custom system prompt | |
--tools |
Enable tool calling (FM) | ||
--help |
-h |
Show usage help |
Without --prompt, arguments pre-configure the interactive REPL:
perspective --mlx # enter REPL with MLX pre-selected
perspective --fm --tools # enter REPL with FM + tools enabledType messages to chat. Use slash commands to control the CLI:
| Command | Description |
|---|---|
/fm |
Switch to Foundation Models backend |
/mlx |
Switch to MLX backend |
/mlx-model <id> |
Set MLX model (e.g. mlx-community/gemma-3-4b-it-4bit) |
/temperature <n> |
Set temperature (FM: 0.0-1.0, MLX: 0.0-2.0, default: 0.7) |
/stream |
Toggle streaming (FM only) |
/reset |
Reset conversation |
Tools are disabled by default. Enable them for the FM backend:
| Command | Description |
|---|---|
/tools |
Show tool status and list registered tools |
/tools enable |
Enable tool calling (FM only) |
/tools disable |
Disable tool calling |
| Command | Description |
|---|---|
/system <prompt> |
Set a custom system prompt |
/system |
Show current custom system prompt |
/system default |
Show the built-in default system prompt |
/system clear |
Clear custom system prompt |
| Command | Description |
|---|---|
/help |
Show help |
/quit, /exit |
Exit |
[FM] You: What is iOS?
[FM] Assistant: iOS is Apple's mobile operating system...
[FM] You: /tools enable
[OK] Tools enabled
[FM] You: What's the weather in San Francisco?
[Tool] getWeather: San Francisco
[FM] Assistant: The current weather in San Francisco is 72°F and sunny.
[FM] You: /mlx
[OK] Switched to MLX backend
[MLX:gemma-3-1b-it-qat-4bit] You: Tell me a joke
[MLX] Assistant: Why do programmers prefer dark mode? ...
- Create a tool in
Sources/PerspectiveCLI/Tools/:
import Foundation
import FoundationModels
struct MyCustomTool: Tool {
let name = "myTool"
let description = "Description of what your tool does."
@Generable
struct Arguments {
@Guide(description: "Parameter description.")
var query: String
}
func call(arguments: Arguments) async throws -> String {
return "Result for: \(arguments.query)"
}
}- Register it in
Sources/PerspectiveCLI/Tools/ToolRegistry.swift:
private init() {
register(ExampleWeatherTool())
register(MyCustomTool())
}- Build and run. Enable tools with
/tools enableto use them.
Sources/PerspectiveCLI/
├── PerspectiveCLI.swift # Entry point + chat loop + commands
├── Backends/
│ ├── FoundationModelsBackend.swift # Apple FM with native tool calling
│ └── MLXBackend.swift # MLX open-weight models via mlx-swift
├── Tools/
│ ├── ToolRegistry.swift # Central tool registry
│ └── ExampleWeatherTool.swift # Example tool (mock weather data)
└── Models/
├── CLIModels.swift # In-memory conversation tracking
└── FoundationModelCoordinator.swift
- FM backend: Tools are passed to
LanguageModelSessionwhich handles calling them natively. Only active when tools are enabled. - MLX backend: Runs open-weight models from HuggingFace via mlx-swift. Models are downloaded and cached on first use. Supports both LLM and VLM models.
- ToolRegistry: Register a tool once, it's available to both backends.
MIT License. See LICENSE for details.
