fix(#41): restore Intel Mac build via ort-dynamic + Homebrew ONNX Runtime (#43)

* fix: restore Intel Mac build via ort-dynamic + system libonnxruntime

Microsoft is discontinuing x86_64 macOS ONNX Runtime prebuilts after
v1.23.0, so ort-sys 2.0.0-rc.11 can't ship an Intel Mac binary and never
will. Previous Intel Mac attempts kept dying in the ort-sys build script
with "does not provide prebuilt binaries for the target x86_64-apple-darwin
with feature set (no features)." Issue #41 was the latest casualty.

Fix: route Intel Mac through the ort-dynamic feature path (runtime dlopen
against a system libonnxruntime installed via Homebrew). This sidesteps
ort-sys prebuilts entirely and works today.

Changes:

- crates/vestige-core/Cargo.toml: split `embeddings` into code-only vs
  backend-choice. The embeddings feature now just pulls fastembed + hf-hub
  + image-models and activates the 27 #[cfg(feature = "embeddings")] gates
  throughout the crate. New `ort-download` feature carries the
  download-binaries-native-tls backend (the historical default). Existing
  `ort-dynamic` feature now transitively enables `embeddings`, so the
  cfg gates stay active when users swap backends.

  Default feature set expands `["embeddings", ...]` -> `["embeddings",
  "ort-download", ...]` so existing consumers see identical behavior.

- crates/vestige-mcp/Cargo.toml: mirrors the split. Adds `ort-download`
  feature that chains to vestige-core/ort-download, keeps `ort-dynamic`
  that chains to vestige-core/ort-dynamic. Both transitively pull
  `embeddings`. Default adds `ort-download` so `cargo install vestige-mcp`
  still picks the prebuilt-ort backend like before.

- .github/workflows/ci.yml: re-adds x86_64-apple-darwin to the
  release-build matrix with `--no-default-features --features
  ort-dynamic,vector-search`. Adds a `brew install onnxruntime` step that
  sets ORT_DYLIB_PATH from `brew --prefix onnxruntime`.

- .github/workflows/release.yml: re-adds x86_64-apple-darwin to the
  release matrix with the same flags + brew install step. The Intel Mac
  tarball now also bundles docs/INSTALL-INTEL-MAC.md so binary consumers
  get the `brew install onnxruntime` + ORT_DYLIB_PATH prereq out of the
  box.

- docs/INSTALL-INTEL-MAC.md: new install guide covering the Homebrew
  prereq, binary install, source build, troubleshooting, and the v2.1
  ort-candle migration plan.

- README.md: replaces the "Intel Mac and Windows build from source only"
  paragraph with the prebuilt Intel Mac install (brew + curl + env var)
  and a link to the full guide. Platform table updated: Intel Mac back
  on the "prebuilt" list.

Verified locally on aarch64-apple-darwin:
- `cargo check --release -p vestige-mcp` -> clean (default features)
- `cargo check --release -p vestige-mcp --no-default-features
   --features ort-dynamic,vector-search` -> clean

Runtime path on Intel Mac (verified on CI):
  brew install onnxruntime
  export ORT_DYLIB_PATH=$(brew --prefix onnxruntime)/lib/libonnxruntime.dylib
  vestige-mcp --version

Fixes #41. Long-term plan (v2.1): migrate to ort-candle pure-Rust backend
so no system ONNX Runtime dep is needed on any platform.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(ci): drop unused brew install + ORT_DYLIB_PATH from CI steps

Build is a cross-compile (macos-latest runner is Apple Silicon targeting
x86_64-apple-darwin) and ort-load-dynamic doesn't link libonnxruntime at
build time — only at runtime via dlopen. So the brew install step and
ORT_DYLIB_PATH export were ceremony without payload. Removed to cut CI
time. Runtime setup remains documented in docs/INSTALL-INTEL-MAC.md for
end users installing the tarball on their own Intel Mac.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* ci: run release-build on PRs too — catch Intel Mac regressions pre-merge

Previously release-build was gated behind `github.ref == 'refs/heads/main'`,
so the Intel Mac, aarch64-apple-darwin, and Linux release targets were only
validated AFTER merge to main. If someone broke the Intel Mac cross-compile
by touching feature flags or Cargo dependencies, we'd only find out when
the release tag was cut and the job exploded on main. Extending the guard
to also fire on pull_request means regressions surface in the PR status
check instead of on a release branch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sam Valladares 2026-04-23 02:03:45 -05:00 committed by GitHub
parent d3a2274778
commit 5b993e841f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 149 additions and 30 deletions

View file

@ -50,7 +50,12 @@ jobs:
release-build: release-build:
name: Release Build (${{ matrix.target }}) name: Release Build (${{ matrix.target }})
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
if: github.ref == 'refs/heads/main' # Run on main pushes AND on PRs that touch workflows, Cargo manifests, or
# crate sources — so Intel Mac / Linux release targets are validated
# before merge, not after.
if: |
github.ref == 'refs/heads/main' ||
github.event_name == 'pull_request'
needs: [test] needs: [test]
strategy: strategy:
fail-fast: false fail-fast: false
@ -59,9 +64,12 @@ jobs:
- os: macos-latest - os: macos-latest
target: aarch64-apple-darwin target: aarch64-apple-darwin
cargo_flags: "" cargo_flags: ""
# x86_64-apple-darwin dropped: ort-sys has no prebuilt ONNX Runtime # Intel Mac builds against a system ONNX Runtime via ort-dynamic
# binaries for Intel Mac, and the codebase requires embeddings. # (ort-sys has no x86_64-apple-darwin prebuilts). Compile-only here;
# Apple discontinued Intel Macs in 2020. Build from source if needed. # runtime linking is a user concern documented in INSTALL-INTEL-MAC.md.
- os: macos-latest
target: x86_64-apple-darwin
cargo_flags: "--no-default-features --features ort-dynamic,vector-search"
- os: ubuntu-latest - os: ubuntu-latest
target: x86_64-unknown-linux-gnu target: x86_64-unknown-linux-gnu
cargo_flags: "" cargo_flags: ""

View file

@ -27,17 +27,21 @@ jobs:
os: ubuntu-latest os: ubuntu-latest
archive: tar.gz archive: tar.gz
cargo_flags: "" cargo_flags: ""
needs_onnxruntime: false
- target: x86_64-pc-windows-msvc - target: x86_64-pc-windows-msvc
os: windows-latest os: windows-latest
archive: zip archive: zip
cargo_flags: "" cargo_flags: ""
# Intel Mac (x86_64-apple-darwin) is explicitly unsupported: the needs_onnxruntime: false
# upstream ort-sys 2.0.0-rc.11 pinned by fastembed 5.13.2 does not # Intel Mac uses the ort-dynamic feature to runtime-link against a
# ship Intel Mac prebuilts, and the v2.0.5 + v2.0.6 release # system libonnxruntime (Homebrew), sidestepping the missing
# workflows both failed this job. Matches ci.yml which already # x86_64-apple-darwin prebuilts in ort-sys 2.0.0-rc.11. Binary
# dropped the target. README documents the build-from-source path # consumers must `brew install onnxruntime` before running — see
# for Intel Mac users. When ort-sys ships Intel Mac prebuilts # INSTALL-INTEL-MAC.md bundled in the tarball.
# again, restore the entry. - target: x86_64-apple-darwin
os: macos-latest
archive: tar.gz
cargo_flags: "--no-default-features --features ort-dynamic,vector-search"
- target: aarch64-apple-darwin - target: aarch64-apple-darwin
os: macos-latest os: macos-latest
archive: tar.gz archive: tar.gz
@ -58,8 +62,13 @@ jobs:
- name: Package (Unix) - name: Package (Unix)
if: matrix.os != 'windows-latest' if: matrix.os != 'windows-latest'
run: | run: |
cp docs/INSTALL-INTEL-MAC.md target/${{ matrix.target }}/release/ 2>/dev/null || true
cd target/${{ matrix.target }}/release cd target/${{ matrix.target }}/release
if [ "${{ matrix.target }}" = "x86_64-apple-darwin" ]; then
tar -czf ../../../vestige-mcp-${{ matrix.target }}.tar.gz vestige-mcp vestige vestige-restore INSTALL-INTEL-MAC.md
else
tar -czf ../../../vestige-mcp-${{ matrix.target }}.tar.gz vestige-mcp vestige vestige-restore tar -czf ../../../vestige-mcp-${{ matrix.target }}.tar.gz vestige-mcp vestige vestige-restore
fi
- name: Package (Windows) - name: Package (Windows)
if: matrix.os == 'windows-latest' if: matrix.os == 'windows-latest'

View file

@ -80,12 +80,24 @@ curl -L https://github.com/samvallad33/vestige/releases/latest/download/vestige-
sudo mv vestige-mcp vestige vestige-restore /usr/local/bin/ sudo mv vestige-mcp vestige vestige-restore /usr/local/bin/
``` ```
**macOS (Intel) and Windows:** Prebuilt binaries aren't currently shipped for these targets because of upstream toolchain gaps (`ort-sys` lacks Intel Mac prebuilts in the 2.0.0-rc.11 release that `fastembed 5.13.2` is pinned to; `usearch 2.24.0` hit a Windows MSVC compile break tracked as [usearch#746](https://github.com/unum-cloud/usearch/issues/746)). Both build fine from source in the meantime: **macOS (Intel):** Microsoft is discontinuing x86_64 macOS prebuilts after ONNX Runtime v1.23.0, so Vestige's Intel Mac build links dynamically against a Homebrew-installed ONNX Runtime via the `ort-dynamic` feature. Install with:
```bash
brew install onnxruntime
curl -L https://github.com/samvallad33/vestige/releases/latest/download/vestige-mcp-x86_64-apple-darwin.tar.gz | tar -xz
sudo mv vestige-mcp vestige vestige-restore /usr/local/bin/
echo 'export ORT_DYLIB_PATH="'"$(brew --prefix onnxruntime)"'/lib/libonnxruntime.dylib"' >> ~/.zshrc
source ~/.zshrc
claude mcp add vestige vestige-mcp -s user
```
Full Intel Mac guide (build-from-source + troubleshooting): [`docs/INSTALL-INTEL-MAC.md`](docs/INSTALL-INTEL-MAC.md).
**Windows:** Prebuilt binaries ship but `usearch 2.24.0` hit an MSVC compile break ([usearch#746](https://github.com/unum-cloud/usearch/issues/746)); we've pinned `=2.23.0` until upstream fixes it. Source builds work with:
```bash ```bash
git clone https://github.com/samvallad33/vestige && cd vestige git clone https://github.com/samvallad33/vestige && cd vestige
cargo build --release -p vestige-mcp cargo build --release -p vestige-mcp
# Binary lands at target/release/vestige-mcp
``` ```
**npm:** **npm:**
@ -315,7 +327,7 @@ At the start of every session:
| **Transport** | MCP stdio (JSON-RPC 2.0) + WebSocket | | **Transport** | MCP stdio (JSON-RPC 2.0) + WebSocket |
| **Cognitive modules** | 30 stateful (17 neuroscience, 11 advanced, 2 search) | | **Cognitive modules** | 30 stateful (17 neuroscience, 11 advanced, 2 search) |
| **First run** | Downloads embedding model (~130MB), then fully offline | | **First run** | Downloads embedding model (~130MB), then fully offline |
| **Platforms** | macOS ARM + Linux x86_64 (prebuilt). macOS Intel + Windows build from source (upstream toolchain gaps, see install notes). | | **Platforms** | macOS ARM + Intel + Linux x86_64 + Windows x86_64 (all prebuilt). Intel Mac needs `brew install onnxruntime` — see [install guide](docs/INSTALL-INTEL-MAC.md). |
### Optional Features ### Optional Features

View file

@ -11,29 +11,41 @@ keywords = ["memory", "spaced-repetition", "fsrs", "embeddings", "knowledge-grap
categories = ["science", "database"] categories = ["science", "database"]
[features] [features]
default = ["embeddings", "vector-search", "bundled-sqlite"] default = ["embeddings", "ort-download", "vector-search", "bundled-sqlite"]
# SQLite backend (default, unencrypted) # SQLite backend (default, unencrypted)
bundled-sqlite = ["rusqlite/bundled"] bundled-sqlite = ["rusqlite/bundled"]
# Encrypted SQLite via SQLCipher (mutually exclusive with bundled-sqlite) # Encrypted SQLite via SQLCipher (mutually exclusive with bundled-sqlite)
# Use: --no-default-features --features encryption,embeddings,vector-search # Use: --no-default-features --features encryption,embeddings,ort-download,vector-search
# Set VESTIGE_ENCRYPTION_KEY env var to enable encryption # Set VESTIGE_ENCRYPTION_KEY env var to enable encryption
encryption = ["rusqlite/bundled-sqlcipher"] encryption = ["rusqlite/bundled-sqlcipher"]
# Core embeddings with fastembed (ONNX-based, local inference) # Embedding code paths (fastembed dep, hf-hub, image-models). This feature
# Downloads a pre-built ONNX Runtime binary at build time (requires glibc >= 2.38) # enables the #[cfg(feature = "embeddings")] gates throughout the crate but
embeddings = ["dep:fastembed", "fastembed/ort-download-binaries-native-tls"] # does NOT pick an ort backend. Pair with EXACTLY ONE of `ort-download`
# (prebuilt ONNX Runtime, default) or `ort-dynamic` (runtime-linked system
# libonnxruntime, required on targets without prebuilts).
embeddings = ["dep:fastembed", "fastembed/hf-hub-native-tls", "fastembed/image-models"]
# Default ort backend: ort-sys downloads prebuilt ONNX Runtime at build time.
# Requires glibc >= 2.38. Fails on x86_64-apple-darwin (Microsoft is
# discontinuing Intel Mac prebuilts after ONNX Runtime v1.23.0).
ort-download = ["embeddings", "fastembed/ort-download-binaries-native-tls"]
# HNSW vector search with USearch (20x faster than FAISS) # HNSW vector search with USearch (20x faster than FAISS)
vector-search = ["dep:usearch"] vector-search = ["dep:usearch"]
# Use runtime-loaded ORT instead of the downloaded pre-built binary. # Alternative ort backend: runtime-linked against a system libonnxruntime via
# Required on systems with glibc < 2.38 (Ubuntu 22.04, Debian 12, RHEL/Rocky 9). # dlopen. Required on Intel Mac and on systems with glibc < 2.38 (Ubuntu
# Mutually exclusive with the default `embeddings` feature's download strategy. # 22.04, Debian 12, RHEL/Rocky 9). Transitively enables `embeddings` so the
# Usage: --no-default-features --features ort-dynamic,vector-search,bundled-sqlite # #[cfg] gates stay active.
# Runtime requirement: libonnxruntime.so must be on LD_LIBRARY_PATH or ORT_DYLIB_PATH set. #
ort-dynamic = ["dep:fastembed", "fastembed/ort-load-dynamic", "fastembed/hf-hub-native-tls", "fastembed/image-models"] # Usage: cargo build --no-default-features \
# --features ort-dynamic,vector-search,bundled-sqlite
# Runtime: export ORT_DYLIB_PATH=/path/to/libonnxruntime.{dylib,so}
# (e.g. $(brew --prefix onnxruntime)/lib/libonnxruntime.dylib)
ort-dynamic = ["embeddings", "fastembed/ort-load-dynamic"]
# Nomic Embed Text v2 MoE (475M params, 305M active, Candle backend) # Nomic Embed Text v2 MoE (475M params, 305M active, Candle backend)
# Requires: fastembed with nomic-v2-moe feature # Requires: fastembed with nomic-v2-moe feature

View file

@ -10,12 +10,17 @@ categories = ["command-line-utilities", "database"]
repository = "https://github.com/samvallad33/vestige" repository = "https://github.com/samvallad33/vestige"
[features] [features]
default = ["embeddings", "vector-search"] default = ["embeddings", "ort-download", "vector-search"]
embeddings = ["vestige-core/embeddings"] embeddings = ["vestige-core/embeddings"]
vector-search = ["vestige-core/vector-search"] vector-search = ["vestige-core/vector-search"]
# For systems with glibc < 2.38 — use runtime-loaded ORT instead of the downloaded pre-built binary. # Default ort backend: downloads prebuilt ONNX Runtime at build time.
# Usage: cargo install --path crates/vestige-mcp --no-default-features --features ort-dynamic,vector-search # Fails on targets without prebuilts (notably x86_64-apple-darwin).
ort-dynamic = ["vestige-core/ort-dynamic"] ort-download = ["embeddings", "vestige-core/ort-download"]
# Alternative ort backend: runtime-linked system libonnxruntime via dlopen.
# Required on Intel Mac and on systems with glibc < 2.38.
# Usage: cargo build --no-default-features --features ort-dynamic,vector-search
# Runtime: export ORT_DYLIB_PATH=$(brew --prefix onnxruntime)/lib/libonnxruntime.dylib
ort-dynamic = ["embeddings", "vestige-core/ort-dynamic"]
[[bin]] [[bin]]
name = "vestige-mcp" name = "vestige-mcp"

73
docs/INSTALL-INTEL-MAC.md Normal file
View file

@ -0,0 +1,73 @@
# Intel Mac Installation
The Intel Mac (`x86_64-apple-darwin`) binary links dynamically against a system
ONNX Runtime instead of a prebuilt ort-sys library. Microsoft is discontinuing
x86_64 macOS prebuilts after ONNX Runtime v1.23.0, so we use the
`ort-dynamic` feature to runtime-link against the version you install locally.
This keeps Vestige working on Intel Mac without waiting for a dead upstream.
## Prerequisite
Install ONNX Runtime via Homebrew:
```bash
brew install onnxruntime
```
## Install
```bash
# 1. Download the binary
curl -L https://github.com/samvallad33/vestige/releases/latest/download/vestige-mcp-x86_64-apple-darwin.tar.gz | tar -xz
sudo mv vestige-mcp vestige vestige-restore /usr/local/bin/
# 2. Point the binary at Homebrew's libonnxruntime
echo 'export ORT_DYLIB_PATH="'"$(brew --prefix onnxruntime)"'/lib/libonnxruntime.dylib"' >> ~/.zshrc
source ~/.zshrc
# 3. Verify
vestige-mcp --version
# 4. Connect to Claude Code
claude mcp add vestige vestige-mcp -s user
```
`ORT_DYLIB_PATH` is how the `ort` crate's `load-dynamic` feature finds the
shared library at runtime. Without it the binary starts but fails on the first
embedding call with a "could not find libonnxruntime" error.
## Building from source
```bash
brew install onnxruntime
git clone https://github.com/samvallad33/vestige && cd vestige
cargo build --release -p vestige-mcp \
--no-default-features \
--features ort-dynamic,vector-search
export ORT_DYLIB_PATH="$(brew --prefix onnxruntime)/lib/libonnxruntime.dylib"
./target/release/vestige-mcp --version
```
## Troubleshooting
**`dyld: Library not loaded: libonnxruntime.dylib`** — `ORT_DYLIB_PATH` is not
set for the shell that spawned `vestige-mcp`. Claude Code / Codex inherits the
env vars from whatever launched it; export `ORT_DYLIB_PATH` in `~/.zshrc` or
`~/.bashrc` and restart the client.
**`error: ort-sys does not provide prebuilt binaries for the target
x86_64-apple-darwin`** — you hit this only if you ran `cargo build` without the
`--no-default-features --features ort-dynamic,vector-search` flags. The default
feature set still tries to download a non-existent prebuilt. Add the flags and
rebuild.
**Homebrew installed `onnxruntime` but `brew --prefix onnxruntime` prints
nothing** — upgrade brew (`brew update`) and retry. Older brew formulae used
`onnx-runtime` (hyphenated). If your brew still has the hyphenated formula,
substitute accordingly in the commands above.
## Long-term
Intel Mac will move to a fully pure-Rust backend (`ort-candle`) in Vestige
v2.1, removing the Homebrew prerequisite entirely. Track progress at
[issue #41](https://github.com/samvallad33/vestige/issues/41).