Metadata-Version: 2.4
Name: rootmemory
Version: 0.1.0
Summary: Provenance-aware memory for multi-agent AI systems: tells corroboration apart from repetition
Author-email: Shubham Ambavane <ambavane26@gmail.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/Shubs5758/RootMemory
Project-URL: Repository, https://github.com/Shubs5758/RootMemory
Project-URL: Issues, https://github.com/Shubs5758/RootMemory/issues
Project-URL: Documentation, https://github.com/Shubs5758/RootMemory#readme
Keywords: ai,agents,multi-agent,memory,provenance,langgraph,langchain,knowledge-graph,evidence
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Database
Classifier: Typing :: Typed
Requires-Python: >=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: sqlalchemy>=2.0
Requires-Dist: pydantic>=2.7
Requires-Dist: pydantic-settings>=2.3
Requires-Dist: structlog>=24.1
Provides-Extra: api
Requires-Dist: fastapi>=0.115; extra == "api"
Requires-Dist: uvicorn[standard]>=0.30; extra == "api"
Requires-Dist: alembic>=1.13; extra == "api"
Provides-Extra: postgres
Requires-Dist: psycopg[binary]>=3.1; extra == "postgres"
Provides-Extra: langchain
Requires-Dist: langchain-core>=0.3; extra == "langchain"
Provides-Extra: langgraph
Requires-Dist: langgraph>=0.2; extra == "langgraph"
Requires-Dist: langchain-core>=0.3; extra == "langgraph"
Provides-Extra: llm
Requires-Dist: openai>=1.30; extra == "llm"
Provides-Extra: all
Requires-Dist: fastapi>=0.115; extra == "all"
Requires-Dist: uvicorn[standard]>=0.30; extra == "all"
Requires-Dist: alembic>=1.13; extra == "all"
Requires-Dist: psycopg[binary]>=3.1; extra == "all"
Requires-Dist: langgraph>=0.2; extra == "all"
Requires-Dist: langchain-core>=0.3; extra == "all"
Requires-Dist: openai>=1.30; extra == "all"
Provides-Extra: dev
Requires-Dist: pytest>=8.2; extra == "dev"
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
Requires-Dist: httpx>=0.27; extra == "dev"
Requires-Dist: mypy>=1.10; extra == "dev"
Requires-Dist: ruff>=0.5; extra == "dev"
Requires-Dist: build>=1.2; extra == "dev"
Requires-Dist: twine>=5.1; extra == "dev"
Dynamic: license-file

# RootMemory

**Provenance-aware memory for multi-agent AI systems. It tells corroboration apart from repetition.**

[![PyPI](https://img.shields.io/pypi/v/rootmemory.svg)](https://pypi.org/project/rootmemory/)
[![Python](https://img.shields.io/pypi/pyversions/rootmemory.svg)](https://pypi.org/project/rootmemory/)
[![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)

```bash
pip install rootmemory
```

## The problem

A customer writes *"we're targeting October, but the date isn't final."*

```
Agent A reads the email  ->  "the deadline is October 15"
Agent B reads Agent A    ->  "the deadline is October 15"
Agent C reads Agent B    ->  "the deadline is October 15"
```

Your shared memory now shows three agents agreeing. There is still only **one**
source, and it did not say that. Every belief traces back to the same email —
but a list of conclusions has forgotten that, so the system counts three votes
and acts.

RootMemory keeps those numbers apart:

```
agreeing agents            3
supporting beliefs         3
independent evidence roots 1   <- the only number that reflects reality
```

## Quick start

```python
from rootmemory import RootMemory, open_memory

with open_memory("sqlite+pysqlite:///memory.db") as session:
    memory = RootMemory(session)

    research = memory.register_agent("ResearchAgent")
    risk     = memory.register_agent("RiskAgent")
    exec_    = memory.register_agent("DecisionAgent")

    # evidence from the outside world
    article = memory.create_observation("news", "Revenue may have slipped.")

    # three agents, but only the first one read the article
    b1 = memory.create_belief(research.id, "Supplier under pressure.", "risk", 0.6, [article])
    b2 = memory.create_belief(risk.id,     "Supplier is unstable.",     "risk", 0.8, [b1])
    b3 = memory.create_belief(exec_.id,    "Significant risk.",         "risk", 0.85, [b2])

    claim = memory.get_or_create_claim("risk", "Supplier is in distress.")
    for belief in (b1, b2, b3):
        memory.support_claim(claim.id, belief.id)

    verdict = memory.evaluate_claim(claim.id)
```

```
agreeing agents          3
supporting beliefs       3
independent sources      1
decision                 REJECT
why                      3 supporting beliefs descend from a single evidence source.
```

Add a genuinely separate source and it promotes. That is the entire idea.

## How it works

Four objects, one rule.

| Object | What it is |
| --- | --- |
| **Observation** | evidence from outside. Immutable — only its validity can change. |
| **Belief** | what an agent concluded. Must cite what it came from. |
| **Claim** | a proposition beliefs support or contradict. |
| **Decision** | an action taken because of a claim. |

**The rule: every belief must say what it was derived from.** RootMemory refuses
to store one that cites nothing. That turns memory into a family tree, so any
belief can be walked back to the real-world evidence at the bottom.

A claim enters shared memory only through the **promotion gate**, which counts
independent evidence roots — never agreeing agents. Contradictions are
preserved rather than overwritten. And retracting a source walks *forward*
through everything built on it: beliefs are retracted, claims downgraded,
dependent decisions flagged `needs_review`.

## Plugging into a framework

The core imports no agent framework. Adapters are optional extras.

### LangChain / LangGraph long-term memory

```bash
pip install "rootmemory[langgraph]"
```

```python
from langchain.agents import create_agent
from rootmemory.integrations.langgraph_store import RootMemoryStore

agent = create_agent(model=..., tools=[...], store=RootMemoryStore(agent_id=risk_id))
```

`BaseStore.put` has nowhere to say *"here is what I read first"*, so the adapter
infers it: the store remembers what it served to that agent and cites it as the
parents of whatever it writes next. Provenance capture with no cooperation from
the model.

### Tools that force citation

```python
from rootmemory.integrations.langchain_tools import build_tools
model = model.bind_tools(build_tools(memory, agent_id))
```

`derived_from` is a **required** field in the tool schema, so a model cannot
record an opinion without saying what it read.

### LangGraph nodes

```python
from rootmemory.integrations.langgraph_memory import MemoryState, remembering

graph.add_node("risk", remembering(memory, risk_id, claim_key="supplier_risk")(assess))
```

State carries belief ids, not just text — text has forgotten where it came from.

### Anything else

`AsyncRootMemory` is plain async Python with no framework types in its
signatures. Non-Python agents can use the REST API.

## Optional extras

| Extra | Adds |
| --- | --- |
| `rootmemory[api]` | FastAPI service, Alembic migrations, and the visual portal at `/ui` |
| `rootmemory[langgraph]` | LangGraph store, node wrapper, LangChain tools |
| `rootmemory[postgres]` | PostgreSQL driver |
| `rootmemory[llm]` | LLM-backed claim normalization |
| `rootmemory[all]` | everything |

The core depends only on SQLAlchemy, Pydantic and structlog. Importing the
memory engine will not drag in a web framework.

## The portal

```bash
pip install "rootmemory[api]"
rootmemory serve
```

Open <http://localhost:8000/ui>. Observations form the floor and everything
built on them stacks above, so an echo chain renders as a tall thin tower on a
single foundation. Click any node to trace it back to the evidence it actually
came from; everything off that path dims.

## Design rules

* Every belief has at least one causal parent. No provenance, no shared memory.
* Observations are never edited or deleted, only marked invalid.
* Only the promotion service may confirm a claim.
* Contradictions are preserved, never overwritten.
* Graph cycles are refused.
* Agreement count and independent-evidence count are always reported separately.
* The core is deterministic. An LLM may write belief text; it never decides what
  counts as evidence.

## Measured against a naive shared scratchpad

Same beliefs, same confidences, same thresholds — the baseline just has no
ancestry to consult.

| Metric | RootMemory | Shared scratchpad |
| --- | --- | --- |
| False corroboration rate | **0.0** | 0.25 |
| Wrong-action rate | **0.0** | 0.5 |
| Promotion precision | **1.0** | 0.5 |
| Repair completeness | **1.0** | 0.0 |

Cost: roughly 5–6x more rows, because the family tree is kept alongside the
conclusions.

## Documentation

* [Running it](docs/running.md) — step-by-step, including the demo and portal
* [Architecture](docs/architecture.md) — the four algorithms in detail
* [API reference](docs/api.md)
* [Deployment](docs/deployment.md) — config, auth, claim normalization, rollout
* [Evaluation](docs/evaluation.md) — generated benchmark results

## Status

Working, tested MVP: 144 tests, type-checked and linted. Runs on SQLite with no
server. PostgreSQL is supported and its migration renders correct DDL, but has
not yet been exercised against a live server.

## License

MIT
