mars: build Mnemosyne env as a Nix derivation (review rework)

Supersedes the venv-based fix attempt in 694317a entirely: replaces the
runtime side-venv with a python3.withPackages derivation
(pkgs/mnemosyne-env.nix: mnemosyne-memory 3.15.1 + mnemosyne-hermes 0.5.0
via fetchPypi, base deps only). Env mounted :ro into the container; the
oneshot only writes the plugins/mnemosyne symlink to the env's
site-packages passthru — a canonical store path valid on both sides. No
runtime fetch, no stamp, no root-executes-luna-writable-code, no
host/container path mismatch, no config.yaml sed.
This commit is contained in:
2026-09-18 23:55:05 +00:00
parent 694317acbb
commit 32dd2abdce
3 changed files with 141 additions and 187 deletions
+86
View File
@@ -0,0 +1,86 @@
# Mnemosyne memory provider for Hermes on mars — packaged for real (Nix).
#
# Why derivations instead of a runtime side-venv: the official Hermes image
# vendors its own Python and stays off-limits to pip (no pip module, PEP 668),
# and a runtime venv built host-side breaks twice over inside the container:
# the venv's pyvenv.cfg records a /nix/store python home the container never
# mounts, and a plugins symlink with an absolute host path points nowhere
# from /opt/data. Building here means nothing is fetched at boot, nothing
# under the provider's control is writable from inside the container, and
# the closure is as reproducible as the rest of the host.
#
# Package set (one shared site-packages — the plugin wrapper imports its
# sibling `mnemosyne` core package, so withPackages, not separate envs):
#
# mnemosyne-memory core engine: SQLite/FTS5 storage, recall, tools.
# Base deps only (PyYAML); the optional extras (llm,
# embeddings via fastembed/onnxruntime, mcp, sync) are
# deliberately NOT pulled — recall uses the bundled FTS5
# lexical path, and the heavyweight ML stack (~hundreds of
# MB, live network on first vector use) buys nothing for
# a first deployment. Adding the embeddings extra later
# is pinning fastembed + sqlite-vec here.
# mnemosyne-hermes the wrapper Hermes discovers under $HERMES_HOME/plugins
# (installs itself as package `hermes_memory_provider`).
# Hard dependency: mnemosyne-memory, PyYAML.
#
# Platform note: both sdists are pure Python (build no C extensions), so
# nothing here constrains the host arch beyond the interpreter itself.
{
python3,
fetchPypi,
}:
let
python = python3;
mnemosyneMemory = python.pkgs.buildPythonPackage rec {
pname = "mnemosyne-memory";
version = "3.15.1";
pyproject = true;
src = fetchPypi {
inherit pname version;
sha256 = "sha256-lspUMxc0pUSkhSUrNdiiO5OJ1NMC/S853EYSanXtXKM=";
};
build-system = with python.pkgs; [ setuptools ];
# Base dependency set — everything else in the upstream metadata is an
# optional extra (llm / embeddings / mcp / sync / test / dev) and is not
# installed; see the file-level comment.
dependencies = with python.pkgs; [ pyyaml ];
doCheck = false; # upstream tests want a live Hermes + LLM key present
pythonImportsCheck = [ "mnemosyne" ];
};
mnemosyneHermes = python.pkgs.buildPythonPackage rec {
pname = "mnemosyne-hermes";
version = "0.5.0";
pyproject = true;
src = fetchPypi {
inherit pname version;
sha256 = "sha256-CzEvnUw5oPFtT5bHQQ/GBdy2C/E7qShQn32irIRYKqw=";
};
build-system = with python.pkgs; [ setuptools ];
# The wrapper declares `mnemosyne-memory[embeddings]>=3.11.1` on PyPI, but
# the embeddings extra is only consulted when vector recall is enabled
# (see above) — pass the core dependency explicitly rather than dragging
# in onnxruntime for nothing.
dependencies = [ mnemosyneMemory ] ++ (with python.pkgs; [ pyyaml ]);
doCheck = false;
pythonImportsCheck = [ "hermes_memory_provider" ];
};
# The exposed value is the python env itself (a store path mounted :ro).
# Hermes only needs the site-packages dir inside it; `sitePackages` is a
# passthru the python interpreter derivation (and hence withPackages envs)
# exposes, so the caller uses `${env.sitePackages}` instead of guessing
# the python version in a path literal.
in
python.withPackages (_: [ mnemosyneMemory mnemosyneHermes ])