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

getmnemo

v0.2.2

Published

Official TypeScript / JavaScript SDK for Mnemo Memory — long-term memory infrastructure for AI agents.

Readme

getmnemo

Official TypeScript / JavaScript SDK for Mnemo Memory — long-term memory infrastructure for AI agents.

npm install getmnemo

Zero runtime dependencies. Works in Node 18+, Bun, Deno, Cloudflare Workers, and any other modern server or edge JS runtime with fetch.

A default apiKey is full-access — keep it server-side. Scoped keys do exist: the key-mint dialog lets you grant read / write / delete / billing scopes individually. For browser or client-exposed contexts, mint a scoped read-only key (or proxy through a server route) rather than shipping a full-access key.

Quickstart

import { Mnemo } from 'getmnemo'

const memory = new Mnemo({
  apiKey: process.env.GETMNEMO_API_KEY!,
  workspaceId: process.env.GETMNEMO_WORKSPACE_ID!,
})

// Store an atomic fact, scoped to a container (e.g. a user)
await memory.add({
  content: 'User prefers Japanese short-grain rice for onigiri.',
  containerTag: 'user:jane',
  memoryType: 'preference',
})

// Retrieve relevant facts from the same container
const { results } = await memory.search({
  q: 'what kind of rice does the user like?',
  containerTag: 'user:jane',
})
for (const hit of results) {
  console.log(hit.score.toFixed(2), hit.content)
}

Containers

Memories live in containers. Identify a container two ways:

  • containerTag — a string like "user:jane" (the simplest, recommended form)
  • scope — the structured equivalent { type: 'user', id: 'jane' }

add and search require a container. Set one per call, or set defaultContainerTag on the client once so every call falls back to it:

const memory = new Mnemo({
  apiKey: process.env.GETMNEMO_API_KEY!,
  workspaceId: process.env.GETMNEMO_WORKSPACE_ID!,
  defaultContainerTag: 'user:jane',
})

await memory.add({ content: 'Likes onigiri.' }) // uses user:jane
await memory.search({ q: 'food preferences?' })  // uses user:jane

If neither a per-call container nor a default is set, add/search throw before hitting the network.

API surface

| Method | Purpose | |---|---| | search({ q, containerTag?, scope?, limit?, searchMode?, strategies?, excludeIds? }) | Hybrid retrieval. Returns SearchResponse. | | add({ content, memoryType?, containerTag?, scope?, metadata? }) | Store an atomic fact. Returns AddResponse. | | update(memoryId, { content?, memoryType?, metadata?, source? }) | Patch an existing memory. | | get(memoryId) | Fetch a single memory. | | delete(memoryId) | Remove a memory. | | list({ containerTag?, limit?, cursor?, scopeType?, scopeId? }) | Cursor-paginated list. |

Response types (SearchResponse, AddResponse, Memory, …) are provisional — reconstructed from observed live payloads pending a fully-annotated API spec.

Search strategies

search() accepts two agent-facing retrieval controls:

| Option | Values | Use when | |---|---|---| | strategies | temporal, graph, rerank, agentic | The caller knows the query needs a specific retrieval strategy. Strategies are additive: baseline retrieval still runs. | | excludeIds | string[] | The caller already has some memory/document/fact ids in context and wants fresh results instead of duplicates. |

const res = await memory.search({
  q: 'what changed after the dentist appointment?',
  containerTag: 'user:jane',
  strategies: ['temporal', 'graph'],
  excludeIds: ['mem_123'],
})

console.log(res.strategiesRan)

Strategy trade-offs: temporal is usually cheap, graph may add moderate latency, while rerank and agentic can add seconds and extra model cost. The SDK deliberately keeps backend mode flags internal; use strategies when you want to steer retrieval.

Memory types

add() accepts an optional memoryType for callers that want to classify a memory at write time:

await memory.add({
  content: 'User avoids shellfish.',
  memoryType: 'preference',
  containerTag: 'user:jane',
})

Known backend types are memory, preference, fact, observation, event, note, reminder, and goal. If an unknown value is sent, the API stores the item as memory instead of rejecting the whole write batch.

Errors

All HTTP failures throw MnemoHTTPError with .status and .body. Aborted requests throw MnemoTimeoutError. Both inherit from MnemoError.

import { Mnemo, MnemoHTTPError } from 'getmnemo'

try {
  await memory.search({ q: 'rice', containerTag: 'user:jane' })
} catch (err) {
  if (err instanceof MnemoHTTPError && err.status === 401) {
    console.error('API key rejected:', err.body)
  } else {
    throw err
  }
}

Configuration

| Option | Default | Notes | |---|---|---| | apiKey | (required) | from https://app.mnemohq.com/settings/api-keys | | workspaceId | (required) | sent as the x-workspace-id header | | defaultContainerTag | none | fallback container for add/search | | baseUrl | https://api.mnemohq.com | override for self-hosted | | timeoutMs | 30000 | per-request abort timeout | | fetch | global fetch | inject for testing or proxying |

Develop

npm install
npm test
npm run build

CI smoke gate

The publish workflow (.github/workflows/publish.yml) will not publish to npm unless a real production round-trip passes first. A smoke job runs on the same v* tag trigger and the publish job depends on it via needs: smoke, so a failed smoke blocks the release.

npm run smoke (scripts/prod-smoke.mjs) writes a memory to container A and another to container B against prod, confirms the add/search round-trip via response.results, then asserts tenant isolation: a search scoped to B must not return A's memory, and vice versa. A leak exits non-zero with a loud TENANT ISOLATION FAILURE — treat that as a production security finding, not a flaky test. Created memories are deleted on cleanup (cleanup failure only warns).

It needs three secrets, which must be ORG-level (no repo-level twin) — a repo-level twin shadows the org secret, which is exactly the failure mode that broke an earlier publish:

| Secret | Purpose | |---|---| | MNEMO_API_KEY | Scoped test key. Needs delete scope so the smoke can clean up the memories it creates (plus write + search). | | MNEMO_WORKSPACE_ID | Throwaway test workspace id. | | MNEMO_TEST_CONTAINER | Base containerTag (e.g. ci-smoke); the script derives unique per-run A/B containers from it. |

License

MIT