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

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 lint --strict over the Packages/ and App/ directories before each push (fix issues with swift-format format --in-place --recursive Packages App).

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 docs/CONTRIBUTING.md for the architecture guide and layer definitions at the documented upstream baseline.

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–v6 ABI) · Native Plugins │
├──────────┬──────────┬───────────┬───────────────────┤
│ Identity │ Relay │ Tools │ Skills · Methods │
├──────────┴──────────┴───────────┴───────────────────┤
│ Sandbox VM (Alpine · Apple Containerization) │
│ vsock bridge · VirtioFS · per-agent isolation │
└─────────────────────────────────────────────────────┘

Most features are accessible through Settings… (⌘ ,).

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​

Plugins extend agent capabilities. They are native binaries that expose tools via the MCP protocol.

Quick Start​

# Scaffold a new Swift plugin
osaurus tools create MyPlugin --language 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​

The snippets below are illustrative sketches of each component's role, not literal declarations from the codebase — check the source for the real signatures.

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 (a class in the real codebase):

final class 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 the Server → API Reference tab for endpoint testing. Open Settings… (⌘ ,) and click Insights or Server (under Developer Tools).

Full Developer Tools guide →

Resources​

Osaurus Documentation​

External Documentation​

Community​

Security​

Reporting Vulnerabilities​

See docs/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.