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

@cycgraph/memory

v0.5.0

Published

Temporal and hierarchical memory for LLM agents — knowledge graph, episode segmentation, semantic deduplication, and efficient retrieval. Powers compound learning in @cycgraph/orchestrator.

Readme

@cycgraph/memory

A temporal knowledge graph + hierarchical memory layer

npm License: Apache 2.0 Standalone


A utility package for building temporal knowledge graphs with xMemory-inspired hierarchical retrieval. Designed for TypeScript applications that want richer recall than a flat similarity search — provenance, time-bounded validity, entity relationships, and a hierarchy that lets prompts drill down only when they need to. Works standalone with any stack, or drops into @cycgraph/orchestrator for cross-run agent learning.

Install

npm install @cycgraph/memory

Optional packages

Core Concepts

  • Temporal validity — every record carries validity date ranges, where facts are invalidated, not deleted, so you can ask "what was true on 2026-01-15?" without losing the audit trail.
  • Entities + typed relationships — a directed graph alongside the embedding layer. Facts can be reached by similarity, by tag or by walking out from an entity ID.
  • xMemory-inspired hierarchy — Queries can start at the theme level and drill down only when more detail is needed, reducing prompt tokens versus returning every matching fact.
  • Retrieval paths that don't require embeddings — query by tags, by entity IDs, or by full embedding similarity. Pick whichever the situation calls for.
  • Provenance on every record — useful for trust, audit, and debugging.
  • Same interface, in-memory or Postgres — develop against in-memory store, ship with Postgres adapter. One-line swap.

Use Cases

  • Agents that learn across sessions — store distilled lessons after each run, retrieve them by tag in the next.
  • RAG with temporal awareness — ask "what was true on 2026-01-15?" not just "what's in the embedding store right now."
  • Knowledge graphs for support / triage workflows — entities, relationships, episode-grouped conversations.
  • Memory for any LLM stack — Vercel AI SDK, LangChain.js, the OpenAI SDK directly. No orchestrator required.

Example

import {
  InMemoryMemoryStore,
  InMemoryMemoryIndex,
  RuleBasedExtractor,
  SimpleEpisodeSegmenter,
  retrieveMemory,
} from '@cycgraph/memory';

const store = new InMemoryMemoryStore();
const index = new InMemoryMemoryIndex();

/**
 * 1. Ingest messages → episodes → facts
 */
const segmenter = new SimpleEpisodeSegmenter({ gap_threshold_ms: 30000 });
const extractor = new RuleBasedExtractor({ minSentenceLength: 15 });

const messages = [
  {
    id: crypto.randomUUID(),
    role: 'user',
    content: 'Alice works at Acme Corp.',
    timestamp: new Date(),
    metadata: {},
  },
  {
    id: crypto.randomUUID(),
    role: 'assistant',
    content: 'Acme Corp acquired Widget Co in 2024.',
    timestamp: new Date(),
    metadata: {},
  },
];

for (const ep of await segmenter.segment(messages)) {
  await store.putEpisode(ep);
  const extracted = await extractor.extract(ep);

  for (const f of extracted.facts) {
    await store.putFact(f);
  }
  for (const e of extracted.entities) {
    await store.putEntity(e);
  }
  for (const r of extracted.relationships) {
    await store.putRelationship(r);
  }
}

/**
 * 2. Retrieve
 * - by tag (no embedding provider needed)
 * - by entity (no embedding provider needed)
 * - by embedding (requires embedding provider)
 * - combinations of the above
 */
const result = await retrieveMemory(store, index, {
  tags: ['business'],
  max_hops: 0,
  limit: 10,
  min_similarity: 0,
  include_invalidated: false,
});

For Postgres and pgvector backed, see @cycgraph/orchestrator-postgres.

import {
  DrizzleMemoryStore,
  DrizzleMemoryIndex
} from '@cycgraph/orchestrator-postgres';

const store = new DrizzleMemoryStore(db);
const index = new DrizzleMemoryIndex(db);

Retrieval patterns

Tag-only (no embedding needed)

await retrieveMemory(store, index, {
  tags: ['lesson', 'graph:research-v1'],
  limit: 20,
  max_hops: 0,
  min_similarity: 0,
  include_invalidated: false,
});

Entity-based (knowledge graph traversal)

await retrieveMemory(store, index, {
  entity_ids: [aliceId],
  max_hops: 2,
  limit: 20,
  min_similarity: 0.5,
  include_invalidated: false,
});

Embedding-based (semantic similarity over themes → facts)

await retrieveMemory(store, index, {
  embedding: await embed('source credibility methodology'),
  limit: 20,
  max_hops: 0,
  min_similarity: 0.5,
  include_invalidated: false,
});

Temporal filtering

await retrieveMemory(store, index, {
  valid_at: new Date('2026-01-15'),
  limit: 20,
  max_hops: 0,
  min_similarity: 0,
  include_invalidated: false,
});

Memory consolidation

The memory consolidator deduplicates near-identical facts, applies time-decay scoring to prune low-relevance facts, and removes orphaned themes while keeping the store within budget without losing the audit trail.

import { MemoryConsolidator } from '@cycgraph/memory';

const consolidator = new MemoryConsolidator(store, index, {
  maxFacts: 10_000,
  decayHalfLifeDays: 30,
  dedupThreshold: 0.9,
  deleteMode: 'soft',
});

const report = await consolidator.consolidate();

A separate ConflictDetector finds facts that semantically contradict each other and applies a resolution policy (keep newest / keep highest-confidence / mark all conflicting). Useful in long-running stores where the LLM extracts subtly different versions of the same fact over time.

Extractors

Extractors are pluggable components that extract facts, entities, and relationships from episodes.

SimpleSemanticExtractor

One fact per episode topic. Fast, minimal coverage. No LLM required.

import { SimpleSemanticExtractor } from '@cycgraph/memory';

const extractor = new SimpleSemanticExtractor();
const facts = await extractor.extract(episode);

RuleBasedExtractor

Multi-fact extraction with regex-based entity detection + verb-inflection relationship matching. No LLM required.

import { RuleBasedExtractor } from '@cycgraph/memory';

const extractor = new RuleBasedExtractor({ minSentenceLength: 20 });
const facts = await extractor.extract(episode);

LLMExtractor

Uses an LLM to extract facts, entities, and relationships from episodes. Falls back to RuleBasedExtractor on parse failure.

import { LLMExtractor } from '@cycgraph/memory';
import type { LLMProvider } from '@cycgraph/memory';

const provider: LLMProvider = {
  complete: async (prompt) => {
    // call your LLM
    return response;
  },
};

const extractor = new LLMExtractor({ provider, maxFactsPerEpisode: 20 });
const facts = await extractor.extract(episode);

Eval-gated retention

Lessons shouldn't live forever just because an agent once wrote them down. The eval-gating primitives keep a lesson only if runs that used it verifiably scored better:

import {
  InMemoryOutcomeLedger,
  evaluateRetention,
  retrieveGatedLessons,
} from '@cycgraph/memory';

const ledger = new InMemoryOutcomeLedger();

await ledger.recordOutcome({ run_id, score, fact_ids });

const report = await evaluateRetention(store, ledger, {
  min_trials: 3,
  promote_margin: 0.05,
  evict_margin: 0.05,
  max_baseline_runs: 40,
});

const lessons = await retrieveGatedLessons(store, {
  tags: ['lesson', 'graph:my-graph-v1'],
  max_facts: 10,
  candidate_slots: 4,
  rest_after_trials: 5,
  ledger,
});

The gate's default decision rule inference uses a Welch-style test with Benjamini–Hochberg FDR control and alpha-spending across doubling baseline brackets (so gating every run doesn't inflate false positives — the peeking problem). Every decision carries an evidence object. And because none of the guarantees are universal, the package ships its own validator.

gateOperatingCharacteristics() - drives the real pipeline with lessons of known effect and tells you the detection/false-positive rates for your policy in under a second — measured on the shipped defaults: ±0.3 effects decided 94–100%, null effects falsely decided 0–2%, sub-resolution effects retired rather than guessed.

Contributing

Issues and PRs welcome. See CONTRIBUTING.md for development setup, coding standards, and the architecture decisions worth knowing before opening a PR. Security disclosures go through SECURITY.md.

License

Apache 2.0.