Skip to main content

Building from Source

Everything you need to build Osaurus from source, contribute, and understand the architecture.

Why Contribute to Osaurus?

Osaurus is built with native Swift—not Python, not Electron, not wrapped web tech. This matters:

AspectPython/ElectronNative Swift
PerformanceInterpreter overhead, GC pausesCompiled, ARC memory management
Startup200ms+ for Python runtimeUnder 10ms binary load
Memory50MB+ baselineMinimal footprint
IntegrationBridging requiredNative macOS APIs

Contributing to Osaurus means building production-quality tools that developers actually want to use daily.

Getting Started

Prerequisites

  • macOS 15.5+ on Apple Silicon
  • Xcode 16.4+ with Command Line Tools
  • Swift 6.0+
  • Git

Clone and Build

# Clone the repository
git clone https://github.com/osaurus-ai/osaurus.git
cd osaurus

# Open in Xcode
open osaurus.xcworkspace

# Build and run the "osaurus" scheme
# Press ⌘R or Product → Run

Git hooks (lefthook)

Install lefthook so the codebase stays consistently formatted:

brew install lefthook
lefthook install

This installs a pre-push hook that runs swift-format over the Packages/ directory before each push.

Project structure

osaurus/
├── App/ # macOS app target (SwiftUI entry point, assets, entitlements)
├── Packages/
│ ├── OsaurusCore/ # Core library — all app logic
│ │ ├── Models/ # Data types, DTOs, configuration stores
│ │ ├── Services/ # Business logic (actors and stateless types)
│ │ ├── Managers/ # UI-facing state holders (@MainActor, observable)
│ │ ├── Views/ # SwiftUI views, organized by feature
│ │ ├── Networking/ # HTTP server, routing, relay
│ │ ├── Storage/ # SQLite databases
│ │ ├── Identity/ # Cryptographic identity and access keys
│ │ ├── Tools/ # MCP tools, plugin ABI, tool registry
│ │ ├── Folder/ # Working-folder context, file ops, batch tool
│ │ ├── Utils/ # Cross-cutting utilities
│ │ └── Tests/ # Unit and integration tests
│ ├── OsaurusCLI/ # CLI (osaurus command)
│ └── OsaurusRepository/ # Plugin registry and installation
├── docs/ # Feature guides and documentation
├── scripts/ # Build, release, and benchmark scripts
├── sandbox/ # Sandbox VM Dockerfile
└── assets/ # DMG packaging assets

See CONTRIBUTING.md for the architecture guide and layer definitions.

Running in Development

  1. Select the osaurus scheme in Xcode
  2. Choose "My Mac" as the run destination
  3. Press ⌘R to build and run
  4. View logs in Xcode's console

Architecture overview

┌─────────────────────────────────────────────────────┐
│ The Harness │
├──────────┬──────────┬────────────┬──────────────────┤
│ Agents │ Memory │ Agent Loop │ Automation │
├──────────┴──────────┴────────────┴──────────────────┤
│ MCP Server + Client │
├──────────┬──────────┬───────────┬───────────────────┤
│ MLX │ OpenAI │ Anthropic │ Ollama / Others │
│ Runtime │ API │ API │ │
├──────────┴──────────┴───────────┴───────────────────┤
│ Plugin System (v1 / v2 ABI) · Native Plugins │
├──────────┬──────────┬───────────┬───────────────────┤
│ Identity │ Relay │ Tools │ Skills · Methods │
├──────────┴──────────┴───────────┴───────────────────┤
│ Sandbox VM (Alpine · Apple Containerization) │
│ vsock bridge · VirtioFS · per-agent isolation │
└─────────────────────────────────────────────────────┘

Most features are accessible through the Management window (⌘ ⇧ M).

Contributing

Finding Issues

Start with issues labeled "good first issue":

Browse Good First Issues →

Pull Request Process

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/my-feature
  3. Make your changes with tests
  4. Run SwiftLint: swiftlint
  5. Submit a PR with a clear description

Commit Messages

Follow conventional commits:

feat: Add support for new model architecture
fix: Resolve memory leak in streaming responses
docs: Update API documentation
test: Add integration tests for tool calling
refactor: Simplify router implementation

Code Style

  • Use descriptive names
  • Document public APIs
  • Keep functions focused and small
  • Prefer immutability (let over var)
  • Follow existing patterns in the codebase

Building Plugins

Osaurus has a powerful plugin system for extending AI agent capabilities. Plugins are native binaries that expose tools via the MCP protocol.

Quick Start

# Scaffold a new Swift plugin
osaurus tools create MyPlugin --swift
cd MyPlugin

# Build
swift build -c release

# Install locally
osaurus tools install .

# Or use dev mode for hot reload
osaurus tools dev com.example.myplugin

Plugin Architecture

Plugins use a C ABI for compatibility:

@_cdecl("osaurus_plugin_entry")
func osaurusPluginEntry() -> UnsafeMutableRawPointer {
// Return function table
}

See the Plugin Authoring Guide for complete documentation.

Why Native Plugins?

Python-based MCP tools (like those using uv) have significant overhead:

  • ~200ms startup for Python interpreter
  • Higher memory due to GC and runtime
  • GIL limitations for parallelism

Native Swift/Rust plugins:

  • Under 10ms load time
  • Minimal memory footprint
  • True parallelism

This matters when AI agents execute dozens of tool calls per session.

Testing

Unit Tests

# Run all tests
xcodebuild test -workspace osaurus.xcworkspace -scheme osaurus

# Run specific test
xcodebuild test -workspace osaurus.xcworkspace -scheme osaurus \
-only-testing:OsaurusTests/MLXServiceTests

Integration Tests

# test_integration.py
import requests

def test_chat_completion():
response = requests.post(
"http://localhost:1337/v1/chat/completions",
json={
"model": "gemma-4-e2b-it-4bit",
"messages": [{"role": "user", "content": "Hello"}]
}
)
assert response.status_code == 200
assert "choices" in response.json()

Performance Testing

# Run benchmark suite
./scripts/run_bench.sh

# Profile with Instruments
xcrun xctrace record --template "Time Profiler" --launch osaurus

Key Components

MLXService

Handles model loading and inference:

class MLXService {
func loadModel(_ name: String) async throws -> MLXModel
func generate(prompt: String, maxTokens: Int) -> AsyncStream<String>
}

PluginManager

Manages tool plugins:

class PluginManager {
func loadPlugin(at path: URL) throws
func invoke(tool: String, arguments: [String: Any]) async throws -> Any
}

HTTPHandler

Processes API requests:

struct HTTPHandler: ChannelInboundHandler {
func channelRead(context: ChannelHandlerContext, data: NIOAny)
}

Debugging

Common Issues

Model loading fails:

// Check model path
print(modelPath.path)

// Verify required files
let required = ["config.json", "model.safetensors"]

Plugin won't load:

# Check code signature
codesign -v libMyPlugin.dylib

# Check for missing symbols
nm -g libMyPlugin.dylib | grep osaurus_plugin_entry

Memory issues:

// Monitor memory
let memory = ProcessInfo.processInfo.physicalMemory
print("Available: \(memory / 1024 / 1024 / 1024)GB")

Debug Logging

#if DEBUG
Logger.shared.level = .trace
#endif

Developer tools

Osaurus has built-in dev tools — Insights for live request monitoring and Server Explorer for endpoint testing. Open the Management window (⌘ ⇧ M) and click Insights or Server.

Full Developer Tools guide →

Resources

Osaurus Documentation

External Documentation

Community

Security

Reporting Vulnerabilities

See SECURITY.md for reporting security issues.

Best Practices

  • Validate all inputs
  • Sanitize file paths in plugins
  • Use secure random for IDs
  • Log security-relevant events

Related:

To contribute, start with good first issues on GitHub.