Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Phase 1 progress

v0.0.2, "it commits". The content-addressed object store and the commit graph.

Decisions (all Accepted)

  • ADR-0008 object encoding and the store engine: redb, CBOR restricted to RFC 8949 §4.2 plus our 64-bit-float rule, ciborium plus a thin pass.
  • ADR-0009 the ref model: branches only, flat namespace, one-line text HEAD, compare-and-swap ref moves, reflog reserved.

mnem-core, built

TicketModuleWhat
#22object, idObject (kind-tagged), MemoryNode, State, Commit, Provenance; ObjectId (BLAKE3, hex, CBOR byte string)
#23codec, objects, errorcanonical CBOR encode/decode; put/get/has over a redb txn; MnemError
#24store, configStore::init/open (upward discovery, nested-store guard), config parsing with the format_version gate
#25refs, headthe refs table with compare-and-swap; Head::{Attached,Detached}; Store::head/set_head/resolve_head
#26commit, stagingpersistent staging; Store::stage/staged/unstage/commit (one write txn per commit)
#27logStore::log/log_head, first-parent and full-graph walks

ADR-0004 tracer-bullet checkpoint

The minimum vertical slice (#23 to #27) is working, ~43 tests, no walls hit. Friction: a redb borrow-lifetime quirk (fixed by inlining a helper) and a clippy version drift (fixed by pinning CI's rust job to 1.93.0). The Rust core continues; the Python fallback is not needed.

mnem CLI, built (#28)

init, add, commit, log, each a thin wrapper over the core. Verified end to end:

$ mnem init
$ mnem add customer-4821 "the customer is on the Enterprise plan" --source ticket-4821
$ mnem commit -m "learn the plan tier"
$ mnem add customer-4821 "the customer downgraded to Pro"
$ mnem commit -m "record the downgrade"
$ mnem log --oneline
ddb2a9ea60a3 record the downgrade
45ee8a6b98b1 learn the plan tier

mnem-py, the Python binding (#29)

A pyo3 cdylib (_mnem) over mnem-core, built by maturin as an abi3 wheel (abi3-py310, one wheel for CPython 3.10 and up). It exposes Store (init, open, add, commit, staged, unstage, log, head, format_version, root) and maps every MnemError variant onto a Python exception hierarchy rooted at mnem.MnemError (ADR-0004). pyproject.toml moved from hatchling to the maturin backend; the version is read from the Cargo workspace at build time. python/mnem/__init__.py re-exports the binding; the ergonomic layer is #30.

The rust CI job excludes mnem-py from cargo test/build (its test binary would need libpython to link); the python job builds the real extension through maturin and runs the binding's smoke tests. The behaviour itself stays tested in the core.

mnem, the Python SDK (#30)

The agent-facing layer, pure ergonomics over the binding (ADR-0004). Store takes str | PathLike, add takes any JSON-serialisable value and does the json.dumps, commit defaults the author to $MNEM_AUTHOR then "unknown" and the time to now (matching the CLI), and log returns Commit dataclasses. Provenance and MemoryNode are dataclasses; add_node stages a MemoryNode. Module-level mnem.init / mnem.open mirror the classmethods. The binding's add grew the remaining three Provenance fields so the SDK carries all of ADR-0003's provenance. A _mnem.pyi stub types the raw extension. Binding tests moved to mnem._mnem; test_sdk.py covers the wrapper.

Round-trip test (#31), the definition of done

crates/mnem-core/tests/round_trip.rs: a fixed synthetic run (a support agent triaging one ticket over three commits, mixing fresh nodes with updates, string / nested / unicode content, and provenance from empty to every field set) is persisted, the Store is dropped so the database file closes, then it is reopened from disk. The test asserts:

  • the whole object table is byte-identical before and after the reload
  • every stored id is still the BLAKE3 hash of its stored bytes, and decoding then re-encoding an object reproduces those bytes exactly
  • the commit history reloads in the same order with the same parents, messages, authors and times
  • HEAD's state holds every node id pointing at its latest value, and an earlier commit's state still holds the pre-update value

Runs in the rust CI job. An agent loop can persist its memory and read it back byte for byte.

The format spec, frozen (#32)

docs/format/README.md is now the full specification: the store directory, discovery and atomicity, the config and HEAD grammars, the three redb tables, object identity, the canonical CBOR profile (RFC 8949 section 4.2 plus the three Mnemosyne rules), and a field table for each object kind. It is marked frozen for the 0.0.x line: format_version 1, the same for every 0.0.x release.

docs/format/golden-vectors.md pins six canonical objects with their exact CBOR hex and ObjectId. crates/mnem-core/tests/golden_vectors.rs checks both that the encoder still produces those bytes and that the doc still lists them, so the format cannot drift without a red test.

The wheel job (#33)

CI now has a wheel job separate from the editable python job: it builds a release wheel with maturin build --release, checks the archive bundles _mnem.abi3.so, _mnem.pyi and py.typed, installs it into a clean environment, and runs the SDK tests from outside the repo so import mnem can only resolve to the installed wheel. The wheel is uploaded as a build artefact.

Phase 1 complete, tagged v0.0.2

The substrate core, the mnem CLI, the pyo3 binding, the Python SDK, the format spec and golden vectors, the round-trip test, and the wheel job are all in. The repo-hardening epic (#99) landed alongside: conventional commits, the offline-core deny check, issue forms, the justfile, the consistency checks, and workspace lints. The definition of done is met.

v0.0.2 tagged on main (ADR-0007): workspace version bumped, the changelog section dated, docs/progress/plain-notes.md written. The pending-release issues and the v0.0.2 milestone are closed. Next: Phase 2 (v0.0.3), map #10.