···11+# Changelog
22+33+All notable changes to elixir-mst will be documented in this file.
44+55+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66+and this project adheres to
77+[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
88+99+<!--## [Unreleased] -->
1010+1111+## [0.1.0] - 2026-04-09
1212+1313+Initial release.
1414+1515+[unreleased]: https://github.com/cometsh/elixir-mst/compare/v0.1.0...HEAD
1616+[0.1.0]: https://github.com/cometsh/elixir-mst/releases/tag/v0.1.0
+18
LICENSE
···11+Copyright 2026 comet.sh
22+33+Permission is hereby granted, free of charge, to any person obtaining a copy of
44+this software and associated documentation files (the “Software”), to deal in
55+the Software without restriction, including without limitation the rights to
66+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
77+the Software, and to permit persons to whom the Software is furnished to do so,
88+subject to the following conditions:
99+1010+The above copyright notice and this permission notice shall be included in all
1111+copies or substantial portions of the Software.
1212+1313+THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1414+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
1515+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
1616+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
1717+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1818+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+71-9
README.md
···11-# MST
11+# elixir-mst
2233-**TODO: Add description**
33+An Elixir implementation of [AT Protocol-flavoured Merkle Search Trees (MST)][spec].
44+55+## Overview
66+77+A Merkle Search Tree is a content-addressed, ordered key/value structure.
88+Every unique set of key/value pairs produces a unique root CID, making it
99+suitable for Merkle proofs, efficient diffs, and repository synchronisation.
1010+This library implements the AT Protocol flavour: nodes are encoded as
1111+DRISL, keys are arbitrary byte strings, values are `DASL.CID` links, and
1212+tree depth is derived from the SHA-256 hash of each key.
1313+1414+[spec]: https://atproto.com/specs/repository#mst-structure
415516## Installation
61777-If [available in Hex](https://hex.pm/docs/publish), the package can be installed
88-by adding `mst` to your list of dependencies in `mix.exs`:
1818+Get elixir-mst from [hex.pm](https://hex.pm) by adding it to your `mix.exs`:
9191020```elixir
2121+# mix.exs
1122def deps do
1223 [
1313- {:mst, "~> 0.1.0"}
2424+ {:mst, "~> 0.1"}
1425 ]
1526end
1627```
17281818-Documentation can be generated with
1919-[ExDoc](https://github.com/elixir-lang/ex_doc) and published on
2020-[HexDocs](https://hexdocs.pm). Once published, the docs can be found at
2121-<https://hexdocs.pm/mst>.
2929+Documentation can be found on HexDocs at https://hexdocs.pm/mst.
3030+3131+## Quick start
3232+3333+```elixir
3434+# Build a tree
3535+tree = MST.new()
3636+3737+val = DASL.CID.compute("my record data")
3838+{:ok, tree} = MST.put(tree, "app.bsky.feed.post/3jqfcqzm3ft2j", val)
3939+{:ok, ^val} = MST.get(tree, "app.bsky.feed.post/3jqfcqzm3ft2j")
4040+4141+# Mutate (persistent — the original tree is unchanged)
4242+{:ok, tree2} = MST.put(tree, "app.bsky.feed.post/3jqfcqzm3fz2j", val)
4343+{:ok, tree2} = MST.delete(tree2, "app.bsky.feed.post/3jqfcqzm3ft2j")
4444+4545+# Enumerate in sorted order
4646+{:ok, pairs} = MST.to_list(tree2)
4747+# => [{"app.bsky.feed.post/3jqfcqzm3fz2j", val}]
4848+4949+# Or stream lazily
5050+tree2 |> MST.stream() |> Enum.each(fn {key, cid} -> ... end)
5151+```
5252+5353+## CAR import / export
5454+5555+```elixir
5656+# Export to a CARv1 binary
5757+{:ok, car_bytes} = MST.to_car(tree)
5858+File.write!("repo.car", car_bytes)
5959+6060+# Import from a CARv1 binary
6161+{:ok, tree} = MST.from_car(File.read!("repo.car"))
6262+```
6363+6464+## Diffing two trees
6565+6666+```elixir
6767+{:ok, diff} = MST.diff(tree_a, tree_b)
6868+6969+diff.created_nodes # MapSet of node CIDs added in tree_b
7070+diff.deleted_nodes # MapSet of node CIDs removed from tree_a
7171+7272+for %MST.Diff.Op{key: key, old_value: old, new_value: new} <- diff.record_ops do
7373+ case {old, new} do
7474+ {nil, cid} -> IO.puts("create #{key} → #{cid}")
7575+ {cid, nil} -> IO.puts("delete #{key} (was #{cid})")
7676+ {old, new} -> IO.puts("update #{key}: #{old} → #{new}")
7777+ end
7878+end
7979+```
8080+8181+---
8282+8383+This project is licensed under the [MIT License](./LICENSE)