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

pi-qdrant-memory

v0.6.2

Published

Semantic, cross-session retrieval over durable conversation knowledge for pi.dev, backed by Qdrant.

Readme

pi-qdrant-memory

Semantic, cross-session (single project) retrieval over durable conversation knowledge for pi.dev, backed by Qdrant.

Complements a running ecosystem:

  • codegraph = current code structure (exact/graph). Optional.
  • pi-blackhole = durable decision capture before compaction (lexical recall). Optional.
  • pi-qdrant-memory = semantic retrieval over durable knowledge, indexed code-structure retrieval (optional).

Tools available:

  • memory_save (agent tool) — persist a durable decision/constraint/preference.
  • memory_search (agent tool) — semantic search of prior durable knowledge.
  • code_memory (agent tool, opt-in) — semantic search of indexed code-structure summaries (enabled via codeKnowledge: "on"; see Code memory).
  • memory_forget (agent tool, opt-in) — retract a previously saved memory by exact verbatim text (enabled via memoryForget: "on").

Commands:

  • One /qdrant <key> command — status, settings, remember, search, forget, clear, index, help. The key is the first argument, and the TUI completes it (plus the bounded second token for clear, index and settings).
  • Mode-aware: detects when pi-blackhole is installed and ingests blackhole's durable artifacts; without it, it captures pi's own compaction summary as a session_summary.

All writes are idempotent (deterministic content-hash point ids). Unreachable Qdrant/embeddings degrade gracefully — tools report the problem and never crash the session.

Install

pi install npm:pi-qdrant-memory   # or: pi install git:github.com/lordekeen/pi-qdrant-memory

Quickstart (no package publish): drop src/index.ts into .pi/extensions/.

Runtime is in-process; no background resources are started by the factory (all lifecycle work happens on session_start / compaction events / session_shutdown).

Prerequisites

  • Node >= 22.19 (native TypeScript type-stripping).
  • A running Qdrant server — default http://localhost:6333 (REST).
  • An OpenAI-compatible /embeddings endpoint — default a local llama.cpp OpenAI-format server running nomic-embed-text at 768 dimmension. Ollama or any hosted OpenAI-compatible API also work (set embeddingApiKey).

Config

The global config file lives at ~/.pi/agent/pi-qdrant-memory/pi-qdrant-memory-config.json (honors PI_CODING_AGENT_DIR). It holds all twelve keys and is the layer that applies where no project override exists. A copyable template of the shipped defaults ships at pi-qdrant-memory-config.example.json (repo root, listed in package.json files) — copy it onto the path above to materialize the file. The template equals the built-in DEFAULTS in src/config.ts, which remains the real layer-4 default: a missing global file is not an error, the built-in defaults apply (zero-config run).

Storage layout — ~/.pi/agent/pi-qdrant-memory/ holds the global config file and a projects/ directory with one <projectId>.json override per project (~100 B each).

Precedence, per field, highest first: env → project override → global file → DEFAULTS (see Project overrides). The ten keys below always live in the global file and are edited with /qdrant settings; the two allowlisted keys' defaults are edited by hand using the template.

| Key | Default | Meaning | | --- | --- | --- | | qdrantUrl | http://localhost:6333 | Qdrant REST base URL | | qdrantApiKey | null | Optional Qdrant API key | | embeddingBaseURL | http://localhost:8080/v1 | OpenAI-compatible /embeddings endpoint | | embeddingModel | nomic-embed-text | Embedding model id | | embeddingApiKey | null | Optional key for hosted embedding APIs | | expectedDimension | 768 | Embedding dimension (positive integer); dimension drift recreates on write (after successful embed) and fails safely on read | | scoreThreshold | 0.18 | Search score threshold, 0–1 (per-model; nomic ≈ 0.15–0.2) | | maxResults | 10 | Default memory_search limit | | mode | auto | auto detect | blackhole force Mode 1 | own force Mode 2 | | codeKnowledge | off | on enables structural code summaries + the code_memory tool (next session) | | codeScoreThreshold | 0.55 | Score threshold for code_memory searches, 0–1 (per-model; see Code memory) | | memoryForget | off | on enables model exact-match memory retraction via memory_forget tool (next session) |

Env overrides (highest precedence, above the project and file layers): PI_QDRANT_URL, PI_QDRANT_API_KEY, PI_QDRANT_EMBEDDING_BASE_URL, PI_QDRANT_EMBEDDING_MODEL, PI_QDRANT_EMBEDDING_API_KEY, PI_QDRANT_EXPECTED_DIMENSION, PI_QDRANT_SCORE_THRESHOLD, PI_QDRANT_MAX_RESULTS, PI_QDRANT_MODE, PI_QDRANT_CODE_KNOWLEDGE, PI_QDRANT_CODE_SCORE_THRESHOLD, PI_QDRANT_MEMORY_FORGET.

The global file stores API keys and is written with owner-only permissions (0600); a previously loosened file is tightened on the next save.

Project overrides

Two config keys are repo-shaped and can be overridden per project: codeKnowledge (should this repo be indexed at all) and codeScoreThreshold (how strict code retrieval is in this repo). An override lives at <agentDir>/pi-qdrant-memory/projects/<projectId>.json — a partial config holding only those keys, keyed by the same projectId as the collection.

  • Env still wins: PI_QDRANT_CODE_KNOWLEDGE / PI_QDRANT_CODE_SCORE_THRESHOLD mask a project override.
  • /qdrant settings codeKnowledge on and /qdrant settings codeScoreThreshold 0.6 write this project's store; /qdrant settings <key> default clears the override.
  • A moved or renamed repo orphans its override exactly as it orphans its collection (both are keyed by the git-root realpath hash).
  • scoreThreshold and maxResults are not project-overridable on purpose: scoreThreshold is purely model-calibrated and has no repo-shaped half, and maxResults is a user preference about result volume, not a repo property.

Commands

One command, /qdrant, with a key as its first argument:

  • /qdrant — the status block plus this list (bare form is self-documenting).
  • /qdrant status — connection health + active mode + collection point count.
  • /qdrant settings [key] [value] — open the settings screen, or persist a config field. codeKnowledge and codeScoreThreshold apply to this project (an override); every other key (mode, embeddingBaseURL, embeddingModel, expectedDimension, scoreThreshold, maxResults, memoryForget, …) writes the global config file. <key> default clears an allowlisted override; for the other keys default is an ordinary value. Only the <key> token is bounded — the value is the rest of the line, so URLs and model names keep their punctuation.
    • Bare /qdrant settings opens the settings screen in the TUI: pi's own settings list with all twelve fields (type-ahead search, enum values cycled with Enter, single-line editors for the rest). API keys are shown only as set/not set — never the value — and an empty editor value clears a key. Esc closes the screen and prints settings: unchanged (cancelled); invalid values are rejected with an error and the row rolls back. In RPC the same bare form falls back to the interactive dialog sequence, and in print/headless modes it prints the usage message.
  • /qdrant remember <text> — manual durable save. The text is used verbatim.
  • /qdrant search <query> — manual semantic search. The query is used verbatim.
  • /qdrant forget <query> — search matching memories and delete them interactively with confirmation. The dialog lists the matches (type, score, 60-char preview) and one confirmation deletes at most the 5 closest matches.
  • /qdrant clear all | code — reset the current project's entire memory collection (all) or purge indexed code summaries (code). Exactly one modifier; bare /qdrant clear displays usage guidance. clear all asks for confirmation first (naming the project and the exact count it would delete) and refuses outright in headless modes rather than delete blindly; an empty collection is reported with no dialog.
  • /qdrant index code — re-index code summaries now (the index key takes a kind; today code is the only one). Exactly one kind; bare /qdrant index lists the kinds. Answers "code memory is disabled" rather than indexing when codeKnowledge is off.
  • /qdrant help — list all commands available.

An unrecognised key, or too many tokens where only one is accepted, produces one error entry naming the correction — the command never guesses. Completion is two-level: keys for /qdrant , then the accepted values for clear, index and settings.

Migration notice. Until you run your first /qdrant command, each session start shows a one-line notice that /qdrant-* is now /qdrant <key> (pointing at /qdrant help). It is a transcript message, not an error, and it stops after the first successful /qdrant dispatch — a failed one (unknown key, bad arguments) does not count. The "already shown" flag lives in ~/.pi/agent/pi-qdrant-memory/state.json (honors PI_CODING_AGENT_DIR); deleting that file re-arms the notice. Headless (json/print) sessions never show it.

Statusline

While a session is active the extension shows a footer status entry: 🧠 Memory (N): <mode> (<collection>) — Where N is the number of memories stored in the project collection (code + project knowledge), refreshed at session start and after every successful save/clear/forget (and code sync). When Qdrant is unreachable the count is omitted.

Agent tools

  • memory_save(text, type?) — persist a durable decision/constraint/preference. Type defaults to decision.
  • memory_search(query, type?, limit?) — semantic search of prior durable knowledge (limit capped by maxResults).
  • code_memory(query, limit?) (opt-in) — semantic search of indexed code-structure summaries.
  • memory_forget(text) (opt-in) — retract a previously saved memory by exact verbatim text (gated on memoryForget: "on").

The tools carry always-on prompt guidance (via promptSnippet/promptGuidelines): the model is nudged to call memory_save when a decision/constraint/preference settles (with concise, self-contained statements, without re-recording what auto-capture covers) and to call memory_search when resuming prior work or before re-deciding. When code memory is on, code_memory likewise carries guidance to reach for it on "how/where does X work" questions and to open the returned file:line pointers.

No companion skill is needed for the core loop — the guidance ships with the tools descriptions. You can optionally instruct the model in the System Prompt (APPEND_SYSTEM.md) to nudge its decision on when to save/read memories.

Code memory (optional)

With codeKnowledge: "on", the extension scans the repo at session_start (fire-and-forget) and indexes structural summaries of top-level definitions — exported functions/classes/types, Python defs, per-file anchors — as code points in the same collection. Zero dependencies: the extractor is built in; no external indexer is used. The status row counts {symbols} as per-definition summaries only; the one anchor point per file is represented by the files count, not as a symbol.

  • Freshness: payloads carry file_path + file_sha; unchanged files are skipped, changed files are deleted-and-replaced, vanished files are cleaned up. /qdrant index code forces a resync.

  • Retrieval: the code_memory tool (registered only while enabled) searches code summaries at codeScoreThreshold; memory_search never returns code hits.

    Thresholds are per-model, and this one is load-bearing. The shipped 0.55 was calibrated against nomic-embed-text so that relevant code queries (≈0.6) clear it while unrelated ones (≈0.5) do not — a narrow band, because embedding models compress cosine similarity. On a model that scores lower overall, code search can silently return nothing. To find where your model actually sits, temporarily lower codeScoreThreshold (e.g. to 0.3) and read the score= values in code_memory output, then set it just above the band where unrelated matches stop appearing. Note this only applies to code search: memory_search uses scoreThreshold and never returns code hits.

  • Mid-session flips take effect at the next session start (the settings output reminds you); only indexing can be run immediately via /qdrant index code.

Modes

  • Mode 1 (pi-blackhole present, autodetects): reads pi-blackhole's pending durable artifacts (<agent-dir>/pi-blackhole/*-pending.json) and ingests them at session_start (catch-up) and session_shutdown. It never claims the session_before_compact hook, pi-blackhole owns it.
  • Mode 2 (pi-blackhole absent): claims session_before_compact and captures pi's own compaction summary (from the session_compact event) as a session_summary point — fire-and-forget so capture can never stall compaction. /qdrant remember is the manual safety net.

Forcing mode: own while pi-blackhole is operational is an explicitly contradictory configuration: both extensions claim session_before_compact, and if pi-blackhole cancels compaction (its live-message guard), no mode-2 capture happens. The settings write and /qdrant status both warn; auto avoids the conflict.

An early-session auto snapshot is not yet wired: it needs mid-session content distillation access this extension does not currently have, so Mode 2's safety nets are the compaction capture and /qdrant remember.

Data model (summary)

One Qdrant collection per project, named pi-mem-<16 hex of sha256(git root)>; single unnamed vector, Cosine, on_disk, HNSW. Points carry { type, text, project_id, session_id?, source_entry_id?, ts, source_kind } plus code-provenance fields on code points (file_path, file_sha, symbol, start_line, end_line); keyword payload indexes on source_kind and file_path. Deterministic point ids (sha256(normalized text | source_kind | context)) make every write idempotent.

Development

Zero runtime npm dependencies (Node global fetch + crypto only). TypeScript is erasable-syntax only and runs directly via Node's type stripping — no build step.

npm test          # node --test over test/**/*.test.ts
npm run typecheck # tsc --noEmit (needs devDependencies installed)

Opt-in end-to-end smoke test (requires real Qdrant on :6333 and an OpenAI-compatible embeddings server): QDRANT_MEMORY_SMOKE=1 npm run test:smoke. Server endpoints are overridable via QDRANT_MEMORY_URL, QDRANT_MEMORY_EMBED_URL, QDRANT_MEMORY_EMBED_MODEL, and QDRANT_MEMORY_EMBED_DIM.