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

@automatorswork/memory

v0.7.0

Published

Official SDK for memory.automators.work — sovereign memory as an API for AI agents. Types generated from the live OpenAPI 3.1 spec.

Readme

@automatorswork/memory

Official SDK for memory.automators.worksovereign memory as an API for AI agents.

Three verbs (remember, recall, forget) with semantic search, MMR diversity, RRF hybrid retrieval, LLM-powered synthesis, mining, supersession, and idempotent writes. Zero dependencies.

Install

npm install @automatorswork/memory

Get an API key: memory.automators.work

Quick start

import { Memory } from "@automatorswork/memory";

const mem = new Memory({ apiKey: process.env.MEMORY_API_KEY });

// Store something
await mem.remember({
  content: "User prefers concise answers in Spanish.",
  type: "preference",
  tags: ["lang:es"],
});

// Ask the memory a question (LLM-synthesized answer)
const r = await mem.recall("how does the user like responses?", {
  synthesize: true,
  topK: 3,
});
console.log(r.answer);
// → "The user prefers concise answers in Spanish."

Features

| Capability | Method | |------------|--------| | Store an atomic memory | remember({ content, type?, tags?, supersedes? }) | | Auto-classify via LLM | remember({ content, autoClassify: true }) | | Mine atomic memories from a transcript | mineSession(transcript) | | Semantic search | recall(query) | | Hybrid search (vector + BM25) | recall(query, { rrf: true }) (default) | | MMR diversity | recall(query, { mmr: true, lambda: 0.7 }) (default) | | LLM-synthesized answer | recall(query, { synthesize: true }) | | Supersede a previous entry | remember({ content, supersedes: "prev_id" }) | | Walk supersession chain | chain(id) | | Filter by type / tags / date | recall(q, { type, tags, since }) | | Soft-delete (30d recoverable) | forget(id) | | Bulk forget by ids or query | forgetBulk({ ids }) / forgetBulk({ query, confirm }) | | Export everything (JSONL) | export() | | Stats | stats() |

Cookbook

Idempotent writes

The server uses content-addressed hashing. Sending the same (content, type) twice returns the first entry with idempotent_hit: true — no duplicates, safe to retry.

const a = await mem.remember({ content: "User prefers Rust", type: "preference" });
const b = await mem.remember({ content: "User prefers Rust", type: "preference" });
console.log(a.id === b.id);  // true
console.log(b.idempotent_hit);  // true

Supersession chains

Model "this replaces that" without losing history.

const v1 = await mem.remember({
  content: "User prefers Rust",
  type: "preference",
});

// Later: a newer preference supersedes it
const v2 = await mem.remember({
  content: "User now prefers Go",
  type: "preference",
  supersedes: v1.id,
});

// Recall by default sees only v2
const r = await mem.recall("what language?");  // → v2

// But the full chain is preserved
const history = await mem.chain(v2.id);
// history.chain = [v1 (superseded), v2 (current)]

Mining from a conversation

Extract atomic memories from a transcript using the built-in LLM (Granite 4.0 H Micro).

const transcript = `
User: I prefer TypeScript.
User: Also, deploy only on Fridays.
User: Correction: deploy Wednesdays instead.
`;

const { extracted, entries } = await mem.mineSession(transcript);
// Returns classified atomic memories: preference, decision, correction.

Hybrid retrieval (vector + BM25)

// Default: RRF fuses both channels. Great for exact-keyword queries
// (names, IDs, SKUs) that pure vector search might miss.
await mem.recall("Invoice QX-7731");

// Disable RRF if you only want semantic.
await mem.recall("how does the user feel?", { rrf: false });

Answer-style recall

const r = await mem.recall("what's the deploy schedule?", {
  synthesize: true,
  topK: 5,
});
console.log(r.answer);       // → "Deploys are on Wednesdays."
console.log(r.results);      // the sources used
console.log(r.took_ms.synthesis);  // added latency (~500 ms)

Correction boost

Mark a memory as type: "correction" to have it surface above older entries in recall (2× score multiplier).

await mem.remember({
  content: "User actually uses pnpm, not npm.",
  type: "correction",
});

Plans and limits

| Plan | Memories | Requests/hour | |------|----------|---------------| | Free | 1 | 100 | | Pro | 10 | 10,000 | | Enterprise | unlimited | 100,000 |

Each memory is an isolated container with its own API key. Manage them at memory.automators.work/dashboard.

Data sovereignty

Your data lives in a private git repository — not a black box. You can request a clone URL at any time. Nothing is locked in.

API reference

Full documentation at memory.automators.work/docs.

Webhooks

Every container client (Memory, KnowledgeBase, Collection) exposes the same 7-method webhook surface. Subscribe to mutations, verify the HMAC-SHA256 signature, and log deliveries for debugging.

import { Memory, verifyWebhookSignature } from "@automatorswork/memory";

const mem = new Memory({ apiKey: process.env.MEMORY_KEY });

// 1. Register a receiver — save the returned `secret`, it's shown once.
const wh = await mem.createWebhook({
  url: "https://your-app.example.com/hooks",
  events: ["memory.remember", "memory.forget", "image.upload"],  // or ["*"]
});
console.log("save this:", wh.secret); // whsec_…

// 2. Fire a synthetic test.ping to verify reachability.
await mem.testWebhook(wh.id);  // { ok: true, status: 200, duration_ms: ... }

// 3. In your receiver, verify before acting.
export async function onRequest(request) {
  const rawBody = await request.text();
  const ok = await verifyWebhookSignature({
    secret:  process.env.WEBHOOK_SECRET,
    rawBody,
    header:  request.headers.get("x-memory-signature"),
  });
  if (!ok) return new Response("bad signature", { status: 401 });

  const evt = JSON.parse(rawBody);  // { id, type, timestamp, data, ... }
  switch (evt.type) {
    case "memory.remember": /* … */ break;
    case "memory.forget":   /* … */ break;
  }
  return new Response("ok");
}

Retries, auto-disable, and delivery forensics are handled server-side:

await mem.listWebhookDeliveries(wh.id);  // last 50 attempts, newest first
// → { deliveries: [{ event_type, attempt, ok, status, duration_ms, error, response_snippet, … }] }

await mem.updateWebhook(wh.id, { rotate_secret: true });  // returns a fresh whsec_… once
await mem.updateWebhook(wh.id, { active: false });         // pause without deleting
await mem.deleteWebhook(wh.id);                            // also wipes delivery log

See /docs#webhooks for event payload schemas, retry policy, and signing details.

Types generated from the live OpenAPI spec

All request/response types in index.d.ts are derived from the backend's OpenAPI 3.1 spec (generated/openapi.d.ts), regenerated via openapi-typescript. The raw paths and components["schemas"] are re-exported, so TypeScript users can drill down to any endpoint's exact shape:

import type { Schemas, paths } from "@automatorswork/memory";

type Entry = Schemas["Entry"];
type RememberBody = paths["/v1/remember"]["post"]["requestBody"]["content"]["application/json"];

Staying in sync with the backend

If you're developing against the service (or running the SDK against a fork), regenerate the types and run the drift detector:

npm run sync          # pulls https://memory.automators.work/openapi.json
npm run sync:local    # reads ../ctx-git-service/site/openapi.json
npm run check         # coverage-only, no type regeneration

The drift detector extracts every (METHOD, path) the SDK calls and cross-references it against the spec. A METHOD path present in the SDK but missing from the spec is a hard failure — either the spec is stale or the SDK is calling a removed endpoint. Wired into prepublishOnly so you cannot publish an SDK that calls endpoints the backend doesn't advertise.

Error handling

import { Memory, MemoryError } from "@automatorswork/memory";

try {
  await mem.remember({ content: "…" });
} catch (err) {
  if (err instanceof MemoryError) {
    console.error("status:", err.status);
    console.error("message:", err.message);
    console.error("data:", err.data);
  }
}

Rate limit headers are surfaced by the underlying fetch — pass a custom fetch to observe them:

const mem = new Memory({
  apiKey: "...",
  fetch: async (url, init) => {
    const r = await fetch(url, init);
    console.log("X-RateLimit-Remaining:", r.headers.get("X-RateLimit-Remaining"));
    return r;
  },
});

Node / runtime support

  • Node ≥ 18 for 0.3.x. Node 22 required from 0.4.0 — see POLICIES.md for the migration matrix and rationale.
  • Deno, Bun, Cloudflare Workers, any modern browser — all supported. Uses only Web-standard APIs (fetch, AbortController, crypto.subtle, TextEncoder).
  • ESM only.

Stability

See POLICIES.md for what counts as public API, the deprecation cycle (1-minor minimum before removal), and the backend-version coupling. Short version:

  • SemVer. Inside 0.x, minor bumps can remove already-@deprecated symbols.
  • Anything listed in index.d.ts without a leading underscore and without @deprecated is public.
  • Deprecations land with IDE-visible @deprecated JSDoc + a documented migration; no noisy runtime warnings.

License

MIT