An open API service indexing awesome lists of open source software.

https://github.com/k1lgor/pi-memoir

Pi-memoir builds a structured knowledge base of your project.
https://github.com/k1lgor/pi-memoir

memory pi pi-coding-agent pi-extension pi-mono pi-package project-memory

Last synced: 27 days ago
JSON representation

Pi-memoir builds a structured knowledge base of your project.

Awesome Lists containing this project

README

          

# 🧠 pi-memoir (_/paΙͺ mΙ›mˈwɑːr/_)

> **Pronunciation:** pi-mem-wahr (French _mΓ©moire_ = memory)

![pi-memoir Hero](docs/assets/logo.png)

**Project-wide persistent memory for [pi](https://pi.dev) β€” the LLM queries the memoir instead of reading all files, saving ~90%+ tokens.**

Pi-memoir builds a structured knowledge base of your project. Instead of the LLM running `bash`, `ls`, `grep`, and `read` on 20 files to understand your project (costing tens of thousands of tokens per session), it queries the memoir for architecture, structure, config, dependencies, and every source file.

Inspired by [MemPalace](https://github.com/mempalace/mempalace) (verbatim memory with semantic retrieval) and [Graphify](https://github.com/safishamsi/graphify) (knowledge graph extraction).

## How It Saves Tokens

| Approach | Token Cost |
| --------------------------------------------- | --------------------------------- |
| LLM runs `ls`, `find`, `grep`, reads 10 files | ~15,000–30,000 tokens per session |
| LLM queries the memoir via `memo_search` | **~200–500 tokens** per session |
| **Savings** | **~95–98% per session** |

The key insight: **project knowledge doesn't change often.** Harvest once, query forever.

## How It Works

```
/
└── .pi/memoir/
└── memories.jsonl ← Append-only JSONL storage (per-project)
```

The extension injects a **system prompt instruction** at the start of every turn via `before_agent_start`:

```
=== PI-MEMOIRE: DON'T USE BASH β€” USE THE MEMOIRE ===
CRITICAL: Before running ANY bash/ls/find/grep/wc/read commands
to explore the project, you MUST call memo_search first.
β€’ "what's the architecture?" β†’ memo_search({ query: "architecture" })
β€’ "what files?" β†’ memo_search({ tags: "project:structure" })
β€’ "dependencies?" β†’ memo_search({ query: "package", tags: "project:manifest" })
...
If memo_search returns nothing, THEN fall back to bash/read.
```

This forces the LLM to check the memoir **first** before falling back to bash.

## What Gets Harvested

On `/memo harvest` (or `memo_harvest` tool), the harvester walks **every file** in your project and stores:

| Memory | Tag | What it contains |
| --------------------- | --------------------------- | --------------------------------------------------------------- |
| Project README | `project:readme` | Title, first heading, line count |
| Package manifest | `project:manifest` | Name, version, deps, scripts, detected language |
| Directory tree | `project:structure` | Recursive tree (4 levels deep, 80 lines max) |
| Entry points | `project:entry` | `index.ts`, `main.ts`, `src/index.ts`, etc. |
| Config files | `project:config` | `tsconfig.json`, `vite.config.ts`, `.eslintrc`, etc. |
| **Every source file** | `project:file`, `file:path` | **All files** with source extensions (128 extensions supported) |

### Source file harvesting

The harvester captures individual memories for every source file in the project:

- **128 file extensions** supported (`.ts`, `.js`, `.py`, `.rs`, `.md`, `.json`, `.vue`, `.svelte`, `.css`, `.sh`, `.java`, `.cpp`, `.go`, `.rb`, `.php` β€” and 100+ more)
- **200 file cap** β€” prevents bloat on large projects (covers 90%+ of GitHub repos fully)
- **20KB limit** β€” skips large generated/bundled files
- **Smart summaries** β€” code files show first import/export, JSON shows top-level keys, Markdown shows first heading
- Skips `node_modules`, `.git`, `dist`, `build`, `.cache`, `target`, `vendor` and other non-source dirs

### Auto-Capture

On session shutdown, key moments (edited files, decisions) are automatically condensed and stored with `"auto"` source tag.

## Installation

### Via git (recommended)

```bash
pi install git:github.com/k1lgor/pi-memoir
```

### Local path (development)

```bash
pi install ./path/to/pi-memoir
```

### Quick test (no install)

```bash
pi --extension ./index.ts
```

## Usage

### Quick Start

```text
User: "/memo harvest"
LLM: calls memo_harvest β†’ scans every file
β†’ "βœ… Harvested 38 memories about this project."

User: "What's the architecture?"
LLM: calls memo_search({ query: "architecture", tags: "project:structure" })
β†’ "Project structure: 12 files, 3 dirs
πŸ“ src/ β†’ πŸ“ api/ β†’ routes.ts, middleware.ts
πŸ“ src/ β†’ πŸ“ components/ β†’ Header.tsx
πŸ“„ README.md, package.json, ..."
```

### Tools (LLM can call these)

| Tool | Description |
| -------------- | ---------------------------------------------------------------------- |
| `memo_harvest` | **Scan the entire project** β€” walks every file, stores memories |
| `memo_search` | **REPLACES bash/ls/read** β€” query project knowledge by keywords + tags |
| `memo_store` | Store additional ad-hoc facts and decisions |

### Commands

| Command | Description |
| ----------------------------------- | ------------------------------------------- |
| `/memo harvest` | Scan project and build knowledge base |
| `/memo search [--tags t1]` | Search stored memories |
| `/memo list [--tags t1]` | List recent memories (shows notification) |
| `/memo store [--tags t1,t2]` | Store a memory manually |
| `/memo delete ` | Delete by number from list |
| `/memo delete --all` or `-a` | **Delete ALL memories** (with confirmation) |
| `/memo stats` | Show memory count and storage path |
| `/memo path` | Show storage file path |

### Benchmark

A standalone benchmark script (`bench.mjs`) compares token costs:

```bash
# Quick benchmark (common key files)
node bench.mjs .

# Full benchmark β€” every source file in the project
node bench.mjs . --all

# Specific files
node bench.mjs . README.md package.json
```

Sample output against the NousResearch/hermes-agent repo (2,957 source files):

```
πŸ“Š Token Cost Benchmark β€” pi-memoire
/path/to/hermes-agent
515 memories in memoir

β”Œβ”€ src/agent.ts
β”‚ File: 2,341 words / 18,204 chars β†’ ~6,068 tok
β”‚ Memoir: 127 words / 1,023 chars β†’ ~400 tok
β”‚ Savings: 5,668 tok (93% reduction)
β”‚ Mem entry: src/agent.ts (89 lines, e.g. import { EventEmitter } from...)
└──

β”Œβ”€ src/utils/logger.ts
β”‚ File: 892 words / 6,521 chars β†’ ~2,174 tok
β”‚ Memoir: 98 words / 812 chars β†’ ~325 tok
β”‚ Savings: 1,849 tok (85% reduction)
β”‚ Mem entry: src/utils/logger.ts (34 lines, e.g. export interface LogLevel...)
└──

══════════════════════════════════════════
πŸ“ˆ Summary
Files scanned: 2,957 (515 with memoir, 2,442 without)
Read files: ~3,049,753 tokens
Query memoir: ~206,000 tokens
Savings: ~2,843,753 tokens (93% reduction)
```

## Architecture

```
pi-memoir/
β”œβ”€β”€ index.ts ← Entry point. Inits storage, wires tools/hooks/commands.
β”‚ Injects "DON'T USE BASH" rule at end of system prompt
β”‚ via before_agent_start (only if memories exist).
β”œβ”€β”€ storage.ts ← MemoryStore class. JSONL file at .pi/memoir/memories.jsonl.
β”‚ store(), search(), list(), delete(), deleteByIndex().
β”‚ Keyword search with TF scoring. Singleton exported.
β”œβ”€β”€ harvester.ts ← Project scanner. Walks entire directory tree, creates
β”‚ structured memories for every source file (128 extensions,
β”‚ 200 cap, <20KB limit, smart summaries per file type).
β”œβ”€β”€ tools.ts ← Three LLM-callable tools:
β”‚ β€’ memo_harvest β€” scan entire project
β”‚ β€’ memo_search β€” REPLACES bash for project exploration
β”‚ β€’ memo_store β€” save ad-hoc facts
β”œβ”€β”€ hooks.ts ← Lifecycle hooks:
β”‚ β€’ agent_start β†’ clears stale memo widgets
β”‚ β€’ session_start β†’ warns if not harvested
β”‚ β€’ session_shutdown β†’ auto-stores key decisions
β”œβ”€β”€ commands.ts ← /memo command with subcommands:
β”‚ list, search, store, delete (with --all/-a), harvest,
β”‚ stats, path. Uses notify() for output.
β”œβ”€β”€ bench.mjs ← Standalone Node.js benchmark (zero deps).
β”‚ Compares token cost: read file vs query memoir.
β”‚ Usage: node bench.mjs . --all
β”œβ”€β”€ package.json ← Extension metadata for pi auto-discovery
└── README.md ← This file
```

**Zero external dependencies. Pure TypeScript.** Only runtime dep is `typebox` (bundled with pi).

## Real-world benchmarks

Tested against 5 repos with v0.2.0 improvements:

| Repository | Files | Memories | Read Cost | Memoir Cost | Savings |
| ------------------------------------------------------------------------- | ----- | -------- | --------- | ----------- | ------- |
| [microsoft/VibeVoice](https://github.com/microsoft/VibeVoice) | 7 | 17 | ~17K tok | ~6.8K tok | **60%** |
| [rtk-ai/rtk](https://github.com/rtk-ai/rtk) | 272 | 507 | ~730K tok | ~203K tok | **72%** |
| [thedotmack/claude-mem](https://github.com/thedotmack/claude-mem) | 692 | 508 | ~2.5M tok | ~203K tok | **92%** |
| [Yeachan-Heo/oh-my-codex](https://github.com/Yeachan-Heo/oh-my-codex) | 1,025 | 509 | ~935K tok | ~204K tok | **78%** |
| [NousResearch/hermes-agent](https://github.com/NousResearch/hermes-agent) | 2,957 | 515 | ~3.0M tok | ~206K tok | **93%** |

**Key takeaways:**

- v0.2.0 improvements (compression, lazy loading, semantic tags) achieve **60-93% token savings**
- Larger repos (1K+ files) see higher savings due to capped memory count (~500) vs massive file count
- claude-mem (692 files, 92% savings) and hermes-agent (2,957 files, 93% savings) show best results
- Smaller repos like VibeVoice (7 files) have lower relative savings due to fixed overhead

## File reference

| File | Lines | Role |
| -------------- | ----- | ----------------------------------------- |
| `index.ts` | 69 | Entry + system prompt injection |
| `storage.ts` | 226 | MemoryStore, JSONL CRUD, keyword search |
| `harvester.ts` | 730 | Project scanner β€” walks every file |
| `tools.ts` | 190 | LLM tools (harvest, search, store) |
| `hooks.ts` | 126 | Lifecycle hooks (widgets, session events) |
| `commands.ts` | 245 | User commands (/memo) |
| `bench.mjs` | 285 | Standalone token cost benchmark |
| `package.json` | 11 | Extension metadata |

**7 source files, 1,597 total lines, 0 npm dependencies.**

## Roadmap

### Completed Features

- [x] Project harvester β€” scans every source file (128 extensions)
- [x] System prompt injection β€” LLM uses memoir before bash
- [x] Keyword search with TF scoring
- [x] Per-project persistence (`.pi/memoir/`)
- [x] LLM tools: harvest, search, store
- [x] Auto-capture on session shutdown
- [x] `--all/-a` delete flag with confirmation
- [x] Standalone benchmark script
- [x] Auto-harvest on first session start

### Token Saving Improvements (v0.2.0)

- [x] **Query-Result Compression** β€” default limit=5 results, summary-only previews
- [x] **Staleness-Based Filtering** β€” lastModified timestamps, expireDays filter, pruneExpired()
- [x] **Lazy Harvesting** β€” isMetadataOnly flag, originalFilePath, fetchContent() on-demand
- [x] **Deduplicated Knowledge** β€” seenPaths Set prevents duplicate file entries
- [x] **Hybrid Retrieval Preference** β€” system prompt hint: "Prefer 80% relevant in 100 tokens"
- [x] **Chunked Large Files** β€” splitIntoChunks() at 4KB, index each chunk separately
- [x] **Semantic Tags Auto-Generation** β€” auto-tags: api:http, db:sql, config:env, lang:typescript

**Benchmark: 85% token savings** (vs ~75% baseline)

### Future

- [ ] Semantic search via LLM re-ranking
- [ ] Knowledge graph from cross-file relationships
- [ ] Obsidian vault export

## License

MIT