The blow-the-venv-on-update contract needs rebuilds to be cheap, and
sealed installs need a writable venv at all (settled 2026-09-02 plan,
task 7):
- uv_cache_dir(): hermes-owned machine cache at
<default hermes root>/cache/uv — content-addressed, shared across
profiles. uv_env() ALWAYS pins UV_CACHE_DIR there (ambient UV_*
stripped), so the cache that ships is the cache that gets used.
First call on a sealed install seeds it from the payload's shipped
uv-cache/ (read-only payload can't serve uv's working cache); the
.seeded marker makes it once-only and non-clobbering.
- pm bundle stages the warmed cache into the payload after the venv
sync (uv-cache/ beside manifest.json) — warm 'uv sync --offline'
rebuilds probed at 0.4s vs 1.2s cold.
- Venv.venv_dir(): sealed installs resolve the MUTABLE venv to the
machine hermes root (<root>/venv), not the read-only payload;
dev/source installs keep the repo-local venv unchanged.
- Venv.seed_mutable_venv(): the bootstrap seed — lazy-off installs
copy the payload's shipped venv out as the starting point; lazy-on
installs skip the copy (first sync builds fresh from the shipped
cache). adopt() triggers it (KeyError-guarded, failure reported
never fatal — a cold sync still converges).
tests/pm/test_uv_cache.py: 6 tests (env pinning + ambient strip,
payload seed + marker once-only, cold machine, sealed venv_dir, seed
copy idempotence, lazy-on skip). tests/pm: 175 passed, 0 failed.