npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@nature-labs/living-memory-engine

v0.1.0

Published

A TypeScript memory engine for agents that remember like a mind, not a log — Ebbinghaus decay, consolidation, crystallization, MMR retrieval. Composes a small working context per turn instead of replaying the whole conversation. Zero runtime dependencies,

Readme

@nature-labs/living-memory-engine

npm version TypeScript License

A TypeScript memory engine for agents that remember like a mind, not a log.

Use it when you want a conversation that never ends — and never overflows. Each turn the model sees a small working context composed from memory, not the whole transcript replayed.

Zero runtime dependencies. Pure ESM, ports & adapters, no IO inside the engine. You bring storage, an LLM, and an embedder; the engine brings the memory model.


Why

Most chat memory is one of two cheap tricks: replay the entire history until the context window overflows, or bolt on naive RAG that retrieves by similarity alone and never forgets. Neither models how memory actually works.

Forgetting is a feature. A mind decays what's stale, reinforces what's used, merges duplicates, and crystallizes durable traits out of repetition. That's what this engine does:

  • Ebbinghaus decay — memories lose strength over time unless recalled
  • Consolidation — near-duplicates merge; weak memories get pruned
  • Crystallization — repeated patterns graduate into durable self-facets ("who you are")
  • MMR retrieval — top-K semantic search with diversity, not just similarity
  • Prospective memory — the agent holds intents ("waiting to hear how the interview went") and resolves them
  • Person attribution — who said it vs. who it's about, tracked separately

A real usage snapshot

From a live session of LME Chat, a reference client running this engine in the browser:

Whole conversation        ~267,859 tokens · 482 messages
Fed to the model (turn)   ~2,353 tokens

That turn's context was composed from engine state — Memories (418), Persons (54), Interactions (486), Self (12), Planner (24), plus a short tail of recent turns. An observed example from one session, not a guaranteed ratio — the point is that context size is bounded by your retrieval config, not by conversation length.


Install

npm install @nature-labs/living-memory-engine

ESM only. Node >= 20, or any modern bundler/browser — the engine itself uses no Node APIs.


Quick start

The engine is a state machine you drive. One turn: ingest → retrieve → inject → your LLM call → ingest → tick.

import {
  MemoryEngine, SeededRandom, randomK, formatInjection,
} from '@nature-labs/living-memory-engine';

const engine = new MemoryEngine({
  storage,                        // load()/save() one JSON snapshot — file, IndexedDB, anything
  chat,                           // your LLM: stream / extract / describeImage / summarizePattern
  embed,                          // text -> number[] — any embedding model
  clock: { now: () => Date.now() },
  random: new SeededRandom(1337), // deterministic if you want it to be
  policy: randomK(3, 7),          // when repetition crystallizes into a trait
  systemPrompt: '',               // identity can start empty — it emerges
});

await engine.ingestUser('my sister got the job at the hospital!');
const ctx = await engine.retrieve('my sister got the job at the hospital!');
const inject = formatInjection(ctx);  // [Who you are] / [Relevant memories] / [You are anticipating]

const reply = await yourLLM(inject, ctx.tail);  // the engine never sees your HTTP layer

await engine.ingestModel(reply);
await engine.tick();  // decay · extract · embed · merge · prune · crystallize

For OpenAI-compatible endpoints (OpenAI, Ollama, LM Studio, OpenRouter, DashScope…) there are ready-made ports:

import { makeChatPort, makeEmbedPort } from '@nature-labs/living-memory-engine/provider';

const cfg = { baseURL: 'http://localhost:11434/v1', apiKey: '', model: 'gemma4:e2b' };
const chat = makeChatPort(cfg);
const embed = makeEmbedPort({ ...cfg, model: 'embeddinggemma' });

Mental model

you ── talk ──▶  retrieve: MMR top-K memories + self-facets + pending intents + tail  ──▶  LLM
                        ▲                                                                  │
                        │                                                             reply
              decay · reinforce · merge · prune · crystallize  ◀── tick ◀─────────────────┘

tick() is where memory lives. After each exchange the engine extracts new episodic memories, embeds them, decays old ones, reinforces what was recalled, merges near-duplicates, prunes what faded — and when a pattern repeats enough, crystallizes it into a self-facet that shapes every future turn.

The LLM never receives the whole history. Identity is not written in the system prompt; it accumulates.


API pointers

  • new MemoryEngine(deps) — deps are four ports + clock/random/policy. No IO inside.
  • engine.ingestUser(text, image?, speaker?) / engine.ingestModel(text) — record the exchange.
  • engine.retrieve(query) — compose the working context (selfTier, episodic, prospective, tail).
  • formatInjection(ctx) — render it as the system-side context block.
  • engine.tick() — run the memory lifecycle.
  • Primitives are exported if you want to build your own loop: decay, reinforce, merge, prune, detectPatterns, cosineSimilarity, mmrSearch, placeMemory, resolvePerson.

| Port | Shape | Typical adapter | |---|---|---| | StoragePort | load()/save() one JSON-serializable snapshot | a file, IndexedDB, SQLite row | | ChatPort | stream, extract, describeImage, summarizePattern | any LLM (see ./provider) | | EmbedPort | embed(text) → number[] \| null | any embedding model; null = backfill later | | Clock / Random | now() / seeded RNG | injectable ⇒ every behavior is deterministic under test |

The whole engine is ~40 kB unpacked, 95 deterministic tests — fake clock, seeded RNG, in-memory storage. No network, no flakes.


Engine vs. MCP

This package is the substrate. @nature-labs/lme-mcp wraps it as an MCP server so coding agents get persistent memory across sessions. Same engine, different boundary:

  • Engine (this package) — memory inside one mind: composes each turn's working context
  • MCP — memory between minds: a shared store your agents visit over a protocol

Building your own agent, character, or chat surface → you want the engine. Just want your coding agent to remember things → you want the MCP.


Status

Experimental, evolving fast, not vaporware: this exact code powers LME Chat and the published MCP server. Semver starts at 0.1.0 — expect additive changes; snapshots are forward-compatible by design (new fields are optional).

Source: github.com/v1b3x0r/living-memory-engine (engine/)


apache-2.0 license. built in chiang mai.

"forgetting is a feature."