Skip to content

chore(release): v0.3.2#20

Merged
raymondj99 merged 1 commit into
mainfrom
chore/release-v0.3.2
May 18, 2026
Merged

chore(release): v0.3.2#20
raymondj99 merged 1 commit into
mainfrom
chore/release-v0.3.2

Conversation

@raymondj99
Copy link
Copy Markdown
Owner

@raymondj99 raymondj99 commented May 18, 2026

Summary

Two production-quality fixes:

  1. openmemory model download now installs the platform-matched ONNX Runtime — fixes a hard blocker where every fresh install of vector / hybrid mode panicked with cannot open shared object file: libonnxruntime.so. The downloader resolves the host target (linux x86_64/aarch64, macOS arm64/x86_64), fetches Microsoft's signed v1.20.0 tarball, verifies SHA-256, extracts the lib/ subtree into <home>/runtime/onnxruntime-1.20.0/, and the CLI sets ORT_DYLIB_PATH at startup. User-set ORT_DYLIB_PATH / LD_LIBRARY_PATH always wins.

  2. integration_concurrent_recall_runs_in_parallel flake fix — the single-thread baseline already took the median of 3 runs but the parallel measurement ran exactly once, so any GH runner cgroup stall could red the gate. Parallel now runs 3× and the assertion uses the minimum elapsed time. A real reader-serialisation regression still flunks every attempt.

Test plan

  • cargo check --workspace --all-features clean
  • cargo clippy --workspace --all-features -- -D warnings clean
  • cargo test --workspace --all-features 580 pass / 0 fail
  • cargo test integration_concurrent_recall_runs_in_parallel passes on the host with the new median-of-3 logic
  • CI green on this PR
  • Tag v0.3.1...v0.3.2, release workflow ships openmemory-0.3.2-* artifacts, demo VM installs cleanly and omdemos check --mode vector works without manual LD_LIBRARY_PATH plumbing

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • openmemory model download now automatically installs the required ONNX Runtime with platform-specific matching and integrity verification.
    • Runtime library path is automatically configured without overwriting user environment settings.
  • Bug Fixes

    • Improved reliability of concurrent integration tests.

Review Change Stack

Two production-quality fixes that unblock embeddings on clean installs
and stabilise the workspace CI signal.

* `openmemory model download` now installs the platform-matched ONNX
  Runtime 1.20.0 alongside the model. `ort` is compiled with
  `load-dynamic` and the release tarball ships only the binary, so
  every fresh install of vector or hybrid mode previously panicked
  with `cannot open shared object file: libonnxruntime.so`. The
  downloader resolves the host target (linux x86_64/aarch64, macOS
  arm64/x86_64), fetches the Microsoft release tarball, verifies its
  SHA-256, extracts `lib/` into `<home>/runtime/onnxruntime-<ver>/`,
  and the CLI sets `ORT_DYLIB_PATH` at startup. User-supplied
  `ORT_DYLIB_PATH` / `LD_LIBRARY_PATH` always wins.

* `integration_concurrent_recall_runs_in_parallel` now runs the
  parallel measurement three times and asserts on the minimum,
  matching the single-thread baseline's median-of-3 noise filter.
  A single GitHub runner cgroup stall no longer reds the gate while
  a real reader-serialisation regression still flunks all three
  attempts.

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

coderabbitai Bot commented May 18, 2026

Warning

.coderabbit.yaml has a parsing error

The CodeRabbit configuration file in this repository has a parsing error and default settings were used instead. Please fix the error(s) in the configuration file. You can initialize chat with CodeRabbit to get help with the configuration file.

💥 Parsing errors (1)
Validation error: String must contain at most 250 character(s) at "tone_instructions"
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
📝 Walkthrough

Walkthrough

This PR adds automatic ONNX Runtime 1.20.0 installation and dynamic library path initialization to the openmemory CLI. A new RuntimeManager downloads platform-matched runtimes from Microsoft, verifies via SHA-256, extracts the lib subtree, and wires ORT_DYLIB_PATH at startup. The model download command integrates runtime installation, and a flaky integration test is stabilized via multi-run timing.

Changes

ONNX Runtime Installation and CLI Integration

Layer / File(s) Summary
RuntimeManager module and core installation logic
crates/openmemory-embed/src/runtime.rs
New RuntimeManager struct coordinates platform-pinned ONNX Runtime 1.20.0 downloads from Microsoft GitHub releases, enforces SHA-256 verification, safely extracts the lib/ subtree with path-traversal rejection, creates unversioned dylib symlinks on Unix, and conditionally sets ORT_DYLIB_PATH only when unset by the user. Includes timeout/size enforcement during download and unit tests.
Error types and config support
crates/openmemory-embed/src/error.rs, crates/openmemory-core/src/config.rs, crates/openmemory-embed/src/lib.rs
Add EmbedError::Config variant, expose Config::runtime_dir() for shared runtime directory resolution, and declare public runtime module with RuntimeManager and ONNX_RUNTIME_VERSION re-exports.
Workspace and crate dependency updates
Cargo.toml, crates/openmemory-embed/Cargo.toml
Bump workspace version to 0.3.2, update all internal crate dependencies to 0.3.2, and add flate2 and tar workspace dependencies for tarball extraction.
CLI integration: model download and startup initialization
crates/openmemory-cli/src/commands/model.rs, crates/openmemory-cli/src/main.rs
Refactor openmemory model download to invoke RuntimeManager::install() via new install_runtime() helper. Add init_ort_dylib_path() to CLI entrypoint that conditionally wires installed dylib location to ORT_DYLIB_PATH at startup, respecting user-supplied environment overrides and embeddings feature gates.
Integration test stabilization
crates/openmemory-graph/tests/integration.rs
Run integration_concurrent_recall_runs_in_parallel parallel timing measurement three times per barrier, record each attempt's duration, and assert using the minimum elapsed time to reduce noise while preserving detection of real serialization regressions.
Release notes documentation
CHANGELOG.md
Document v0.3.2 release: platform-matched ONNX Runtime 1.20.0 installation workflow, environment variable precedence rules, and integration test stabilization.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • raymondj99/openmemory#18: Version and changelog promotion to 0.3.1; this PR builds on that baseline with new feature logic for ONNX Runtime management.

Poem

🐰 A rabbit with runtime dreams,
Downloads and installs with gleaming schemes,
SHA-256 verified, symlinks aligned,
ONNX paths wired, no more undefined,
Three test runs ensure no slip—
Onward to version 0.3.2! 🚀

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'chore(release): v0.3.2' directly and specifically identifies the PR's primary purpose: releasing version 0.3.2. It clearly summarizes the main change across all modified files (CHANGELOG, Cargo.toml version bumps, and implementation of v0.3.2 features).
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/release-v0.3.2

Comment @coderabbitai help to get the list of available commands and usage tips.

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented May 18, 2026

Merging this PR will not alter performance

✅ 19 untouched benchmarks


Comparing chore/release-v0.3.2 (61fa665) with main (3bfb07b)

Open in CodSpeed

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@CHANGELOG.md`:
- Line 12: The CHANGELOG.md contains reference-style headings like "## [0.3.2] -
2026-05-17" but lacks the corresponding link definitions and the Unreleased
compare still points at v0.2.1; add reference link definitions for [0.3.2],
[0.3.1], and [0.3.0] at the bottom of the file pointing to their GitHub
compare/release URLs, and update the [Unreleased] reference to compare from
v0.3.2 (e.g., v0.3.2..HEAD) so the Unreleased section and the new 0.3.x links
resolve correctly.

In `@crates/openmemory-embed/src/runtime.rs`:
- Around line 190-197: The current install code in runtime.rs (the branch that
checks if dylib.exists() and the later extraction block around the second
occurrence) can report "already installed" for an incomplete extraction because
files are written directly into the final directory; change the install to
extract into a temporary directory (e.g., derive temp path from the target dir
like target_dir.with_extension(".tmp-<pid|uuid>") or use tempfile::TempDir),
perform the full extraction there, and then atomically promote it into place
with std::fs::rename (or std::fs::rename on Windows-equivalent) to replace/move
into the final directory; update the existence check to consider only the final
promoted path (or a completion marker file created after rename) so partial
extracts are ignored, and ensure proper cleanup of the temp dir on errors—apply
the same pattern to both the block that currently checks dylib.exists() and the
extraction/promotion block referenced later.
- Around line 243-260: The method set_ort_dylib_path_if_present currently
ignores LD_LIBRARY_PATH; update it to respect LD_LIBRARY_PATH precedence by
checking if env var "LD_LIBRARY_PATH" is set and whether any directory listed
contains the expected ONNX Runtime dylib before setting ORT_DYLIB_PATH.
Concretely, inside set_ort_dylib_path_if_present (and after obtaining dylib via
self.dylib_path()), if LD_LIBRARY_PATH is Some, split it on ':' (and on
platform-specific separator if needed), iterate directories and check for the
presence of the same dylib file name (or libonnxruntime basename) using
Path::join and exists(); if any match, return without calling std::env::set_var;
otherwise proceed to set ORT_DYLIB_PATH as before.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d129935e-7e94-4bc7-93a2-92b8235d9269

📥 Commits

Reviewing files that changed from the base of the PR and between 3bfb07b and 61fa665.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (10)
  • CHANGELOG.md
  • Cargo.toml
  • crates/openmemory-cli/src/commands/model.rs
  • crates/openmemory-cli/src/main.rs
  • crates/openmemory-core/src/config.rs
  • crates/openmemory-embed/Cargo.toml
  • crates/openmemory-embed/src/error.rs
  • crates/openmemory-embed/src/lib.rs
  • crates/openmemory-embed/src/runtime.rs
  • crates/openmemory-graph/tests/integration.rs

Comment thread CHANGELOG.md

## [Unreleased]

## [0.3.2] - 2026-05-17
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add missing release link references and update the Unreleased compare base.

The new 0.3.x headings are reference-style links but there are no [0.3.2], [0.3.1], or [0.3.0] definitions, and Unreleased still compares from v0.2.1. This leaves broken/stale navigation in the changelog.

Suggested patch
-[Unreleased]: https://github.com/raymondj99/openmemory/compare/v0.2.1...HEAD
+[Unreleased]: https://github.com/raymondj99/openmemory/compare/v0.3.2...HEAD
+[0.3.2]: https://github.com/raymondj99/openmemory/compare/v0.3.1...v0.3.2
+[0.3.1]: https://github.com/raymondj99/openmemory/compare/v0.3.0...v0.3.1
+[0.3.0]: https://github.com/raymondj99/openmemory/compare/v0.2.1...v0.3.0
 [0.2.1]: https://github.com/raymondj99/openmemory/compare/v0.2.0...v0.2.1
 [0.2.0]: https://github.com/raymondj99/openmemory/compare/v0.1.0...v0.2.0
 [0.1.0]: https://github.com/raymondj99/openmemory/releases/tag/v0.1.0

Also applies to: 335-338

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CHANGELOG.md` at line 12, The CHANGELOG.md contains reference-style headings
like "## [0.3.2] - 2026-05-17" but lacks the corresponding link definitions and
the Unreleased compare still points at v0.2.1; add reference link definitions
for [0.3.2], [0.3.1], and [0.3.0] at the bottom of the file pointing to their
GitHub compare/release URLs, and update the [Unreleased] reference to compare
from v0.3.2 (e.g., v0.3.2..HEAD) so the Unreleased section and the new 0.3.x
links resolve correctly.

Comment on lines +190 to +197
if dylib.exists() {
info!(
"ONNX Runtime {} already installed at {}",
ONNX_RUNTIME_VERSION,
dylib.display()
);
return Ok(dylib);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Prevent false “installed” state with atomic install finalization.

The install flow extracts directly into the final directory, but later runs treat the install as complete as soon as the versioned dylib exists. If extraction is interrupted, future runs can skip reinstall with an incomplete runtime tree.

Proposed direction (extract to temp dir, then promote atomically)
- let install_dir = self.install_dir(&art);
- let lib_dir = install_dir.join("lib");
- let dylib = lib_dir.join(art.dylib_name);
- if dylib.exists() {
+ let install_dir = self.install_dir(&art);
+ let dylib = install_dir.join("lib").join(art.dylib_name);
+ if dylib.exists() {
      return Ok(dylib);
  }

  // staging dir already exists
+ let staged_install = staging.join(art.archive_root);
+ let staged_lib = staged_install.join("lib");

- extract_lib_subtree(&tarball, &install_dir, art.archive_root)?;
- ensure_dylib_symlink(&lib_dir, art.dylib_name, art.dylib_symlink)?;
+ extract_lib_subtree(&tarball, &staged_install, art.archive_root)?;
+ ensure_dylib_symlink(&staged_lib, art.dylib_name, art.dylib_symlink)?;

+ if install_dir.exists() {
+     fs::remove_dir_all(&install_dir)?;
+ }
+ fs::rename(&staged_install, &install_dir)?;

Also applies to: 222-233

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/openmemory-embed/src/runtime.rs` around lines 190 - 197, The current
install code in runtime.rs (the branch that checks if dylib.exists() and the
later extraction block around the second occurrence) can report "already
installed" for an incomplete extraction because files are written directly into
the final directory; change the install to extract into a temporary directory
(e.g., derive temp path from the target dir like
target_dir.with_extension(".tmp-<pid|uuid>") or use tempfile::TempDir), perform
the full extraction there, and then atomically promote it into place with
std::fs::rename (or std::fs::rename on Windows-equivalent) to replace/move into
the final directory; update the existence check to consider only the final
promoted path (or a completion marker file created after rename) so partial
extracts are ignored, and ensure proper cleanup of the temp dir on errors—apply
the same pattern to both the block that currently checks dylib.exists() and the
extraction/promotion block referenced later.

Comment on lines +243 to +260
/// Set `ORT_DYLIB_PATH` for the current process if (1) the user
/// hasn't already set it, (2) the user hasn't set `LD_LIBRARY_PATH`
/// to a directory containing libonnxruntime, and (3) the runtime
/// manager has a freshly installed dylib. Idempotent and safe to
/// call from `main` before any `ort` code runs.
pub fn set_ort_dylib_path_if_present(&self) {
if std::env::var_os("ORT_DYLIB_PATH").is_some() {
return;
}
let Some(dylib) = self.dylib_path() else {
return;
};
if !dylib.exists() {
return;
}
// SAFETY: `set_var` is safe in single-threaded contexts; we
// call this from `main` before any worker threads are spawned.
std::env::set_var("ORT_DYLIB_PATH", &dylib);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Honor LD_LIBRARY_PATH precedence before setting ORT_DYLIB_PATH.

This method currently only checks ORT_DYLIB_PATH. If a user intentionally relies on LD_LIBRARY_PATH, this code still sets ORT_DYLIB_PATH and overrides that choice.

Small fix
 pub fn set_ort_dylib_path_if_present(&self) {
-    if std::env::var_os("ORT_DYLIB_PATH").is_some() {
+    if std::env::var_os("ORT_DYLIB_PATH").is_some()
+        || std::env::var_os("LD_LIBRARY_PATH").is_some()
+    {
         return;
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/// Set `ORT_DYLIB_PATH` for the current process if (1) the user
/// hasn't already set it, (2) the user hasn't set `LD_LIBRARY_PATH`
/// to a directory containing libonnxruntime, and (3) the runtime
/// manager has a freshly installed dylib. Idempotent and safe to
/// call from `main` before any `ort` code runs.
pub fn set_ort_dylib_path_if_present(&self) {
if std::env::var_os("ORT_DYLIB_PATH").is_some() {
return;
}
let Some(dylib) = self.dylib_path() else {
return;
};
if !dylib.exists() {
return;
}
// SAFETY: `set_var` is safe in single-threaded contexts; we
// call this from `main` before any worker threads are spawned.
std::env::set_var("ORT_DYLIB_PATH", &dylib);
/// Set `ORT_DYLIB_PATH` for the current process if (1) the user
/// hasn't already set it, (2) the user hasn't set `LD_LIBRARY_PATH`
/// to a directory containing libonnxruntime, and (3) the runtime
/// manager has a freshly installed dylib. Idempotent and safe to
/// call from `main` before any `ort` code runs.
pub fn set_ort_dylib_path_if_present(&self) {
if std::env::var_os("ORT_DYLIB_PATH").is_some()
|| std::env::var_os("LD_LIBRARY_PATH").is_some()
{
return;
}
let Some(dylib) = self.dylib_path() else {
return;
};
if !dylib.exists() {
return;
}
// SAFETY: `set_var` is safe in single-threaded contexts; we
// call this from `main` before any worker threads are spawned.
std::env::set_var("ORT_DYLIB_PATH", &dylib);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/openmemory-embed/src/runtime.rs` around lines 243 - 260, The method
set_ort_dylib_path_if_present currently ignores LD_LIBRARY_PATH; update it to
respect LD_LIBRARY_PATH precedence by checking if env var "LD_LIBRARY_PATH" is
set and whether any directory listed contains the expected ONNX Runtime dylib
before setting ORT_DYLIB_PATH. Concretely, inside set_ort_dylib_path_if_present
(and after obtaining dylib via self.dylib_path()), if LD_LIBRARY_PATH is Some,
split it on ':' (and on platform-specific separator if needed), iterate
directories and check for the presence of the same dylib file name (or
libonnxruntime basename) using Path::join and exists(); if any match, return
without calling std::env::set_var; otherwise proceed to set ORT_DYLIB_PATH as
before.

@raymondj99 raymondj99 merged commit 11f7d3d into main May 18, 2026
14 checks passed
@raymondj99 raymondj99 deleted the chore/release-v0.3.2 branch May 18, 2026 04:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant