Contributing to Osaurus

May 19, 2026 · View on GitHub

Thanks for your interest in contributing! We welcome bug reports, feature ideas, documentation improvements, and code contributions.

Please take a moment to read this guide to help streamline the process for everyone.

Ways to contribute

  • Report bugs and regressions
  • Suggest enhancements and new features
  • Improve documentation and examples
  • Triage issues and review pull requests
  • Implement fixes and features

Getting started (development)

Requirements:

  • macOS 15.5+
  • Apple Silicon (M1 or newer)
  • Xcode 16.4+

Build and run:

  1. Open osaurus.xcworkspace in Xcode 16.4+
  2. Select the osaurus target and press Run
  3. In the app UI, choose a port (default 1337), then Start
  4. Download a model from the Model Manager to generate text locally

Project layout and API overview are in README.md. For a complete feature inventory, see FEATURES.md.

Architecture guide

Layer definitions

The core library (Packages/OsaurusCore/) follows a layered architecture. Each layer has a specific role and set of rules.

Models — Pure data. No logic, no side effects, no singletons.

  • Structs, enums, Codable types, API DTOs, configuration types
  • Organized into domain subfolders: API/, Chat/, Agent/, Configuration/, Method/, Plugin/, Memory/, Voice/, Theme/, Tool/, Work/, Schedule/, Watcher/
  • Rule: if it has @Published or static let shared, it does not belong here

Services — Business logic. Not observable. Not UI-aware.

  • Swift actor for concurrent work (ChatEngine, MemoryService)
  • Stateless struct for pure functions (Router, PromptBuilder)
  • Organized into domain subfolders: Chat/, Context/, Inference/, Method/, ModelRuntime/, MCP/, Memory/, Sandbox/, Skill/, Tool/, Voice/, Provider/, Plugin/, Keychain/
  • Rule: services do NOT conform to ObservableObject or @Observable
  • Rule: if it drives UI directly, it is a Manager, not a Service
  • Naming: suffix with Service or Engine

Managers — UI state. Observable. Main actor.

  • @MainActor classes with @Observable (preferred) or ObservableObject
  • Own published properties that SwiftUI views bind to
  • Coordinate Services, Stores, and other Managers
  • Grouped into Chat/, Model/, Plugin/ subfolders; remaining at root
  • Rule: managers always run on @MainActor
  • Naming: suffix with Manager

Views — SwiftUI. Organized by feature, not by type.

  • Each feature has its own subfolder: Chat/, Agent/, Model/, Plugin/, Memory/, Voice/, Work/, Settings/, Theme/, Skill/, Toast/, Schedule/, Watcher/, Identity/, Sandbox/, Insights/, Onboarding/, Management/
  • Common/ holds only generic, reusable primitives (buttons, layouts, glass effects)
  • A view that only makes sense in one feature goes in that feature's folder

Networking — HTTP server, NIO, routing, relay tunnels, server controller.

Storage — SQLite databases and file persistence.

Tools — MCP tool definitions, registry, and plugin ABI.

Identity — Cryptographic keys and access control.

Utils — Cross-cutting helpers with no domain knowledge.

Where to put new code

You're adding...Put it in...
A new data type or DTOModels/{domain}/
Backend logic (no UI)Services/{domain}/ as an actor
UI state that views observeManagers/ as @MainActor observable class
A new screen or panelViews/{feature}/
A reusable UI widgetViews/Common/
A new MCP toolTools/
A new testTests/{matching-source-directory}/

Naming conventions

PatternName suffixExample
Observable UI state holderManagerAgentManager, ToastManager
Actor-based business logicService or EngineMemoryService, ChatEngine
Stateless logicService or nonePromptBuilder, SearchService
JSON file persistenceStoreAgentStore, ScheduleStore
SQLite persistenceDatabaseMemoryDatabase, MethodDatabase
SwiftUI viewViewChatView, AgentsView
Test fileTests suffixChatEngineTests, MemoryTests

Tool calling (developer notes)

  • OpenAI‑compatible DTOs live in Models/API/OpenAIAPI.swift (Tool, ToolFunction, ToolCall, DeltaToolCall, etc.).
  • Prompt templating is handled internally by vmlx-swift. Osaurus does not assemble prompts manually.
  • Tool-call detection lives entirely in vmlx-swift's BatchEngine.generate, which emits authoritative Generation.toolCall(ToolCall) events. Osaurus's GenerationEventMapper simply translates each one into a ModelRuntimeEvent.toolInvocation.
  • Streaming tool calls reach the wire as OpenAI-style deltas inside Networking/HTTPHandler.swift (and the equivalent Anthropic / Open Responses writers in Models/Chat/ResponseWriters.swift).

Development workflow

  • Create a feature branch from main (e.g., feat/..., fix/..., docs/...)
  • Write clear, focused commits; prefer Conventional Commits where practical
  • Open a pull request early for feedback if helpful
  • Keep PRs small and focused; describe user-facing changes and test steps

Code style

  • Follow standard Swift naming and clarity guidelines
  • Prefer clear, multi-line code over terse one-liners
  • Add doc comments for non-obvious logic; avoid redundant comments
  • Handle errors explicitly and avoid swallowing exceptions

Dependencies

The workspace lockfile at osaurus.xcworkspace/xcshareddata/swiftpm/Package.resolved is the single source of truth for pinned dependency versions. Xcode updates this file automatically when you add, remove, or update a package. Commit the changed Package.resolved alongside your other changes.

OsaurusCore uses a single consolidated vmlx-swift pin for local inference: MLX, MLXLMCommon, MLXLLM, MLXVLM, Tokenizers, Jinja, chat templates, reasoning parsers, cache layers, media plumbing, and runtime MTP policy all come from that package. Do not add separate root dependencies on mlx-swift, vmlx-swift-lm, swift-transformers, or Jinja for inference work.

SwiftPM mirrors still live in both osaurus.xcworkspace/xcshareddata/swiftpm/configuration/ and App/osaurus.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/configuration/. They only protect transitive non-inference packages that still reference the Hugging Face package identities. The vendored tokenizer/template/runtime helper modules are prefixed inside vmlx-swift itself (VMLXTokenizers, VMLXJinja, VMLXEventSource, VMLXHuggingFace, VMLXHub, VMLXGeneration, VMLXModels), so Osaurus must not add package-level moduleAliases for the inference graph. yyjson remains the single shared C package dependency because linking both a vendored copy and the transitive upstream copy exports duplicate yyjson_* symbols. Keep the two mirror files in sync until upstream transitive packages no longer refer to the Hugging Face package identities.

swift-sdk also pulls EventSource transitively. OsaurusCore declares the same package at the root with the AsyncHTTPClient trait enabled so EventSource's conditional AsyncHTTPClient transport compiles with declared NIO and shim dependencies when the consolidated MLX/Numerics graph is present. This is a non-inference graph fix; do not replace it with tokenizer/runtime roots.

CI resolves dependencies from this committed lockfile and builds with -disableAutomaticPackageResolution, so it uses the exact same versions you tested locally. If the resolved file is stale relative to Package.swift, CI will fail rather than silently pulling different versions.

Package-level resolved files (e.g. Packages/*/Package.resolved) are gitignored and not used by CI.

Testing

  • Add or update tests in Packages/OsaurusCore/Tests/ where reasonable
  • Ensure the project builds and tests pass in Xcode before submitting

Commit and PR guidelines

  • Link related issues (e.g., Closes #123)
  • Include screenshots or screen recordings for UI changes
  • Update README.md/docs when behavior or configuration changes
  • Ensure new public types/functions have clear names and documentation

Documentation contributions

Good documentation is just as important as good code. Here's how to contribute to docs.

Documentation structure

DocumentPurpose
README.mdProject overview, quick start, feature highlights
FEATURES.mdSource of truth — feature inventory and architecture
REMOTE_PROVIDERS.mdRemote provider setup and configuration
REMOTE_MCP_PROVIDERS.mdRemote MCP provider setup
DEVELOPER_TOOLS.mdInsights and Server Explorer guide
plugins/README.mdPlugin authoring: tools, routes, storage, config UI, and web apps
OpenAI_API_GUIDE.mdAPI usage, tool calling, streaming
SHARED_CONFIGURATION_GUIDE.mdShared configuration for teams

When adding a new feature

  1. Update FEATURES.md first — Add a row to the Feature Matrix with:

    • Feature name and status
    • README section (if applicable)
    • Documentation file (if applicable)
    • Code location
  2. Update the README — If the feature should be highlighted:

    • Add to the "Highlights" table
    • Add to "Key Features" section
    • Update "What is Osaurus?" if it's a major feature
  3. Create dedicated documentation — For significant features:

    • Create a new doc in /docs/ (e.g., FEATURE_NAME.md)
    • Add to the Documentation Index in FEATURES.md
    • Link from the README
  4. Update the Architecture Overview — If the feature adds new components, update the diagram in FEATURES.md

When modifying an existing feature

  1. Update the relevant row in FEATURES.md
  2. Update any affected documentation files
  3. Note breaking changes in the feature's documentation

Documentation style

  • Use clear, concise language
  • Include practical examples
  • Add tables for options and configuration
  • Use code blocks for commands and payloads
  • Link to related documentation

Documentation PRs

  • Use the docs/... branch prefix
  • No code changes required for review
  • Update FEATURES.md for any feature-related changes

Reporting a bug

Please use the "Bug report" issue template and include:

  • Steps to reproduce
  • Expected vs actual behavior
  • Logs or screenshots if relevant
  • Environment: macOS version, Apple Silicon chip, Xcode version

Suggesting a feature

Use the "Feature request" issue template and describe:

  • The problem you're trying to solve
  • Proposed solution or alternatives
  • Any additional context or prior art (links welcome)

Localization

Osaurus supports English (source), German, and Simplified Chinese. All UI strings live in the OsaurusCore string catalog; see LOCALIZATION.md for how to add strings, add languages, and run validation.

Security

Please do not create public issues for security vulnerabilities. See SECURITY.md for our security policy and private reporting process.

Code of Conduct

This project follows the Contributor Covenant. By participating, you agree to uphold our CODE_OF_CONDUCT.md.


Join the community

Thank you for helping make Osaurus better!