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

@memel06/mnemonio

v0.1.7

Published

Persistent structured memory layer for LLM agents

Readme

mnemonio

mnemonio.com

Persistent structured memory layer for LLM agents. Mnemonio gives your agent a file-based memory system that survives across sessions -- markdown files with YAML frontmatter, a manifest file, semantic search, automatic extraction from conversations, and periodic consolidation.

It ships as an MCP server, a CLI, and a TypeScript library. LLM operations use a callback you provide, so it works with any provider.

MCP Server

The fastest way to get started. Add mnemonio to your MCP client settings and your AI coding assistant gets persistent memory automatically.

Setup

{
  "mcpServers": {
    "mnemonio": {
      "command": "npx",
      "args": ["-p", "@memel06/mnemonio", "mnemonio-mcp"],
      "env": {
        "MNEMONIO_DIR": "./.mnemonio"
      }
    }
  }
}

For LLM-dependent tools (search, extract, distill), create a .env file in your project root (and add it to .gitignore):

MNEMONIO_API_KEY=your-api-key
MNEMONIO_BASE_URL=https://your-llm-provider.com/v1
MNEMONIO_MODEL=your-model

Mnemonio loads .env automatically.

You can also pass these as env vars in the MCP config if you prefer:

{
  "mcpServers": {
    "mnemonio": {
      "command": "npx",
      "args": ["-p", "@memel06/mnemonio", "mnemonio-mcp"],
      "env": {
        "MNEMONIO_DIR": "./.mnemonio",
        "MNEMONIO_BASE_URL": "https://your-llm-provider.com/v1",
        "MNEMONIO_MODEL": "your-model"
      }
    }
  }
}

The server auto-detects the provider from the base URL:

| Base URL contains | Provider | Token param | Auth | Endpoint | |-------------------|----------|-------------|------|----------| | openai.com | OpenAI (modern) | max_completion_tokens | Bearer | /chat/completions | | anthropic.com | Anthropic | max_tokens | x-api-key | /v1/messages | | openrouter.ai | OpenRouter | max_tokens | Bearer | /chat/completions | | anything else | Generic (OpenAI-compatible) | max_tokens | Bearer | /chat/completions |

Override auto-detection with MNEMONIO_PROVIDER (in .env or MCP config):

MNEMONIO_PROVIDER=anthropic
MNEMONIO_API_KEY=sk-ant-...
MNEMONIO_BASE_URL=https://api.anthropic.com
MNEMONIO_MODEL=claude-sonnet-4-6-20250514

Valid provider values: openai, openai-classic, anthropic, openrouter.

Available Tools

| Tool | LLM needed | Team aware | Description | |------|-----------|------------|-------------| | memory_list | No | Yes | List all memories, optionally filtered by type or tags | | memory_read | No | Yes | Read full content of a memory file | | memory_save | No | No | Save a new memory with frontmatter + manifest entry | | memory_delete | No | No | Delete a memory file and remove it from the manifest | | memory_search | Yes | Yes | Semantic search across all memories, with optional tag pre-filter | | memory_extract | Yes | No | Auto-extract durable facts from a conversation | | memory_distill | Yes | No | Consolidate: merge duplicates, prune stale, tighten | | memory_stats | No | Yes | File count, size, type breakdown |

Team Memory

Team memory is a shared, read-only directory that gives every developer's agent the same baseline context -- coding standards, onboarding notes, project conventions. Commit it to your repo so the whole team shares it.

MCP Server

Set MNEMONIO_TEAM_DIR in your MCP config:

{
  "mcpServers": {
    "mnemonio": {
      "command": "npx",
      "args": ["-p", "@memel06/mnemonio", "mnemonio-mcp"],
      "env": {
        "MNEMONIO_DIR": "./.mnemonio",
        "MNEMONIO_TEAM_DIR": "./team-memory"
      }
    }
  }
}

Team memories automatically appear in memory_list, memory_read, memory_search, and memory_stats. Write operations (memory_save, memory_extract, memory_distill) only touch the private directory.

CLI

Use --team-dir with any read command:

mnemonio list .mnemonio --team-dir ./team-memory
mnemonio search "coding standards" .mnemonio --team-dir ./team-memory

Library

const store = createMnemonioStore({
  memoryDir: './.mnemonio',
  teamDir: './team-memory',
});

// Combined prompt includes both private and team memories
const prompt = await store.buildCombinedPrompt();

// Path traversal protection for team writes
const safePath = await store.validateTeamWritePath('notes.md');

Security

Path traversal attacks (symlinks, ../ segments, null bytes) are blocked by validateTeamWritePath. Use isTeamPath to check if a path falls within the team directory.

CLI

npm install -g @memel06/mnemonio

The CLI reads MNEMONIO_API_KEY from your environment for LLM-dependent commands (search, distill). It auto-detects the provider from MNEMONIO_BASE_URL (or you can set MNEMONIO_PROVIDER explicitly) and works with OpenAI, Anthropic, OpenRouter, and any OpenAI-compatible endpoint.

mnemonio init [dir]                        Create memory directory with MANIFEST.md
mnemonio scan [dir] [--team-dir <d>] [--json]               Display all memory file headers
mnemonio list [dir] [--type <t>] [--team-dir <d>] [--json]  List memories with descriptions + age
mnemonio search <query> [dir] [--team-dir <d>] [--json]     Find relevant memories (LLM required)
mnemonio distill [dir] [--force] [--json]  Run consolidation pass (LLM required)
mnemonio stats [dir] [--team-dir <d>] [--json]              File count, size, type breakdown
mnemonio prune [dir] [--max-age <days>] [--dry-run]         Remove stale/empty files

All commands default to the current directory if [dir] is omitted. Use --team-dir to include a shared team memory directory in listings, search, and stats.

Library

npm install @memel06/mnemonio

Quick Start

import { createMnemonioStore } from '@memel06/mnemonio';

const store = createMnemonioStore({
  memoryDir: './.mnemonio',
});

// Create the memory directory and MANIFEST.md if they don't exist
await store.ensureDir();

// Inject memory context into your system prompt
const memoryPrompt = await store.buildPrompt();
const systemPrompt = `You are a helpful assistant.\n\n${memoryPrompt}`;

// List all memory files
const headers = await store.scan();
console.log(store.formatManifest(headers));

// Get stats
const stats = await store.stats();
console.log(`${stats.totalFiles} files, ${stats.totalBytes} bytes`);

With an LLM (search, extraction, distillation)

The quickest way is to use the built-in resolveLlm helper, which reads MNEMONIO_API_KEY, MNEMONIO_BASE_URL, MNEMONIO_MODEL, and MNEMONIO_PROVIDER from your environment and auto-detects the provider:

import { createMnemonioStore, resolveLlm } from '@memel06/mnemonio';

const store = createMnemonioStore({
  memoryDir: './.mnemonio',
  llm: resolveLlm(),
});

Or wire up your own callback for full control:

import { createMnemonioStore, type LlmCallback } from '@memel06/mnemonio';

const llm: LlmCallback = async ({ system, messages, maxTokens }) => {
  const response = await yourClient.chat({
    model: 'your-model',
    max_tokens: maxTokens,
    system,
    messages,
  });
  return response.text;
};

const store = createMnemonioStore({
  memoryDir: './.mnemonio',
  llm,
});

// Semantic search
const results = await store.findRelevant('database testing approach');

// Extract memories from a conversation
await store.extract({
  messages: [
    { role: 'user', content: "Don't mock the database in integration tests." },
    { role: 'assistant', content: 'Understood, I will use the real database.' },
  ],
});

// Consolidate (merge duplicates, prune stale entries)
await store.distill({ force: true });

Configuration

interface MnemonioConfig {
  /** Path to the memory directory */
  memoryDir: string;

  /** Optional path to a shared team memory directory */
  teamDir?: string;

  /** LLM callback -- required for search, extract, distill */
  llm?: LlmCallback;

  /** Name of the entrypoint file (default: "MANIFEST.md") */
  entrypointName?: string;

  /** Max lines to include from MANIFEST.md in prompts (default: 200) */
  maxEntrypointLines?: number;

  /** Max bytes to include from MANIFEST.md in prompts (default: 25000) */
  maxEntrypointBytes?: number;

  /** Optional structured logger */
  logger?: (msg: string, level: 'debug' | 'info' | 'warn' | 'error') => void;
}

The LlmCallback type accepts any provider. You wire it up once:

type LlmCallback = (params: {
  system: string;
  messages: ReadonlyArray<{ role: 'user' | 'assistant'; content: string }>;
  maxTokens: number;
}) => Promise<string>;

API Reference

Methods (no LLM required)

| Method | Returns | Description | |--------|---------|-------------| | ensureDir() | Promise<void> | Create memory dir and MANIFEST.md if missing | | scan(signal?) | Promise<MemoryHeader[]> | List all memory files with frontmatter metadata | | readEntrypoint() | Promise<EntrypointTruncation> | Read MANIFEST.md with truncation info | | buildPrompt() | Promise<string> | Build memory context string for system prompts | | buildCombinedPrompt() | Promise<string> | Build prompt including team memory | | stats(signal?) | Promise<MnemonioStats> | File count, total size, type breakdown, age range | | formatManifest(headers) | string | Format headers as a human-readable manifest |

Methods (LLM required)

| Method | Returns | Description | |--------|---------|-------------| | findRelevant(query, opts?) | Promise<RelevantMemory[]> | Semantic search across memories | | extract(config) | Promise<ExtractResult> | Extract memories from a conversation | | distill(config?) | Promise<DistillResult> | Consolidate: merge duplicates, prune stale, tighten |

Lock Management

| Method | Returns | Description | |--------|---------|-------------| | readLastDistilledAt() | Promise<number> | Timestamp of last distillation | | tryAcquireLock() | Promise<number \| null> | Acquire distillation lock (null if held) | | rollbackLock(priorMtime) | Promise<void> | Restore lock mtime on failure |

Team Security

| Method | Returns | Description | |--------|---------|-------------| | validateTeamWritePath(filePath) | Promise<string> | Resolve and validate path within team dir | | isTeamPath(filePath) | boolean | Check if path is inside team directory |

Memory File Format

Each memory is a markdown file with YAML frontmatter:

---
name: testing-approach
description: Team prefers integration tests with real DB over mocks
type: directive
tags: [testing, database]
---

Always use the real database for integration tests.

> reason: A prior incident where mocked tests passed but production broke on a
> schema change.

> scope: Use test containers or a dedicated test database. Never mock
> the DB layer in integration suites.

The MANIFEST.md file in the memory directory serves as the entrypoint. It contains short one-line pointers to individual memory files. Mnemonio auto-truncates it when injecting into prompts to stay within token budgets.

Memory Types

| Type | Purpose | |------|---------| | identity | Information about the user -- role, goals, preferences, expertise | | directive | Corrections and confirmed approaches -- behavioral guidance | | context | Ongoing work, decisions, timelines, incidents | | bookmark | Pointers to external systems, docs, dashboards, resources |

Extended Frontmatter

| Field | Required | Description | |-------|----------|-------------| | name | No | Human-readable slug for the memory | | description | No | One-line summary shown in listings and manifests | | type | No | identity, directive, context, or bookmark | | tags | No | Freeform labels for cross-cutting concerns | | expires | No | ISO date after which this memory is automatically excluded from all operations |

License

MIT