151 lines
5.1 KiB
Markdown
151 lines
5.1 KiB
Markdown
|
|
# aether-tools-rs — atom + 4 binaries
|
|||
|
|
|
|||
|
|
The unified rewrite of aether-tools onto a single atomic primitive.
|
|||
|
|
**1517 production LOC across 4 binaries** (vs ~7000 LOC in the
|
|||
|
|
original 7-crate suite) — driven by one core idea:
|
|||
|
|
|
|||
|
|
> An answer, once given, is true until forgotten.
|
|||
|
|
|
|||
|
|
Concretely: a content-addressed memo table that lives on disk as an
|
|||
|
|
append-only JSONL ledger. Every binary in this workspace is a thin
|
|||
|
|
binding around three operations:
|
|||
|
|
|
|||
|
|
1. **`canonicalize(input)`** — collapse equivalent inputs to a stable
|
|||
|
|
byte form (regex-based Rust-error abstraction by default; identity
|
|||
|
|
otherwise).
|
|||
|
|
2. **`record(sig, scope, body, worked?, ts)`** — append a fact to the
|
|||
|
|
audit log.
|
|||
|
|
3. **`ask(sig) → value | miss`** — cache-or-compute.
|
|||
|
|
|
|||
|
|
## Crates
|
|||
|
|
|
|||
|
|
| Crate | LOC | Role |
|
|||
|
|
|---|---:|---|
|
|||
|
|
| `aether-atom` | 577 | The atomic core: fingerprint, canonicalize, lattice, ask/demote/remember |
|
|||
|
|
| `aether-recall-mcp` | 311 | MCP-over-stdio server (the 4 tools that drive opencode's recall loop) |
|
|||
|
|
| `aether-net-mini` | 245 | TCP JSON-RPC daemon: `put`/`get` over the atom |
|
|||
|
|
| `aether-ask` | 326 | HTTP front-end: cache-or-fallback to ollama, dark-mode UI |
|
|||
|
|
| `aec-atom` | 250 | REPL: `lookup`/`remember`/`stats`/`compact`/`replay`/`fingerprint` |
|
|||
|
|
| `examples/library_usage` | ~80 | Drop-in pattern for any third-party crate that wants memory |
|
|||
|
|
|
|||
|
|
Total **1517 production LOC** (excluding the example).
|
|||
|
|
|
|||
|
|
## Tests
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
atom 28 unit
|
|||
|
|
aether-recall-mcp 1 integration (spawns binary, full lifecycle)
|
|||
|
|
aether-net-mini 5 unit
|
|||
|
|
aether-ask 2 unit + 4 integration (HTTP routes + cache hit assertion)
|
|||
|
|
aec-atom 10 unit
|
|||
|
|
─────
|
|||
|
|
50 passing
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
`cargo test --workspace` runs all of them in ~0.30 s.
|
|||
|
|
|
|||
|
|
## Clippy
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
$ cargo clippy --workspace --all-targets
|
|||
|
|
(clean — no warnings, no errors)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Configuration
|
|||
|
|
|
|||
|
|
Every binary takes its data directory from a single helper in the atom:
|
|||
|
|
|
|||
|
|
```rust
|
|||
|
|
aether_atom::data_dir("AETHER_RECALL_DIR")
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Resolution order: env var → `$HOME/.aether-recall/` → `./.aether-recall/`.
|
|||
|
|
Override with `AETHER_RECALL_DIR=/path/to/ledger`.
|
|||
|
|
|
|||
|
|
Per-binary tunables:
|
|||
|
|
|
|||
|
|
| Binary | Env var | Default |
|
|||
|
|
|---|---|---|
|
|||
|
|
| `aether-recall-mcp` | `AETHER_RECALL_LOOKUP_RETENTION_DAYS` | 30 |
|
|||
|
|
| `aether-ask` | `AETHER_ASK_PORT`, `OLLAMA_HOST`, `OLLAMA_PORT`, `OLLAMA_MODEL` | 8082 / 127.0.0.1 / 11434 / dolphin-llama3:8b |
|
|||
|
|
| `aether-net-mini` | `AETHER_NET_DATA_DIR` | `$HOME/.aether-recall/` |
|
|||
|
|
| `aec-atom` | `AEC_COMPACT_DAYS` | 30 |
|
|||
|
|
|
|||
|
|
## Run
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
cargo build --release --workspace
|
|||
|
|
|
|||
|
|
# Stand up an MCP server (used by opencode)
|
|||
|
|
AETHER_RECALL_DIR=~/.aether-recall ./target/release/aether-recall-mcp &
|
|||
|
|
|
|||
|
|
# Run an HTTP gateway alongside
|
|||
|
|
AETHER_ASK_PORT=8082 ./target/release/aether-ask &
|
|||
|
|
|
|||
|
|
# Optionally stand up a DHT node
|
|||
|
|
./target/release/aether-net-mini daemon --listen 0.0.0.0:9001 &
|
|||
|
|
|
|||
|
|
# Or poke at the ledger live
|
|||
|
|
./target/release/aec-atom
|
|||
|
|
ae> remember "error[E0308]: expected i32, found &str" "use .to_string()"
|
|||
|
|
ae> lookup "error[E0308]: expected i32, found &str"
|
|||
|
|
ae> stats
|
|||
|
|
ae> replay
|
|||
|
|
ae> quit
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Use the atom in your own code
|
|||
|
|
|
|||
|
|
```toml
|
|||
|
|
[dependencies]
|
|||
|
|
aether-atom = { path = "/home/cosmos/aether-atom" } # or git / crates.io
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
```rust
|
|||
|
|
use aether_atom::{data_dir, fingerprint, rust_canonicalize, Lattice};
|
|||
|
|
|
|||
|
|
let mut lat = Lattice::open(&data_dir("MY_DATA_DIR"))?;
|
|||
|
|
let sig = fingerprint(rust_canonicalize(my_input).as_slice());
|
|||
|
|
match lat.lookup(&sig, "global") {
|
|||
|
|
Some(hit) => return hit.value, // cache hit
|
|||
|
|
None => { let v = compute(my_input); // cache miss
|
|||
|
|
lat.record(sig, "global", &v, Some(true));
|
|||
|
|
return v; }
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
See `examples/library_usage/` for a 50-LOC working program with tests.
|
|||
|
|
|
|||
|
|
## Bench approx (in-process, sdb fs)
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
10,000 cached ask() ops (incl. disk write): 801 ms = 80 µs/op
|
|||
|
|
100,000 raw lookup() ops (incl. disk write): 8.5 s = 85 µs/op
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
vs the original aether-recall README's claim of ~200 µs per cached
|
|||
|
|
lookup — about **2.5×** faster, chiefly because bodies are Arc-shared
|
|||
|
|
on the hit path so there's never a memcpy of the cached value.
|
|||
|
|
|
|||
|
|
## What this is NOT
|
|||
|
|
|
|||
|
|
- Not a chat product. A primitive your tools build on.
|
|||
|
|
- Not a peer-to-peer replication mesh. `replicate` is a placeholder.
|
|||
|
|
Both peers inherit the same atom ledger if they share the data dir.
|
|||
|
|
- Not a model registry. `aether-ask` delegates to whatever ollama is
|
|||
|
|
reachable; it doesn't manage model storage.
|
|||
|
|
|
|||
|
|
## Built from this premise
|
|||
|
|
|
|||
|
|
Today the aether suite was 7 crates, ~7000 LOC. The original had
|
|||
|
|
*three* divergent fingerprint schemes, *three* append-only ledgers,
|
|||
|
|
~900 ms subprocess overhead per ask, a hardcoded WSL2 path in three
|
|||
|
|
places, two dead kelp of dependencies (`sha3`, `hex`, `rand`, `chrono`)
|
|||
|
|
and two stubbed modules. This rewrite collapses that to one
|
|||
|
|
fingerprint, one ledger, one canonical linker (the atom), and four
|
|||
|
|
bindings — each adding a real surface (MCP tool, TCP verb, HTTP verb,
|
|||
|
|
or REPL command).
|
|||
|
|
|
|||
|
|
The atom is the most essential layer: prove it works, prove it
|
|||
|
|
benchmarks, and every wrapper is an obligation.
|