We're open source. If actrone-memory has been useful to you, a star on GitHub means a lot to us.

actrone-memorymit licencetypescript and python

Your agent’s memory, written down.

Two-tier memory for AI agents. Every turn is stored, every durable fact is extracted and classified, and recall is fused from three signals then trimmed to the token budget you set. You can read all of it. No API key and no database to start.

npm install actrone-memory  ·  pip install actrone-memory

agent: assistantsession: s1long-term store · 6 memories
The six durable facts the demo scenario teaches, each with the tier that holds it, its sensitivity classification and its topic tag.
memorytiersensitivitytopic
Name is AlexL2piiidentity
Works as a Python developerL2nonerole
Prefers concise answers over long explanationsL2lowpreference
alex@acme.comL2piicontact
On-call rotation happens every weekL2noneoperations
Feeling anxious about the product launchL2sensitivewellbeing

retrieveContext("assistant", "s1", "when does the on-call rotation happen", 4096)

→ top result: On-call rotation happens every week

→ after a session reset: 0 turns, 6 facts still there

licence
MIT, free forever
to start
no services, no API key, nothing leaves the machine
tiers
L1 session turns · L2 semantic
recall
dense and lexical, RRF fused, recency weighted
classification
none · low · pii · sensitive
stores
in-memory default; Redis, Postgres, Qdrant, pgvector adapters; or your own
quality eval
ships one. recall@5 0.929, offline, CI-gated
integrations
16 frameworks in Python, 11 in TypeScript
Zero setup

Store a turn. That is the whole setup.

MemoryManager.create() with no arguments gives you an in-process store and a dependency-free embedder. No Redis, no Qdrant, no OpenAI key. Swap any of the three later by passing an adapter, one of the built-in ones for Redis, Postgres, Qdrant or pgvector, or a store you wrote yourself against the same interface. The manager and your calling code do not change.
store.ts
import { MemoryManager } from "actrone-memory";

async function main() {
  // In-memory store plus a local embedder. Nothing to run, nothing to configure.
  const mm = await MemoryManager.create();
  await mm.storeTurn(
    "assistant",
    "s1",
    "My name is Alex and I work as a Python developer.",
    "Good to meet you, Alex.",
  );
}

main();
store.py
import asyncio
from actrone_memory import create_memory_manager

async def main():
    # In-memory store plus a local embedder. Nothing to run, nothing to configure.
    async with create_memory_manager() as memory:
        await memory.store_turn(
            agent_id="assistant",
            session_id="s1",
            user_message="My name is Alex and I work as a Python developer.",
            assistant_message="Good to meet you, Alex.",
        )

asyncio.run(main())
Sensitivity

Every fact carries its sensitivity

Extraction pulls durable facts out of a turn and tags each one. The tag travels with the memory, so you can redact, filter or audit on it. This is memory that is governance-adjacent by construction, which is the thing a black-box memory store cannot give you.
  • none2 in the demo

    Ordinary project facts and preferences. Stored plainly, always recallable.

  • low1 in the demo

    Identifying but not private. Role, employer, stated preference.

  • pii2 in the demo

    Personal data. Name, email, phone. Masked in place when redaction is on.

  • sensitive1 in the demo

    Health, finance, credentials, wellbeing. Masked with pii, and worth a policy.

Hybrid recall

Recall is fused, not guessed

Pure vector search returns things that sound related. Actrone runs a dense search and a lexical search, weights recency, then fuses the three ranked lists with reciprocal rank fusion. An item that places well on two signals beats an item that wins one. Reranking is optional on top.

dense

embedding similarity

1on-call rotation
2Python developer
3concise answers
4product launch

lexical

bm25 term overlap

1on-call rotation
2product launch
3Python developer
4alex@acme.com

recency

decay over turns

1product launch
2on-call rotation
3alex@acme.com
4concise answers

fused · rrf

then pruned to budget

1on-call rotation
2product launch
3Python developer
4alex@acme.comover budget
per-signal orderings are illustrative. the asserted claim: for the query "when does the on-call rotation happen", the on-call memory ranks first on every profile after a session reset (spec/scenario.json, recall[0]).
Token budget

Context that fits, every time

You pass a token budget. The manager fetches turns and searches long-term memory in parallel, allocates the budget across them, ranks, then prunes to fit. You never get back a context object that blows your window, and you never write the trimming logic yourself.
token_budget2 612 used of 4 096
  • system prompt 320
  • recent turns (L1) 1 480
  • memories (L2) 812
  • unused 1 484
one worked example. the guarantee is the invariant: totalTokensUsed ≤ tokenBudget, asserted on every recall (docs/assertions.md, A7).
Both languages

The same call, in both languages

Not “we also have a Python version”. The same architecture, the same method names in each language’s casing, and the same result shapes, verified by a cross-language acceptance harness that runs one scenario against both backends.
recall.ts
const ctx = await mm.retrieveContext(
  "assistant",
  "s1",
  "when does the on-call rotation happen",
  4096,
);

ctx.recentTurns;
ctx.episodicMemories;
recall.py
ctx = await memory.retrieve_context(
    agent_id="assistant",
    session_id="s1",
    query="when does the on-call rotation happen",
    token_budget=4096,
)

ctx.recent_turns
ctx.episodic_memories
parityidentical result on both backends: 6 facts, same sensitivity split, same top recall, budget-bounded by the same invariant.
Captions available in English
Full transcript

A fact lands. It is classified as it arrives. Teach an agent who you are today. By tomorrow's session, it has forgotten. Actrone Memory. Open source, local first. Teach it once. It decides what is worth keeping, and classifies how sensitive each fact is, the moment it lands. Names and emails, PII. Health and mood, sensitive. Governance aware, in the free library. New session. It forgets the conversation, not you. Hybrid recall brings the right fact back: dense, keyword and recency, fused, inside your token budget. One toggle, and the sensitive memories mask themselves. TypeScript or Python. The same behaviour, verified identical. And it ships its own quality eval, so that number cannot quietly rot. Free and open, forever. Install it, star it, and bring it into production when you are ready.

Limits

What this does not do

Every memory library’s landing page lists what it does. Here is the other half, on the homepage rather than three clicks into a README, because you will find it out on day two anyway and we would rather you trust the first list.
  • PII tagging is not PII protection on a cloud model

    The pii and sensitive tags are produced by the extraction step, and that step sees the raw text. With the defaults, extraction and embedding run in-process, so nothing leaves your machine and the protection is real. Point either at a cloud provider and the raw text, including everything tagged pii, is sent to that provider. This library does not tokenise before inference. The hosted platform does.

  • It stores and recalls. It does not build a knowledge graph

    Turns and extracted facts, retrieved well. It does not do the entity consolidation or temporal graph reasoning some alternatives do. If your problem is "my agent forgets", this fits. If your problem is "resolve conflicting facts about an entity over time", it does not, yet.

  • We publish our own eval, not a head-to-head

    The library ships a quality eval that runs offline in one command and is gated in CI at recall@5 >= 0.85. It currently scores 0.929. Two things that number is not. It is not a public-dataset result: the bundled set is LongMemEval-style, not LongMemEval itself. And it is not a comparison: we have never run Mem0 or Zep through the harness, so there are no head-to-head figures here, and there will not be until we have run them. The zero-dependency default embedder is keyword overlap, so paraphrases score low.

  • The two languages are at parity in the core, not in the adapters

    MemoryManager behaves identically in both. The framework integrations do not: Python ships deep adapters as optional extras, and TypeScript ships structural helpers. If you need a specific framework adapter, check the integrations page before you commit.

Loading the Founding 500 waitlist.