Skip to content

levain 0.5.7

Choose a tag to compare

@phillipclapham phillipclapham released this 04 Oct 14:40
· 4398 commits to main since this release

levain wrap no longer cancels a wrap that is not its own: it chooses its wrap's token itself, gives it to anneal, and cancels by it on every exit. The Claude Code install no longer tells its entity that levain wrap recomposes its memory. Levain now requires anneal-memory 0.9.30.

Upgrade Levain together with anneal-memory. Levain 0.5.7 needs anneal-memory 0.9.30 (prepare_wrap(wrap_token=...)), and the pip floor pulls it. levain update refreshes an install's CLAUDE.md and memory seed to the corrected wording (an edited copy is kept and the new one staged under .levain/pending/).

Fixed

  • levain wrap now checks the schema the wrap froze, not only the one the store had before the wrap started (listed as known open in 0.5.6). The partnership check runs again once anneal has started the wrap, on the schema anneal froze for it, and the composing model's instructions are built from that same schema. A store moved off the partnership schema before anneal read it for the wrap is refused (exit 2) and the wrap is cancelled; nothing is saved. This narrows the window, it does not close it: see Known open issues.
  • An interrupt during levain wrap before anneal returned the wrap's token could cancel another program's wrap (known open since 0.4.x, listed in 0.5.6). levain wrap now chooses the wrap's token itself and hands it to anneal, so every cancel (Ctrl-C, the wall-clock stop, a store error) names the wrap Levain started, and anneal clears it only if it still carries that token. Discarding a prior run's stuck wrap (the unattended seat's self-heal, and --reset) names the token it read in the same way, so a wrap another program opened in between is left alone; one that went idle in between counts as discarded. This needs anneal-memory 0.9.30, which Levain now requires.
  • A store error after the wrap had started left that wrap open (found in review of the change above). levain wrap treated every store error as happening before anything was written, so an error after anneal had started the wrap returned without cancelling it, and the next wrap found one in progress. It now cancels its own wrap first.
  • Cancelling a failed wrap could clear another program's wrap on the same store. After a failure, --dry-run, an empty compose, or an unexpected status from anneal, levain wrap either read the wrap's token and then cleared whatever wrap was open, or cleared it without reading the token at all, so a wrap another program started in between was the one cleared. The token is now compared and the wrap cleared in one step by anneal, a wrap that is not ours is left alone, and an unexpected status cancels by Levain's own token, which clears a wrap Levain opened and never another program's.
  • A cancel that failed was reported as done. When the store could not be written (for example, locked by another program) or its wrap state could not be confirmed (no token, or a damaged in-progress record), levain wrap still said the wrap had been cancelled, and --dry-run exited 0 with its wrap left open. It now says the wrap could not be cancelled and how to discard it, and --dry-run exits 1.
  • The Claude Code install no longer tells its entity that levain wrap recomposes its memory. levain wrap refuses a Claude Code install ("not a clean OpenHands entity"); a Claude Code entity writes .levain/memory.continuity.md itself through the MCP prepare_wrap, then save_continuity sequence. The generated CLAUDE.md and the adapter README named the wrong mechanism, as did the 0.5.5 entry below (errata: that entry's "recomposes" is the entity's own wrap, not the levain wrap command). Existing installs: levain update refreshes the corrected CLAUDE.md and seed (an edited copy is kept and the new one staged under .levain/pending/).
  • The memory seed no longer points the entity at an "Association Context" section. anneal names it ## Episode Associations and usually leaves it out of the wrap package, because a wrap's own links are among episodes that have left the next window.

Added

  • A GitHub Actions workflow (.github/workflows/test.yml) runs the test suite on Ubuntu for Python 3.12 and 3.13 on pushes to main and seat/** branches, tags and pull requests.

Known open issues

  • levain wrap --reset no longer clears a wrap whose metadata cannot be read, unless anneal calls that state partial (new in 0.5.7). It used to clear whatever wrap was open; without a token to name, a forced clear would also take any wrap another program opened in its place. anneal-memory --db <the entity's .levain/memory.db> wrap-status shows the wrap, and wrap-cancel --partial or wrap-cancel --wrap-token <its token> on the same --db clears a dead one; Levain's message spells those commands out with the entity's store.
  • A second stop that lands while levain wrap is cancelling can leave the wrap open (since 0.4.x). A Ctrl-C followed by the wall-clock stop while the cancel is running strands the wrap until the next run's discard or --reset.
  • A failed cancel is still reported as a clean one on the wall-clock stop (since 0.4.x). If the store is locked by another process when levain wrap cancels after a timeout, the wrap stays open and the report still says it was cancelled; the next run's discard (or --reset) clears it.
  • If another program clears Levain's wrap while it composes, the failure message says the memory was committed (since 0.4.x). Nothing was saved and the episodes are still unwrapped: re-run.
  • --reset and the unattended discard cannot tell a dead wrap from another program's live one beyond Levain's lock and the wrap's age (since 0.4.x). They clear the wrap they read by its token; whether that wrap is dead is the operator's judgement for --reset.
  • An error raised after the memory was saved is reported as a store read failure (since 0.4.x). If showing the result fails after the save committed, levain wrap says it could not read the store and exits 2, though the memory was saved; a re-run then finds nothing to consolidate.