Share HuggingFace model cache via App Group and update TMPDIR handling

keypair34 committed Apr 28, 2026 at 20:36 UTC 39be9e7cfaec27304f38cee1842b9a77a92d8922
3 files changed +30 -21
Examples/OndeExample/InferenceEnvironment.swift
+15 -21
@@ -1,34 +1,28 @@
1 import Foundation
2
3 -/// Configures the environment variables that the Onde Rust core requires when
4 -/// running inside an iOS/tvOS app sandbox.
3 +/// Points `HF_HOME` and `HF_HUB_CACHE` at the Onde shared App Group container
4 +/// so downloaded models are available to every Onde-powered app on the device.
5 ///
6 -/// Call this **before** any `OndeChatEngine` method — ideally in your `@main`
7 -/// App struct's `init()`.
8 -///
9 -/// What each variable does:
10 -/// - `HF_HOME` – root of the HuggingFace Hub cache inside the app container
11 -/// - `HF_HUB_CACHE` – models subdirectory (avoids the default `~/.cache` path
12 -/// which is unreachable in the sandbox)
13 -/// - `TMPDIR` – the system-provided temporary directory for the process
6 +/// Call this once at launch, before creating an `OndeChatEngine`.
7 func setupInferenceEnvironment() {
8 let fm = FileManager.default
9
17 - // Base directory for all Onde / HuggingFace data.
18 - // Application Support is backed up by iCloud by default; use Caches if
19 - // you prefer a purgeable location and are OK re-downloading models.
20 - let appSupport = fm.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0]
21 - let hfHome = appSupport.appendingPathComponent("huggingface", isDirectory: true)
10 + // All Onde apps use this App Group to share the HuggingFace model cache.
11 + // If the group isn't available (e.g. entitlement missing during development),
12 + // fall back to the app's own Application Support directory.
13 + let base: URL = fm.containerURL(
14 + forSecurityApplicationGroupIdentifier: "group.com.ondeinference.apps"
15 + ) ?? fm.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0]
16
23 - // Create the directory tree up-front so hf-hub never has to.
24 - let hfHubCache = hfHome.appendingPathComponent("hub", isDirectory: true)
17 + let hfHome = base.appendingPathComponent("models", isDirectory: true)
18 + let hfHubCache = hfHome.appendingPathComponent("hub", isDirectory: true)
19 try? fm.createDirectory(at: hfHubCache, withIntermediateDirectories: true)
20
21 setenv("HF_HOME", hfHome.path, 1)
22 setenv("HF_HUB_CACHE", hfHubCache.path, 1)
23
30 - // The Rust std-lib respects TMPDIR; make sure it points inside our sandbox.
31 - if let tmp = ProcessInfo.processInfo.environment["TMPDIR"] {
32 - setenv("TMPDIR", tmp, 1) // already set by iOS — just make it explicit
33 - }
24 + // Make sure TMPDIR points inside the sandbox for the Rust side.
25 + let tmp = base.appendingPathComponent("tmp", isDirectory: true)
26 + try? fm.createDirectory(at: tmp, withIntermediateDirectories: true)
27 + setenv("TMPDIR", tmp.path, 1)
28 }
Examples/OndeExample/OndeExample.entitlements new
+10
@@ -0,0 +1,10 @@
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3 +<plist version="1.0">
4 +<dict>
5 + <key>com.apple.security.application-groups</key>
6 + <array>
7 + <string>group.com.ondeinference.apps</string>
8 + </array>
9 +</dict>
10 +</plist>
Examples/OndeExample/project.yml
+5
@@ -20,6 +20,11 @@ targets:
20 excludes:
21 - project.yml
22 - "*.xcodeproj"
23 + entitlements:
24 + path: OndeExample.entitlements
25 + properties:
26 + com.apple.security.application-groups:
27 + - group.com.ondeinference.apps
28 dependencies:
29 - package: Onde
30 product: Onde