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

memoryrouter-claude

v2.6.1

Published

Deterministic, project-scoped persistent memory for Claude Code: automatic hook retrieval/capture plus an optional OAuth MCP control surface.

Readme

memoryrouter-claude

Deterministic, project-scoped persistent memory for Claude Code. Automatic hooks durably capture one user prompt and one final user-visible response per turn, retrieve relevant memory through a separate read-only request, and restore memory after compaction or resume.

npx memoryrouter-claude init
npx memoryrouter-claude doctor

MemoryRouter complements Claude Code's local auto memory: it is semantic, cross-machine, cross-platform, and durable beyond one context window.

Architecture: hooks are automatic; MCP is explicit

The integration deliberately uses two surfaces:

  • Hooks are the automatic memory engine. They run at deterministic Claude Code lifecycle points whether or not the model chooses a tool.
  • The OAuth MCP server is the manual/control surface. Claude can explicitly search or store memory when asked, and resources expose vault information.
npx memoryrouter-claude mcp install       # local Claude MCP scope by default
claude mcp login memoryrouter             # OAuth; select the same vault as the hook key

Use /mcp in Claude Code to inspect the connection. The MCP endpoint is https://mcp.memoryrouter.ai/mcp; the Memory Key is never written into MCP or Claude settings. The explicit operations available today are:

  • Recall: ask Claude to search MemoryRouter; it uses search_memories.
  • Remember: ask Claude to remember durable content; it uses store_memory.
  • Status: inspect memory://vault/stats in the MCP resource browser (or run memoryrouter-claude status).
  • Forget: requires the real delete capability described below; use the dashboard until it ships.

Teams that deliberately want MemoryRouter tools loaded up front rather than deferred by Claude Code tool search can commit this .mcp.json (Claude still asks each user to approve and authenticate it):

{
  "mcpServers": {
    "memoryrouter": {
      "type": "http",
      "url": "https://mcp.memoryrouter.ai/mcp",
      "alwaysLoad": true
    }
  }
}

Current server dependencies: the public MCP server exposes search/store plus stats/recent resources, but does not yet expose per-memory deletion or a project-handle argument. Automatic hook memory is hard-partitioned in the ccp_… project vault, while today's remote MCP tools operate on the personal/global surface. Full project-scoped MCP recall/remember requires the server to accept and enforce the same project handle. Do not represent /forget as working until the server ships a real ID-backed delete tool. Use the MemoryRouter dashboard for deletion today. The hook package does not weaken project isolation, fake IDs, or pretend deletion succeeded.

Lifecycle

| Claude Code event | Automatic action | Notes | |---|---|---| | SessionStart | Warm project vault | Async hook; does not block startup | | UserPromptSubmit | Create one local typed user_prompt, then deliver it and run semantic recall in parallel | Capture and /prepare recall are separate requests; recall stays read-only | | Stop | Durably accept one typed assistant_final | Uses last_assistant_message; conservative transcript fallback accepts only a complete, main-chain, text-only final record | | StopFailure | Retry an unacknowledged prompt | Marks the local turn failed; never invents or stores a final response | | PreCompact / PostCompact | Retry already-created pending events | Compaction summaries and transcript deltas are not captured | | SessionStart: compact | Re-retrieve and inject memory | Official post-compaction reinjection path | | SessionStart: resume/fork | Re-retrieve and inject memory | Restores external memory at session boundaries | | SubagentStop | No capture | Subagent and delegated chatter is always excluded | | SessionEnd | Retry pending typed events | Does not scan or ingest the transcript |

Deterministic capture and durable retry safety

Each Claude Code turn has a crash-safe local record under ~/.memoryrouter/state/ with a stable client session ID, monotonic turn ID, and two stable idempotency keys. The client writes that record before network I/O and marks an event accepted only when the typed server contract returns durable: true with status: accepted or duplicate.

The typed request is opt-in through capture_event on POST /v1/memory/ingest:

{
  "session_id": "ccp_project_partition",
  "capture_event": {
    "version": 1,
    "source": "claude-code-hooks",
    "event_type": "user_prompt",
    "idempotency_key": "cce_stable_event_key",
    "project_id": "ccp_project_partition",
    "client_session_id": "claude-session-id",
    "turn_id": "cct_stable_turn_id",
    "occurred_at": 1785990000000,
    "content": "the exact user prompt"
  }
}

Server acceptance is ordered for lost-response safety:

  1. D1 reserves (memory_key, idempotency_key) and pins the target Durable Object shard before any conversation buffer is touched.
  2. The pinned Durable Object atomically inserts its local event receipt, appends the typed content, updates the pending buffer, and persists any complete chunks to a durable embedding outbox.
  3. D1 marks the receipt buffered.
  4. Only then does the endpoint return 202 with durable: true.
  5. A retry after a lost response follows the pinned shard, sees the existing receipt, returns duplicate, and cannot append again.

The two accepted event types map server-side to user and assistant. Legacy clients that send messages[] without capture_event retain the existing fire-and-forget behavior; this release does not silently change their contract.

What automatic capture excludes

Automatic capture never ingests intermediate assistant text, tool calls, commands, file edits, tool results, tool failures, injected memory, thinking/signature blocks, compaction summaries, StopFailure error text, or subagent transcripts. For a normal Stop, last_assistant_message is authoritative. The transcript fallback refuses malformed/partial JSON, sidechains, or a tool-use record as the last assistant record. An empty or uncertain final remains locally open for a later retry rather than guessing.

Retry, interruption, and retention behavior

  • On the first 2.1 hook run, any v2.0 pendingCapture transcript digest is discarded rather than replayed, because it may contain tool/intermediate/subagent chatter. Only the legacy batch ID and discard reason remain locally for diagnosis.
  • Repeated UserPromptSubmit delivery while a turn is open resumes the same prompt event. The same text submitted after a completed final creates a new turn and new idempotency keys.
  • Repeated Stop delivery retries the same final event or becomes a no-op after acceptance.
  • A lost 202 leaves the local event pending. The next applicable hook sends byte-for-byte identical typed event identity; server receipts prevent a second append.
  • A different prompt arriving before the prior final marks the prior local turn interrupted and starts a new turn. Any unacknowledged event remains retryable; no synthetic final is created.
  • Before a new prompt is appended, older pending prompt/final events are retried in original turn order. If an older event is still unavailable, the new prompt remains locally pending rather than reordering the server buffer.
  • Local state is retained for 30 days by default. Server idempotency receipts are retained for 90 days, then bounded cleanup may remove completed receipts. Replaying an event after both retention windows is outside the retry guarantee.
  • Read-only keys can recall but cannot durably accept capture. Pending local events are retained rather than falsely marked committed.

Deterministic project isolation

Automatic storage and recall use a stable project handle as the MemoryRouter session_id, rather than Claude Code's ephemeral session UUID. That gives hard server-side project partitioning and makes memory available to later Claude sessions in the same project.

Identity precedence:

  1. MEMORYROUTER_PROJECT_ID explicit environment override
  2. .memoryrouter.json projectId / project
  3. ~/.memoryrouter/config.json projectId / project
  4. normalized Git remote (git@host:Org/Repo.git and HTTPS normalize identically)
  5. Git common directory (makes worktrees share identity when no remote exists)
  6. canonical CLAUDE_PROJECT_DIR / current directory for non-Git workspaces

Only ccp_<24 hex> is sent to MemoryRouter. Raw local paths, Git credentials, and remote URLs stay local. Worktrees of one repository share an ID; unrelated no-Git directories do not.

Project configuration

An optional non-secret .memoryrouter.json at the project root can be committed:

{
  "projectId": "acme-api",
  "memoryScope": "project",
  "includeGlobal": false,
  "captureEnabled": true
}

Create .memoryrouterignore at the project root, set "enabled": false, or export MEMORYROUTER_DISABLE=1 to disable automatic recall/capture for a sensitive workspace without uninstalling hooks.

Personal/global memory

Project memory is the secure default. To deliberately use one personal/global vault across projects:

npx memoryrouter-claude init --global --yes

To recall both isolated project memory and personal/global memory while continuing to write automatic captures only to the project:

npx memoryrouter-claude init --include-global --yes

Global recall is opt-in because it can intentionally surface facts across projects.

Install, upgrade, and scopes

npx memoryrouter-claude init --project       # .claude/settings.json; team/shareable
npx memoryrouter-claude init --local         # .claude/settings.local.json; private project
npx memoryrouter-claude init --user          # ~/.claude/settings.json; all projects
npx memoryrouter-claude init --key mk_xxx --local --yes

Running init again is the upgrade path. It migrates config to the current schema, removes only older MemoryRouter-owned hook entries, and adds one current set. Foreign settings and hooks are preserved. Corrupt JSON is rejected without modification.

The key is stored only at ~/.memoryrouter/config.json with mode 0600 in a mode 0700 directory. Project settings contain only the hook command.

Commands

| Command | Purpose | |---|---| | npx memoryrouter-claude init | Install or upgrade automatic hooks | | npx memoryrouter-claude doctor | Diagnose config, permissions, hooks, project ID, pending capture, API, and MCP | | npx memoryrouter-claude status | Show key, vault stats, consolidation debt, and active project scope | | npx memoryrouter-claude date-search | Retrieve memories from a specific time window with tier and importance filters | | npx memoryrouter-claude inspect | Drill down a memory's lineage by id: sources it consolidated and what it became | | npx memoryrouter-claude reflect | Consolidate memories into reflections using your local claude CLI | | npx memoryrouter-claude mcp install | Add the OAuth MCP manual surface with current Claude CLI syntax | | npx memoryrouter-claude mcp status | Inspect MCP configuration | | npx memoryrouter-claude mcp remove | Remove MCP only; hooks stay installed | | npx memoryrouter-claude off | Remove MemoryRouter hooks from local/project/user settings | | npx memoryrouter-claude off --purge | Also delete private key/config/checkpoint state |

Date search (time-window retrieval)

Retrieve memories from a specific time window. Use for questions like 'what happened last week' or 'most important things this month or lately'. For importance questions set importance to 7 or higher with tiers 2,3, since only reflections carry importance ratings. Omit --query for a chronological review; include --query to rank by relevance within the window. Resolve relative phrases like 'lately' to concrete ISO dates before calling.

npx memoryrouter-claude date-search --from 2026-08-10                          # chronological review
npx memoryrouter-claude date-search --from 2026-08-01 --to 2026-08-15 --query "launches"
npx memoryrouter-claude date-search --from 2026-08-10 --tiers 2,3 --importance 7   # most important lately
npx memoryrouter-claude date-search --from 2026-08-10 --json                   # raw server response
npx memoryrouter-claude inspect --id <memory id>                                # lineage drill-down

Flags: --from (required, ISO 8601), --to (default now), --query, --tiers 1,2,3 (only tiers 2 and 3 carry importance ratings), --importance N (minimum threshold 1 to 10; raw memories are excluded whenever this is set), --max-tokens N (1000 to 200000), --json. Truncated windows print a continuation cursor. The injected recall context also carries a one-line hint teaching Claude this exact pattern, so the agent can answer "what are the most important things we've done lately?" by itself.

Reflections (memory consolidation)

MemoryRouter's Reflection Hierarchy consolidates raw memories into higher-level reflections. This package runs the loop headless with YOUR local Claude Code as the reflecting model (you pay your own inference; MemoryRouter never calls a provider):

npx memoryrouter-claude reflect                     # one batch, raw -> reflections
npx memoryrouter-claude reflect --tier 2            # reflections -> high-level reflections
npx memoryrouter-claude reflect --batches all       # run until the pool is empty
npx memoryrouter-claude reflect --max-tokens 20000  # smaller batches for faster model turns
npx memoryrouter-claude reflect --dry-run           # print the prompt; commit nothing

How it works, and the guarantees it keeps:

  • The server authors the reflection instructions. Each checkout carries the contract; this package passes it to claude -p verbatim and never adds its own reflection guidance. If a checkout carries no contract, reflect refuses rather than inventing a prompt.
  • The model never sees memory IDs. The prompt contains only instructions and dated memory texts; the commit is {batch_id, entries[]} only, and entries are text plus importance, nothing else.
  • No local state. Each batch is protected by a 15 minute server-side lease. If a run crashes or is interrupted, the lease expires and the memories return to the pool; re-running simply continues. --dry-run deliberately lets its lease expire.
  • Idempotent commits. Re-committing a completed batch is success, never a duplicate.

When your unconsolidated memory crosses the server threshold, injected recall context includes a one-line consolidation suggestion on every injection, and status shows the current debt. The MCP surface (mcp install) exposes the same capability as in-session tools once the server-side reflect tools ship there.

Automatic consolidation (default on)

You do not have to run reflect yourself. When a retrieval response reports debt above the server's threshold, the hooks spawn the same reflect loop as a detached background process:

  • Your session is never blocked and never sees the run; output goes to ~/.memoryrouter/consolidate.log.
  • At most 3 batches per trigger, with a fresh debt check between batches; the run stops as soon as debt drops below the threshold.
  • A machine-wide lockfile (~/.memoryrouter/consolidate.lock, stale after 20 minutes) prevents concurrent sessions from double-firing, and a 30 minute cooldown follows each completed run.
  • The threshold always comes from the server response; nothing is hardcoded locally.
  • The reflecting model is your own local claude (you pay your own inference). MemoryRouter bills the checkout/commit tokens at the normal 1x raw rate.

Opt out with "autoConsolidate": false in ~/.memoryrouter/config.json. The suggestion line and manual reflect keep working; only the automatic background trigger is disabled.

Historical import (agent-driven)

New vaults usually sit next to months of existing Claude Code history on disk. The import flow brings it in with a strict division of labor: the server owns the extraction prompt, your local agent owns discovery/parsing, and this package owns transport. The agent never uploads; this CLI never parses history.

npx memoryrouter-claude import --instructions        # print the server's extraction prompt
npx memoryrouter-claude import --instructions --run  # or run it headless via claude -p
npx memoryrouter-claude import --file extract.jsonl  # validate, preview, quote, approve, upload
npx memoryrouter-claude import --file extract.jsonl --yes   # non-interactive approval
npx memoryrouter-claude import --dismiss             # permanently silence the import nudge

How it works, and the guarantees it keeps:

  • The server owns the prompt (GET /v1/memory/imports/instructions, versioned like the reflection contract). Prompt improvements reach every user instantly, with no package update, and the extraction adapts to whatever transcript format is actually on disk.
  • The agent only reads local files and writes one JSONL extract (four fields per record: external_id, content, timestamp, role). No network calls, no credentials in the extract.
  • --file is the only upload path. It validates the extract locally, computes the same deterministic identity math as the server (record hashes, archive id, vault fingerprint), shows the record count, date range, estimated tokens, and the server's price quote, and requires explicit approval before any write.
  • Fully idempotent. The import id is derived from content + destination, batches carry Idempotency-Keys, and the server dedupes by external_id. Re-running after any interruption replays committed batches for free and resumes where it left off. Duplicates are never re-billed.
  • The Memory Key never appears in the prompt or the extract file. It rides only in the Authorization header.

When a vault is new (small, no completed import, not dismissed), injected recall context includes a one-line import suggestion on every injection until an import completes or you --dismiss.

Configuration

~/.memoryrouter/config.json is versioned and migrated non-destructively:

{
  "configVersion": 2,
  "apiKey": "mk_...",
  "memoryScope": "project",
  "includeGlobal": false,
  "captureEnabled": true,
  "contextLimit": 2000,
  "density": "balanced",
  "maxContextChars": 9500,
  "stateTtlDays": 30
}

Environment overrides:

| Variable | Purpose | |---|---| | MEMORYROUTER_API_KEY | Key override; highest key precedence | | MEMORYROUTER_PROJECT_ID | Explicit stable project identity | | MEMORYROUTER_DISABLE=1 | Disable automatic hooks without uninstalling | | MEMORYROUTER_API_BASE | Test/self-hosted API base | | MEMORYROUTER_CONFIG_DIR | Test/managed config location | | MEMORYROUTER_DEBUG=1 | Diagnostic stderr from hooks |

Read-only mode uses the canonical :read suffix, for example mk_xxx:read. The legacy mk_ro_ form is still accepted by the API for compatibility but should not be used in new setup instructions. A read-only key retrieves normally and the server returns a successful skipped result for capture.

Local retention and failure behavior

  • Typed turn records, stable event keys, acceptance status, and the latest prompt are kept at ~/.memoryrouter/state/<session>.json, mode 0600, for safe retry and reinjection.
  • State files are pruned after 30 days by default.
  • Local typed turn records can contain prompt and final-response text (up to 100,000 characters per event). Use .memoryrouterignore, enabled: false, or MEMORYROUTER_DISABLE=1 for sensitive projects.
  • Every hook exits successfully from Claude Code's perspective. Retrieval failures produce no injected context; write failures retain pending typed events for retry.
  • Hook wall clocks are 8 seconds for retrieval and 27 seconds for capture paths, below their configured Claude Code timeouts.

Development

npm run check
npm test
npm pack --dry-run

No runtime dependencies. Requires Node.js 18+ and Claude Code.

License

MIT © MemoryRouter