Skip to main content
Glama
README.md
# polarmem

Local-first memory engine for AI agents. Your agent's entire long-term memory
in one small file — embeddings stored in polar-quantized form.

## Why polarmem

- **Private by default** — a single SQLite file on your disk, local ONNX
  embeddings, no cloud calls, no API keys.
- **Compact** — polar quantization packs each embedding into a fraction of
  its float32 size while keeping recall close to exact search (see
  benchmark below).
- **Human-like recall** — results are ranked by semantic similarity ×
  recency × usage frequency, the same mix that makes a memory feel "top of
  mind." Outdated facts are superseded, not deleted, so history stays
  intact.

## Benchmark

Recall@10 on synthetic clustered data (dim 384, 5000 vectors, 20 clusters).
Reproduce with [`benchmarks/bench_quantization.py`](benchmarks/bench_quantization.py)
(relative link — if it 404s, e.g. on PyPI, run the script from a clone):

```bash
python benchmarks/bench_quantization.py
```

| Method | Bytes/vector | Recall@10 |
|---|---|---|
| float32 (exact) | 1536 | 1.000 |
| int8 | 384 | 0.983 |
| binary (sign) | 48 | 0.427 |
| polar 8/8 | 388 | 0.987 |
| polar 8/4 | 292 | 0.947 |
| polar 4/4 | 196 | 0.865 |

Polar 8/8 matches int8's footprint with slightly better recall. Polar 8/4
and 4/4 open up intermediate size/quality points that int8 and binary
simply don't offer — useful when you want to shrink storage further
without falling off the binary cliff (recall collapses to 0.427 there).
`angle_bits`/`radius_bits` are a tunable knob on `PolarMem` and
`PolarQuantizer` (default 8/8; 8/4 is a good default if you want tighter
storage and can accept a small recall hit).

## Honest positioning

Polar quantization follows the approach in ["PolarQuant: Leveraging Polar
Transformation for Efficient Key Cache Quantization"](https://arxiv.org/abs/2502.00527)
(arXiv:2502.00527, arXiv preprint). The recall scoring mechanics are
inspired by ["Generative Agents: Interactive Simulacra of Human
Behavior"](https://arxiv.org/abs/2304.03442) (Park et al., 2023,
arXiv:2304.03442). polarmem's contribution is packaging this into a
persistent, local-first memory product for AI agents — not inventing the
underlying quantization or scoring techniques.

## Install

```bash
pip install polarmem
```

Not yet published to PyPI. Until then, install from source:

```bash
git clone <this-repo>
cd polarmem
pip install -e .
```

Contributing? This is a src-layout package, so `pip install -e .` alone
won't put `polarmem` on the test runner's path with dev tooling — run
`pip install -e .[dev]` before `pytest`.

## Connect to Claude Code

Add polarmem as an MCP server:

```json
{
  "mcpServers": {
    "polarmem": {
      "command": "polarmem-mcp",
      "env": { "POLARMEM_DB": "C:/Users/you/.polarmem/memory.db" }
    }
  }
}
```

This exposes six tools: `remember`, `recall`, `forget`, `supersede`,
`stats`, and `digest`. Call `digest` once at the start of a session to
prime the agent's context with its most relevant memories.

## Python API

```python
from polarmem import PolarMem

with PolarMem("project.mem") as mem:
    result = mem.remember("The staging DB migrated to us-east-1 on 2026-03-01")
    print(result["conflicts"])   # candidate memories this may contradict

    hits = mem.recall("where is the staging database")
    for h in hits:
        print(h["score"], h["text"])

    mem.forget(hits[0]["id"])
    print(mem.stats())
```

## CLI

```bash
polarmem remember "text to store"      # store a fact
polarmem recall "query" [--limit N]    # search memory
polarmem stats                         # count, db size, quantization settings
polarmem viz [--out FILE]              # render the polar memory map to HTML
polarmem export PATH                   # dump memory to diffable JSONL
polarmem import PATH                   # load memory from JSONL
```

Configure with environment variables: `POLARMEM_DB` (db path, defaults to
`~/.polarmem/memory.db`) and `POLARMEM_EMBEDDER` (set to `hash` to use the
offline test embedder instead of the local ONNX model).

## Team memory via git

Embeddings aren't exported — only text and metadata — so the JSONL is
small, diffable, and independent of any particular model or bit-depth:

```bash
polarmem export mem.jsonl   # dump your memory
git add mem.jsonl && git commit -m "share memory"   # commit + push
git pull                                             # teammate pulls
polarmem import mem.jsonl   # teammate re-embeds locally; conflicts: first import wins
```

## Polar map

`polarmem viz` renders a self-contained HTML page: angle encodes the
memory's meaning cluster (2D projection of the embedding space), radius
encodes age, and point size encodes how often the memory has been
recalled. Useful for eyeballing what an agent actually remembers.

## How it works

1. Text is embedded locally (bge-small, 384 dimensions, ONNX via
   fastembed — no network calls after the first model download).
2. The embedding is passed through a random rotation, then split into 2D
   pairs and converted to polar coordinates (angle, radius) per pair.
3. Angles and radii are quantized to 4 or 8 bits each and packed into a
   compact blob stored in SQLite.
4. The rotation matrix is persisted alongside the database — QR
   decomposition isn't guaranteed bit-identical across BLAS builds, so
   re-deriving it from a seed wouldn't reliably decode old blobs.
5. Recall is two-stage: a fast angular scan over decoded vectors narrows
   to a candidate pool, then similarity × recency × frequency reranks
   that pool for the final results.

## Limitations

- The default embedding model is English-optimized (bge-small-en-v1.5).
- One PolarMem instance should own a db file at a time — it assumes
  exclusive access, not a lock. Concurrent instances against the same
  file are not supported; they tolerate deletes, but adds made by
  another instance become visible only after reopen.
- Tested up to roughly 10<sup>4</sup> memories per db; larger scales are
  untested.
- Not yet published to PyPI — install from source.