0013 — ONNX Runtime auto-provisioning & bundling¶
Status: IN PROGRESS (2026-07-05) — Slice 1 (auto-provisioning) & Slice 3
(config/UI/docs) landed and verified live (a removal with no path configured
auto-downloaded ORT and inpainted); Slice 2 (bundling the runtime in the macOS
.app) rides 0010's packaging work, and auto-download already covers macOS in
the meantime. Remove the last manual step from the local ML
capabilities: make the ONNX Runtime shared library arrive automatically, the
way the models already do, so enabling eye detection or object removal never
asks the user to find, download, or path-in libonnxruntime. Companion to
0004 (face.*), 0008
(remove.*), 0010 (the macOS app that bundles it),
and the master ML-runtime open question (0001 §13-Q1).
§7 resolved (2026-07-05, Matt): do both — bundle the runtime in the shipped macOS app and auto-download everywhere else. Implementation may begin.
Why now. Testing in the studio (2026-07-05) surfaced the gap: enabling eye detection produced "load onnxruntime: libonnxruntime.so: cannot open shared object file". The models auto-download and checksum-verify (
pkg/face/models), but the runtime library was deliberately left manual — a code comment reads "The ORT shared library is not auto-fetched — it's platform-specific and stays config-supplied via face.library_path." For a photographer's tool that is the wrong trade: it demands the one piece of platform knowledge Hailey should never need, gives a cryptic error when absent, and must be set twice (face.library_pathandremove.library_path).
1. Goals¶
- Zero manual runtime path. With eye detection or object removal enabled and
no path configured, krites obtains a working
libonnxruntimeon its own. - One resolution, shared by both providers — face and remove resolve the same library; the path is never configured twice.
- Bundled on the shipped Mac app (
0010) so Hailey's machine needs no download at all — the dylib ships inside the.app. - Auto-download fallback (download → extract → checksum-verify → cache) for the CLI and any unbundled platform, mirroring the model fetcher.
library_pathstays as an advanced override, not a requirement.
Non-goals¶
- No CGO. The
shota3506/onnxruntime-puregobindingdlopens the lib at runtime; this spec only decides which path it dlopens (0004R-FACE-2). - No change to model provisioning (already automatic).
- Windows support is out of scope for the first cut (Hailey is macOS; dev is
Linux) — the resolver errors clearly there, pointing at
library_path.
2. Resolution order¶
A single resolver returns the library path, trying in order (R-ORT-1):
- Explicit override —
onnxruntime.library_path(new, shared), or the legacyface.library_path/remove.library_path(still honoured). Non-empty wins, unconditionally — the escape hatch for a hand-built or system lib. - Bundled — a lib shipped alongside the executable (the macOS
.app, §4). Located relative to the binary, so it moves with the app. - Auto-provisioned — the pinned ORT release for the current platform, downloaded, extracted, checksum-verified, and cached (§3). Fetched once.
The resolved path is passed into onnx.Config.LibraryPath by both providers, so
the onnx adapters and the binding are unchanged.
3. Auto-provisioning (the fallback)¶
R-ORT-2 — pinned, per-platform, checksum-verified. A pinned ONNX Runtime
version (providing C-API ≥ 23, the binding's target) maps GOOS/GOARCH to
Microsoft's official release archive:
| Platform | Asset (example, version pinned in code) |
|---|---|
linux/amd64 |
onnxruntime-linux-x64-<v>.tgz |
linux/arm64 |
onnxruntime-linux-aarch64-<v>.tgz |
darwin/arm64 |
onnxruntime-osx-arm64-<v>.tgz |
darwin/amd64 |
onnxruntime-osx-x86_64-<v>.tgz |
The archive is downloaded to a temp file, its SHA-256 verified against a pinned
per-platform hash (refusing a mismatch), the lib/libonnxruntime.* entry
extracted into the cache ($XDG_CACHE_HOME/krites/runtime/<v>/), and its path
returned. A subsequent run finds the cached lib and skips the download
(R-ORT-3). A platform whose checksum is not yet pinned fails with a clear message
naming library_path — never an unverified download (R-ORT-4).
Reuse. This mirrors
pkg/face/models(verify → fetch → cache) but adds archive extraction (tar.gz via stdlibarchive/tar+compress/gzip). ORT is MIT-licensed, so download, cache, and redistribution are all unrestricted (unlike the Places2 model caveat,0008§4.1).
4. Bundling in the macOS app (0010)¶
R-ORT-5. The goreleaser .app build embeds the platform libonnxruntime.dylib
(+ its MIT LICENSE) inside the bundle (Contents/Frameworks or beside the
binary), and the resolver's bundled step (§2.2) finds it there. So a
double-click install has the runtime present from first launch — auto-download in
§3 never runs on Hailey's Mac. This is additive to 0010's packaging slice.
5. Config & UI¶
R-ORT-6. A new shared key onnxruntime.library_path overrides the resolver
for both providers; face.library_path / remove.library_path remain as
per-provider overrides for back-compat but are no longer required. In the studio
Settings panel the runtime path becomes an optional "Advanced" field, not a
prerequisite — enabling a capability no longer footguns the user into the
missing-library error (the resolver supplies it).
6. Docs (Definition of Done)¶
- Update the face/eye and object-removal how-tos: enabling them "just works"; no
library path needed. The config reference marks
*.library_pathoptional and documentsonnxruntime.library_path+ the resolution order. - A short explanation of where the runtime comes from (bundled vs downloaded).
7. Open questions¶
- Q1 — bundle vs download vs both. ✅ RESOLVED (2026-07-05, Matt): both. Bundle in the shipped Mac app; auto-download for CLI/other platforms.
- Q2 — which platforms to pin now. Recommend: pin every checksum we can fetch and verify at implementation time (Linux x64 is the dev box; macOS arm64 is Hailey's target and also bundled). Gate unpinned platforms with the §3 error. Confirm.
- Q3 — ORT version pin & cadence. Pin one version providing C-API 23; bump deliberately (like the model pins). Mirror to an artefact we control before a released build (the same hardening TODO the model pins carry).
8. Slices¶
- Slice 1 — the resolver + wiring. ✅ LANDED (2026-07-05).
pkg/onnxruntime: resolution order (override → bundled → auto-download), all four Linux/macOS platforms pinned against ORT 1.23.0, download+extract(tar.gz)+checksum+cache.faceprovider+inpaintproviderresolve through it; sharedonnxruntime.library_path. Unit-tested (order, extract, checksum-mismatch) + a real network download (INT_TEST). Verified live: a studio removal with no path configured auto-provisioned ORT and inpainted. - Slice 2 — macOS bundle. ⏳ Rides
0010. The bundled-path resolution step is done and tested; embedding the dylib in the.appvia goreleaser lands with0010's packaging slice (no Mac build here yet). Auto-download covers macOS until then. - Slice 3 — config/UI/docs. ✅ LANDED (2026-07-05). Panel library-path
fields marked optional ("downloaded automatically — leave blank"); config
reference gains an ONNX Runtime section +
onnxruntime.library_pathand marks the legacy per-provider paths optional; the face/eye and object-removal how-tos note the runtime auto-provisions. Enabling a capability no longer requires a path.