Ctrl K
ComunidadGuías…

docs/src/native-swift-embedding.md

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# 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.

## Recommended POC Architecture

```
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:

```bash
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

```bash
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

```bash
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.

### Recommended packaging for Xcode

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.