NAOMS Devlog

Building a sovereign, local-first memory & identity system โ€” in the open, honestly.

Honoring Loro: The Tree That Moves Without Breaking

How two people can reorganize the same data at once without ever clobbering each other

Vision Fellow Travelers free April 1, 2026ยท5 min readยทmeta
TL;DR When two people rearrange the same shared structure at the same time, their edits can merge cleanly instead of colliding. Here's our tribute to Loro, the library that nailed that hard problem, what we took from it, and where our need for encryption and identity led us to build alongside it.

The Loro homepage โ€” "Reimagine state management with CRDTs." A high-performance CRDT library for local-first, real-time collaboration.

Loro โ€” loro.dev

There is a specific kind of problem that looks easy until you try to do it concurrently: moving a node from one place in a tree to another, while someone else is moving the same node somewhere else. Do it naively and you can end up with the node in two places, or in none, or โ€” worst of all โ€” with a cycle where a folder becomes its own grandparent. Loro solved this cleanly, and this piece is written in its honor.

What they do well

Loro is a high-performance CRDT library โ€” a Conflict-free Replicated Data Type engine โ€” written in Rust with WebAssembly bindings for JavaScript and TypeScript, plus native Swift bindings for Apple platforms. It reached a production-ready 1.0 in 2025 and represents, frankly, the current state of the art in CRDT research. Where earlier libraries gave you maps, lists, and text that converge without coordination, Loro pushed the frontier into shapes that were genuinely hard.

The headline is the Moveable Tree CRDT. Tree nodes can be moved between parents, and when two replicas concurrently move the same node to different places, the result is resolved deterministically โ€” no duplication, no orphaning, no illegal cycles. There is also a Moveable List, where items can be repositioned, not merely inserted and deleted, so drag-and-drop reordering works correctly across replicas. For text, Loro uses the Fugue algorithm, which produces provably more intuitive interleaving of concurrent edits than the older approaches โ€” when two people type into the same sentence at once, the result reads the way a human would expect.

Underneath, the craftsmanship is serious. An Eg-walker approach reduces the computation and memory overhead that CRDTs are notorious for. Shallow Snapshots let a large document load from recent state alone, the way a shallow git clone skips ancient history โ€” which matters enormously when histories grow long. And Loro ships genuine version control primitives: branch, merge, and time-travel to any past version, all while staying real-time-syncable. It is, in effect, git-like history and document-like collaboration in one library. It is MIT-licensed, well-funded, and has real momentum in the local-first community. That is years of careful, generous open-source work, and it shows.

Where to find it

If you want to understand how the newest generation of CRDTs handles the shapes that defeated earlier ones โ€” moveable trees, moveable lists, intuitive text โ€” Loro is where to start reading.

What we took

The deepest thing we took from Loro is not code. It is a conviction that reorganizing a hierarchy is a first-class problem, not an afterthought.

Our memory system is not a static pile of records. It grows, and as it grows it needs to be reshaped โ€” memories regrouped into new categories, hierarchies restructured during consolidation, nodes reparented as understanding deepens. That is exactly the operation Loro made safe: a move within a tree, resolved deterministically even under concurrent edits. Loro proved, as the CRDT pioneers Automerge and Yjs did before it, that you do not have to choose between "let the structure evolve" and "keep replicas in agreement." You can have both. We took that conviction directly.

We also took Loro's layering discipline โ€” its refreshing honesty about what it is not. Loro is, by its own description, a CRDT library and nothing more: no storage, no networking, no encryption, no identity. Far from a weakness, this is a clarifying gift. It told us exactly which job a CRDT engine does โ€” provide the conflict-resolution primitives โ€” and which jobs belong to the layers around it: storage, transport, encryption, and identity. That clean separation of concerns is a pattern we adopted in our own architecture, where the part that resolves concurrent change is kept distinct from the parts that persist, encrypt, and authenticate it.

And we took the snapshot insight: that a system accumulating a lifetime of history must be able to load from recent state without replaying everything. Loro's shallow snapshots are the same idea our own loading path needs โ€” start from a compact recent picture, fetch deeper history only when asked.

What we did differently (and why)

Here we have to be careful and generous, because where we diverge from Loro is not a place Loro got something wrong โ€” it is the boundary Loro itself drew with total clarity.

Our memory is a general graph, and Loro's tree is a tree. A Moveable Tree is strictly hierarchical: every node has exactly one parent. Our memory model is a property graph with arbitrary edges โ€” a memory can relate to many others in many typed ways at once, not just hang beneath a single parent. Loro's tree is the right structure for hierarchies and an honest mismatch for general graphs, and Loro says as much plainly. So rather than force our graph into a tree, we model relationships natively and reserve tree-style reparenting for the genuinely hierarchical parts. This is not disagreement with Loro; it is taking Loro's own advice about where its tree fits.

We require encryption and identity in the same breath as merge โ€” and a CRDT library, correctly, provides neither. For us, who may read a memory, who may have written it, and whether a change is authentically signed are not optional overlays โ€” they are inseparable from the data itself. Loro deliberately stays out of that territory, which is the right call for a focused, reusable library. It meant, though, that we could not simply adopt a CRDT engine as our foundation and be done; the conflict-resolution layer had to compose with encryption-by-default and cryptographic identity, which in our world come first. Our own signed-event chain folds a history of authenticated commits into current state by a deterministic function โ€” the same convergence principle Loro embodies, reached through a structure that carries signatures and access control in its bones.

We weighed the WASM trade-off honestly, as Loro invites you to. The Rust-to- WebAssembly path that gives Loro its speed also adds bundle size and memory overhead, which matters in the resource-constrained corners we care about. Loro is transparent about this. Naming the cost out loud โ€” rather than discovering it later โ€” is part of why studying Loro made us better engineers, regardless of which primitives we ended up using.

The honest summary: Loro gave us a conviction and a boundary. The conviction โ€” that hierarchies can be reorganized concurrently and safely โ€” reshaped how we think about a memory that grows. The boundary โ€” that a CRDT engine resolves conflicts and deliberately leaves storage, encryption, and identity to its neighbors โ€” clarified our whole architecture. We built alongside Loro rather than strictly on top of it, and we did so with real admiration for a project that advanced the state of the art and was scrupulously honest about its own edges.

To the Loro team: thank you for making the tree that moves without breaking, and for telling us, plainly, exactly where your tree ends. Both lessons made it into our foundations.


Written by AI agents from real project logs; owned and edited by Mujo.

โ† more in Vision   home โœฆ   all โ†’