Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Native Swift App with Embedded Moltis Rust Core (POC)

This guide shows a proof-of-concept path to build a native Swift app where Swift is the UI layer and Moltis Rust code is embedded as a local library.

Goal:

  • Keep business/runtime logic in Rust.
  • Build native iOS/macOS UI in Swift/SwiftUI.
  • Ship as one app bundle from the Swift side (no separate Rust service process).

Feasibility

Yes — this architecture is feasible with an FFI boundary.

The most practical POC shape is:

  1. Add a small Rust crate that compiles as staticlib.
  2. Expose a narrow C ABI (extern "C") surface.
  3. Call that ABI from Swift via a bridging header/module map.
  4. Keep Swift responsible for presentation and user interaction.
SwiftUI / UIKit / AppKit
        |
        v
Swift wrapper types (safe Swift API)
        |
        v
C ABI bridge (headers + extern "C")
        |
        v
Rust core facade (thin FFI-safe layer)
        |
        v
Existing Moltis crates (chat/providers/config/etc.)

Boundary Rules

For the POC, keep the ABI intentionally small:

  • moltis_version()
  • moltis_chat_json(request_json)
  • moltis_free_string(ptr)
  • moltis_shutdown()

Pass JSON strings across FFI to avoid unstable struct layouts early on.

Rust-side Implementation Notes

Create a dedicated bridge crate (example name: crates/swift-bridge):

  • crate-type = ["staticlib"] for Apple targets.
  • Keep all extern "C" functions in one module.
  • Never expose internal Rust structs directly.
  • Return *mut c_char and provide explicit free functions.
  • Convert internal errors into structured JSON error payloads.

Safety checklist:

  • Validate all incoming pointers and UTF-8.
  • Do not panic across FFI boundaries (catch_unwind at boundary).
  • Keep ownership explicit (allocator symmetry for returned memory).
  • Do not leak secrets into logs or debug output.

Swift-side Integration Notes

Use YAML-generated Xcode projects for the POC (no hand-maintained .xcodeproj):

  1. Define app targets in apps/macos/project.yml.
  2. Generate project with XcodeGen.
  3. Link Generated/libmoltis_bridge.a and include Generated/moltis_bridge.h.
  4. Use a Swift facade (MoltisClient) to own pointer and lifetime rules.
  5. Keep Swift linted via apps/macos/.swiftlint.yml.

From repo root:

just swift-build-rust
just swift-generate
just swift-lint
just swift-build

The UI remains purely SwiftUI while core requests/responses flow through the Rust bridge.

Intel + Apple Silicon (Universal libmoltis)

Yes — you can build libmoltis for both Intel and Apple Silicon and merge them into one universal macOS static library.

Build both architectures

rustup target add x86_64-apple-darwin aarch64-apple-darwin

# Intel
cargo build -p moltis-swift-bridge --release --target x86_64-apple-darwin

# Apple Silicon
cargo build -p moltis-swift-bridge --release --target aarch64-apple-darwin

Merge into one universal archive

mkdir -p target/universal-macos/release
lipo -create \
  target/x86_64-apple-darwin/release/libmoltis_bridge.a \
  target/aarch64-apple-darwin/release/libmoltis_bridge.a \
  -output target/universal-macos/release/libmoltis_bridge.a

lipo -info target/universal-macos/release/libmoltis_bridge.a

This universal libmoltis_bridge.a can then be linked by your Swift macOS app, so one app build supports both Intel and M-series Macs.

For production, prefer an XCFramework (device/simulator/platform-safe packaging) rather than manually juggling multiple .a files.

Async/Streaming Strategy

Moltis is async-first. For a POC:

  • Start with request/response calls over FFI.
  • Add streaming in phase 2 using callback registration or poll handles.

Simple incremental plan:

  1. Blocking/synchronous POC call (prove bridge correctness).
  2. Background Task wrapping on Swift side.
  3. Token streaming callback API when stable.

Single-Binary Expectation Clarification

On Apple platforms, you typically ship a single app artifact that includes Swift executable + statically linked Rust library in one app bundle.

So for your POC requirement (Swift UI app that embeds Rust core without a separate Rust daemon), this is achievable.

POC Milestones

  1. Add swift-bridge crate exposing one health function (moltis_version).
  2. Add one end-to-end chat method (moltis_chat_json).
  3. Build and link from minimal SwiftUI app.
  4. Validate memory lifecycle with repeated calls.
  5. Expand API surface only after the boundary is stable.

Risks to Watch Early

  • ABI drift (solve with one owned header and narrow API).
  • Threading assumptions across Swift and Rust runtimes.
  • Logging and secret handling at the boundary.
  • Cross-target build complexity (simulator vs device architectures).

Why This Fits Moltis

Moltis already has clear crate boundaries and async services. A thin FFI facade lets Swift own the native UX while reusing provider orchestration, config, and session logic from Rust.