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-graphiti

v0.6.0

Published

🕸️ Persistent knowledge graph for Pi via Graphiti MCP. Ambient recall, automatic episode writes on session events, /graph command.

Readme

pi-graphiti

🕸️ Persistent knowledge-graph extension for Pi, backed by a Graphiti MCP server.

What it gives you

This extension wraps Graphiti MCP server. The MCP server provides add_memory, search_nodes, etc. as raw tools.

  • graph tool — single pi-native tool with three actions (add / search / episodes) so you don't need pi-mcp-adapter to use graphiti.
  • Automatic episode writes — pushes a snapshot every N user turns, before context compaction, and on session shutdown. No need for the model to remember to write.
  • LLM curation pass (on by default) — the turn-based nudge spawns a short-lived child pi -p (loading only this extension, so it just has the graph tool) that reviews the recent conversation and decides what is worth persisting and at which scope (project vs global), then calls graph add itself — or says "Nothing to save." Set reviewEnabled: false to fall back to raw snapshot pushes (all project scope) that rely purely on graphiti's server-side extraction.
  • Proactive in-turn saving — the system-prompt policy tells the agent when to persist proactively (corrections, preferences, durable facts/decisions, conventions, end of significant work), so it saves during normal turns instead of only on the background nudge.
  • Correction detector (on by default) — a user correcting the agent fires an immediate curation review, capturing the highest-signal "you should have remembered that" moment right away. Set correctionDetection: false to disable.
  • System-prompt policy block — every session starts knowing the graph exists and when to use it.
  • Optional ambient recall — opt-in injection of relevant entities/facts at session start, keyed on the latest user message.
  • Project/global scoping (on by default) — split of graph memory into a per-project group and a shared global group, so project-specific facts and cross-project knowledge stay separated. Set projectScoping: false to collapse to a single bucket.
  • /graph slash command — status, search, ingest, dump, load, clear directly from the prompt.

Requirements

A running Graphiti MCP server (FalkorDB or Neo4j backend). Stand one up by following Graphiti's docs, or run /graph setup after installing to provision and start a local Docker stack for you.

Default URL the extension expects: http://localhost:8000/mcp/ (Graphiti's default HTTP endpoint).

Install

# from npm (once published)
pi install npm:pi-graphiti

# or pinned from git
pi install git:github.com/p2c2e/[email protected]

Configure

Configuration is optional — defaults work against a local graphiti server. You can run /graph setup to configure to your liking.

Config file: ~/.pi/agent/pi-graphiti-config.json

{
  "enabled": true,
  "url": "http://localhost:8000/mcp/",
  "groupId": "",
  "injectContext": false,
  "projectScoping": true,
  "nudgeInterval": 10,
  "flushOnCompact": true,
  "flushOnShutdown": true,
  "flushMinTurns": 6
}

Environment overrides (take precedence over the JSON file):

| Variable | Default | Notes | | ------------------------------- | ----------------------------- | ----- | | PI_GRAPHITI_ENABLED | true | Set to false to disable without uninstalling. | | PI_GRAPHITI_URL | http://localhost:8000/mcp/ | MCP endpoint. | | PI_GRAPHITI_GROUP_ID | pigraphiti<user><host> | Sanitized to [A-Za-z0-9_]+ — hyphens corrupt RediSearch queries. | | PI_GRAPHITI_INJECT_CONTEXT | false | Inject recall block at session start. | | PI_GRAPHITI_PROJECT_SCOPING | true | Split memory into per-project (<groupId>_proj_<project>) + global groups. Set false for a single bucket. | | PI_GRAPHITI_NUDGE_INTERVAL | 10 | User turns between background pushes. | | PI_GRAPHITI_REVIEW_ENABLED | true | Nudge runs an LLM curation pass (child pi -p) that picks facts + scope. false = raw snapshot push. | | PI_GRAPHITI_CORRECTION_DETECTION | true | Detect user corrections in real time and fire an immediate curation review (rate-limited, reachability-gated). | | PI_GRAPHITI_REVIEW_RECENT | 0 | Recent messages fed to the curation review. 0 = all. | | PI_GRAPHITI_LLM_MODEL | (default model) | Model override for the review subprocess (e.g. a cheap/fast model). | | PI_GRAPHITI_LLM_THINKING | (off when model set) | Thinking level for the review subprocess. | | PI_GRAPHITI_FLUSH_ON_COMPACT | true | Push snapshot before compaction. | | PI_GRAPHITI_FLUSH_ON_SHUTDOWN | true | Push snapshot on shutdown. | | PI_GRAPHITI_FLUSH_MIN_TURNS | 6 | Minimum user turns before flush triggers. | | PI_GRAPHITI_TIMEOUT_MS | 60000 | Per-call timeout for real work (writes, searches, episode reads). | | PI_GRAPHITI_STATUS_TIMEOUT_MS | 3000 | Budget for cheap reachability probes (get_status). Bounds how long a hung server can delay a turn. See outage resilience. | | PI_GRAPHITI_SPOOL | true | Spool episodes to disk when the server is down and replay them automatically. Set false to drop failed writes instead. | | PI_GRAPHITI_SPOOL_MAX_ENTRIES | 200 | Max spooled episodes (newest win). | | PI_GRAPHITI_SPOOL_MAX_BYTES | 8388608 | Max total spool size (8MB). | | PI_GRAPHITI_SPOOL_MAX_AGE_DAYS| 14 | Spooled episodes older than this are discarded on drain. | | PI_GRAPHITI_SPOOL_DRAIN_BATCH | 25 | Max episodes replayed per drain cycle (/graph spool drain replays all). |

Usage

The graph tool is exposed to the LLM automatically. From the user side:

/graph                       Status + recent episodes + active group
/graph setup                 Interactive wizard: set group id + project scoping, and configure/start the backend (local Docker stack or external MCP server)
/graph search QUERY          search_nodes + search_memory_facts
/graph dump [path]           Export ALL episodes (every group) to markdown; use before reverting to flat files
/graph load <path>           Re-import episodes from a dump file back into their original group ids
/graph ingest <path> [global] Memorize a text file: chunk it and push the chunks as episodes into the current project's graph memory (or the global group with "global")
/graph clear                 clear_graph for the active group (destructive)
/graph spool                 Show the offline write queue (episodes captured while the server was down); `drain` replays now, `clear` discards
/graph uninstall             Tear down the local Docker stack, but ONLY if /graph setup started it; run before `pi remove`

Uninstalling: run /graph uninstall (alias /graph teardown) before pi remove. It stops the local Docker stack only when the setup wizard started it (config startedBySetup); a pre-existing or external stack is left running with a message. pi remove itself only edits settings and cannot run teardown. A best-effort preuninstall npm script does the same cleanup for plain npm uninstall.

When the MCP server is down

Graphiti is an optional accelerator, never a blocker: every path catches failures and the agent keeps working. Cost of an outage:

  • Server stopped / port closed (the common case): connections are refused in ~1ms. No measurable impact.
  • Server hung / black-holed (paused container, VPN drop, wedged FalkorDB): reachability probes are capped at PI_GRAPHITI_STATUS_TIMEOUT_MS (3s) rather than the 60s work timeout, getStatus() enforces that deadline internally so no call site can forget it, and concurrent callers share one probe.
  • Sustained outage: failed probes back off 5s -> 15s -> 60s -> 300s (cap), so a dead server costs ~12 probes/hour instead of 120. A success resets the breaker immediately, and every /graph subcommand force-probes so you never wait out a backoff window.
  • No memory is lost. Episodes that cannot be written (turn nudge, pre-compact and shutdown flushes, and the agent's own graph add) are appended to a disk spool at ~/.pi/agent/pi-graphiti-spool/pending.jsonl and replayed automatically on the next healthy cycle. /graph shows the pending depth; /graph spool drain forces a replay and /graph spool clear discards. Bounded by entry count, total bytes, and age; anything the spool does drop is recorded in dead-letter.jsonl rather than deleted silently. (One gap: the correction detector still skips rather than spools during an outage.)
  • Shutdown does no network I/O at all - it spools synchronously, so a slow server cannot make the episode race process exit. The pre-compact flush, which the host awaits, has its own 5s write budget and spools on expiry.

Full analysis, per-path blocking table, and the remaining tracked work (outage notification, compact-flush budget) are in docs/design/outage-resilience.md.

Scope (when projectScoping is enabled)

The graph tool accepts a scope argument:

  • add / episodes: "project" (default) or "global".
  • search: "both" (default, unions project + global), "project", or "global".

The per-project group id is derived as <groupId>_proj_<sanitizedProjectName>, where the project name is the current working directory's basename. With scoping disabled (projectScoping: false), every operation uses the single groupId bucket and scope is ignored.

Ingesting a document from the CLI

To load an arbitrary text file (notes, docs, transcripts) into graphiti episode memory outside of a pi session, use the ingest script:

npm run ingest -- <file> [options]
# or: npx tsx scripts/ingest-file.ts <file> [options]

Options:

  • --group <id> target group_id (sanitized to [A-Za-z0-9_]).
  • --name <base> episode base name (default: file basename).
  • --source <kind> text | message | json (default: text).
  • --chunk-chars <n> per-episode safety cap (default: 8000; 0 = whole file as one episode). Chunking is paragraph-driven: each paragraph is its own episode, and a paragraph larger than the cap is split into sentences packed up to the cap (hard-cut only if a single sentence still exceeds it).
  • --dry-run show the chunk plan without writing.

Group precedence: --group > PI_GRAPHITI_GROUP_ID > default. The document is written to that one explicit group (project scoping does not remap it), so you can drop a file into a specific bucket:

PI_GRAPHITI_GROUP_ID=myscratch npx tsx scripts/ingest-file.ts notes.md --chunk-chars 6000

Episodes extract asynchronously; allow ~30-90s before the entities/facts are searchable.

Coexistence with other memory extensions

This extension is self-contained and stores everything in its own graphiti group IDs, so it can run alongside other memory extensions without conflict.

  • It registers its own graph tool, so the LLM picks it based on tool descriptions.
  • Its before_agent_start hook appends its own block to the system prompt — Pi composes multiple such blocks safely.
  • It uses its own group IDs / storage, so there are no double-writes.
  • To share a graph across machines/installs, set PI_GRAPHITI_GROUP_ID to the same value.

Design notes

  • Direct HTTP MCP client (no pi mcp dependency). Lets us own timeouts, retries, and silent degradation.
  • Group IDs are sanitized to [A-Za-z0-9_]+ because FalkorDB/RediSearch treats - as a NOT operator and silently corrupts queries.
  • Async extraction — add_memory queues entity/fact extraction server-side. A just-added episode may not be searchable for tens of seconds.
  • Fail-quiet — if the graphiti server is unreachable, all writes/reads degrade silently. The extension is an accelerator, never a blocker.

License

MIT