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

rememori

v0.7.0

Published

Agent memory that runs anywhere JavaScript runs. Pure TypeScript, zero dependencies, embedded.

Readme

rememori

npm license zero dependencies

Agent memory that runs anywhere JavaScript runs.

Pure TypeScript. Zero runtime dependencies. No native bindings, no compiler toolchain, no database server. One file on disk — or IndexedDB in the browser. Works in Node, Bun and browsers today.

Status: v0.7 — early but moving fast. Vector recall, entity graph, temporal decay, HNSW index, browser/IndexedDB support, relevance floor, an explicit feedback loop (reinforce/demote, evidence-gated) and an MCP server are in. The API below is tested; minor breaking changes possible until v1.0.

Why

Every AI agent forgets everything when the session ends. Fixing that today means wiring up a vector database, an embedding pipeline, and a retrieval layer — or adopting a memory platform with servers, backends, and cloud tiers.

rememori is not a platform. It's a primitive — the SQLite of agent memory:

npm install rememori
import { Memory } from 'rememori';
import { ollama } from 'rememori/embedders';

const mem = await Memory.open('./agent.rememori', {
  embedder: ollama('nomic-embed-text'),
});

// remember
await mem.remember('User prefers dark mode, hates notifications', {
  tags: ['prefs'],
  importance: 0.8,
});

// recall — cosine similarity × importance × optional temporal decay
const hits = await mem.recall('what UI settings does the user like?', {
  limit: 5,
  halfLifeDays: 90,
});

// reinforce — this memory actually made it into the answer:
// resets its decay clock, hardens its ranking (log-damped, capped)
await mem.reinforce(hits[0].id);

// forget
await mem.forget(hits[0].id);

Three verbs. That’s the API.

Feedback loop closed (v0.7)

  • demote(id) — symmetric negative feedback (log-damped, capped at −0.15): a used-and-wrong memory takes an explicit hit instead of waiting for decay, so "recalled and harmful" stops sharing a path with "never recalled".
  • reinforceFromOutput(hits, output) — evidence-gated reinforcement: only memories whose text verifiably appears in the final answer (quoted token run, or high distinct-token containment) get reinforced. Pure text matching, no embeddings — trusting the model's own "that helped" would rebuild the entrenchment loop one level up, and embedding similarity between memory and answer is the soft version of the same mistake.
  • collisions(id, { threshold = 0.8, limit = 5 }) — near-duplicate detection at write time. The engine only detects proximity; deciding duplicate vs update vs contradiction is the caller's job, because embeddings can't detect contradictions — they embrace them ("needs Node 20" and "needs Node 18" embed almost identically). Typical flow: remember()collisions() → your LLM adjudicates → demote() or forget() the loser.
  • get(id) — read one memory (text, tags, entities, importance, reinforcement state) as a defensive copy, without its vector.
  • The evidence check is exported standalone as useEvidence(memoryText, output, options?) if you want the verdict without the side effect. Numeric tokens veto both evidence paths (an output saying "Node 18" is never evidence for a memory saying "Node 20"). Known limitation: unsegmented CJK matches only on exact substring reuse.

Reinforcement — why it's explicit

A memory you use every day should not decay like one you never touch. But auto-reinforcing on recall would create a feedback loop: an early wrong memory keeps surfacing, keeps getting "reinforced", entrenches. So the signal is explicit — call reinforce(id) when a memory actually contributed to the answer, not when it merely appeared in candidates. Surfacing ≠ being useful; keeping the reinforcement signal outside the ranking system is what breaks the loop. Mechanically: the decay anchor moves to the last reinforcement (used memories stop ageing), plus a min(0.15, 0.05·log₂(1+n)) scoring bonus — hardens, can't run away. recall() stays a pure read.

Entity graph

Every memory is linked to the named entities it mentions (bipartite memory↔entity graph). Extraction is pluggable: the zero-dependency default spots capitalized names; plug an LLM-backed extractor for quality, or pass extractor: false to opt out.

// recall is hybrid by default: memories sharing entities with the query
// get a score bonus, so graph-linked memories surface even when
// embedding similarity alone would miss them
const hits = await mem.recall('any updates from Giorgio?');
hits[0].sharedEntities; // ['Giorgio']

// explore the graph
mem.entities();        // top entities by linked memories
mem.entity('Giorgio'); // linked memories + co-occurring entities

Fully local chat agent (Ollama)

A complete chat agent with persistent memory across restarts — everything on your machine, no cloud: examples/ollama-chat.mjs (~50 lines, runnable).

In the browser — no server at all

Storage works on IndexedDB out of the box (idb:// paths), and transformers.js gives you local embeddings. Fully private semantic memory, nothing leaves the machine:

import { pipeline } from '@huggingface/transformers';
import { Memory } from 'rememori';

const extractor = await pipeline('feature-extraction', 'Xenova/all-MiniLM-L6-v2');

const mem = await Memory.open('idb://agent', {
  embedder: {
    async embed(texts) {
      const out = await extractor(texts, { pooling: 'mean', normalize: true });
      return out.tolist().map((v) => new Float32Array(v));
    },
  },
});

Runnable single-file demo: examples/browser-demo.html.

Design

  • Embedder is an interface, never bundled. Bring Ollama (local, private), any OpenAI-compatible endpoint, or your own (texts) => Float32Array[] function.
  • Storage is an adapter. Append-only JSONL file with tombstones and compaction on Node/Bun, IndexedDB in the browser (idb://name), :memory: for tests. KV (edge) adapter is on the roadmap.
  • Recall scoring: (cosine + entityBonus + hardening) × importance × 0.5^(age/halfLife) where entityBonus = min(0.3, 0.1 × shared entities) and hardening = ±min(0.15, 0.05 × log₂(1+|feedback|)) from reinforce/demote. Decay is anchored to the last reinforcement, not creation. Recency, importance, the graph and use-feedback are first-class, not an afterthought.
  • Relevance floor. Embedding models never score unrelated texts at zero, so without a floor an off-topic query returns the least-irrelevant memories instead of nothing. Set minSimilarity (per instance or per recall) to cut on raw cosine before any weighting; entity-graph matches are exempt. The right value is model-dependent — measured on a mixed memory set (bench/retrieval-eval.mjs): correct hits vs best off-topic hit never overlapped, with a clean gap at ~0.5 for nomic-embed-text and ~0.3 for all-MiniLM-L6-v2.
  • Exact search first, HNSW when it pays. Below ~1000 memories, an exact scan over contiguous Float32Arrays wins on every axis. Past that, a pure-TS HNSW graph index kicks in automatically (index: 'auto', the default; force with 'hnsw' or 'flat'). Tag/date-filtered recalls always use the exact scan.

Scale

Synthetic 384-dim embeddings with realistic low-dimensional structure, Apple M-class CPU, ef=200 (what recall() uses). Run it yourself: node bench/hnsw.bench.mjs.

| memories | exact scan | HNSW | recall@10 | |---|---|---|---| | 1,000 | 0.5 ms/query | (index off — scan wins) | 100% | | 10,000 | 4.4 ms/query | 2.3 ms/query | 100% | | 50,000 | 26 ms/query | 2.8 ms/query | 100% |

Index build is one-time, ~2–4 ms per memory, incremental on remember(). Honest caveat: uniformly random high-dimensional vectors (the worst case for any ANN index — distances concentrate) degrade recall; real embedding models produce structured vectors that behave like the table above.

MCP server — memory for Claude Code

rememori-mcp wraps the engine as a Model Context Protocol server. One command gives Claude Code (or any MCP client) persistent semantic memory across sessions:

claude mcp add rememori -- npx -y rememori-mcp

Roadmap

  • ~~v0.2 — entity graph (bipartite memory↔entity) + hybrid recall~~ ✅ shipped
  • ~~v0.3 — browser support: IndexedDB storage + transformers.js recipe~~ ✅ shipped
  • ~~MCP server wrapper~~ ✅ shipped as rememori-mcp
  • ~~v0.4 — pure-TS HNSW index~~ ✅ shipped
  • ~~v0.5 — relevance floor (minSimilarity), measured per-model defaults~~ ✅ shipped
  • ~~v0.6 — explicit reinforcement: decay anchoring + log-damped hardening~~ ✅ shipped
  • ~~v0.7 — demote(), evidence-gated reinforceFromOutput(), collision detection~~ ✅ shipped
  • v0.8 — LongMemEval harness

Non-goals

Multi-user servers, auth, cloud sync, multimodal ingestion, LLM-managed memory. If you need a full memory platform with document pipelines and graph databases, use Cognee or Mem0 — they're good at that. rememori is for when you want memory inside your process, in five minutes.

License

MIT