Files
aether-tools-rs/README.md
T
2026-07-09 17:05:13 -04:00

151 lines
5.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.