{"_id":"@brianmichel/pi-noodle","name":"@brianmichel/pi-noodle","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@brianmichel/pi-noodle","version":"0.1.0","description":"Long-term memory for Pi — local libSQL database with vector search.","type":"module","keywords":["pi","pi.dev","pi-package","pi-extension","pi-plugin","ai-agent","agent-memory","memory","libsql","turso","vector-search"],"license":"MIT","repository":{"type":"git","url":"git+https://github.com/brianmichel/pi-noodle.git"},"homepage":"https://github.com/brianmichel/pi-noodle#readme","bugs":{"url":"https://github.com/brianmichel/pi-noodle/issues"},"publishConfig":{"access":"public"},"engines":{"node":">=22"},"scripts":{"build":"npm run check","check":"tsc -p tsconfig.json --noEmit","clean":"echo 'nothing to clean'","test":"node --test --experimental-strip-types test/**/*.test.ts","web:dev":"bun run src/web/dev.ts"},"exports":{".":"./index.ts"},"pi":{"extensions":["./src/index.ts"]},"dependencies":{"@libsql/client":"^0.15.0"},"peerDependencies":{"@earendil-works/pi-ai":"*","@earendil-works/pi-coding-agent":"*"},"devDependencies":{"@earendil-works/pi-ai":"*","@earendil-works/pi-coding-agent":"*","@earendil-works/pi-tui":"^0.75.5","@types/bun":"^1.2.0","@types/node":"^24.10.1","typescript":"^5.9.3"},"_id":"@brianmichel/pi-noodle@0.1.0","gitHead":"574283383596b56d08b8dafe338b383d5b485ad1","_nodeVersion":"22.22.3","_npmVersion":"10.9.8","dist":{"integrity":"sha512-tJi8fKJ31GmeUiruRYh5sjz3MR4lHjAR76w/9b1Rd9tY9YWmeX2qYDRaOCdvWMfQOAjRncLIwXWULxxGaHp2qw==","shasum":"93894c150d98e1282cb339f471c6b1e73cb986bd","tarball":"https://registry.npmjs.org/@brianmichel/pi-noodle/-/pi-noodle-0.1.0.tgz","fileCount":43,"unpackedSize":256775,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIBo8bjnrGgIOS2GY9YOgaLtzjniR3KSZOXt3uo6c8xPtAiEAvBiKVcGhE9UX8O7Y+lm3KvcU9Mhdlw9Gmqt/qu5ddv4="}]},"_npmUser":{"name":"brianmichel","email":"brian.michel@gmail.com"},"directories":{},"maintainers":[{"name":"brianmichel","email":"brian.michel@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/pi-noodle_0.1.0_1780415466287_0.8508629039504778"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-02T15:51:06.117Z","0.1.0":"2026-06-02T15:51:06.433Z","modified":"2026-06-02T15:51:06.657Z"},"maintainers":[{"name":"brianmichel","email":"brian.michel@gmail.com"}],"description":"Long-term memory for Pi — local libSQL database with vector search.","homepage":"https://github.com/brianmichel/pi-noodle#readme","keywords":["pi","pi.dev","pi-package","pi-extension","pi-plugin","ai-agent","agent-memory","memory","libsql","turso","vector-search"],"repository":{"type":"git","url":"git+https://github.com/brianmichel/pi-noodle.git"},"bugs":{"url":"https://github.com/brianmichel/pi-noodle/issues"},"license":"MIT","readme":"# pi-noodle\n\nLong-term memory for Pi.\n\nThis repo is building a small, opinionated memory system that tries to be:\n\n- **useful** — retrieve facts that actually help future turns\n- **safe** — avoid saving temporary or sensitive content\n- **automatic** — capture durable signals from normal conversation\n- **inspectable** — review what was saved, pending, or discarded\n\nUnder the hood it uses [libSQL](https://turso.tech/libsql) for storage and vector similarity search for retrieval.\n\n![](img/dashboard.jpeg)\n\n## Quick start\n\n```bash\n# Install as a Pi extension\npi install @brianmichel/pi-noodle\n\n# In Pi, configure interactively\n/noodle settings\n```\n\nThe setup screen shows the full config on one page:\n1. Database mode — local file or Turso Cloud\n2. Embedding provider — OpenAI, LM Studio, Ollama, or custom\n3. Relevant fields update in place as you switch modes/providers\n4. Required fields are validated before save\n\nSettings are saved to `~/.pi/noodle/config.json` — memories travel with you across all projects.\n\n## `/noodle` command\n\n```\n/noodle                  Show current config (paths, endpoint, masked API key)\n/noodle remember <text>  Save a memory directly\n/noodle forget <query>   Find and delete a memory\n/noodle edit <query>     Find and update a memory\n/noodle review           Review recent auto-saved memories\n/noodle settings         Interactive single-screen configuration editor with validation\n/noodle setup            Alias for /noodle settings\n/noodle init             Create a default config file for manual editing\n/noodle web              Start the Memory Explorer (auto-stops when all tabs close)\n/noodle web stop         Stop the explorer immediately\n/noodle web dev          Dev mode — hot reload on save, use web stop when done\n/noodle web 8080         Start on a custom port\n```\n\nFor UI development outside Pi, run `npm run web:dev` from the repo — it connects to your configured database and reloads the browser whenever you edit `src/web/index.html`.\n\n### Memory Explorer Web UI\n\nLaunch a dark-themed web interface to browse, search, and visualize your memories:\n\n- **Live stats** — total memories, categories, scopes\n- **Category filter** — dropdown of all stored categories\n- **Text search** — substring matching on memory text\n- **Dark mode** — GitHub-inspired color scheme\n\nRun `/noodle web` in Pi to open the explorer in your browser. The server runs in a background process and **shuts down automatically ~2 seconds after you close all tabs**. Use `/noodle web stop` to kill it manually.\n\n## Config file\n\n`~/.pi/noodle/config.json`:\n\n```json\n{\n  \"db\": {\n    \"mode\": \"local\",\n    \"path\": \"/Users/you/.pi/noodle/memories.db\"\n  },\n  \"embedding\": {\n    \"provider\": \"openai\",\n    \"apiKey\": \"sk-...\",\n    \"baseUrl\": \"https://api.openai.com/v1\",\n    \"model\": \"text-embedding-3-small\"\n  }\n}\n```\n\n### Cloud mode (Turso)\n\n```json\n{\n  \"db\": {\n    \"mode\": \"cloud\",\n    \"url\": \"libsql://my-db-org.turso.io\",\n    \"authToken\": \"eyJ...\"\n  },\n  \"embedding\": {\n    \"provider\": \"openai\",\n    \"apiKey\": \"sk-...\",\n    \"baseUrl\": \"https://api.openai.com/v1\",\n    \"model\": \"text-embedding-3-small\"\n  },\n  \"extractor\": {\n    \"mode\": \"balanced\",\n    \"model\": \"deepseek/deepseek-v4-flash:free\",\n    \"triggerEvery\": 10\n  }\n}\n```\n\n### Memory modes\n\nWhen memory mode is not `off`, capture uses a **unified capture pipeline** with policy-gated persistence:\n\n- `conservative`\n  - fewer extraction runs\n  - higher bar for auto-save\n  - softer inferences are usually discarded until reinforced\n- `balanced` (recommended default)\n  - durable facts can auto-save\n  - medium-confidence preferences go to `/noodle review`\n- `proactive`\n  - more frequent extraction\n  - more candidate discovery\n  - pending review queue grows faster, but saved-memory safety rules stay the same\n\nThe extractor model is configurable too, so you can tune quality/speed/cost separately from behavior mode.\n\n## Environment variable overrides\n\nEnv vars take priority over the config file:\n\n| Variable | Overrides |\n|---|---|\n| `NOODLE_CONFIG_PATH` | Config file location |\n| `NOODLE_DB_PATH` | Local DB path |\n| `NOODLE_DB_URL` | Cloud DB URL |\n| `NOODLE_DB_TOKEN` | Cloud DB auth token |\n| `OPENAI_API_KEY` | Embedding API key |\n| `EMBEDDING_BASE_URL` | Embedding endpoint URL |\n| `EMBEDDING_MODEL` | Embedding model name |\n| `NOODLE_EXTRACTOR_MODE` | Memory mode: off / conservative / balanced / proactive |\n| `NOODLE_EXTRACTOR_MODEL` | Extractor model ID |\n| `NOODLE_EXTRACTOR_TRIGGER_EVERY` | Automatic extraction cadence in user turns |\n| `NOODLE_EXTRACTOR_DEBUG` | Show the extractor debug widget: true / false |\n\n## Architecture\n\n```text\nPi lifecycle events\n  └─► MemoryService.capture(event)\n        ├─► heuristic capture\n        ├─► optional LLM extraction\n        ├─► candidate promotion policy\n        └─► conversation capture / consolidation when needed\n                    │\n                    ▼\n              MemoryBackend\n                    │\n               TursoBackend\n               ├─► libSQL (local or cloud)\n               └─► Embedder\n```\n\n### Capture pipeline\n\n```text\ninput / compact / switch / shutdown\n  │\n  └─► MemoryService.capture(event)\n        │\n        ├─► heuristic prefilter\n        │      ├─ blocks sensitive / temporary content\n        │      └─ catches explicit memory asks\n        │\n        ├─► optional LLM extraction\n        │      └─ turns conversation context into memory candidates\n        │\n        ├─► local promotion policy\n        │      ├─ save     → durable memory DB\n        │      ├─ pending  → /noodle review only\n        │      └─ discard  → dropped\n        │\n        └─► retrieval injects only saved memories\n```\n\n### Why it is shaped this way\n\n- Pi only tells the memory system **what event happened**\n- `MemoryService` decides **which capture stages should run**\n- heuristic and LLM candidates share the **same promotion path**\n- pending memories stay out of retrieval until reviewed or reinforced\n\n### What gets stored\n\nEvery memory is a row in SQLite with `text`, `embedding` (F32_BLOB), `category`, `categories`, `scope` (userId/assistantId/sessionId), and arbitrary `metadata`.\n\n### Search\n\nVector similarity via `vector_distance_cos()` in libSQL, ranked by cosine distance, post-filtered by category and threshold.\n\n### Policy and review\n\nThe system intentionally separates:\n\n- **detection** — heuristics and LLM extraction find memory candidates\n- **promotion** — local policy decides save / pending / discard\n- **retrieval** — only saved memories are injected into prompts\n\nThat keeps the system proactive without letting low-confidence guesses pollute retrieval. Pending candidates stay visible in `/noodle review` but are **not** injected until promoted.\n\n## File layout\n\n```\nsrc/\n├── config.ts              # Config resolution (~/.pi/noodle/config.json + env vars)\n├── config-screen.ts       # Flat single-screen config editor for /noodle settings\n├── constants.ts           # DEFAULT_AGENT_ID\n├── types.ts               # NoodleConfig, JsonObject, NotificationTarget, etc.\n├── utils.ts               # maskSecret, describeError, formatJson, extractTextContent\n├── commands.ts            # /noodle command + interactive setup entrypoint\n├── extension.ts           # Pi extension lifecycle hooks\n├── tools.ts               # memory_add / search / list / get / update / delete\n├── session.ts             # Session message collection\n├── queue.ts               # Sequential async write queue\n├── notifications.ts       # UI notification helpers\n└── memory/\n    ├── backend.ts         # MemoryBackend interface\n    ├── types.ts           # MemoryRecord, MemoryScope, etc.\n    ├── turso-backend.ts   # TursoBackend (libSQL + vector search)\n    ├── embedder.ts        # Embedder type\n    ├── embedders/         # openai.ts, lm-studio.ts\n    ├── service.ts         # MemoryService (event-driven capture pipeline + promotion)\n    ├── policy.ts          # Heuristics (classification, repetition, retrieval)\n    └── runtime.ts         # Wiring (config + TursoBackend + MemoryService)\n```\n","readmeFilename":"README.md","_rev":"1-88a43cc6e649063857852804aa8a9ba6"}