Turn natural language into CLI commands using Apple's on-device AI, powered by OpenCode.
What is this?
LocalCode is a proof-of-concept that integrates Apple Foundation Models (AFM) with OpenCode as a local AI provider. Tell it what you want in plain English, it suggests the right command via tool calls, and you approve before execution.
All AI processing happens locally on your Mac. No cloud, no data leaving your machine.
Requirements
- Apple Silicon Mac (M1/M2/M3/M4)
- macOS 26+
- Xcode 26+ (for building the Swift helper)
- Bun 1.3+
- Node 18+ (for OpenCode and npm)
Architecture
LocalCode/
├── LocalCode/Sources/afmhelper/ # Swift AFM helper
│ └── main.swift # Apple FoundationModels integration
├── start-afm-server.sh # HTTP middleware (Bun)
├── setup-localcode.sh # One-command setup script
├── pre-commit.sh # Pre-commit hook with tests
├── test-prompts.sh # Prompt test suite
└── docs/ # VitePress documentation site
Latest Release: v0.0.1-alpha
No fork needed - uses global OpenCode with provider config in ~/.config/opencode/opencode.json
Flow:
- AFM Server wraps Swift helper with OpenAI-compatible API
- OpenCode uses AFM as a provider via
@ai-sdk/openai-compatible - AFM returns command suggestions as tool calls
- OpenCode shows command approval UI → user approves → command executes
Quick Start
Option 1: Makefile (Recommended)
git clone https://github.com/localcodeai/localcode.git cd localcode make run # Install + Start server opencode # Select "LocalCode AFM" provider via /models
Option 2: Step by Step
git clone https://github.com/localcodeai/localcode.git cd localcode make install # Build Swift helper + configure OpenCode make start # Start AFM server opencode # Select "LocalCode AFM" provider via /models
Option 3: Manual
git clone https://github.com/localcodeai/localcode.git cd localcode # Build Swift helper cd LocalCode/Sources/afmhelper swiftc -o afmhelper main.swift -framework FoundationModels -target arm64-apple-macosx26.0 cd ../.. # Configure OpenCode manually (see ~/.config/opencode/opencode.json) # Start server ./start-afm-server.sh & opencode
How It Works
You: "list all python files in this directory"
OpenCode (AFM): [Tool Call: bash { command: "find . -name '*.py'" }]
↑ Approval UI appears with approve/reject buttons
User: clicks approve
OpenCode: executes find . -name '*.py'
Output: ./file1.py
./subdir/file2.py
AFM acts as a command translator - it takes natural language and produces shell commands as tool calls that OpenCode can display with approval UI.
Example Commands to Try
File Operations:
- "list all python files"
- "find all files named hello"
- "show me the largest files in this directory"
- "count all files in this directory"
System & Network:
- "check if port 8080 is in use"
- "show git status"
Search:
- "grep for hello in this directory"
Raycast Integration
Add LocalCode as a Raycast Script Command for quick access from anywhere on your Mac:
- Open Raycast Settings → Script Commands
- Click Add Script Directory
- Select
localcode/raycast-extension/scripts/ - Type "LocalCode" in Raycast to use
The Raycast command:
- Enter a description like "list all python files"
- Command is generated and copied to clipboard
- Paste in terminal to run
Requires the AFM server running (make start).
Testing
Makefile Commands
make test # Run prompt test suite (10 cases) make server-test # Run server curl tests make pre-commit # Run all checks
Manual Testing
# Check server curl http://localhost:8080/v1/models # Test tool call curl -X POST http://localhost:8080/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{"model":"afm","messages":[{"role":"user","content":"hello"}]}'
Test Coverage
- File operations (list, filter, size)
- Search commands (grep, find)
- System commands (git, port check)
- Count/stats (files, lines)
- Simple commands (echo)
Project Status
Working:
- ✅ AFM server with OpenAI-compatible API
- ✅ Tool call responses with description field for OpenCode bash tool
- ✅ SSE streaming support (chunk sequence for tool_calls)
- ✅ OpenCode provider integration via
@ai-sdk/openai-compatible - ✅ Non-streaming mode (set
stream: falsein provider config) - ✅ Command approval UI displays correctly
- ✅ Shell prefix stripping for multi-line commands
Known Limitations:
- Streaming mode with tool_calls may cause issues in some OpenCode configurations
- Non-streaming mode recommended for stable behavior
Installation
Setup Script (Recommended)
git clone https://github.com/localcodeai/localcode.git
cd localcode
./setup-localcode.shThis installs:
localcode-afmcommand to start the server- OpenCode provider configuration
Manual Setup
git clone https://github.com/localcodeai/localcode.git cd localcode ./start-afm-server.sh & # Then configure OpenCode provider manually (see Quick Start)
Development
Run pre-commit hook manually:
Or install as git hook:
cp pre-commit.sh .git/hooks/pre-commit && chmod +x .git/hooks/pre-commit
git config core.hooksPath .git/hooksWhy does this exist?
Apple's Foundation Models framework is new and under-documented. This project proves it's viable for CLI tools and provides a reference implementation for others building on AFM with OpenCode.
Contributing
POCs have rough edges. Contributions welcome:
- Fork and create a feature branch
- Make your changes
- Open a PR
License
MIT