Skip to content

Commit 2d4112f

Browse files
committed
revamp readme
1 parent 3f864a6 commit 2d4112f

5 files changed

Lines changed: 753 additions & 67 deletions

File tree

README.md

Lines changed: 127 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -5,35 +5,107 @@
55
[![License](https://img.shields.io/crates/l/prollytree.svg)](https://github.com/zhangfengcdt/prollytree/blob/main/LICENSE)
66
[![Downloads](https://img.shields.io/crates/d/prollytree.svg)](https://crates.io/crates/prollytree)
77

8-
A **probabilistic B-tree** implementation in Rust that combines B-tree efficiency with Merkle tree cryptographic properties. Designed for distributed systems, version control, and verifiable data structures.
8+
**Versioned, namespaced, semantically-searchable storage for AI agents** — built on a probabilistic B-tree with Merkle properties.
99

10-
## Features
10+
ProllyTree gives an agent a long-term memory it can branch, merge, and audit like source code: every write is committed to a real Git history, every memory is cryptographically verifiable, and the bundled text index lets the agent recall by meaning rather than exact key. Implemented in Rust with first-class Python bindings.
11+
12+
## Why ProllyTree for agent memory
1113

12-
- **High Performance**: O(log n) operations with cache-friendly probabilistic balancing
13-
- **Cryptographically Verifiable**: Merkle tree properties for data integrity and inclusion proofs
14-
- **Multiple Storage Backends**: In-memory, File, RocksDB, and Git-backed persistence
15-
- **Distributed-Ready**: Efficient diff, sync, and three-way merge with pluggable conflict resolvers
16-
- **Python Bindings**: Full API coverage via PyO3 with async support
17-
- **SQL Interface**: Query trees with SQL via GlueSQL integration
14+
- **Per-agent namespaces.** Run many isolated agents against one store — each gets its own prolly tree (key space, search index, history) inside the same Git repo. One commit covers every namespace atomically.
15+
- **Semantic recall.** Vector / text indexes live inside any namespace. Search by meaning ("what did the user say about billing last week?") and resolve hits back to the original message via the primary tree.
16+
- **Branchable scratch spaces.** Spin up an `experiment` branch for tool-call replays, A/B prompt strategies, or speculative reasoning. Discard or merge back. Real Git branches — `gh` / `git log` work.
17+
- **Auditable.** Every memory mutation is a Git commit. Diff what an agent learned between two timestamps, rewind to a known-good state, or merge knowledge across agent instances with three-way conflict resolution.
18+
- **Cryptographically verifiable.** Each value carries a Merkle inclusion proof. Useful when an agent's memory crosses trust boundaries (replicas, audit logs, ZK use cases).
19+
- **No standalone vector database needed.** The text index and the primary store share one transaction. No syncing job, no eventual-consistency window between memory and embeddings.
1820

19-
## Quick Start
21+
## Features
2022

21-
Add to your `Cargo.toml`:
23+
| Capability | What it gives you |
24+
|---|---|
25+
| **Versioned KV store** | Git-backed branch / commit / diff / three-way merge on raw key-value state |
26+
| **Namespaced KV store** | Many isolated prolly trees in one Git repo, atomic across namespaces |
27+
| **Text / vector search** | Versioned ANN index inside any namespace; bundled MiniLM, hash, and callable embedders |
28+
| **Multi-chunk indexing** | Split docs into chunks at index time, dedup on search by document |
29+
| **Cascade mode** | One primary write auto-mirrors into every registered text index |
30+
| **Drift detection + repair** | `audit_text_index` and `purge_text_index_orphans` |
31+
| **Large-value externalization** | Values above a threshold land in content-addressed blobs; `gc_blobs()` reclaims them |
32+
| **Cryptographic proofs** | Merkle inclusion / absence proofs on every value |
33+
| **Multiple storage backends** | In-memory, File, RocksDB, Git-backed |
34+
| **SQL interface** | Query the tree as relational tables via GlueSQL |
35+
| **Python bindings** | Full surface via PyO3 — versioning, namespaces, text search, SQL |
36+
| **`git-prolly` CLI** | Git-style command surface over the versioning + SQL layers |
37+
38+
## Quick start
39+
40+
### Rust
2241

2342
```toml
2443
[dependencies]
25-
prollytree = "0.3.5-beta"
26-
27-
# Optional features
2844
prollytree = { version = "0.3.5-beta", features = ["git", "sql"] }
45+
# Add `proximity` for the text-search surface, `proximity_text` for bundled MiniLM.
46+
```
47+
48+
### Python
49+
50+
```bash
51+
pip install prollytree # ships with git, sql, proximity, proximity_text by default
2952
```
3053

3154
## Examples
3255

33-
### Verifiable key-value store
56+
### Versioned + namespaced agent memory
57+
58+
Each agent gets its own namespace; one Git commit covers all of them.
59+
60+
```python
61+
from prollytree import NamespacedKvStore
62+
63+
store = NamespacedKvStore("./agent_memory")
64+
65+
# Two agents, two isolated key spaces, one repo.
66+
store.ns_insert("agent:planner", b"task:current", b"draft Q3 roadmap")
67+
store.ns_insert("agent:executor", b"task:current", b"deploy feature flag")
68+
store.commit("seed agent state")
69+
70+
# Branch to experiment without disturbing the live store.
71+
store.branch("experiment")
72+
store.ns_insert("agent:planner", b"task:current", b"try alternative plan")
73+
store.commit("alternative planning")
74+
75+
store.checkout("main")
76+
store.ns_get("agent:planner", b"task:current") # b"draft Q3 roadmap" — main is unchanged
77+
```
78+
79+
### Semantic recall over an agent's memory
3480

35-
A ProllyTree is a Merkle tree, so any key-value pair comes with a cryptographic
36-
inclusion proof.
81+
The text index lives inside the namespace. Search by meaning, resolve back to the original message.
82+
83+
```python
84+
from prollytree import NamespacedKvStore, MiniLmEmbedder
85+
86+
store = NamespacedKvStore("./agent_memory")
87+
emb = MiniLmEmbedder() # bundled all-MiniLM-L6-v2
88+
89+
store.text_index_open("agent:assistant", "by_body", emb)
90+
store.set_cascade("agent:assistant", ["by_body"]) # primary writes auto-index
91+
92+
# Capture every observation; index updates atomically with the primary tree.
93+
store.ns_insert("agent:assistant", b"obs:1",
94+
b"user prefers dark mode interfaces")
95+
store.ns_insert("agent:assistant", b"obs:2",
96+
b"user is learning ML with Python")
97+
store.commit("memories from session 42")
98+
99+
# Recall by meaning, not exact phrasing.
100+
for obs_id, distance in store.text_index_search(
101+
"agent:assistant", "by_body", "what's the user's interface preference?", k=3):
102+
body = store.ns_get("agent:assistant", obs_id).decode()
103+
print(f"{obs_id} (d={distance:.3f}): {body}")
104+
```
105+
106+
### Verifiable raw KV (when you want proofs)
107+
108+
The raw `ProllyTree` ships a Merkle inclusion proof for every key.
37109

38110
```rust
39111
use prollytree::tree::{ProllyTree, Tree};
@@ -46,10 +118,7 @@ let proof = tree.generate_proof(b"user:alice");
46118
assert!(tree.verify(proof, b"user:alice", Some(b"Alice")));
47119
```
48120

49-
### Git-backed versioning
50-
51-
The `git` feature stores tree nodes as Git objects, so commits, branches, and merges
52-
work natively on key-value state.
121+
### Git-backed flat store (single key space)
53122

54123
```rust
55124
use prollytree::git::versioned_store::StoreFactory;
@@ -61,69 +130,85 @@ store.commit("Initial config")?;
61130
store.create_branch("experimental")?;
62131
store.insert(b"config/api_key".to_vec(), b"v2".to_vec())?;
63132
store.commit("Try new key")?;
64-
// → diff, merge, history available; see the user guide
65133
```
66134

67-
See [`examples/`](examples/) for SQL queries, additional storage backends, and agent
68-
memory patterns.
135+
See [`examples/`](examples/) (Rust) and [`python/examples/`](python/examples/) (Python) for namespaces, text search, cascade, merge resolvers, and SQL.
136+
137+
## Embedders
138+
139+
The text-search surface ships three embedders. All three plug into `text_index_open(...)` the same way.
140+
141+
| Embedder | Pulls in | Use it for |
142+
|---|---|---|
143+
| `HashEmbedder` | nothing extra | Tests, demos, exact-match recall |
144+
| `MiniLmEmbedder` | Candle (pure Rust) + ~90 MB weights | Real semantic search, offline-friendly |
145+
| `CallableEmbedder` | your callable | OpenAI, Cohere, sentence-transformers, your own model |
69146

70-
## Feature Flags
147+
Embedder identity (`id` + `version`) is persisted with the index. Reopening with a mismatched embedder surfaces a clear error — no silent mixing of vectors from different models.
148+
149+
## Feature flags
71150

72151
| Feature | Description | Default |
73-
|---------|-------------|---------|
74-
| `git` | Git-backed versioned storage with branching, merging, and history | Yes |
152+
|---|---|---|
153+
| `git` | Git-backed versioned storage with branching, merging, history | Yes |
75154
| `sql` | SQL query interface via GlueSQL | Yes |
155+
| `proximity` | Vector index + text-search infrastructure (ML-free) | No |
156+
| `proximity_text` | Bundled Candle + all-MiniLM-L6-v2 embedder | No |
76157
| `rocksdb_storage` | RocksDB persistent storage backend | No |
77158
| `python` | Python bindings via PyO3 | No |
78159
| `tracing` | Observability via the `tracing` crate | No |
79-
| `digest_base64` | Base64 encoding for digests | Yes |
160+
161+
Python PyPI wheels ship `git`, `sql`, `rocksdb_storage`, `proximity`, and `proximity_text` enabled. Rust users opt in:
80162

81163
```toml
82164
[dependencies.prollytree]
83165
version = "0.3.5-beta"
84-
features = ["git", "sql", "rocksdb_storage"]
166+
features = ["git", "sql", "proximity", "proximity_text"]
85167
```
86168

87169
## Performance
88170

89-
**Benchmarks (Apple M3 Pro, 18GB RAM):**
90-
- Insert: ~8-21 us (scales O(log n))
91-
- Lookup: ~1-3 us (sub-linear due to caching)
171+
Benchmarks on Apple M3 Pro / 18 GB RAM:
172+
173+
- Insert: ~8–21 µs (scales O(log n))
174+
- Lookup: ~1–3 µs (sub-linear due to caching)
92175
- Memory: ~100 bytes per key-value pair
93176
- Batch operations: ~25% faster than individual ops
94177

95-
Run benchmarks: `cargo bench`
178+
Run `cargo bench` to reproduce. The vector index uses a lazy-rebuild pattern — mutations are amortised, the first search after a mutation pays the rebuild cost.
96179

97180
## Testing
98181

99182
```bash
100183
# Rust tests
101-
cargo test --features "git sql"
184+
cargo test --features "git sql proximity"
102185

103-
# Python tests (build bindings first)
186+
# Python tests (build bindings first; --all-features includes proximity)
104187
./python/build_python.sh --all-features --install
105188
python -m pytest python/tests/
106189
```
107190

108-
## Documentation & Examples
191+
## Documentation
109192

110-
- **[User Guide & Theory](https://zhangfengcdt.github.io/prollytree/)** – mkdocs site with the full tour (theory, CLI, Python, examples)
111-
- **[Rust API Reference](https://docs.rs/prollytree)** – auto-generated from source
112-
- **[Use Cases & Examples](examples/)** – version control, SQL, proofs, storage backends
113-
- **[Python Bindings](python/README.md)** – Python-specific quickstart
193+
- **[User Guide](https://zhangfengcdt.github.io/prollytree/)** — mkdocs site (architecture, CLI, Python API, examples, theory)
194+
- **[Text Search Guide](https://zhangfengcdt.github.io/prollytree/text_search/)** — design, embedder identity, cascade, merge, externalisation
195+
- **[Browser Demo](https://zhangfengcdt.github.io/prollytree/text_search_demo.html)** — interactive single-page demo of the text-search workflow
196+
- **[Rust API Reference](https://docs.rs/prollytree)** — auto-generated from source
197+
- **[Python Quickstart](python/README.md)** — Python-specific intro
198+
- **[Runnable Examples](examples/)** — verifiable KV, versioning, namespaces, text search, SQL, multi-agent worktrees
114199

115-
## CLI Tool
200+
## CLI
116201

117202
```bash
118203
cargo install prollytree --features git
119204
git-prolly --help
120205
```
121206

122-
See the [user guide](https://zhangfengcdt.github.io/prollytree/) for a full CLI walkthrough.
207+
See the [user guide](https://zhangfengcdt.github.io/prollytree/cli/) for the full CLI walkthrough.
123208

124209
## Contributing
125210

126-
We welcome contributions! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
211+
Contributions welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).
127212

128213
## License
129214

docs/examples/text_search.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ Runnable Python examples for the text-index + vector-search surface on `Namespac
44

55
A complete runnable script — covering every snippet on this page plus a MiniLM end-to-end demo — lives at [`python/examples/text_index_example.py`](https://github.com/zhangfengcdt/prollytree/blob/main/python/examples/text_index_example.py).
66

7+
!!! tip "Browser demo"
8+
Want to see the workflow without installing anything? The [interactive demo](../text_search_demo.html) runs a toy search against a static corpus in your browser, and includes the same code snippets shown below.
9+
710
## Setup
811

912
```python

docs/text_search.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
ProllyTree includes a **version-controlled approximate-nearest-neighbour (ANN) index** that sits inside any namespace of a `NamespacedKvStore`. You can do semantic similarity search on the same data that the rest of the store versions, branches, and merges — without standing up a separate vector database.
44

5+
!!! tip "Try it in your browser"
6+
Open the [interactive demo](text_search_demo.html) for a self-contained walkthrough — namespaced store + text indexes + cascade + live search, no install required.
7+
58
For the conceptual model see [Architecture → Proximity / text-search layer](architecture.md#7-proximity-text-search-layer). For runnable code see [Examples → Text Search](examples/text_search.md).
69

710
## When to use it

0 commit comments

Comments
 (0)