# grit

[![CI](https://github.com/bofeizhu/grit/actions/workflows/ci.yml/badge.svg)](https://github.com/bofeizhu/grit/actions/workflows/ci.yml)

An embedded, **bi-temporal property graph for agent memory**. One SQLite
file, in-process, written in Rust. No server, no daemon, no network — compiles
for macOS, Windows, Linux, iOS, and Android.

grit is Layer 1 of a three-layer agent-memory stack: it does deterministic
graph **storage and hybrid retrieval** only. Entity extraction and dedup
judgment (Layer 2) and the agent harness (Layer 3) live elsewhere. The full
design contract — invariants, scope limits, testing bar — is in
[AGENTS.md](AGENTS.md) and is binding for anyone (human or agent) working here.

## What works today (v0.1 core)

- **Append-only, bi-temporal writes.** Every mutation is a `GraphOp` recorded
  in an op-log; graph tables are derived state in the same transaction. Edges
  carry event time (`valid_at`/`invalid_at`) and system time
  (`created_at`/`expired_at`); invalidations are belief-versioned, so
  *"what did I believe in March?"* is a query (`as_at`), not archaeology.
- **Sync-ready semantics before sync exists.** UUIDv7 keys, hybrid logical
  clocks, and op application that is idempotent and commutative for
  concurrent ops — property-tested across adversarial interleavings
  (merge cycles, purges racing adds, out-of-order invalidations).
- **Hybrid retrieval.** FTS5 BM25 + sqlite-vec cosine + validity-filtered
  graph expansion, fused with reciprocal rank fusion, returned with episode
  provenance under an item/token budget.
- **Merge & forget.** `MergeNodes` executes Layer 2's dedup decisions
  (cycle-safe canonical resolution); `Purge` is the only destructive op —
  exact-id, tombstoned, audited in the op-log.
- **Data outlives the library.** Lossless JSONL export/import of the full
  graph + oplog (`grit-cli export/import`).

```rust
use grit_core::{Budget, GraphOp, Grit, Options, Query, Traversal};

let g = Grit::open("memory.db", Options::new("laptop"))?;
g.apply(GraphOp::AddEpisode { /* … */ })?;
let hits = g.search(Query::text("exactness").group("algebra").budget(Budget::items(20)))?;
let ctx  = g.traverse(&[node_id], &Traversal::default().depth(2))?;
let past = g.node_history(node_id)?;            // bi-temporal audit
```

## Workspace

| Crate | Purpose |
|-------|---------|
| `grit-core` | Schema, oplog writer actor, traversal, hybrid search — the product |
| `grit-compat` | Parked, fail-loud Graphiti/FalkorDB-dialect template-translator stub (see the re-scoped compatibility section in AGENTS.md) |
| `grit-cli` | Dev tool: import/export, stats, ad-hoc search/traverse |

Planned next (see AGENTS.md): the Rust port of Graphiti's extraction pipeline
(Layer 2, separate repo) validated by golden-trace fixtures captured from
Python Graphiti + FalkorDB. A Python `GritDriver` for upstream Graphiti is
deferred — an optional adoption play, not a milestone.

## Commands

```bash
cargo build --workspace
cargo test  --workspace          # unit + property + crash + migration + plan-pinning tests
cargo test -p grit-core --release --test envelope -- --ignored   # latency tripwire
cargo bench -p grit-core --bench hot_paths                       # criterion (precision)
cargo clippy --workspace --all-targets -- -D warnings
cargo fmt   --all
```

The test suite includes a `kill -9` crash harness (derived tables must equal
a full oplog replay after any crash), oplog merge-law property tests, frozen
schema-version fixtures, and `EXPLAIN QUERY PLAN` pinning. Everything runs
offline.

## License

MIT OR Apache-2.0, at your option. See [NOTICE](NOTICE) for attributions
(Graphiti schema concepts, simple-graph traversal templates, Cortex scoring
ideas).
