{"id":"3a94f24e-9d32-4f45-a794-d01fd8deb570","entityType":"agent","slug":"clawhub-gianni-dalerta-memory-tools","name":"Memory Tools","canonicalUrl":"https://www.xpersona.co/agent/clawhub-gianni-dalerta-memory-tools","canonicalPath":"/agent/clawhub-gianni-dalerta-memory-tools","generatedAt":"2026-10-09T11:56:21.233Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T07:47:19.347Z","emptyReason":null},"description":"Agent-controlled memory plugin for OpenClaw with confidence scoring, decay, and semantic search. The agent decides WHEN to store/retrieve memories — no auto-...","descriptionLabel":"Source description","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 3.5K downloads reported by the source. Last updated 10/9/2026.","installCommand":"clawhub skill install s17cc17ezh3q3w2b25qwem3dxh884zt1:memory-tools","sourceUrl":"https://clawhub.ai/gianni-dalerta/memory-tools","homepage":"https://clawhub.ai/gianni-dalerta/skills/memory-tools","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/gianni-dalerta/memory-tools","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/gianni-dalerta/skills/memory-tools","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":71,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"Memory Tools technical dossier on Xpersona with agent coverage, OPENCLEW support, and live trust metadata."},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-09T07:47:19.347Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T07:47:19.347Z","emptyReason":null},"stars":null,"forks":null,"downloads":3512,"packageName":null,"latestVersion":"2.0.4","tractionLabel":"3.5K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T07:47:19.347Z","emptyReason":null},"lastUpdatedAt":"2026-10-09T07:47:19.347Z","lastCrawledAt":"2026-10-09T07:47:19.347Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-10T07:47:19.347Z","lastVerifiedAt":null,"highlights":[{"version":"2.0.4","createdAt":"2026-02-18T19:20:20.054Z","changelog":"Security hardening: changed high-impact behaviors to opt-in defaults (autoInjectInstructions=false, autoMigrateLegacy=false), removed startup systemPrompt override path, and kept explicit config-based enablement for instruction context injection and legacy migration.","fileCount":26,"zipByteSize":48214},{"version":"2.0.3","createdAt":"2026-02-18T18:53:15.745Z","changelog":"Fixes lockfile/package mismatch causing npm ci failures. Adds robust QMD runtime compatibility handling (including Node ABI/better-sqlite3 mismatch detection) with automatic fallback to basic mode instead of startup crashes. Documents Node/QMD compatibility guidance and fallback env flag.","fileCount":26,"zipByteSize":48947},{"version":"2.0.2","createdAt":"2026-02-18T17:25:07.858Z","changelog":"Security hardening: cleaned release artifacts to remove legacy v1 OpenAI/LanceDB files, added prepublish release verification, removed stale embedding/apiKey type surface, added explicit autoMigrateLegacy control, and hardened QMD execution plus local fallback search when QMD is unavailable.","fileCount":26,"zipByteSize":48213},{"version":"2.0.1","createdAt":"2026-02-18T04:16:31.533Z","changelog":"Remove OpenAI dependency, fix security scan issues","fileCount":26,"zipByteSize":154702},{"version":"2.0.0","createdAt":"2026-02-18T03:16:13.133Z","changelog":"v2: File-based storage with QMD search, auto-migration from v1","fileCount":27,"zipByteSize":154838},{"version":"1.1.3","createdAt":"2026-02-14T23:40:33.592Z","changelog":"Fix: include built dist/ in published package; add prepublishOnly script","fileCount":34,"zipByteSize":164233},{"version":"1.1.2","createdAt":"2026-02-14T16:37:23.809Z","changelog":"Fix database initialization race conditions that caused 'Database not initialized' errors on startup","fileCount":20,"zipByteSize":144382},{"version":"1.1.1","createdAt":"2026-02-09T18:37:48.370Z","changelog":"fix: close LanceDB connection and reset state on service stop (fixes SIGUSR1 restart issue)","fileCount":20,"zipByteSize":144286}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s17cc17ezh3q3w2b25qwem3dxh884zt1:memory-tools","setupComplexity":"low","setupSteps":["Install using `clawhub skill install s17cc17ezh3q3w2b25qwem3dxh884zt1:memory-tools` in an isolated environment before connecting it to live workloads.","No published capability contract is available yet, so validate auth and request/response behavior manually.","Review the upstream CLAWHUB listing at https://clawhub.ai/gianni-dalerta/memory-tools before using production credentials."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-gianni-dalerta-memory-tools/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-gianni-dalerta-memory-tools/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-gianni-dalerta-memory-tools/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-gianni-dalerta-memory-tools/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-gianni-dalerta-memory-tools/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-gianni-dalerta-memory-tools/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-09T11:56:21.228Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-gianni-dalerta-memory-tools/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-gianni-dalerta-memory-tools/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-gianni-dalerta-memory-tools/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-gianni-dalerta-memory-tools/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T07:47:19.347Z","emptyReason":null},"readme":"Skill: Memory Tools\n\nOwner: gianni-dalerta\n\nSummary: Agent-controlled memory plugin for OpenClaw with confidence scoring, decay, and semantic search. The agent decides WHEN to store/retrieve memories — no auto-...\n\nTags: latest:2.0.4\n\nVersion history:\n\nv2.0.4 | 2026-02-18T19:20:20.054Z | user\n\nSecurity hardening: changed high-impact behaviors to opt-in defaults (autoInjectInstructions=false, autoMigrateLegacy=false), removed startup systemPrompt override path, and kept explicit config-based enablement for instruction context injection and legacy migration.\n\nv2.0.3 | 2026-02-18T18:53:15.745Z | user\n\nFixes lockfile/package mismatch causing npm ci failures. Adds robust QMD runtime compatibility handling (including Node ABI/better-sqlite3 mismatch detection) with automatic fallback to basic mode instead of startup crashes. Documents Node/QMD compatibility guidance and fallback env flag.\n\nv2.0.2 | 2026-02-18T17:25:07.858Z | user\n\nSecurity hardening: cleaned release artifacts to remove legacy v1 OpenAI/LanceDB files, added prepublish release verification, removed stale embedding/apiKey type surface, added explicit autoMigrateLegacy control, and hardened QMD execution plus local fallback search when QMD is unavailable.\n\nv2.0.1 | 2026-02-18T04:16:31.533Z | user\n\nRemove OpenAI dependency, fix security scan issues\n\nv2.0.0 | 2026-02-18T03:16:13.133Z | user\n\nv2: File-based storage with QMD search, auto-migration from v1\n\nv1.1.3 | 2026-02-14T23:40:33.592Z | user\n\nFix: include built dist/ in published package; add prepublishOnly script\n\nv1.1.2 | 2026-02-14T16:37:23.809Z | user\n\nFix database initialization race conditions that caused 'Database not initialized' errors on startup\n\nv1.1.1 | 2026-02-09T18:37:48.370Z | user\n\nfix: close\n  LanceDB connection and reset state on service stop (fixes SIGUSR1 restart\n  issue)\n\nv1.1.0 | 2026-02-08T20:02:28.606Z | user\n\nSwitch from better-sqlite3 to sql.js (WASM) - eliminates NODE_MODULE_VERSION errors across different Node.js versions\n\nv1.0.5 | 2026-02-07T22:37:32.256Z | user\n\nAdd explicit Docker gateway start command\n\nv1.0.4 | 2026-02-07T22:35:51.619Z | user\n\nImproved install docs with Docker instructions and troubleshooting\n\nv1.0.3 | 2026-02-07T22:16:14.044Z | user\n\nFix: auto-create database directory on first run\n\nv1.0.2 | 2026-02-07T22:13:45.798Z | user\n\nFix: make embedding config optional (auto-uses OPENAI_API_KEY env var)\n\nv1.0.1 | 2026-02-07T22:06:36.041Z | user\n\nImproved installation docs with proper plugin activation steps\n\nv1.0.0 | 2026-02-07T21:51:39.743Z | user\n\nInitial release - agent-controlled memory with confidence scoring\n\nArchive index:\n\nArchive v2.0.4: 26 files, 48214 bytes\n\nFiles: CLAUDE.md (2126b), clawdbot.plugin.json (1426b), openclaw.plugin.json (1426b), package-lock.json (32215b), package.json (1410b), README.md (13521b), scripts/verify-release.mjs (1199b), SKILL.md (5972b), src/config.ts (2053b), src/file-manager.ts (12565b), src/index.ts (12213b), src/migration.ts (11904b), src/plugin-types.ts (1447b), src/qmd.ts (11184b), src/store.test.ts (10457b), src/store.ts (8459b), src/tools.test.ts (7005b), src/tools.ts (21256b), src/types.ts (2386b), test/docker/docker-compose.yml (298b), test/docker/run-tests.sh (423b), test/docker/seed-v1-data.js (4109b), test/docker/test-migration.sh (4817b), tsconfig.json (540b), vitest.config.ts (404b), _meta.json (131b)\n\nFile v2.0.4:SKILL.md\n\n---\nname: memory-tools\ndescription: Agent-controlled memory plugin for OpenClaw with confidence scoring, decay, and semantic search. The agent decides WHEN to store/retrieve memories — no auto-capture noise. v2 uses file-based storage with optional QMD search (no external APIs required).\nhomepage: https://github.com/Purple-Horizons/memory-tools\nmetadata:\n  openclaw:\n    emoji: 🧠\n    kind: plugin\n---\n\n# Memory Tools v2\n\nAgent-controlled persistent memory for OpenClaw.\n\n## What's New in v2\n\n- **File-based storage** — Memories stored as readable markdown files\n- **No external APIs** — No OpenAI dependency, everything runs locally\n- **QMD search (optional)** — BM25 + vector + reranking via local GGUF models\n- **Auto-migration** — Seamlessly upgrades from v1 SQLite/LanceDB storage\n\n## Why Memory-as-Tools?\n\nTraditional memory systems auto-capture everything, flooding context with irrelevant information. Memory Tools follows the [AgeMem](https://arxiv.org/abs/2409.02634) approach: **the agent decides** when to store and retrieve memories.\n\n## Features\n\n- **6 Memory Tools**: `memory_store`, `memory_update`, `memory_forget`, `memory_search`, `memory_summarize`, `memory_list`\n- **Confidence Scoring**: Track how certain you are (1.0 = explicit, 0.5 = inferred)\n- **Importance Scoring**: Prioritize critical instructions over nice-to-know facts\n- **Decay/Expiration**: Temporal memories automatically become stale\n- **Human-readable storage**: Markdown files with YAML frontmatter\n- **Conflict Resolution**: New info auto-supersedes old (no contradictions)\n\n## Installation\n\n### Step 1: Install from ClawHub\n\n```bash\nclawhub install memory-tools\n```\n\n### Step 2: Build the plugin\n\n```bash\ncd skills/memory-tools\nnpm install\nnpm run build\n```\n\n### Step 3: Activate the plugin\n\n```bash\nopenclaw plugins install --link .\nopenclaw plugins enable memory-tools\n```\n\n### Step 4: Restart the gateway\n\n```bash\nopenclaw gateway restart\n```\n\n### Optional: Install QMD for better search\n\n```bash\nnpm install -g @tobilu/qmd\n```\n\nWithout QMD, basic filtering works. With QMD, you get semantic search (BM25 + vector + reranking).\n\n### Node Compatibility (QMD)\n\n- QMD may not be compatible with the newest Node ABI immediately.\n- If QMD fails (for example `NODE_MODULE_VERSION` mismatch), memory-tools falls back to basic mode.\n- To force basic mode: `MEMORY_TOOLS_DISABLE_QMD=true`.\n- For best QMD stability, use a Node LTS version supported by your installed QMD build.\n\n## Security Model\n\n- No API keys or external credentials are required.\n- Data is stored locally in `~/.openclaw/memories` (or configured `memoriesPath`).\n- The plugin can prepend standing-instruction context at `before_agent_start` when `autoInjectInstructions=true`.\n- The plugin can auto-migrate legacy v1 data from `~/.openclaw/memory/tools/memory.db` when `autoMigrateLegacy=true`.\n- Defaults are conservative: both `autoInjectInstructions` and `autoMigrateLegacy` are `false`.\n\n## Storage Format\n\nMemories are stored as markdown files in `~/.openclaw/memories/`:\n\n```\n~/.openclaw/memories/\n├── facts/\n│   └── abc123-def4-5678-90ab-cdef12345678.md\n├── preferences/\n│   └── def456-7890-abcd-ef12-345678901234.md\n├── instructions/\n│   └── ghi789-0abc-def1-2345-678901234567.md\n└── .deleted/\n    └── old-memory.md\n```\n\nEach memory file:\n\n```markdown\n---\nid: abc123-def4-5678-90ab-cdef12345678\ncategory: preference\nconfidence: 0.9\nimportance: 0.7\ncreated_at: 2024-01-15T10:30:00Z\ntags: [ui, settings]\n---\n\nUser prefers dark mode in all applications.\n```\n\n## Memory Categories\n\n| Category | Use For | Example |\n|----------|---------|---------|\n| fact | Static information | \"User's dog is named Rex\" |\n| preference | Likes/dislikes | \"User prefers dark mode\" |\n| event | Temporal things | \"Dentist Tuesday 3pm\" |\n| relationship | People connections | \"Sarah is user's wife\" |\n| instruction | Standing orders | \"Always respond in Spanish\" |\n| decision | Choices made | \"We decided to use PostgreSQL\" |\n| context | Situational info | \"User is job hunting\" |\n| entity | Named things | \"Project Apollo is their startup\" |\n\n## Tool Reference\n\n### memory_store\n```\nmemory_store({\n  content: \"User prefers bullet points\",\n  category: \"preference\",\n  confidence: 0.9,\n  importance: 0.7,\n  tags: [\"formatting\", \"communication\"]\n})\n```\n\n### memory_search\n```\nmemory_search({\n  query: \"formatting preferences\",\n  category: \"preference\",\n  limit: 10\n})\n```\n\n### memory_update\n```\nmemory_update({\n  id: \"abc123\",\n  content: \"User now prefers numbered lists\",\n  confidence: 1.0\n})\n```\n\n### memory_forget\n```\nmemory_forget({\n  query: \"bullet points\",\n  reason: \"User corrected preference\"\n})\n```\n\n### memory_summarize\n```\nmemory_summarize({\n  topic: \"user's work projects\",\n  maxMemories: 20\n})\n```\n\n### memory_list\n```\nmemory_list({\n  category: \"instruction\",\n  sortBy: \"importance\",\n  limit: 20\n})\n```\n\n## CLI Commands\n\n```bash\n# Show memory statistics\nopenclaw memory-tools stats\n\n# List memories\nopenclaw memory-tools list\nopenclaw memory-tools list --category fact\n\n# Search memories (requires QMD)\nopenclaw memory-tools search \"dark mode\"\n\n# Export all memories as JSON\nopenclaw memory-tools export\n\n# Force re-index with QMD\nopenclaw memory-tools reindex\n\n# Show storage path\nopenclaw memory-tools path\n```\n\n## Debugging\n\nMemories are plain markdown files — just read them:\n\n```bash\ncat ~/.openclaw/memories/facts/*.md\nls ~/.openclaw/memories/\n```\n\nExport all memories:\n\n```bash\nopenclaw memory-tools export > memories.json\n```\n\n## Migration from v1\n\nv2 automatically detects v1 databases and migrates them:\n\n1. On startup, v2 checks for `~/.openclaw/memory/tools/memory.db`\n2. If found, exports all memories to markdown files\n3. Original database preserved as backup\n4. No manual action required\n\nTo enable auto-migration, set `autoMigrateLegacy: true` in plugin config.\n\n## License\n\nMIT — [Purple Horizons](https://github.com/Purple-Horizons)\n\nFile v2.0.4:README.md\n\n<p align=\"center\">\n  <img src=\"header.png\" alt=\"memory-tools\" width=\"100%\">\n</p>\n\n# OpenClaw Memory Tools v2\n\nAgent-controlled memory plugin for OpenClaw with confidence scoring, decay, and semantic search.\n\n## What's New in v2\n\n- **File-based storage** - Memories stored as readable markdown files\n- **No external APIs** - No OpenAI dependency, everything runs locally\n- **QMD search (optional)** - BM25 + vector + reranking via local GGUF models\n- **Auto-migration** - Seamlessly upgrades from v1 SQLite/LanceDB storage\n\n## Why Memory-as-Tools?\n\nTraditional AI memory systems auto-capture everything, flooding context with irrelevant information. **Memory-as-Tools** follows the [AgeMem](https://arxiv.org/abs/2409.02634) approach: the agent decides **when** to store and retrieve memories.\n\n```\nTraditional: Agent -> always retrieves -> context flooded\nMemory-as-Tools: Agent -> decides IF/WHAT to remember -> uses tools explicitly\n```\n\n## Features\n\n- **6 Memory Tools**: `memory_store`, `memory_update`, `memory_forget`, `memory_search`, `memory_summarize`, `memory_list`\n- **Confidence Scoring**: Track how certain you are about each memory (1.0 = explicit, 0.5 = inferred)\n- **Importance Scoring**: Prioritize critical instructions over nice-to-know facts\n- **Decay/Expiration**: Temporal memories (events) automatically become stale\n- **Human-readable storage**: Markdown files with YAML frontmatter\n- **Semantic Search**: Optional QMD-powered hybrid search (BM25 + vector + reranking)\n- **Zero External Dependencies**: Everything runs locally, no API keys needed\n- **Standing Instructions**: Auto-inject category=\"instruction\" memories at conversation start\n\n## Installation\n\n### Step 1: Install from ClawHub\n\n```bash\nclawhub install memory-tools\n```\n\n### Step 2: Build the plugin\n\n```bash\ncd skills/memory-tools\nnpm install\nnpm run build\n```\n\n### Step 3: Activate the plugin\n\n```bash\nopenclaw plugins install --link .\nopenclaw plugins enable memory-tools\n```\n\n### Step 4: Restart the gateway\n\n```bash\nopenclaw gateway restart\n```\n\n### Optional: Install QMD for better search\n\n```bash\nnpm install -g @tobilu/qmd\n```\n\nWithout QMD, basic category/tag filtering works. With QMD, you get semantic search (BM25 + vector + reranking using local GGUF models).\n\n### Node Compatibility (QMD)\n\n- `memory-tools` works without QMD on modern Node versions.\n- QMD dependencies (notably `better-sqlite3`) may lag behind the latest Node ABI.\n- If QMD fails on startup (for example `NODE_MODULE_VERSION` mismatch on Node v25), the plugin now falls back to basic mode.\n- To force basic mode explicitly, set `MEMORY_TOOLS_DISABLE_QMD=true`.\n- Recommended for full QMD stability: use a Node LTS version supported by your installed QMD build.\n\n## Configuration\n\nAdd to `~/.openclaw/openclaw.json`:\n\n```json\n{\n  \"plugins\": {\n    \"slots\": {\n      \"memory\": \"memory-tools\"\n    },\n    \"entries\": {\n      \"memory-tools\": {\n        \"enabled\": true,\n        \"config\": {\n          \"memoriesPath\": \"~/.openclaw/memories\",\n          \"autoInjectInstructions\": false,\n          \"autoMigrateLegacy\": false\n        }\n      }\n    }\n  },\n  \"tools\": {\n    \"alsoAllow\": [\"group:plugins\"]\n  }\n}\n```\n\n### Security Model\n\n- No API keys or external credentials are required by this plugin.\n- Data is stored locally in `~/.openclaw/memories` (or your configured `memoriesPath`).\n- The plugin can prepend standing-instruction context at `before_agent_start` only when `autoInjectInstructions=true`.\n- The plugin can auto-migrate legacy v1 data from `~/.openclaw/memory/tools/memory.db` only when `autoMigrateLegacy=true`.\n- Defaults are conservative: both `autoInjectInstructions` and `autoMigrateLegacy` are `false`.\n\n### Verify Installation\n\n```bash\n# Restart gateway\nopenclaw gateway stop && openclaw gateway run\n\n# Check plugin loaded\nopenclaw plugins list\n\n# Test CLI\nopenclaw memory-tools stats\n```\n\n## Storage Format\n\nMemories are stored as markdown files in `~/.openclaw/memories/`:\n\n```\n~/.openclaw/memories/\n├── facts/\n│   └── abc123-def4-5678-90ab-cdef12345678.md\n├── preferences/\n│   └── def456-7890-abcd-ef12-345678901234.md\n├── instructions/\n│   └── ghi789-0abc-def1-2345-678901234567.md\n└── .deleted/\n    └── old-memory.md\n```\n\nEach memory file contains YAML frontmatter with metadata:\n\n```markdown\n---\nid: abc123-def4-5678-90ab-cdef12345678\ncategory: preference\nconfidence: 0.9\nimportance: 0.7\ncreated_at: 2024-01-15T10:30:00Z\ntags: [ui, settings]\n---\n\nUser prefers dark mode in all applications.\n```\n\n## Memory Categories\n\n| Category | Use For | Example |\n|----------|---------|---------|\n| `fact` | Static information | \"User's dog is named Rex\" |\n| `preference` | Likes/dislikes | \"User prefers dark mode\" |\n| `event` | Temporal things | \"Dentist appointment Tuesday 3pm\" |\n| `relationship` | People connections | \"User's sister is Sarah\" |\n| `context` | Current work | \"Working on React project\" |\n| `instruction` | Standing orders | \"Always respond in Spanish\" |\n| `decision` | Choices made | \"We decided to use PostgreSQL\" |\n| `entity` | Contact info | \"User's email is x@y.com\" |\n\n## Tool Reference\n\n### memory_store\n\nStore a new memory.\n\n```typescript\nmemory_store({\n  content: \"User prefers bullet points\",\n  category: \"preference\",\n  confidence: 0.9,      // How sure (0-1)\n  importance: 0.7,      // How critical (0-1)\n  decayDays: null,      // null = permanent\n  tags: [\"formatting\"]\n})\n```\n\n### memory_update\n\nUpdate an existing memory.\n\n```typescript\nmemory_update({\n  id: \"abc-123\",\n  content: \"User prefers numbered lists\",  // Optional\n  confidence: 0.95                          // Optional\n})\n```\n\n### memory_forget\n\nDelete a memory.\n\n```typescript\nmemory_forget({\n  id: \"abc-123\",           // If known\n  query: \"bullet points\",  // Or search\n  reason: \"User corrected\"\n})\n```\n\n### memory_search\n\nSemantic search (uses QMD if installed, otherwise basic filtering).\n\n```typescript\nmemory_search({\n  query: \"formatting preferences\",\n  category: \"preference\",      // Optional filter\n  minConfidence: 0.7,          // Optional filter\n  limit: 10\n})\n```\n\n### memory_summarize\n\nGet topic summary.\n\n```typescript\nmemory_summarize({\n  topic: \"user's work\",\n  maxMemories: 20\n})\n```\n\n### memory_list\n\nBrowse all memories.\n\n```typescript\nmemory_list({\n  category: \"instruction\",\n  sortBy: \"importance\",\n  limit: 20\n})\n```\n\n## CLI Commands\n\n```bash\n# Show statistics\nopenclaw memory-tools stats\n\n# List memories\nopenclaw memory-tools list --category preference\n\n# Search memories (uses QMD if installed)\nopenclaw memory-tools search \"dark mode\"\n\n# Export all memories as JSON\nopenclaw memory-tools export\n\n# Force re-index with QMD\nopenclaw memory-tools reindex\n\n# Show storage path\nopenclaw memory-tools path\n```\n\n## Debugging\n\nMemories are plain markdown files - just read them:\n\n```bash\ncat ~/.openclaw/memories/facts/*.md\nls ~/.openclaw/memories/\n```\n\nExport all memories:\n\n```bash\nopenclaw memory-tools export > memories.json\n```\n\n## Architecture\n\n```\n┌─────────────────────────────────────────────────────────┐\n│                    OpenClaw Agent                       │\n│                                                         │\n│  Agent decides: \"This is worth remembering\"             │\n│         ↓                                               │\n│  Calls: memory_store(...)                               │\n└─────────────────────────────────────────────────────────┘\n                          ↓\n┌─────────────────────────────────────────────────────────┐\n│                   Memory Tools                          │\n├─────────────────────────────────────────────────────────┤\n│  store │ update │ forget │ search │ summarize │ list   │\n└─────────────────────────────────────────────────────────┘\n                          ↓\n┌─────────────────────────────────────────────────────────┐\n│                 Storage Layer                           │\n│  ┌──────────────────────────────────────────────────┐  │\n│  │           Markdown Files (YAML frontmatter)       │  │\n│  │           ~/.openclaw/memories/{category}/*.md    │  │\n│  └──────────────────────────────────────────────────┘  │\n│                          ↓                              │\n│  ┌──────────────────────────────────────────────────┐  │\n│  │        QMD Search (optional)                      │  │\n│  │        BM25 + Vector + Reranking                  │  │\n│  └──────────────────────────────────────────────────┘  │\n└─────────────────────────────────────────────────────────┘\n```\n\n## Migration from v1\n\nv2 automatically detects v1 databases and migrates them:\n\n1. On startup, v2 checks for `~/.openclaw/memory/tools/memory.db`\n2. If found, exports all memories to markdown files\n3. Original database preserved as backup\n4. No manual action required\n\nTo enable auto-migration, set `\"autoMigrateLegacy\": true` in plugin config.\n\n## Development\n\n```bash\n# Install dependencies\nnpm install\n\n# Run tests\nnpm test\n\n# Run tests with coverage\nnpm test:coverage\n\n# Type check\nnpm run typecheck\n\n# Build\nnpm run build\n```\n\n### Environment Variables\n\n- `MEMORY_TOOLS_DISABLE_QMD=true` - Disable QMD for testing\n\nNo environment variables are required for credentials.\n\n## Comparison with Other Memory Systems\n\n| Feature | [memU](https://github.com/NevaMind-AI/memU) | [claude-mem](https://github.com/thedotmack/claude-mem) | **memory-tools** |\n|---------|------|------------|--------------|\n| **Architecture** | 3-tier hierarchical (Resource -> Item -> Category) | Hook-based observer with lifecycle events | Tool-based agent control |\n| **Storage Trigger** | Automatic extraction during background processing | Lifecycle hooks (SessionStart, PostToolUse, etc.) | Agent explicitly decides when to store |\n| **Storage Backend** | Custom hierarchical | Custom | Markdown files + optional QMD |\n| **External APIs** | Varies | Varies | None required |\n| **Conflict Handling** | None - relies on proactive pattern detection | None - auto-capture model | Auto-supersede + explicit forget |\n| **Context Injection** | Proactive - predicts and pre-loads context | Progressive disclosure (3-layer filtering) | On-demand via memory_search |\n| **Token Efficiency** | Compression via fact extraction | ~10x savings via progressive disclosure | Semantic search with configurable limits |\n| **Auditability** | Background processing | Hook-based capture | Human-readable markdown files |\n| **User Corrections** | Accumulates conflicting facts | Accumulates conflicting facts | Replaces old with new automatically |\n| **Best For** | 24/7 agents with predictable patterns | Automatic session continuity | Personal assistants with ongoing relationships |\n\n### Design Philosophy\n\nDifferent memory systems optimize for different things:\n\n- **Automatic systems** (memU, claude-mem) minimize agent cognitive load by extracting memories in the background. Trade-off: less control over what's captured, conflicts accumulate.\n\n- **Agent-controlled systems** (memory-tools) put the agent in charge of what matters. Trade-off: requires active management, but memories are deliberate choices.\n\nFor agents that maintain ongoing relationships with users - where someone might say \"no, my favorite color is purple, not blue\" - explicit conflict handling prevents contradictory memories from accumulating. Every memory has a clear provenance: the agent decided it was worth remembering, and corrections replace rather than compete with old information.\n\nThe file-based storage means you can always `ls ~/.openclaw/memories/` and read exactly what your agent knows. Each memory is a plain markdown file you can edit, delete, or backup.\n\n## References\n\n- [AgeMem Paper](https://arxiv.org/abs/2409.02634) - Memory operations as first-class tools\n- [QMD](https://github.com/tobilu/qmd) - Local hybrid search with GGUF models\n- [memU](https://github.com/NevaMind-AI/memU) - Hierarchical memory with proactive context\n- [claude-mem](https://github.com/thedotmack/claude-mem) - Hook-based automatic memory\n- [Mem0](https://github.com/mem0ai/mem0) - AI memory layer\n- [OpenClaw](https://github.com/openclaw/openclaw) - Personal AI assistant\n\n## License\n\nMIT - [Purple Horizons](https://github.com/Purple-Horizons)\n\nFile v2.0.4:_meta.json\n\n{\n  \"ownerId\": \"kn7ajybsnj998tbfcgvrc7731s803brp\",\n  \"slug\": \"memory-tools\",\n  \"version\": \"2.0.4\",\n  \"publishedAt\": 1771442420054\n}\n\nFile v2.0.4:CLAUDE.md\n\n# CLAUDE.md\n\nProject context for Claude Code.\n\n## Project\n\n**memory-tools v2** - Agent-controlled memory plugin for OpenClaw/ClawHub.\n\n- **Repo**: `Purple-Horizons/memory-tools`\n- **ClawHub slug**: `memory-tools`\n- **Owner**: gianni-dalerta\n\n## Architecture (v2)\n\n- **File-based storage** - Memories stored as markdown files with YAML frontmatter\n- **QMD search** - Optional BM25 + vector + reranking via local GGUF models\n- **No external APIs** - No OpenAI dependency, everything runs locally\n- **Auto-migration** - Seamlessly upgrades from v1 SQLite/LanceDB storage\n\n### Storage Structure\n```\n~/.openclaw/memories/\n├── facts/\n│   └── abc123.md\n├── preferences/\n│   └── def456.md\n├── instructions/\n│   └── ghi789.md\n└── .deleted/\n    └── old-memory.md\n```\n\n### Memory File Format\n```markdown\n---\nid: abc123-def4-5678-90ab-cdef12345678\ncategory: preference\nconfidence: 0.9\nimportance: 0.7\ncreated_at: 2024-01-15T10:30:00Z\ntags: [ui, settings]\n---\n\nUser prefers dark mode in all applications.\n```\n\n## Key Decisions\n\n- **v2 rewrote storage layer**: Switched from SQLite + LanceDB + OpenAI to file-based + QMD\n- **QMD is optional**: Works without QMD (basic file listing), better search with QMD installed\n- **Auto-migration**: v2 detects v1 databases and automatically exports to markdown files\n- **Backward compatible API**: Tools interface unchanged, existing integrations work\n\n## QMD Integration\n\nQMD provides hybrid search (BM25 + vector + reranking) using local GGUF models:\n- `npm install -g @tobilu/qmd` to install\n- Models download on first use (~2GB total)\n- Without QMD: basic category/tag filtering only\n- With QMD: semantic search across all memories\n\n## Publishing to ClawHub\n\n```bash\nclawhub publish . --slug memory-tools --version X.Y.Z --changelog \"description\"\n```\n\nAlways use `--slug memory-tools` to update the correct skill.\n\n## Build & Test\n\n```bash\nnpm run build    # TypeScript compile\nnpm test         # Run vitest (uses MEMORY_TOOLS_DISABLE_QMD=true in CI)\n```\n\n## Environment Variables\n\n- `MEMORY_TOOLS_DISABLE_QMD=true` - Disable QMD for testing\n\nFile v2.0.4:clawdbot.plugin.json\n\n{\n  \"id\": \"memory-tools\",\n  \"kind\": \"memory\",\n  \"name\": \"Memory Tools\",\n  \"description\": \"Agent-controlled memory with file-based storage and optional QMD search. No external APIs required.\",\n  \"version\": \"2.0.4\",\n  \"uiHints\": {\n    \"memoriesPath\": {\n      \"label\": \"Memories Path\",\n      \"placeholder\": \"~/.clawdbot/memories\",\n      \"advanced\": true,\n      \"help\": \"Directory for storing memory files\"\n    },\n    \"autoInjectInstructions\": {\n      \"label\": \"Auto-Inject Instructions\",\n      \"help\": \"Inject standing instructions (category='instruction') at conversation start\"\n    },\n    \"autoMigrateLegacy\": {\n      \"label\": \"Auto-Migrate Legacy DB\",\n      \"advanced\": true,\n      \"help\": \"Automatically migrate v1 database to markdown files on startup\"\n    },\n    \"qmdCollection\": {\n      \"label\": \"QMD Collection\",\n      \"advanced\": true,\n      \"help\": \"QMD collection name for semantic search index\"\n    }\n  },\n  \"configSchema\": {\n    \"type\": \"object\",\n    \"additionalProperties\": false,\n    \"properties\": {\n      \"memoriesPath\": {\n        \"type\": \"string\",\n        \"description\": \"Directory for storing memory markdown files\"\n      },\n      \"autoInjectInstructions\": {\n        \"type\": \"boolean\",\n        \"default\": false\n      },\n      \"autoMigrateLegacy\": {\n        \"type\": \"boolean\",\n        \"default\": false\n      },\n      \"qmdCollection\": {\n        \"type\": \"string\",\n        \"default\": \"memories\"\n      }\n    }\n  }\n}\n\nFile v2.0.4:openclaw.plugin.json\n\n{\n  \"id\": \"memory-tools\",\n  \"kind\": \"memory\",\n  \"name\": \"Memory Tools\",\n  \"description\": \"Agent-controlled memory with file-based storage and optional QMD search. No external APIs required.\",\n  \"version\": \"2.0.4\",\n  \"uiHints\": {\n    \"memoriesPath\": {\n      \"label\": \"Memories Path\",\n      \"placeholder\": \"~/.openclaw/memories\",\n      \"advanced\": true,\n      \"help\": \"Directory for storing memory files\"\n    },\n    \"autoInjectInstructions\": {\n      \"label\": \"Auto-Inject Instructions\",\n      \"help\": \"Inject standing instructions (category='instruction') at conversation start\"\n    },\n    \"autoMigrateLegacy\": {\n      \"label\": \"Auto-Migrate Legacy DB\",\n      \"advanced\": true,\n      \"help\": \"Automatically migrate v1 database to markdown files on startup\"\n    },\n    \"qmdCollection\": {\n      \"label\": \"QMD Collection\",\n      \"advanced\": true,\n      \"help\": \"QMD collection name for semantic search index\"\n    }\n  },\n  \"configSchema\": {\n    \"type\": \"object\",\n    \"additionalProperties\": false,\n    \"properties\": {\n      \"memoriesPath\": {\n        \"type\": \"string\",\n        \"description\": \"Directory for storing memory markdown files\"\n      },\n      \"autoInjectInstructions\": {\n        \"type\": \"boolean\",\n        \"default\": false\n      },\n      \"autoMigrateLegacy\": {\n        \"type\": \"boolean\",\n        \"default\": false\n      },\n      \"qmdCollection\": {\n        \"type\": \"string\",\n        \"default\": \"memories\"\n      }\n    }\n  }\n}\n\nFile v2.0.4:package-lock.json\n\n{\n  \"name\": \"memory-tools\",\n  \"version\": \"2.0.4\",\n  \"lockfileVersion\": 3,\n  \"requires\": true,\n  \"packages\": {\n    \"\": {\n      \"name\": \"memory-tools\",\n      \"version\": \"2.0.4\",\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"@sinclair/typebox\": \"0.34.48\",\n        \"sql.js\": \"^1.13.0\"\n      },\n      \"devDependencies\": {\n        \"@types/node\": \"^22.0.0\",\n        \"@types/sql.js\": \"^1.4.9\",\n        \"@vitest/coverage-v8\": \"^2.1.0\",\n        \"typescript\": \"^5.7.0\",\n        \"vitest\": \"^2.1.0\"\n      },\n      \"peerDependencies\": {\n        \"openclaw\": \">=2026.0.0\"\n      },\n      \"peerDependenciesMeta\": {\n        \"openclaw\": {\n          \"optional\": true\n        }\n      }\n    },\n    \"node_modules/@ampproject/remapping\": {\n      \"version\": \"2.3.0\",\n      \"dev\": true,\n      \"license\": \"Apache-2.0\",\n      \"dependencies\": {\n        \"@jridgewell/gen-mapping\": \"^0.3.5\",\n        \"@jridgewell/trace-mapping\": \"^0.3.24\"\n      },\n      \"engines\": {\n        \"node\": \">=6.0.0\"\n      }\n    },\n    \"node_modules/@babel/helper-string-parser\": {\n      \"version\": \"7.27.1\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">=6.9.0\"\n      }\n    },\n    \"node_modules/@babel/helper-validator-identifier\": {\n      \"version\": \"7.28.5\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">=6.9.0\"\n      }\n    },\n    \"node_modules/@babel/parser\": {\n      \"version\": \"7.29.0\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"@babel/types\": \"^7.29.0\"\n      },\n      \"bin\": {\n        \"parser\": \"bin/babel-parser.js\"\n      },\n      \"engines\": {\n        \"node\": \">=6.0.0\"\n      }\n    },\n    \"node_modules/@babel/types\": {\n      \"version\": \"7.29.0\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"@babel/helper-string-parser\": \"^7.27.1\",\n        \"@babel/helper-validator-identifier\": \"^7.28.5\"\n      },\n      \"engines\": {\n        \"node\": \">=6.9.0\"\n      }\n    },\n    \"node_modules/@bcoe/v8-coverage\": {\n      \"version\": \"0.2.3\",\n      \"dev\": true,\n      \"license\": \"MIT\"\n    },\n    \"node_modules/@esbuild/darwin-arm64\": {\n      \"version\": \"0.21.5\",\n      \"cpu\": [\n        \"arm64\"\n      ],\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"optional\": true,\n      \"os\": [\n        \"darwin\"\n      ],\n      \"engines\": {\n        \"node\": \">=12\"\n      }\n    },\n    \"node_modules/@isaacs/cliui\": {\n      \"version\": \"8.0.2\",\n      \"dev\": true,\n      \"license\": \"ISC\",\n      \"dependencies\": {\n        \"string-width\": \"^5.1.2\",\n        \"string-width-cjs\": \"npm:string-width@^4.2.0\",\n        \"strip-ansi\": \"^7.0.1\",\n        \"strip-ansi-cjs\": \"npm:strip-ansi@^6.0.1\",\n        \"wrap-ansi\": \"^8.1.0\",\n        \"wrap-ansi-cjs\": \"npm:wrap-ansi@^7.0.0\"\n      },\n      \"engines\": {\n        \"node\": \">=12\"\n      }\n    },\n    \"node_modules/@istanbuljs/schema\": {\n      \"version\": \"0.1.3\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">=8\"\n      }\n    },\n    \"node_modules/@jridgewell/gen-mapping\": {\n      \"version\": \"0.3.13\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"@jridgewell/sourcemap-codec\": \"^1.5.0\",\n        \"@jridgewell/trace-mapping\": \"^0.3.24\"\n      }\n    },\n    \"node_modules/@jridgewell/resolve-uri\": {\n      \"version\": \"3.1.2\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">=6.0.0\"\n      }\n    },\n    \"node_modules/@jridgewell/sourcemap-codec\": {\n      \"version\": \"1.5.5\",\n      \"dev\": true,\n      \"license\": \"MIT\"\n    },\n    \"node_modules/@jridgewell/trace-mapping\": {\n      \"version\": \"0.3.31\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"@jridgewell/resolve-uri\": \"^3.1.0\",\n        \"@jridgewell/sourcemap-codec\": \"^1.4.14\"\n      }\n    },\n    \"node_modules/@pkgjs/parseargs\": {\n      \"version\": \"0.11.0\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"optional\": true,\n      \"engines\": {\n        \"node\": \">=14\"\n      }\n    },\n    \"node_modules/@rollup/rollup-darwin-arm64\": {\n      \"version\": \"4.57.1\",\n      \"cpu\": [\n        \"arm64\"\n      ],\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"optional\": true,\n      \"os\": [\n        \"darwin\"\n      ]\n    },\n    \"node_modules/@sinclair/typebox\": {\n      \"version\": \"0.34.48\",\n      \"license\": \"MIT\"\n    },\n    \"node_modules/@types/emscripten\": {\n      \"version\": \"1.41.5\",\n      \"dev\": true,\n      \"license\": \"MIT\"\n    },\n    \"node_modules/@types/estree\": {\n      \"version\": \"1.0.8\",\n      \"dev\": true,\n      \"license\": \"MIT\"\n    },\n    \"node_modules/@types/node\": {\n      \"version\": \"22.19.10\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"undici-types\": \"~6.21.0\"\n      }\n    },\n    \"node_modules/@types/sql.js\": {\n      \"version\": \"1.4.9\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"@types/emscripten\": \"*\",\n        \"@types/node\": \"*\"\n      }\n    },\n    \"node_modules/@vitest/coverage-v8\": {\n      \"version\": \"2.1.9\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"@ampproject/remapping\": \"^2.3.0\",\n        \"@bcoe/v8-coverage\": \"^0.2.3\",\n        \"debug\": \"^4.3.7\",\n        \"istanbul-lib-coverage\": \"^3.2.2\",\n        \"istanbul-lib-report\": \"^3.0.1\",\n        \"istanbul-lib-source-maps\": \"^5.0.6\",\n        \"istanbul-reports\": \"^3.1.7\",\n        \"magic-string\": \"^0.30.12\",\n        \"magicast\": \"^0.3.5\",\n        \"std-env\": \"^3.8.0\",\n        \"test-exclude\": \"^7.0.1\",\n        \"tinyrainbow\": \"^1.2.0\"\n      },\n      \"funding\": {\n        \"url\": \"https://opencollective.com/vitest\"\n      },\n      \"peerDependencies\": {\n        \"@vitest/browser\": \"2.1.9\",\n        \"vitest\": \"2.1.9\"\n      },\n      \"peerDependenciesMeta\": {\n        \"@vitest/browser\": {\n          \"optional\": true\n        }\n      }\n    },\n    \"node_modules/@vitest/expect\": {\n      \"version\": \"2.1.9\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"@vitest/spy\": \"2.1.9\",\n        \"@vitest/utils\": \"2.1.9\",\n        \"chai\": \"^5.1.2\",\n        \"tinyrainbow\": \"^1.2.0\"\n      },\n      \"funding\": {\n        \"url\": \"https://opencollective.com/vitest\"\n      }\n    },\n    \"node_modules/@vitest/mocker\": {\n      \"version\": \"2.1.9\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"@vitest/spy\": \"2.1.9\",\n        \"estree-walker\": \"^3.0.3\",\n        \"magic-string\": \"^0.30.12\"\n      },\n      \"funding\": {\n        \"url\": \"https://opencollective.com/vitest\"\n      },\n      \"peerDependencies\": {\n        \"msw\": \"^2.4.9\",\n        \"vite\": \"^5.0.0\"\n      },\n      \"peerDependenciesMeta\": {\n        \"msw\": {\n          \"optional\": true\n        },\n        \"vite\": {\n          \"optional\": true\n        }\n      }\n    },\n    \"node_modules/@vitest/pretty-format\": {\n      \"version\": \"2.1.9\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"tinyrainbow\": \"^1.2.0\"\n      },\n      \"funding\": {\n        \"url\": \"https://opencollective.com/vitest\"\n      }\n    },\n    \"node_modules/@vitest/runner\": {\n      \"version\": \"2.1.9\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"@vitest/utils\": \"2.1.9\",\n        \"pathe\": \"^1.1.2\"\n      },\n      \"funding\": {\n        \"url\": \"https://opencollective.com/vitest\"\n      }\n    },\n    \"node_modules/@vitest/snapshot\": {\n      \"version\": \"2.1.9\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"@vitest/pretty-format\": \"2.1.9\",\n        \"magic-string\": \"^0.30.12\",\n        \"pathe\": \"^1.1.2\"\n      },\n      \"funding\": {\n        \"url\": \"https://opencollective.com/vitest\"\n      }\n    },\n    \"node_modules/@vitest/spy\": {\n      \"version\": \"2.1.9\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"tinyspy\": \"^3.0.2\"\n      },\n      \"funding\": {\n        \"url\": \"https://opencollective.com/vitest\"\n      }\n    },\n    \"node_modules/@vitest/utils\": {\n      \"version\": \"2.1.9\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"@vitest/pretty-format\": \"2.1.9\",\n        \"loupe\": \"^3.1.2\",\n        \"tinyrainbow\": \"^1.2.0\"\n      },\n      \"funding\": {\n        \"url\": \"https://opencollective.com/vitest\"\n      }\n    },\n    \"node_modules/ansi-regex\": {\n      \"version\": \"6.2.2\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">=12\"\n      },\n      \"funding\": {\n        \"url\": \"https://github.com/chalk/ansi-regex?sponsor=1\"\n      }\n    },\n    \"node_modules/ansi-styles\": {\n      \"version\": \"4.3.0\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"color-convert\": \"^2.0.1\"\n      },\n      \"engines\": {\n        \"node\": \">=8\"\n      },\n      \"funding\": {\n        \"url\": \"https://github.com/chalk/ansi-styles?sponsor=1\"\n      }\n    },\n    \"node_modules/assertion-error\": {\n      \"version\": \"2.0.1\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">=12\"\n      }\n    },\n    \"node_modules/balanced-match\": {\n      \"version\": \"1.0.2\",\n      \"dev\": true,\n      \"license\": \"MIT\"\n    },\n    \"node_modules/brace-expansion\": {\n      \"version\": \"2.0.2\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"balanced-match\": \"^1.0.0\"\n      }\n    },\n    \"node_modules/cac\": {\n      \"version\": \"6.7.14\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">=8\"\n      }\n    },\n    \"node_modules/chai\": {\n      \"version\": \"5.3.3\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"assertion-error\": \"^2.0.1\",\n        \"check-error\": \"^2.1.1\",\n        \"deep-eql\": \"^5.0.1\",\n        \"loupe\": \"^3.1.0\",\n        \"pathval\": \"^2.0.0\"\n      },\n      \"engines\": {\n        \"node\": \">=18\"\n      }\n    },\n    \"node_modules/check-error\": {\n      \"version\": \"2.1.3\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">= 16\"\n      }\n    },\n    \"node_modules/color-convert\": {\n      \"version\": \"2.0.1\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"color-name\": \"~1.1.4\"\n      },\n      \"engines\": {\n        \"node\": \">=7.0.0\"\n      }\n    },\n    \"node_modules/color-name\": {\n      \"version\": \"1.1.4\",\n      \"dev\": true,\n      \"license\": \"MIT\"\n    },\n    \"node_modules/cross-spawn\": {\n      \"version\": \"7.0.6\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"path-key\": \"^3.1.0\",\n        \"shebang-command\": \"^2.0.0\",\n        \"which\": \"^2.0.1\"\n      },\n      \"engines\": {\n        \"node\": \">= 8\"\n      }\n    },\n    \"node_modules/debug\": {\n      \"version\": \"4.4.3\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"ms\": \"^2.1.3\"\n      },\n      \"engines\": {\n        \"node\": \">=6.0\"\n      },\n      \"peerDependenciesMeta\": {\n        \"supports-color\": {\n          \"optional\": true\n        }\n      }\n    },\n    \"node_modules/deep-eql\": {\n      \"version\": \"5.0.2\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">=6\"\n      }\n    },\n    \"node_modules/eastasianwidth\": {\n      \"version\": \"0.2.0\",\n      \"dev\": true,\n      \"license\": \"MIT\"\n    },\n    \"node_modules/emoji-regex\": {\n      \"version\": \"9.2.2\",\n      \"dev\": true,\n      \"license\": \"MIT\"\n    },\n    \"node_modules/es-module-lexer\": {\n      \"version\": \"1.7.0\",\n      \"dev\": true,\n      \"license\": \"MIT\"\n    },\n    \"node_modules/esbuild\": {\n      \"version\": \"0.21.5\",\n      \"dev\": true,\n      \"hasInstallScript\": true,\n      \"license\": \"MIT\",\n      \"bin\": {\n        \"esbuild\": \"bin/esbuild\"\n      },\n      \"engines\": {\n        \"node\": \">=12\"\n      },\n      \"optionalDependencies\": {\n        \"@esbuild/aix-ppc64\": \"0.21.5\",\n        \"@esbuild/android-arm\": \"0.21.5\",\n        \"@esbuild/android-arm64\": \"0.21.5\",\n        \"@esbuild/android-x64\": \"0.21.5\",\n        \"@esbuild/darwin-arm64\": \"0.21.5\",\n        \"@esbuild/darwin-x64\": \"0.21.5\",\n        \"@esbuild/freebsd-arm64\": \"0.21.5\",\n        \"@esbuild/freebsd-x64\": \"0.21.5\",\n        \"@esbuild/linux-arm\": \"0.21.5\",\n        \"@esbuild/linux-arm64\": \"0.21.5\",\n        \"@esbuild/linux-ia32\": \"0.21.5\",\n        \"@esbuild/linux-loong64\": \"0.21.5\",\n        \"@esbuild/linux-mips64el\": \"0.21.5\",\n        \"@esbuild/linux-ppc64\": \"0.21.5\",\n        \"@esbuild/linux-riscv64\": \"0.21.5\",\n        \"@esbuild/linux-s390x\": \"0.21.5\",\n        \"@esbuild/linux-x64\": \"0.21.5\",\n        \"@esbuild/netbsd-x64\": \"0.21.5\",\n        \"@esbuild/openbsd-x64\": \"0.21.5\",\n        \"@esbuild/sunos-x64\": \"0.21.5\",\n        \"@esbuild/win32-arm64\": \"0.21.5\",\n        \"@esbuild/win32-ia32\": \"0.21.5\",\n        \"@esbuild/win32-x64\": \"0.21.5\"\n      }\n    },\n    \"node_modules/estree-walker\": {\n      \"version\": \"3.0.3\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"@types/estree\": \"^1.0.0\"\n      }\n    },\n    \"node_modules/expect-type\": {\n      \"version\": \"1.3.0\",\n      \"dev\": true,\n      \"license\": \"Apache-2.0\",\n      \"engines\": {\n        \"node\": \">=12.0.0\"\n      }\n    },\n    \"node_modules/foreground-child\": {\n      \"version\": \"3.3.1\",\n      \"dev\": true,\n      \"license\": \"ISC\",\n      \"dependencies\": {\n        \"cross-spawn\": \"^7.0.6\",\n        \"signal-exit\": \"^4.0.1\"\n      },\n      \"engines\": {\n        \"node\": \">=14\"\n      },\n      \"funding\": {\n        \"url\": \"https://github.com/sponsors/isaacs\"\n      }\n    },\n    \"node_modules/fsevents\": {\n      \"version\": \"2.3.3\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"optional\": true,\n      \"os\": [\n        \"darwin\"\n      ],\n      \"engines\": {\n        \"node\": \"^8.16.0 || ^10.6.0 || >=11.0.0\"\n      }\n    },\n    \"node_modules/glob\": {\n      \"version\": \"10.5.0\",\n      \"dev\": true,\n      \"license\": \"ISC\",\n      \"dependencies\": {\n        \"foreground-child\": \"^3.1.0\",\n        \"jackspeak\": \"^3.1.2\",\n        \"minimatch\": \"^9.0.4\",\n        \"minipass\": \"^7.1.2\",\n        \"package-json-from-dist\": \"^1.0.0\",\n        \"path-scurry\": \"^1.11.1\"\n      },\n      \"bin\": {\n        \"glob\": \"dist/esm/bin.mjs\"\n      },\n      \"funding\": {\n        \"url\": \"https://github.com/sponsors/isaacs\"\n      }\n    },\n    \"node_modules/has-flag\": {\n      \"version\": \"4.0.0\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">=8\"\n      }\n    },\n    \"node_modules/html-escaper\": {\n      \"version\": \"2.0.2\",\n      \"dev\": true,\n      \"license\": \"MIT\"\n    },\n    \"node_modules/is-fullwidth-code-point\": {\n      \"version\": \"3.0.0\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">=8\"\n      }\n    },\n    \"node_modules/isexe\": {\n      \"version\": \"2.0.0\",\n      \"dev\": true,\n      \"license\": \"ISC\"\n    },\n    \"node_modules/istanbul-lib-coverage\": {\n      \"version\": \"3.2.2\",\n      \"dev\": true,\n      \"license\": \"BSD-3-Clause\",\n      \"engines\": {\n        \"node\": \">=8\"\n      }\n    },\n    \"node_modules/istanbul-lib-report\": {\n      \"version\": \"3.0.1\",\n      \"dev\": true,\n      \"license\": \"BSD-3-Clause\",\n      \"dependencies\": {\n        \"istanbul-lib-coverage\": \"^3.0.0\",\n        \"make-dir\": \"^4.0.0\",\n        \"supports-color\": \"^7.1.0\"\n      },\n      \"engines\": {\n        \"node\": \">=10\"\n      }\n    },\n    \"node_modules/istanbul-lib-source-maps\": {\n      \"version\": \"5.0.6\",\n      \"dev\": true,\n      \"license\": \"BSD-3-Clause\",\n      \"dependencies\": {\n        \"@jridgewell/trace-mapping\": \"^0.3.23\",\n        \"debug\": \"^4.1.1\",\n        \"istanbul-lib-coverage\": \"^3.0.0\"\n      },\n      \"engines\": {\n        \"node\": \">=10\"\n      }\n    },\n    \"node_modules/istanbul-reports\": {\n      \"version\": \"3.2.0\",\n      \"dev\": true,\n      \"license\": \"BSD-3-Clause\",\n      \"dependencies\": {\n        \"html-escaper\": \"^2.0.0\",\n        \"istanbul-lib-report\": \"^3.0.0\"\n      },\n      \"engines\": {\n        \"node\": \">=8\"\n      }\n    },\n    \"node_modules/jackspeak\": {\n      \"version\": \"3.4.3\",\n      \"dev\": true,\n      \"license\": \"BlueOak-1.0.0\",\n      \"dependencies\": {\n        \"@isaacs/cliui\": \"^8.0.2\"\n      },\n      \"funding\": {\n        \"url\": \"https://github.com/sponsors/isaacs\"\n      },\n      \"optionalDependencies\": {\n        \"@pkgjs/parseargs\": \"^0.11.0\"\n      }\n    },\n    \"node_modules/loupe\": {\n      \"version\": \"3.2.1\",\n      \"dev\": true,\n      \"license\": \"MIT\"\n    },\n    \"node_modules/lru-cache\": {\n      \"version\": \"10.4.3\",\n      \"dev\": true,\n      \"license\": \"ISC\"\n    },\n    \"node_modules/magic-string\": {\n      \"version\": \"0.30.21\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"@jridgewell/sourcemap-codec\": \"^1.5.5\"\n      }\n    },\n    \"node_modules/magicast\": {\n      \"version\": \"0.3.5\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"@babel/parser\": \"^7.25.4\",\n        \"@babel/types\": \"^7.25.4\",\n        \"source-map-js\": \"^1.2.0\"\n      }\n    },\n    \"node_modules/make-dir\": {\n      \"version\": \"4.0.0\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"semver\": \"^7.5.3\"\n      },\n      \"engines\": {\n        \"node\": \">=10\"\n      },\n      \"funding\": {\n        \"url\": \"https://github.com/sponsors/sindresorhus\"\n      }\n    },\n    \"node_modules/minimatch\": {\n      \"version\": \"9.0.5\",\n      \"dev\": true,\n      \"license\": \"ISC\",\n      \"dependencies\": {\n        \"brace-expansion\": \"^2.0.1\"\n      },\n      \"engines\": {\n        \"node\": \">=16 || 14 >=14.17\"\n      },\n      \"funding\": {\n        \"url\": \"https://github.com/sponsors/isaacs\"\n      }\n    },\n    \"node_modules/minipass\": {\n      \"version\": \"7.1.2\",\n      \"dev\": true,\n      \"license\": \"ISC\",\n      \"engines\": {\n        \"node\": \">=16 || 14 >=14.17\"\n      }\n    },\n    \"node_modules/ms\": {\n      \"version\": \"2.1.3\",\n      \"dev\": true,\n      \"license\": \"MIT\"\n    },\n    \"node_modules/nanoid\": {\n      \"version\": \"3.3.11\",\n      \"dev\": true,\n      \"funding\": [\n        {\n          \"type\": \"github\",\n          \"url\": \"https://github.com/sponsors/ai\"\n        }\n      ],\n      \"license\": \"MIT\",\n      \"bin\": {\n        \"nanoid\": \"bin/nanoid.cjs\"\n      },\n      \"engines\": {\n        \"node\": \"^10 || ^12 || ^13.7 || ^14 || >=15.0.1\"\n      }\n    },\n    \"node_modules/package-json-from-dist\": {\n      \"version\": \"1.0.1\",\n      \"dev\": true,\n      \"license\": \"BlueOak-1.0.0\"\n    },\n    \"node_modules/path-key\": {\n      \"version\": \"3.1.1\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">=8\"\n      }\n    },\n    \"node_modules/path-scurry\": {\n      \"version\": \"1.11.1\",\n      \"dev\": true,\n      \"license\": \"BlueOak-1.0.0\",\n      \"dependencies\": {\n        \"lru-cache\": \"^10.2.0\",\n        \"minipass\": \"^5.0.0 || ^6.0.2 || ^7.0.0\"\n      },\n      \"engines\": {\n        \"node\": \">=16 || 14 >=14.18\"\n      },\n      \"funding\": {\n        \"url\": \"https://github.com/sponsors/isaacs\"\n      }\n    },\n    \"node_modules/pathe\": {\n      \"version\": \"1.1.2\",\n      \"dev\": true,\n      \"license\": \"MIT\"\n    },\n    \"node_modules/pathval\": {\n      \"version\": \"2.0.1\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">= 14.16\"\n      }\n    },\n    \"node_modules/picocolors\": {\n      \"version\": \"1.1.1\",\n      \"dev\": true,\n      \"license\": \"ISC\"\n    },\n    \"node_modules/postcss\": {\n      \"version\": \"8.5.6\",\n      \"dev\": true,\n      \"funding\": [\n        {\n          \"type\": \"opencollective\",\n          \"url\": \"https://opencollective.com/postcss/\"\n        },\n        {\n          \"type\": \"tidelift\",\n          \"url\": \"https://tidelift.com/funding/github/npm/postcss\"\n        },\n        {\n          \"type\": \"github\",\n          \"url\": \"https://github.com/sponsors/ai\"\n        }\n      ],\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"nanoid\": \"^3.3.11\",\n        \"picocolors\": \"^1.1.1\",\n        \"source-map-js\": \"^1.2.1\"\n      },\n      \"engines\": {\n        \"node\": \"^10 || ^12 || >=14\"\n      }\n    },\n    \"node_modules/rollup\": {\n      \"version\": \"4.57.1\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"@types/estree\": \"1.0.8\"\n      },\n      \"bin\": {\n        \"rollup\": \"dist/bin/rollup\"\n      },\n      \"engines\": {\n        \"node\": \">=18.0.0\",\n        \"npm\": \">=8.0.0\"\n      },\n      \"optionalDependencies\": {\n        \"@rollup/rollup-android-arm-eabi\": \"4.57.1\",\n        \"@rollup/rollup-android-arm64\": \"4.57.1\",\n        \"@rollup/rollup-darwin-arm64\": \"4.57.1\",\n        \"@rollup/rollup-darwin-x64\": \"4.57.1\",\n        \"@rollup/rollup-freebsd-arm64\": \"4.57.1\",\n        \"@rollup/rollup-freebsd-x64\": \"4.57.1\",\n        \"@rollup/rollup-linux-arm-gnueabihf\": \"4.57.1\",\n        \"@rollup/rollup-linux-arm-musleabihf\": \"4.57.1\",\n        \"@rollup/rollup-linux-arm64-gnu\": \"4.57.1\",\n        \"@rollup/rollup-linux-arm64-musl\": \"4.57.1\",\n        \"@rollup/rollup-linux-loong64-gnu\": \"4.57.1\",\n        \"@rollup/rollup-linux-loong64-musl\": \"4.57.1\",\n        \"@rollup/rollup-linux-ppc64-gnu\": \"4.57.1\",\n        \"@rollup/rollup-linux-ppc64-musl\": \"4.57.1\",\n        \"@rollup/rollup-linux-riscv64-gnu\": \"4.57.1\",\n        \"@rollup/rollup-linux-riscv64-musl\": \"4.57.1\",\n        \"@rollup/rollup-linux-s390x-gnu\": \"4.57.1\",\n        \"@rollup/rollup-linux-x64-gnu\": \"4.57.1\",\n        \"@rollup/rollup-linux-x64-musl\": \"4.57.1\",\n        \"@rollup/rollup-openbsd-x64\": \"4.57.1\",\n        \"@rollup/rollup-openharmony-arm64\": \"4.57.1\",\n        \"@rollup/rollup-win32-arm64-msvc\": \"4.57.1\",\n        \"@rollup/rollup-win32-ia32-msvc\": \"4.57.1\",\n        \"@rollup/rollup-win32-x64-gnu\": \"4.57.1\",\n        \"@rollup/rollup-win32-x64-msvc\": \"4.57.1\",\n        \"fsevents\": \"~2.3.2\"\n      }\n    },\n    \"node_modules/semver\": {\n      \"version\": \"7.7.4\",\n      \"dev\": true,\n      \"license\": \"ISC\",\n      \"bin\": {\n        \"semver\": \"bin/semver.js\"\n      },\n      \"engines\": {\n        \"node\": \">=10\"\n      }\n    },\n    \"node_modules/shebang-command\": {\n      \"version\": \"2.0.0\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"shebang-regex\": \"^3.0.0\"\n      },\n      \"engines\": {\n        \"node\": \">=8\"\n      }\n    },\n    \"node_modules/shebang-regex\": {\n      \"version\": \"3.0.0\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">=8\"\n      }\n    },\n    \"node_modules/siginfo\": {\n      \"version\": \"2.0.0\",\n      \"dev\": true,\n      \"license\": \"ISC\"\n    },\n    \"node_modules/signal-exit\": {\n      \"version\": \"4.1.0\",\n      \"dev\": true,\n      \"license\": \"ISC\",\n      \"engines\": {\n        \"node\": \">=14\"\n      },\n      \"funding\": {\n        \"url\": \"https://github.com/sponsors/isaacs\"\n      }\n    },\n    \"node_modules/source-map-js\": {\n      \"version\": \"1.2.1\",\n      \"dev\": true,\n      \"license\": \"BSD-3-Clause\",\n      \"engines\": {\n        \"node\": \">=0.10.0\"\n      }\n    },\n    \"node_modules/sql.js\": {\n      \"version\": \"1.13.0\",\n      \"license\": \"MIT\"\n    },\n    \"node_modules/stackback\": {\n      \"version\": \"0.0.2\",\n      \"dev\": true,\n      \"license\": \"MIT\"\n    },\n    \"node_modules/std-env\": {\n      \"version\": \"3.10.0\",\n      \"dev\": true,\n      \"license\": \"MIT\"\n    },\n    \"node_modules/string-width\": {\n      \"version\": \"5.1.2\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"eastasianwidth\": \"^0.2.0\",\n        \"emoji-regex\": \"^9.2.2\",\n        \"strip-ansi\": \"^7.0.1\"\n      },\n      \"engines\": {\n        \"node\": \">=12\"\n      },\n      \"funding\": {\n        \"url\": \"https://github.com/sponsors/sindresorhus\"\n      }\n    },\n    \"node_modules/string-width-cjs\": {\n      \"name\": \"string-width\",\n      \"version\": \"4.2.3\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"emoji-regex\": \"^8.0.0\",\n        \"is-fullwidth-code-point\": \"^3.0.0\",\n        \"strip-ansi\": \"^6.0.1\"\n      },\n      \"engines\": {\n        \"node\": \">=8\"\n      }\n    },\n    \"node_modules/string-width-cjs/node_modules/ansi-regex\": {\n      \"version\": \"5.0.1\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">=8\"\n      }\n    },\n    \"node_modules/string-width-cjs/node_modules/emoji-regex\": {\n      \"version\": \"8.0.0\",\n      \"dev\": true,\n      \"license\": \"MIT\"\n    },\n    \"node_modules/string-width-cjs/node_modules/strip-ansi\": {\n      \"version\": \"6.0.1\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"ansi-regex\": \"^5.0.1\"\n      },\n      \"engines\": {\n        \"node\": \">=8\"\n      }\n    },\n    \"node_modules/strip-ansi\": {\n      \"version\": \"7.1.2\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"ansi-regex\": \"^6.0.1\"\n      },\n      \"engines\": {\n        \"node\": \">=12\"\n      },\n      \"funding\": {\n        \"url\": \"https://github.com/chalk/strip-ansi?sponsor=1\"\n      }\n    },\n    \"node_modules/strip-ansi-cjs\": {\n      \"name\": \"strip-ansi\",\n      \"version\": \"6.0.1\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"ansi-regex\": \"^5.0.1\"\n      },\n      \"engines\": {\n        \"node\": \">=8\"\n      }\n    },\n    \"node_modules/strip-ansi-cjs/node_modules/ansi-regex\": {\n      \"version\": \"5.0.1\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">=8\"\n      }\n    },\n    \"node_modules/supports-color\": {\n      \"version\": \"7.2.0\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"has-flag\": \"^4.0.0\"\n      },\n      \"engines\": {\n        \"node\": \">=8\"\n      }\n    },\n    \"node_modules/test-exclude\": {\n      \"version\": \"7.0.1\",\n      \"dev\": true,\n      \"license\": \"ISC\",\n      \"dependencies\": {\n        \"@istanbuljs/schema\": \"^0.1.2\",\n        \"glob\": \"^10.4.1\",\n        \"minimatch\": \"^9.0.4\"\n      },\n      \"engines\": {\n        \"node\": \">=18\"\n      }\n    },\n    \"node_modules/tinybench\": {\n      \"version\": \"2.9.0\",\n      \"dev\": true,\n      \"license\": \"MIT\"\n    },\n    \"node_modules/tinyexec\": {\n      \"version\": \"0.3.2\",\n      \"dev\": true,\n      \"license\": \"MIT\"\n    },\n    \"node_modules/tinypool\": {\n      \"version\": \"1.1.1\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \"^18.0.0 || >=20.0.0\"\n      }\n    },\n    \"node_modules/tinyrainbow\": {\n      \"version\": \"1.2.0\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">=14.0.0\"\n      }\n    },\n    \"node_modules/tinyspy\": {\n      \"version\": \"3.0.2\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">=14.0.0\"\n      }\n    },\n    \"node_modules/typescript\": {\n      \"version\": \"5.9.3\",\n      \"dev\": true,\n      \"license\": \"Apache-2.0\",\n      \"bin\": {\n        \"tsc\": \"bin/tsc\",\n        \"tsserver\": \"bin/tsserver\"\n      },\n      \"engines\": {\n        \"node\": \">=14.17\"\n      }\n    },\n    \"node_modules/undici-types\": {\n      \"version\": \"6.21.0\",\n      \"dev\": true,\n      \"license\": \"MIT\"\n    },\n    \"node_modules/vite\": {\n      \"version\": \"5.4.21\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"esbuild\": \"^0.21.3\",\n        \"postcss\": \"^8.4.43\",\n        \"rollup\": \"^4.20.0\"\n      },\n      \"bin\": {\n        \"vite\": \"bin/vite.js\"\n      },\n      \"engines\": {\n        \"node\": \"^18.0.0 || >=20.0.0\"\n      },\n      \"funding\": {\n        \"url\": \"https://github.com/vitejs/vite?sponsor=1\"\n      },\n      \"optionalDependencies\": {\n        \"fsevents\": \"~2.3.3\"\n      },\n      \"peerDependencies\": {\n        \"@types/node\": \"^18.0.0 || >=20.0.0\",\n        \"less\": \"*\",\n        \"lightningcss\": \"^1.21.0\",\n        \"sass\": \"*\",\n        \"sass-embedded\": \"*\",\n        \"stylus\": \"*\",\n        \"sugarss\": \"*\",\n        \"terser\": \"^5.4.0\"\n      },\n      \"peerDependenciesMeta\": {\n        \"@types/node\": {\n          \"optional\": true\n        },\n        \"less\": {\n          \"optional\": true\n        },\n        \"lightningcss\": {\n          \"optional\": true\n        },\n        \"sass\": {\n          \"optional\": true\n        },\n        \"sass-embedded\": {\n          \"optional\": true\n        },\n        \"stylus\": {\n          \"optional\": true\n        },\n        \"sugarss\": {\n          \"optional\": true\n        },\n        \"terser\": {\n          \"optional\": true\n        }\n      }\n    },\n    \"node_modules/vite-node\": {\n      \"version\": \"2.1.9\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"cac\": \"^6.7.14\",\n        \"debug\": \"^4.3.7\",\n        \"es-module-lexer\": \"^1.5.4\",\n        \"pathe\": \"^1.1.2\",\n        \"vite\": \"^5.0.0\"\n      },\n      \"bin\": {\n        \"vite-node\": \"vite-node.mjs\"\n      },\n      \"engines\": {\n        \"node\": \"^18.0.0 || >=20.0.0\"\n      },\n      \"funding\": {\n        \"url\": \"https://opencollective.com/vitest\"\n      }\n    },\n    \"node_modules/vitest\": {\n      \"version\": \"2.1.9\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"@vitest/expect\": \"2.1.9\",\n        \"@vitest/mocker\": \"2.1.9\",\n        \"@vitest/pretty-format\": \"^2.1.9\",\n        \"@vitest/runner\": \"2.1.9\",\n        \"@vitest/snapshot\": \"2.1.9\",\n        \"@vitest/spy\": \"2.1.9\",\n        \"@vitest/utils\": \"2.1.9\",\n        \"chai\": \"^5.1.2\",\n        \"debug\": \"^4.3.7\",\n        \"expect-type\": \"^1.1.0\",\n        \"magic-string\": \"^0.30.12\",\n        \"pathe\": \"^1.1.2\",\n        \"std-env\": \"^3.8.0\",\n        \"tinybench\": \"^2.9.0\",\n        \"tinyexec\": \"^0.3.1\",\n        \"tinypool\": \"^1.0.1\",\n        \"tinyrainbow\": \"^1.2.0\",\n        \"vite\": \"^5.0.0\",\n        \"vite-node\": \"2.1.9\",\n        \"why-is-node-running\": \"^2.3.0\"\n      },\n      \"bin\": {\n        \"vitest\": \"vitest.mjs\"\n      },\n      \"engines\": {\n        \"node\": \"^18.0.0 || >=20.0.0\"\n      },\n      \"funding\": {\n        \"url\": \"https://opencollective.com/vitest\"\n      },\n      \"peerDependencies\": {\n        \"@edge-runtime/vm\": \"*\",\n        \"@types/node\": \"^18.0.0 || >=20.0.0\",\n        \"@vitest/browser\": \"2.1.9\",\n        \"@vitest/ui\": \"2.1.9\",\n        \"happy-dom\": \"*\",\n        \"jsdom\": \"*\"\n      },\n      \"peerDependenciesMeta\": {\n        \"@edge-runtime/vm\": {\n          \"optional\": true\n        },\n        \"@types/node\": {\n          \"optional\": true\n        },\n        \"@vitest/browser\": {\n          \"optional\": true\n        },\n        \"@vitest/ui\": {\n          \"optional\": true\n        },\n        \"happy-dom\": {\n          \"optional\": true\n        },\n        \"jsdom\": {\n          \"optional\": true\n        }\n      }\n    },\n    \"node_modules/which\": {\n      \"version\": \"2.0.2\",\n      \"dev\": true,\n      \"license\": \"ISC\",\n      \"dependencies\": {\n        \"isexe\": \"^2.0.0\"\n      },\n      \"bin\": {\n        \"node-which\": \"bin/node-which\"\n      },\n      \"engines\": {\n        \"node\": \">= 8\"\n      }\n    },\n    \"node_modules/why-is-node-running\": {\n      \"version\": \"2.3.0\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"siginfo\": \"^2.0.0\",\n        \"stackback\": \"0.0.2\"\n      },\n      \"bin\": {\n        \"why-is-node-running\": \"cli.js\"\n      },\n      \"engines\": {\n        \"node\": \">=8\"\n      }\n    },\n    \"node_modules/wrap-ansi\": {\n      \"version\": \"8.1.0\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"ansi-styles\": \"^6.1.0\",\n        \"string-width\": \"^5.0.1\",\n        \"strip-ansi\": \"^7.0.1\"\n      },\n      \"engines\": {\n        \"node\": \">=12\"\n      },\n      \"funding\": {\n        \"url\": \"https://github.com/chalk/wrap-ansi?sponsor=1\"\n      }\n    },\n    \"node_modules/wrap-ansi-cjs\": {\n      \"name\": \"wrap-ansi\",\n      \"version\": \"7.0.0\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"ansi-styles\": \"^4.0.0\",\n        \"string-width\": \"^4.1.0\",\n        \"strip-ansi\": \"^6.0.0\"\n      },\n      \"engines\": {\n        \"node\": \">=10\"\n      },\n      \"funding\": {\n        \"url\": \"https://github.com/chalk/wrap-ansi?sponsor=1\"\n      }\n    },\n    \"node_modules/wrap-ansi-cjs/node_modules/ansi-regex\": {\n      \"version\": \"5.0.1\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">=8\"\n      }\n    },\n    \"node_modules/wrap-ansi-cjs/node_modules/emoji-regex\": {\n      \"version\": \"8.0.0\",\n      \"dev\": true,\n      \"license\": \"MIT\"\n    },\n    \"node_modules/wrap-ansi-cjs/node_modules/string-width\": {\n      \"version\": \"4.2.3\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"emoji-regex\": \"^8.0.0\",\n        \"is-fullwidth-code-point\": \"^3.0.0\",\n        \"strip-ansi\": \"^6.0.1\"\n      },\n      \"engines\": {\n        \"node\": \">=8\"\n      }\n    },\n    \"node_modules/wrap-ansi-cjs/node_modules/strip-ansi\": {\n      \"version\": \"6.0.1\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"ansi-regex\": \"^5.0.1\"\n      },\n      \"engines\": {\n        \"node\": \">=8\"\n      }\n    },\n    \"node_modules/wrap-ansi/node_modules/ansi-styles\": {\n      \"version\": \"6.2.3\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">=12\"\n      },\n      \"funding\": {\n        \"url\": \"https://github.com/chalk/ansi-styles?sponsor=1\"\n      }\n    }\n  }\n}\n\nFile v2.0.4:package.json\n\n{\n  \"name\": \"memory-tools\",\n  \"version\": \"2.0.4\",\n  \"description\": \"Memory-as-Tools plugin for OpenClaw - Agent-controlled persistent memory with QMD-powered search\",\n  \"type\": \"module\",\n  \"main\": \"dist/index.js\",\n  \"types\": \"dist/index.d.ts\",\n  \"scripts\": {\n    \"clean\": \"rm -rf dist\",\n    \"build\": \"npm run clean && tsc\",\n    \"test\": \"vitest run\",\n    \"test:watch\": \"vitest\",\n    \"test:coverage\": \"vitest run --coverage\",\n    \"lint\": \"oxlint\",\n    \"typecheck\": \"tsc --noEmit\",\n    \"verify:release\": \"node scripts/verify-release.mjs\",\n    \"prepublishOnly\": \"npm run build && npm run verify:release\"\n  },\n  \"dependencies\": {\n    \"@sinclair/typebox\": \"0.34.48\",\n    \"sql.js\": \"^1.13.0\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^22.0.0\",\n    \"@types/sql.js\": \"^1.4.9\",\n    \"@vitest/coverage-v8\": \"^2.1.0\",\n    \"typescript\": \"^5.7.0\",\n    \"vitest\": \"^2.1.0\"\n  },\n  \"peerDependencies\": {\n    \"openclaw\": \">=2026.0.0\"\n  },\n  \"peerDependenciesMeta\": {\n    \"openclaw\": {\n      \"optional\": true\n    }\n  },\n  \"openclaw\": {\n    \"extensions\": [\n      \"./dist/index.js\"\n    ]\n  },\n  \"files\": [\n    \"dist\",\n    \"README.md\"\n  ],\n  \"keywords\": [\n    \"openclaw\",\n    \"memory\",\n    \"ai-agent\",\n    \"plugin\",\n    \"vector-search\",\n    \"qmd\",\n    \"local-llm\"\n  ],\n  \"author\": \"Purple Horizons\",\n  \"license\": \"MIT\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/Purple-Horizons/memory-tools.git\"\n  }\n}\n\nFile v2.0.4:tsconfig.json\n\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"lib\": [\"ES2022\"],\n    \"outDir\": \"dist\",\n    \"rootDir\": \"src\",\n    \"declaration\": true,\n    \"declarationMap\": true,\n    \"sourceMap\": true,\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": true,\n    \"noEmit\": false\n  },\n  \"include\": [\"src/**/*\"],\n  \"exclude\": [\"node_modules\", \"dist\", \"**/*.test.ts\"]\n}\n\nFile v2.0.4:test/docker/docker-compose.yml\n\nversion: '3.8'\n\nservices:\n  migration-test:\n    build:\n      context: ../..\n      dockerfile: test/docker/Dockerfile\n    volumes:\n      - ../..:/app/memory-tools:ro\n      - test-data:/home/testuser/.openclaw\n    environment:\n      - HOME=/home/testuser\n      - NODE_ENV=test\n\nvolumes:\n  test-data:\n\nArchive v2.0.3: 26 files, 48947 bytes\n\nFiles: CLAUDE.md (2126b), clawdbot.plugin.json (1424b), openclaw.plugin.json (1424b), package-lock.json (32215b), package.json (1410b), README.md (13596b), scripts/verify-release.mjs (1199b), SKILL.md (6068b), src/config.ts (2055b), src/file-manager.ts (12565b), src/index.ts (13566b), src/migration.ts (11904b), src/plugin-types.ts (1447b), src/qmd.ts (11184b), src/store.test.ts (10457b), src/store.ts (8459b), src/tools.test.ts (7005b), src/tools.ts (21256b), src/types.ts (2386b), test/docker/docker-compose.yml (298b), test/docker/run-tests.sh (423b), test/docker/seed-v1-data.js (4109b), test/docker/test-migration.sh (4817b), tsconfig.json (540b), vitest.config.ts (404b), _meta.json (131b)\n\nFile v2.0.3:SKILL.md\n\n---\nname: memory-tools\ndescription: Agent-controlled memory plugin for OpenClaw with confidence scoring, decay, and semantic search. The agent decides WHEN to store/retrieve memories — no auto-capture noise. v2 uses file-based storage with optional QMD search (no external APIs required).\nhomepage: https://github.com/Purple-Horizons/memory-tools\nmetadata:\n  openclaw:\n    emoji: 🧠\n    kind: plugin\n---\n\n# Memory Tools v2\n\nAgent-controlled persistent memory for OpenClaw.\n\n## What's New in v2\n\n- **File-based storage** — Memories stored as readable markdown files\n- **No external APIs** — No OpenAI dependency, everything runs locally\n- **QMD search (optional)** — BM25 + vector + reranking via local GGUF models\n- **Auto-migration** — Seamlessly upgrades from v1 SQLite/LanceDB storage\n\n## Why Memory-as-Tools?\n\nTraditional memory systems auto-capture everything, flooding context with irrelevant information. Memory Tools follows the [AgeMem](https://arxiv.org/abs/2409.02634) approach: **the agent decides** when to store and retrieve memories.\n\n## Features\n\n- **6 Memory Tools**: `memory_store`, `memory_update`, `memory_forget`, `memory_search`, `memory_summarize`, `memory_list`\n- **Confidence Scoring**: Track how certain you are (1.0 = explicit, 0.5 = inferred)\n- **Importance Scoring**: Prioritize critical instructions over nice-to-know facts\n- **Decay/Expiration**: Temporal memories automatically become stale\n- **Human-readable storage**: Markdown files with YAML frontmatter\n- **Conflict Resolution**: New info auto-supersedes old (no contradictions)\n\n## Installation\n\n### Step 1: Install from ClawHub\n\n```bash\nclawhub install memory-tools\n```\n\n### Step 2: Build the plugin\n\n```bash\ncd skills/memory-tools\nnpm install\nnpm run build\n```\n\n### Step 3: Activate the plugin\n\n```bash\nopenclaw plugins install --link .\nopenclaw plugins enable memory-tools\n```\n\n### Step 4: Restart the gateway\n\n```bash\nopenclaw gateway restart\n```\n\n### Optional: Install QMD for better search\n\n```bash\nnpm install -g @tobilu/qmd\n```\n\nWithout QMD, basic filtering works. With QMD, you get semantic search (BM25 + vector + reranking).\n\n### Node Compatibility (QMD)\n\n- QMD may not be compatible with the newest Node ABI immediately.\n- If QMD fails (for example `NODE_MODULE_VERSION` mismatch), memory-tools falls back to basic mode.\n- To force basic mode: `MEMORY_TOOLS_DISABLE_QMD=true`.\n- For best QMD stability, use a Node LTS version supported by your installed QMD build.\n\n## Security Model\n\n- No API keys or external credentials are required.\n- Data is stored locally in `~/.openclaw/memories` (or configured `memoriesPath`).\n- The plugin can inject `systemPrompt` and `prependContext` at `before_agent_start` when `autoInjectInstructions=true`.\n- The plugin can auto-migrate legacy v1 data from `~/.openclaw/memory/tools/memory.db` when `autoMigrateLegacy=true`.\n- Disable injection with `autoInjectInstructions=false` if you want stricter control.\n- Disable migration with `autoMigrateLegacy=false` if you do not want startup migration behavior.\n\n## Storage Format\n\nMemories are stored as markdown files in `~/.openclaw/memories/`:\n\n```\n~/.openclaw/memories/\n├── facts/\n│   └── abc123-def4-5678-90ab-cdef12345678.md\n├── preferences/\n│   └── def456-7890-abcd-ef12-345678901234.md\n├── instructions/\n│   └── ghi789-0abc-def1-2345-678901234567.md\n└── .deleted/\n    └── old-memory.md\n```\n\nEach memory file:\n\n```markdown\n---\nid: abc123-def4-5678-90ab-cdef12345678\ncategory: preference\nconfidence: 0.9\nimportance: 0.7\ncreated_at: 2024-01-15T10:30:00Z\ntags: [ui, settings]\n---\n\nUser prefers dark mode in all applications.\n```\n\n## Memory Categories\n\n| Category | Use For | Example |\n|----------|---------|---------|\n| fact | Static information | \"User's dog is named Rex\" |\n| preference | Likes/dislikes | \"User prefers dark mode\" |\n| event | Temporal things | \"Dentist Tuesday 3pm\" |\n| relationship | People connections | \"Sarah is user's wife\" |\n| instruction | Standing orders | \"Always respond in Spanish\" |\n| decision | Choices made | \"We decided to use PostgreSQL\" |\n| context | Situational info | \"User is job hunting\" |\n| entity | Named things | \"Project Apollo is their startup\" |\n\n## Tool Reference\n\n### memory_store\n```\nmemory_store({\n  content: \"User prefers bullet points\",\n  category: \"preference\",\n  confidence: 0.9,\n  importance: 0.7,\n  tags: [\"formatting\", \"communication\"]\n})\n```\n\n### memory_search\n```\nmemory_search({\n  query: \"formatting preferences\",\n  category: \"preference\",\n  limit: 10\n})\n```\n\n### memory_update\n```\nmemory_update({\n  id: \"abc123\",\n  content: \"User now prefers numbered lists\",\n  confidence: 1.0\n})\n```\n\n### memory_forget\n```\nmemory_forget({\n  query: \"bullet points\",\n  reason: \"User corrected preference\"\n})\n```\n\n### memory_summarize\n```\nmemory_summarize({\n  topic: \"user's work projects\",\n  maxMemories: 20\n})\n```\n\n### memory_list\n```\nmemory_list({\n  category: \"instruction\",\n  sortBy: \"importance\",\n  limit: 20\n})\n```\n\n## CLI Commands\n\n```bash\n# Show memory statistics\nopenclaw memory-tools stats\n\n# List memories\nopenclaw memory-tools list\nopenclaw memory-tools list --category fact\n\n# Search memories (requires QMD)\nopenclaw memory-tools search \"dark mode\"\n\n# Export all memories as JSON\nopenclaw memory-tools export\n\n# Force re-index with QMD\nopenclaw memory-tools reindex\n\n# Show storage path\nopenclaw memory-tools path\n```\n\n## Debugging\n\nMemories are plain markdown files — just read them:\n\n```bash\ncat ~/.openclaw/memories/facts/*.md\nls ~/.openclaw/memories/\n```\n\nExport all memories:\n\n```bash\nopenclaw memory-tools export > memories.json\n```\n\n## Migration from v1\n\nv2 automatically detects v1 databases and migrates them:\n\n1. On startup, v2 checks for `~/.openclaw/memory/tools/memory.db`\n2. If found, exports all memories to markdown files\n3. Original database preserved as backup\n4. No manual action required\n\nTo disable auto-migration, set `autoMigrateLegacy: false` in plugin config.\n\n## License\n\nMIT — [Purple Horizons](https://github.com/Purple-Horizons)\n\nFile v2.0.3:README.md\n\n<p align=\"center\">\n  <img src=\"header.png\" alt=\"memory-tools\" width=\"100%\">\n</p>\n\n# OpenClaw Memory Tools v2\n\nAgent-controlled memory plugin for OpenClaw with confidence scoring, decay, and semantic search.\n\n## What's New in v2\n\n- **File-based storage** - Memories stored as readable markdown files\n- **No external APIs** - No OpenAI dependency, everything runs locally\n- **QMD search (optional)** - BM25 + vector + reranking via local GGUF models\n- **Auto-migration** - Seamlessly upgrades from v1 SQLite/LanceDB storage\n\n## Why Memory-as-Tools?\n\nTraditional AI memory systems auto-capture everything, flooding context with irrelevant information. **Memory-as-Tools** follows the [AgeMem](https://arxiv.org/abs/2409.02634) approach: the agent decides **when** to store and retrieve memories.\n\n```\nTraditional: Agent -> always retrieves -> context flooded\nMemory-as-Tools: Agent -> decides IF/WHAT to remember -> uses tools explicitly\n```\n\n## Features\n\n- **6 Memory Tools**: `memory_store`, `memory_update`, `memory_forget`, `memory_search`, `memory_summarize`, `memory_list`\n- **Confidence Scoring**: Track how certain you are about each memory (1.0 = explicit, 0.5 = inferred)\n- **Importance Scoring**: Prioritize critical instructions over nice-to-know facts\n- **Decay/Expiration**: Temporal memories (events) automatically become stale\n- **Human-readable storage**: Markdown files with YAML frontmatter\n- **Semantic Search**: Optional QMD-powered hybrid search (BM25 + vector + reranking)\n- **Zero External Dependencies**: Everything runs locally, no API keys needed\n- **Standing Instructions**: Auto-inject category=\"instruction\" memories at conversation start\n\n## Installation\n\n### Step 1: Install from ClawHub\n\n```bash\nclawhub install memory-tools\n```\n\n### Step 2: Build the plugin\n\n```bash\ncd skills/memory-tools\nnpm install\nnpm run build\n```\n\n### Step 3: Activate the plugin\n\n```bash\nopenclaw plugins install --link .\nopenclaw plugins enable memory-tools\n```\n\n### Step 4: Restart the gateway\n\n```bash\nopenclaw gateway restart\n```\n\n### Optional: Install QMD for better search\n\n```bash\nnpm install -g @tobilu/qmd\n```\n\nWithout QMD, basic category/tag filtering works. With QMD, you get semantic search (BM25 + vector + reranking using local GGUF models).\n\n### Node Compatibility (QMD)\n\n- `memory-tools` works without QMD on modern Node versions.\n- QMD dependencies (notably `better-sqlite3`) may lag behind the latest Node ABI.\n- If QMD fails on startup (for example `NODE_MODULE_VERSION` mismatch on Node v25), the plugin now falls back to basic mode.\n- To force basic mode explicitly, set `MEMORY_TOOLS_DISABLE_QMD=true`.\n- Recommended for full QMD stability: use a Node LTS version supported by your installed QMD build.\n\n## Configuration\n\nAdd to `~/.openclaw/openclaw.json`:\n\n```json\n{\n  \"plugins\": {\n    \"slots\": {\n      \"memory\": \"memory-tools\"\n    },\n    \"entries\": {\n      \"memory-tools\": {\n        \"enabled\": true,\n        \"config\": {\n          \"memoriesPath\": \"~/.openclaw/memories\",\n          \"autoInjectInstructions\": true,\n          \"autoMigrateLegacy\": true\n        }\n      }\n    }\n  },\n  \"tools\": {\n    \"alsoAllow\": [\"group:plugins\"]\n  }\n}\n```\n\n### Security Model\n\n- No API keys or external credentials are required by this plugin.\n- Data is stored locally in `~/.openclaw/memories` (or your configured `memoriesPath`).\n- The plugin can inject `systemPrompt` and `prependContext` at `before_agent_start` when `autoInjectInstructions=true`.\n- The plugin can auto-migrate legacy v1 data from `~/.openclaw/memory/tools/memory.db` when `autoMigrateLegacy=true`.\n- Set `autoInjectInstructions=false` if you do not want startup prompt/context injection.\n- Set `autoMigrateLegacy=false` if you do not want automatic migration reads/writes.\n\n### Verify Installation\n\n```bash\n# Restart gateway\nopenclaw gateway stop && openclaw gateway run\n\n# Check plugin loaded\nopenclaw plugins list\n\n# Test CLI\nopenclaw memory-tools stats\n```\n\n## Storage Format\n\nMemories are stored as markdown files in `~/.openclaw/memories/`:\n\n```\n~/.openclaw/memories/\n├── facts/\n│   └── abc123-def4-5678-90ab-cdef12345678.md\n├── preferences/\n│   └── def456-7890-abcd-ef12-345678901234.md\n├── instructions/\n│   └── ghi789-0abc-def1-2345-678901234567.md\n└── .deleted/\n    └── old-memory.md\n```\n\nEach memory file contains YAML frontmatter with metadata:\n\n```markdown\n---\nid: abc123-def4-5678-90ab-cdef12345678\ncategory: preference\nconfidence: 0.9\nimportance: 0.7\ncreated_at: 2024-01-15T10:30:00Z\ntags: [ui, settings]\n---\n\nUser prefers dark mode in all applications.\n```\n\n## Memory Categories\n\n| Category | Use For | Example |\n|----------|---------|---------|\n| `fact` | Static information | \"User's dog is named Rex\" |\n| `preference` | Likes/dislikes | \"User prefers dark mode\" |\n| `event` | Temporal things | \"Dentist appointment Tuesday 3pm\" |\n| `relationship` | People connections | \"User's sister is Sarah\" |\n| `context` | Current work | \"Working on React project\" |\n| `instruction` | Standing orders | \"Always respond in Spanish\" |\n| `decision` | Choices made | \"We decided to use PostgreSQL\" |\n| `entity` | Contact info | \"User's email is x@y.com\" |\n\n## Tool Reference\n\n### memory_store\n\nStore a new memory.\n\n```typescript\nmemory_store({\n  content: \"User prefers bullet points\",\n  category: \"preference\",\n  confidence: 0.9,      // How sure (0-1)\n  importance: 0.7,      // How critical (0-1)\n  decayDays: null,      // null = permanent\n  tags: [\"formatting\"]\n})\n```\n\n### memory_update\n\nUpdate an existing memory.\n\n```typescript\nmemory_update({\n  id: \"abc-123\",\n  content: \"User prefers numbered lists\",  // Optional\n  confidence: 0.95                          // Optional\n})\n```\n\n### memory_forget\n\nDelete a memory.\n\n```typescript\nmemory_forget({\n  id: \"abc-123\",           // If known\n  query: \"bullet points\",  // Or search\n  reason: \"User corrected\"\n})\n```\n\n### memory_search\n\nSemantic search (uses QMD if installed, otherwise basic filtering).\n\n```typescript\nmemory_search({\n  query: \"formatting preferences\",\n  category: \"preference\",      // Optional filter\n  minConfidence: 0.7,          // Optional filter\n  limit: 10\n})\n```\n\n### memory_summarize\n\nGet topic summary.\n\n```typescript\nmemory_summarize({\n  topic: \"user's work\",\n  maxMemories: 20\n})\n```\n\n### memory_list\n\nBrowse all memories.\n\n```typescript\nmemory_list({\n  category: \"instruction\",\n  sortBy: \"importance\",\n  limit: 20\n})\n```\n\n## CLI Commands\n\n```bash\n# Show statistics\nopenclaw memory-tools stats\n\n# List memories\nopenclaw memory-tools list --category preference\n\n# Search memories (uses QMD if installed)\nopenclaw memory-tools search \"dark mode\"\n\n# Export all memories as JSON\nopenclaw memory-tools export\n\n# Force re-index with QMD\nopenclaw memory-tools reindex\n\n# Show storage path\nopenclaw memory-tools path\n```\n\n## Debugging\n\nMemories are plain markdown files - just read them:\n\n```bash\ncat ~/.openclaw/memories/facts/*.md\nls ~/.openclaw/memories/\n```\n\nExport all memories:\n\n```bash\nopenclaw memory-tools export > memories.json\n```\n\n## Architecture\n\n```\n┌─────────────────────────────────────────────────────────┐\n│                    OpenClaw Agent                       │\n│                                                         │\n│  Agent decides: \"This is worth remembering\"             │\n│         ↓                                               │\n│  Calls: memory_store(...)                               │\n└─────────────────────────────────────────────────────────┘\n                          ↓\n┌─────────────────────────────────────────────────────────┐\n│                   Memory Tools                          │\n├─────────────────────────────────────────────────────────┤\n│  store │ update │ forget │ search │ summarize │ list   │\n└─────────────────────────────────────────────────────────┘\n                          ↓\n┌─────────────────────────────────────────────────────────┐\n│                 Storage Layer                           │\n│  ┌──────────────────────────────────────────────────┐  │\n│  │           Markdown Files (YAML frontmatter)       │  │\n│  │           ~/.openclaw/memories/{category}/*.md    │  │\n│  └──────────────────────────────────────────────────┘  │\n│                          ↓                              │\n│  ┌──────────────────────────────────────────────────┐  │\n│  │        QMD Search (optional)                      │  │\n│  │        BM25 + Vector + Reranking                  │  │\n│  └──────────────────────────────────────────────────┘  │\n└─────────────────────────────────────────────────────────┘\n```\n\n## Migration from v1\n\nv2 automatically detects v1 databases and migrates them:\n\n1. On startup, v2 checks for `~/.openclaw/memory/tools/memory.db`\n2. If found, exports all memories to markdown files\n3. Original database preserved as backup\n4. No manual action required\n\nTo disable auto-migration, set `\"autoMigrateLegacy\": false` in plugin config.\n\n## Development\n\n```bash\n# Install dependencies\nnpm install\n\n# Run tests\nnpm test\n\n# Run tests with coverage\nnpm test:coverage\n\n# Type check\nnpm run typecheck\n\n# Build\nnpm run build\n```\n\n### Environment Variables\n\n- `MEMORY_TOOLS_DISABLE_QMD=true` - Disable QMD for testing\n\nNo environment variables are required for credentials.\n\n## Comparison with Other Memory Systems\n\n| Feature | [memU](https://github.com/NevaMind-AI/memU) | [claude-mem](https://github.com/thedotmack/claude-mem) | **memory-tools** |\n|---------|------|------------|--------------|\n| **Architecture** | 3-tier hierarchical (Resource -> Item -> Category) | Hook-based observer with lifecycle events | Tool-based agent control |\n| **Storage Trigger** | Automatic extraction during background processing | Lifecycle hooks (SessionStart, PostToolUse, etc.) | Agent explicitly decides when to store |\n| **Storage Backend** | Custom hierarchical | Custom | Markdown files + optional QMD |\n| **External APIs** | Varies | Varies | None required |\n| **Conflict Handling** | None - relies on proactive pattern detection | None - auto-capture model | Auto-supersede + explicit forget |\n| **Context Injection** | Proactive - predicts and pre-loads context | Progressive disclosure (3-layer filtering) | On-demand via memory_search |\n| **Token Efficiency** | Compression via fact extraction | ~10x savings via progressive disclosure | Semantic search with configurable limits |\n| **Auditability** | Background processing | Hook-based capture | Human-readable markdown files |\n| **User Corrections** | Accumulates conflicting facts | Accumulates conflicting facts | Replaces old with new automatically |\n| **Best For** | 24/7 agents with predictable patterns | Automatic session continuity | Personal assistants with ongoing relationships |\n\n### Design Philosophy\n\nDifferent memory systems optimize for different things:\n\n- **Automatic systems** (memU, claude-mem) minimize agent cognitive load by extracting memories in the background. Trade-off: less control over what's captured, conflicts accumulate.\n\n- **Agent-controlled systems** (memory-tools) put the agent in charge of what matters. Trade-off: requires active management, but memories are deliberate choices.\n\nFor agents that maintain ongoing relationships with users - where someone might say \"no, my favorite color is purple, not blue\" - explicit conflict handling prevents contradictory memories from accumulating. Every memory has a clear provenance: the agent decided it was worth remembering, and corrections replace rather than compete with old information.\n\nThe file-based storage means you can always `ls ~/.openclaw/memories/` and read exactly what your agent knows. Each memory is a plain markdown file you can edit, delete, or backup.\n\n## References\n\n- [AgeMem Paper](https://arxiv.org/abs/2409.02634) - Memory operations as first-class tools\n- [QMD](https://github.com/tobilu/qmd) - Local hybrid search with GGUF models\n- [memU](https://github.com/NevaMind-AI/memU) - Hierarchical memory with proactive context\n- [claude-mem](https://github.com/thedotmack/claude-mem) - Hook-based automatic memory\n- [Mem0](https://github.com/mem0ai/mem0) - AI memory layer\n- [OpenClaw](https://github.com/openclaw/openclaw) - Personal AI assistant\n\n## License\n\nMIT - [Purple Horizons](https://github.com/Purple-Horizons)\n\nFile v2.0.3:_meta.json\n\n{\n  \"ownerId\": \"kn7ajybsnj998tbfcgvrc7731s803brp\",\n  \"slug\": \"memory-tools\",\n  \"version\": \"2.0.3\",\n  \"publishedAt\": 1771440795745\n}\n\nFile v2.0.3:CLAUDE.md\n\n# CLAUDE.md\n\nProject context for Claude Code.\n\n## Project\n\n**memory-tools v2** - Agent-controlled memory plugin for OpenClaw/ClawHub.\n\n- **Repo**: `Purple-Horizons/memory-tools`\n- **ClawHub slug**: `memory-tools`\n- **Owner**: gianni-dalerta\n\n## Architecture (v2)\n\n- **File-based storage** - Memories stored as markdown files with YAML frontmatter\n- **QMD search** - Optional BM25 + vector + reranking via local GGUF models\n- **No external APIs** - No OpenAI dependency, everything runs locally\n- **Auto-migration** - Seamlessly upgrades from v1 SQLite/LanceDB storage\n\n### Storage Structure\n```\n~/.openclaw/memories/\n├── facts/\n│   └── abc123.md\n├── preferences/\n│   └── def456.md\n├── instructions/\n│   └── ghi789.md\n└── .deleted/\n    └── old-memory.md\n```\n\n### Memory File Format\n```markdown\n---\nid: abc123-def4-5678-90ab-cdef12345678\ncategory: preference\nconfidence: 0.9\nimportance: 0.7\ncreated_at: 2024-01-15T10:30:00Z\ntags: [ui, settings]\n---\n\nUser prefers dark mode in all applications.\n```\n\n## Key Decisions\n\n- **v2 rewrote storage layer**: Switched from SQLite + LanceDB + OpenAI to file-based + QMD\n- **QMD is optional**: Works without QMD (basic file listing), better search with QMD installed\n- **Auto-migration**: v2 detects v1 databases and automatically exports to markdown files\n- **Backward compatible API**: Tools interface unchanged, existing integrations work\n\n## QMD Integration\n\nQMD provides hybrid search (BM25 + vector + reranking) using local GGUF models:\n- `npm install -g @tobilu/qmd` to install\n- Models download on first use (~2GB total)\n- Without QMD: basic category/tag filtering only\n- With QMD: semantic search across all memories\n\n## Publishing to ClawHub\n\n```bash\nclawhub publish . --slug memory-tools --version X.Y.Z --changelog \"description\"\n```\n\nAlways use `--slug memory-tools` to update the correct skill.\n\n## Build & Test\n\n```bash\nnpm run build    # TypeScript compile\nnpm test         # Run vitest (uses MEMORY_TOOLS_DISABLE_QMD=true in CI)\n```\n\n## Environment Variables\n\n- `MEMORY_TOOLS_DISABLE_QMD=true` - Disable QMD for testing\n\nFile v2.0.3:clawdbot.plugin.json\n\n{\n  \"id\": \"memory-tools\",\n  \"kind\": \"memory\",\n  \"name\": \"Memory Tools\",\n  \"description\": \"Agent-controlled memory with file-based storage and optional QMD search. No external APIs required.\",\n  \"version\": \"2.0.3\",\n  \"uiHints\": {\n    \"memoriesPath\": {\n      \"label\": \"Memories Path\",\n      \"placeholder\": \"~/.clawdbot/memories\",\n      \"advanced\": true,\n      \"help\": \"Directory for storing memory files\"\n    },\n    \"autoInjectInstructions\": {\n      \"label\": \"Auto-Inject Instructions\",\n      \"help\": \"Inject standing instructions (category='instruction') at conversation start\"\n    },\n    \"autoMigrateLegacy\": {\n      \"label\": \"Auto-Migrate Legacy DB\",\n      \"advanced\": true,\n      \"help\": \"Automatically migrate v1 database to markdown files on startup\"\n    },\n    \"qmdCollection\": {\n      \"label\": \"QMD Collection\",\n      \"advanced\": true,\n      \"help\": \"QMD collection name for semantic search index\"\n    }\n  },\n  \"configSchema\": {\n    \"type\": \"object\",\n    \"additionalProperties\": false,\n    \"properties\": {\n      \"memoriesPath\": {\n        \"type\": \"string\",\n        \"description\": \"Directory for storing memory markdown files\"\n      },\n      \"autoInjectInstructions\": {\n        \"type\": \"boolean\",\n        \"default\": true\n      },\n      \"autoMigrateLegacy\": {\n        \"type\": \"boolean\",\n        \"default\": true\n      },\n      \"qmdCollection\": {\n        \"type\": \"string\",\n        \"default\": \"memories\"\n      }\n    }\n  }\n}\n\nFile v2.0.3:openclaw.plugin.json\n\n{\n  \"id\": \"memory-tools\",\n  \"kind\": \"memory\",\n  \"name\": \"Memory Tools\",\n  \"description\": \"Agent-controlled memory with file-based storage and optional QMD search. No external APIs required.\",\n  \"version\": \"2.0.3\",\n  \"uiHints\": {\n    \"memoriesPath\": {\n      \"label\": \"Memories Path\",\n      \"placeholder\": \"~/.openclaw/memories\",\n      \"advanced\": true,\n      \"help\": \"Directory for storing memory files\"\n    },\n    \"autoInjectInstructions\": {\n      \"label\": \"Auto-Inject Instructions\",\n      \"help\": \"Inject standing instructions (category='instruction') at conversation start\"\n    },\n    \"autoMigrateLegacy\": {\n      \"label\": \"Auto-Migrate Legacy DB\",\n      \"advanced\": true,\n      \"help\": \"Automatically migrate v1 database to markdown files on startup\"\n    },\n    \"qmdCollection\": {\n      \"label\": \"QMD Collection\",\n      \"advanced\": true,\n      \"help\": \"QMD collection name for semantic search index\"\n    }\n  },\n  \"configSchema\": {\n    \"type\": \"object\",\n    \"additionalProperties\": false,\n    \"properties\": {\n      \"memoriesPath\": {\n        \"type\": \"string\",\n        \"description\": \"Directory for storing memory markdown files\"\n      },\n      \"autoInjectInstructions\": {\n        \"type\": \"boolean\",\n        \"default\": true\n      },\n      \"autoMigrateLegacy\": {\n        \"type\": \"boolean\",\n        \"default\": true\n      },\n      \"qmdCollection\": {\n        \"type\": \"string\",\n        \"default\": \"memories\"\n      }\n    }\n  }\n}\n\nFile v2.0.3:package-lock.json\n\n{\n  \"name\": \"memory-tools\",\n  \"version\": \"2.0.3\",\n  \"lockfileVersion\": 3,\n  \"requires\": true,\n  \"packages\": {\n    \"\": {\n      \"name\": \"memory-tools\",\n      \"version\": \"2.0.3\",\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"@sinclair/typebox\": \"0.34.48\",\n        \"sql.js\": \"^1.13.0\"\n      },\n      \"devDependencies\": {\n        \"@types/node\": \"^22.0.0\",\n        \"@types/sql.js\": \"^1.4.9\",\n        \"@vitest/coverage-v8\": \"^2.1.0\",\n        \"typescript\": \"^5.7.0\",\n        \"vitest\": \"^2.1.0\"\n      },\n      \"peerDependencies\": {\n        \"openclaw\": \">=2026.0.0\"\n      },\n      \"peerDependenciesMeta\": {\n        \"openclaw\": {\n          \"optional\": true\n        }\n      }\n    },\n    \"node_modules/@ampproject/remapping\": {\n      \"version\": \"2.3.0\",\n      \"dev\": true,\n      \"license\": \"Apache-2.0\",\n      \"dependencies\": {\n        \"@jridgewell/gen-mapping\": \"^0.3.5\",\n        \"@jridgewell/trace-mapping\": \"^0.3.24\"\n      },\n      \"engines\": {\n        \"node\": \">=6.0.0\"\n      }\n    },\n    \"node_modules/@babel/helper-string-parser\": {\n      \"version\": \"7.27.1\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">=6.9.0\"\n      }\n    },\n    \"node_modules/@babel/helper-validator-identifier\": {\n      \"version\": \"7.28.5\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">=6.9.0\"\n      }\n    },\n    \"node_modules/@babel/parser\": {\n      \"version\": \"7.29.0\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"@babel/types\": \"^7.29.0\"\n      },\n      \"bin\": {\n        \"parser\": \"bin/babel-parser.js\"\n      },\n      \"engines\": {\n        \"node\": \">=6.0.0\"\n      }\n    },\n    \"node_modules/@babel/types\": {\n      \"version\": \"7.29.0\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"@babel/helper-string-parser\": \"^7.27.1\",\n        \"@babel/helper-validator-identifier\": \"^7.28.5\"\n      },\n      \"engines\": {\n        \"node\": \">=6.9.0\"\n      }\n    },\n    \"node_modules/@bcoe/v8-coverage\": {\n      \"version\": \"0.2.3\",\n      \"dev\": true,\n      \"license\": \"MIT\"\n    },\n    \"node_modules/@esbuild/darwin-arm64\": {\n      \"version\": \"0.21.5\",\n      \"cpu\": [\n        \"arm64\"\n      ],\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"optional\": true,\n      \"os\": [\n        \"darwin\"\n      ],\n      \"engines\": {\n        \"node\": \">=12\"\n      }\n    },\n    \"node_modules/@isaacs/cliui\": {\n      \"version\": \"8.0.2\",\n      \"dev\": true,\n      \"license\": \"ISC\",\n      \"dependencies\": {\n        \"string-width\": \"^5.1.2\",\n        \"string-width-cjs\": \"npm:string-width@^4.2.0\",\n        \"strip-ansi\": \"^7.0.1\",\n        \"strip-ansi-cjs\": \"npm:strip-ansi@^6.0.1\",\n        \"wrap-ansi\": \"^8.1.0\",\n        \"wrap-ansi-cjs\": \"npm:wrap-ansi@^7.0.0\"\n      },\n      \"engines\": {\n        \"node\": \">=12\"\n      }\n    },\n    \"node_modules/@istanbuljs/schema\": {\n      \"version\": \"0.1.3\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">=8\"\n      }\n    },\n    \"node_modules/@jridgewell/gen-mapping\": {\n      \"version\": \"0.3.13\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"@jridgewell/sourcemap-codec\": \"^1.5.0\",\n        \"@jridgewell/trace-mapping\": \"^0.3.24\"\n      }\n    },\n    \"node_modules/@jridgewell/resolve-uri\": {\n      \"version\": \"3.1.2\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">=6.0.0\"\n      }\n    },\n    \"node_modules/@jridgewell/sourcemap-codec\": {\n      \"version\": \"1.5.5\",\n      \"dev\": true,\n      \"license\": \"MIT\"\n    },\n    \"node_modules/@jridgewell/trace-mapping\": {\n      \"version\": \"0.3.31\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"@jridgewell/resolve-uri\": \"^3.1.0\",\n        \"@jridgewell/sourcemap-codec\": \"^1.4.14\"\n      }\n    },\n    \"node_modules/@pkgjs/parseargs\": {\n      \"version\": \"0.11.0\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"optional\": true,\n      \"engines\": {\n        \"node\": \">=14\"\n      }\n    },\n    \"node_modules/@rollup/rollup-darwin-arm64\": {\n      \"version\": \"4.57.1\",\n      \"cpu\": [\n        \"arm64\"\n      ],\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"optional\": true,\n      \"os\": [\n        \"darwin\"\n      ]\n    },\n    \"node_modules/@sinclair/typebox\": {\n      \"version\": \"0.34.48\",\n      \"license\": \"MIT\"\n    },\n    \"node_modules/@types/emscripten\": {\n      \"version\": \"1.41.5\",\n      \"dev\": true,\n      \"license\": \"MIT\"\n    },\n    \"node_modules/@types/estree\": {\n      \"version\": \"1.0.8\",\n      \"dev\": true,\n      \"license\": \"MIT\"\n    },\n    \"node_modules/@types/node\": {\n      \"version\": \"22.19.10\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"undici-types\": \"~6.21.0\"\n      }\n    },\n    \"node_modules/@types/sql.js\": {\n      \"version\": \"1.4.9\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"@types/emscripten\": \"*\",\n        \"@types/node\": \"*\"\n      }\n    },\n    \"node_modules/@vitest/coverage-v8\": {\n      \"version\": \"2.1.9\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"@ampproject/remapping\": \"^2.3.0\",\n        \"@bcoe/v8-coverage\": \"^0.2.3\",\n        \"debug\": \"^4.3.7\",\n        \"istanbul-lib-coverage\": \"^3.2.2\",\n        \"istanbul-lib-report\": \"^3.0.1\",\n        \"istanbul-lib-source-maps\": \"^5.0.6\",\n        \"istanbul-reports\": \"^3.1.7\",\n        \"magic-string\": \"^0.30.12\",\n        \"magicast\": \"^0.3.5\",\n        \"std-env\": \"^3.8.0\",\n        \"test-exclude\": \"^7.0.1\",\n        \"tinyrainbow\": \"^1.2.0\"\n      },\n      \"funding\": {\n        \"url\": \"https://opencollective.com/vitest\"\n      },\n      \"peerDependencies\": {\n        \"@vitest/browser\": \"2.1.9\",\n        \"vitest\": \"2.1.9\"\n      },\n      \"peerDependenciesMeta\": {\n        \"@vitest/browser\": {\n          \"optional\": true\n        }\n      }\n    },\n    \"node_modules/@vitest/expect\": {\n      \"version\": \"2.1.9\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"@vitest/spy\": \"2.1.9\",\n        \"@vitest/utils\": \"2.1.9\",\n        \"chai\": \"^5.1.2\",\n        \"tinyrainbow\": \"^1.2.0\"\n      },\n      \"funding\": {\n        \"url\": \"https://opencollective.com/vitest\"\n      }\n    },\n    \"node_modules/@vitest/mocker\": {\n      \"version\": \"2.1.9\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"@vitest/spy\": \"2.1.9\",\n        \"estree-walker\": \"^3.0.3\",\n        \"magic-string\": \"^0.30.12\"\n      },\n      \"funding\": {\n        \"url\": \"https://opencollective.com/vitest\"\n      },\n      \"peerDependencies\": {\n        \"msw\": \"^2.4.9\",\n        \"vite\": \"^5.0.0\"\n      },\n      \"peerDependenciesMeta\": {\n        \"msw\": {\n          \"optional\": true\n        },\n        \"vite\": {\n          \"optional\": true\n        }\n      }\n    },\n    \"node_modules/@vitest/pretty-format\": {\n      \"version\": \"2.1.9\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"tinyrainbow\": \"^1.2.0\"\n      },\n      \"funding\": {\n        \"url\": \"https://opencollective.com/vitest\"\n      }\n    },\n    \"node_modules/@vitest/runner\": {\n      \"version\": \"2.1.9\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"@vitest/utils\": \"2.1.9\",\n        \"pathe\": \"^1.1.2\"\n      },\n      \"funding\": {\n        \"url\": \"https://opencollective.com/vitest\"\n      }\n    },\n    \"node_modules/@vitest/snapshot\": {\n      \"version\": \"2.1.9\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"@vitest/pretty-format\": \"2.1.9\",\n        \"magic-string\": \"^0.30.12\",\n        \"pathe\": \"^1.1.2\"\n      },\n      \"funding\": {\n        \"url\": \"https://opencollective.com/vitest\"\n      }\n    },\n    \"node_modules/@vitest/spy\": {\n      \"version\": \"2.1.9\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"tinyspy\": \"^3.0.2\"\n      },\n      \"funding\": {\n        \"url\": \"https://opencollective.com/vitest\"\n      }\n    },\n    \"node_modules/@vitest/utils\": {\n      \"version\": \"2.1.9\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"@vitest/pretty-format\": \"2.1.9\",\n        \"loupe\": \"^3.1.2\",\n        \"tinyrainbow\": \"^1.2.0\"\n      },\n      \"funding\": {\n        \"url\": \"https://opencollective.com/vitest\"\n      }\n    },\n    \"node_modules/ansi-regex\": {\n      \"version\": \"6.2.2\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">=12\"\n      },\n      \"funding\": {\n        \"url\": \"https://github.com/chalk/ansi-regex?sponsor=1\"\n      }\n    },\n    \"node_modules/ansi-styles\": {\n      \"version\": \"4.3.0\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"color-convert\": \"^2.0.1\"\n      },\n      \"engines\": {\n        \"node\": \">=8\"\n      },\n      \"funding\": {\n        \"url\": \"https://github.com/chalk/ansi-styles?sponsor=1\"\n      }\n    },\n    \"node_modules/assertion-error\": {\n      \"version\": \"2.0.1\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">=12\"\n      }\n    },\n    \"node_modules/balanced-match\": {\n      \"version\": \"1.0.2\",\n      \"dev\": true,\n      \"license\": \"MIT\"\n    },\n    \"node_modules/brace-expansion\": {\n      \"version\": \"2.0.2\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"balanced-match\": \"^1.0.0\"\n      }\n    },\n    \"node_modules/cac\": {\n      \"version\": \"6.7.14\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">=8\"\n      }\n    },\n    \"node_modules/chai\": {\n      \"version\": \"5.3.3\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"assertion-error\": \"^2.0.1\",\n        \"check-error\": \"^2.1.1\",\n        \"deep-eql\": \"^5.0.1\",\n        \"loupe\": \"^3.1.0\",\n        \"pathval\": \"^2.0.0\"\n      },\n      \"engines\": {\n        \"node\": \">=18\"\n      }\n    },\n    \"node_modules/check-error\": {\n      \"version\": \"2.1.3\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">= 16\"\n      }\n    },\n    \"node_modules/color-convert\": {\n      \"version\": \"2.0.1\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"color-name\": \"~1.1.4\"\n      },\n      \"engines\": {\n        \"node\": \">=7.0.0\"\n      }\n    },\n    \"node_modules/color-name\": {\n      \"version\": \"1.1.4\",\n      \"dev\": true,\n      \"license\": \"MIT\"\n    },\n    \"node_modules/cross-spawn\": {\n      \"version\": \"7.0.6\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"path-key\": \"^3.1.0\",\n        \"shebang-command\": \"^2.0.0\",\n        \"which\": \"^2.0.1\"\n      },\n      \"engines\": {\n        \"node\": \">= 8\"\n      }\n    },\n    \"node_modules/debug\": {\n      \"version\": \"4.4.3\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"ms\": \"^2.1.3\"\n      },\n      \"engines\": {\n        \"node\": \">=6.0\"\n      },\n      \"peerDependenciesMeta\": {\n        \"supports-color\": {\n          \"optional\": true\n        }\n      }\n    },\n    \"node_modules/deep-eql\": {\n      \"version\": \"5.0.2\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">=6\"\n      }\n    },\n    \"node_modules/eastasianwidth\": {\n      \"version\": \"0.2.0\",\n      \"dev\": true,\n      \"license\": \"MIT\"\n    },\n    \"node_modules/emoji-regex\": {\n      \"version\": \"9.2.2\",\n      \"dev\": true,\n      \"license\": \"MIT\"\n    },\n    \"node_modules/es-module-lexer\": {\n      \"version\": \"1.7.0\",\n      \"dev\": true,\n      \"license\": \"MIT\"\n    },\n    \"node_modules/esbuild\": {\n      \"version\": \"0.21.5\",\n      \"dev\": true,\n      \"hasInstallScript\": true,\n      \"license\": \"MIT\",\n      \"bin\": {\n        \"esbuild\": \"bin/esbuild\"\n      },\n      \"engines\": {\n        \"node\": \">=12\"\n      },\n      \"optionalDependencies\": {\n        \"@esbuild/aix-ppc64\": \"0.21.5\",\n        \"@esbuild/android-arm\": \"0.21.5\",\n        \"@esbuild/android-arm64\": \"0.21.5\",\n        \"@esbuild/android-x64\": \"0.21.5\",\n        \"@esbuild/darwin-arm64\": \"0.21.5\",\n        \"@esbuild/darwin-x64\": \"0.21.5\",\n        \"@esbuild/freebsd-arm64\": \"0.21.5\",\n        \"@esbuild/freebsd-x64\": \"0.21.5\",\n        \"@esbuild/linux-arm\": \"0.21.5\",\n        \"@esbuild/linux-arm64\": \"0.21.5\",\n        \"@esbuild/linux-ia32\": \"0.21.5\",\n        \"@esbuild/linux-loong64\": \"0.21.5\",\n        \"@esbuild/linux-mips64el\": \"0.21.5\",\n        \"@esbuild/linux-ppc64\": \"0.21.5\",\n        \"@esbuild/linux-riscv64\": \"0.21.5\",\n        \"@esbuild/linux-s390x\": \"0.21.5\",\n        \"@esbuild/linux-x64\": \"0.21.5\",\n        \"@esbuild/netbsd-x64\": \"0.21.5\",\n        \"@esbuild/openbsd-x64\": \"0.21.5\",\n        \"@esbuild/sunos-x64\": \"0.21.5\",\n        \"@esbuild/win32-arm64\": \"0.21.5\",\n        \"@esbuild/win32-ia32\": \"0.21.5\",\n        \"@esbuild/win32-x64\": \"0.21.5\"\n      }\n    },\n    \"node_modules/estree-walker\": {\n      \"version\": \"3.0.3\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"@types/estree\": \"^1.0.0\"\n      }\n    },\n    \"node_modules/expect-type\": {\n      \"version\": \"1.3.0\",\n      \"dev\": true,\n      \"license\": \"Apache-2.0\",\n      \"engines\": {\n        \"node\": \">=12.0.0\"\n      }\n    },\n    \"node_modules/foreground-child\": {\n      \"version\": \"3.3.1\",\n      \"dev\": true,\n      \"license\": \"ISC\",\n      \"dependencies\": {\n        \"cross-spawn\": \"^7.0.6\",\n        \"signal-exit\": \"^4.0.1\"\n      },\n      \"engines\": {\n        \"node\": \">=14\"\n      },\n      \"funding\": {\n        \"url\": \"https://github.com/sponsors/isaacs\"\n      }\n    },\n    \"node_modules/fsevents\": {\n      \"version\": \"2.3.3\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"optional\": true,\n      \"os\": [\n        \"darwin\"\n      ],\n      \"engines\": {\n        \"node\": \"^8.16.0 || ^10.6.0 || >=11.0.0\"\n      }\n    },\n    \"node_modules/glob\": {\n      \"version\": \"10.5.0\",\n      \"dev\": true,\n      \"license\": \"ISC\",\n      \"dependencies\": {\n        \"foreground-child\": \"^3.1.0\",\n        \"jackspeak\": \"^3.1.2\",\n        \"minimatch\": \"^9.0.4\",\n        \"minipass\": \"^7.1.2\",\n        \"package-json-from-dist\": \"^1.0.0\",\n        \"path-scurry\": \"^1.11.1\"\n      },\n      \"bin\": {\n        \"glob\": \"dist/esm/bin.mjs\"\n      },\n      \"funding\": {\n        \"url\": \"https://github.com/sponsors/isaacs\"\n      }\n    },\n    \"node_modules/has-flag\": {\n      \"version\": \"4.0.0\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">=8\"\n      }\n    },\n    \"node_modules/html-escaper\": {\n      \"version\": \"2.0.2\",\n      \"dev\": true,\n      \"license\": \"MIT\"\n    },\n    \"node_modules/is-fullwidth-code-point\": {\n      \"version\": \"3.0.0\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">=8\"\n      }\n    },\n    \"node_modules/isexe\": {\n      \"version\": \"2.0.0\",\n      \"dev\": true,\n      \"license\": \"ISC\"\n    },\n    \"node_modules/istanbul-lib-coverage\": {\n      \"version\": \"3.2.2\",\n      \"dev\": true,\n      \"license\": \"BSD-3-Clause\",\n      \"engines\": {\n        \"node\": \">=8\"\n      }\n    },\n    \"node_modules/istanbul-lib-report\": {\n      \"version\": \"3.0.1\",\n      \"dev\": true,\n      \"license\": \"BSD-3-Clause\",\n      \"dependencies\": {\n        \"istanbul-lib-coverage\": \"^3.0.0\",\n        \"make-dir\": \"^4.0.0\",\n        \"supports-color\": \"^7.1.0\"\n      },\n      \"engines\": {\n        \"node\": \">=10\"\n      }\n    },\n    \"node_modules/istanbul-lib-source-maps\": {\n      \"version\": \"5.0.6\",\n      \"dev\": true,\n      \"license\": \"BSD-3-Clause\",\n      \"dependencies\": {\n        \"@jridgewell/trace-mapping\": \"^0.3.23\",\n        \"debug\": \"^4.1.1\",\n        \"istanbul-lib-coverage\": \"^3.0.0\"\n      },\n      \"engines\": {\n        \"node\": \">=10\"\n      }\n    },\n    \"node_modules/istanbul-reports\": {\n      \"version\": \"3.2.0\",\n      \"dev\": true,\n      \"license\": \"BSD-3-Clause\",\n      \"dependencies\": {\n        \"html-escaper\": \"^2.0.0\",\n        \"istanbul-lib-report\": \"^3.0.0\"\n      },\n      \"engines\": {\n        \"node\": \">=8\"\n      }\n    },\n    \"node_modules/jackspeak\": {\n      \"version\": \"3.4.3\",\n      \"dev\": true,\n      \"license\": \"BlueOak-1.0.0\",\n      \"dependencies\": {\n        \"@isaacs/cliui\": \"^8.0.2\"\n      },\n      \"funding\": {\n        \"url\": \"https://github.com/sponsors/isaacs\"\n      },\n      \"optionalDependencies\": {\n        \"@pkgjs/parseargs\": \"^0.11.0\"\n      }\n    },\n    \"node_modules/loupe\": {\n      \"version\": \"3.2.1\",\n      \"dev\": true,\n      \"license\": \"MIT\"\n    },\n    \"node_modules/lru-cache\": {\n      \"version\": \"10.4.3\",\n      \"dev\": true,\n      \"license\": \"ISC\"\n    },\n    \"node_modules/magic-string\": {\n      \"version\": \"0.30.21\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"@jridgewell/sourcemap-codec\": \"^1.5.5\"\n      }\n    },\n    \"node_modules/magicast\": {\n      \"version\": \"0.3.5\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"@babel/parser\": \"^7.25.4\",\n        \"@babel/types\": \"^7.25.4\",\n        \"source-map-js\": \"^1.2.0\"\n      }\n    },\n    \"node_modules/make-dir\": {\n      \"version\": \"4.0.0\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"semver\": \"^7.5.3\"\n      },\n      \"engines\": {\n        \"node\": \">=10\"\n      },\n      \"funding\": {\n        \"url\": \"https://github.com/sponsors/sindresorhus\"\n      }\n    },\n    \"node_modules/minimatch\": {\n      \"version\": \"9.0.5\",\n      \"dev\": true,\n      \"license\": \"ISC\",\n      \"dependencies\": {\n        \"brace-expansion\": \"^2.0.1\"\n      },\n      \"engines\": {\n        \"node\": \">=16 || 14 >=14.17\"\n      },\n      \"funding\": {\n        \"url\": \"https://github.com/sponsors/isaacs\"\n      }\n    },\n    \"node_modules/minipass\": {\n      \"version\": \"7.1.2\",\n      \"dev\": true,\n      \"license\": \"ISC\",\n      \"engines\": {\n        \"node\": \">=16 || 14 >=14.17\"\n      }\n    },\n    \"node_modules/ms\": {\n      \"version\": \"2.1.3\",\n      \"dev\": true,\n      \"license\": \"MIT\"\n    },\n    \"node_modules/nanoid\": {\n      \"version\": \"3.3.11\",\n      \"dev\": true,\n      \"funding\": [\n        {\n          \"type\": \"github\",\n          \"url\": \"https://github.com/sponsors/ai\"\n        }\n      ],\n      \"license\": \"MIT\",\n      \"bin\": {\n        \"nanoid\": \"bin/nanoid.cjs\"\n      },\n      \"engines\": {\n        \"node\": \"^10 || ^12 || ^13.7 || ^14 || >=15.0.1\"\n      }\n    },\n    \"node_modules/package-json-from-dist\": {\n      \"version\": \"1.0.1\",\n      \"dev\": true,\n      \"license\": \"BlueOak-1.0.0\"\n    },\n    \"node_modules/path-key\": {\n      \"version\": \"3.1.1\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">=8\"\n      }\n    },\n    \"node_modules/path-scurry\": {\n      \"version\": \"1.11.1\",\n      \"dev\": true,\n      \"license\": \"BlueOak-1.0.0\",\n      \"dependencies\": {\n        \"lru-cache\": \"^10.2.0\",\n        \"minipass\": \"^5.0.0 || ^6.0.2 || ^7.0.0\"\n      },\n      \"engines\": {\n        \"node\": \">=16 || 14 >=14.18\"\n      },\n      \"funding\": {\n        \"url\": \"https://github.com/sponsors/isaacs\"\n      }\n    },\n    \"node_modules/pathe\": {\n      \"version\": \"1.1.2\",\n      \"dev\": true,\n      \"license\": \"MIT\"\n    },\n    \"node_modules/pathval\": {\n      \"version\": \"2.0.1\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">= 14.16\"\n      }\n    },\n    \"node_modules/picocolors\": {\n      \"version\": \"1.1.1\",\n      \"dev\": true,\n      \"license\": \"ISC\"\n    },\n    \"node_modules/postcss\": {\n      \"version\": \"8.5.6\",\n      \"dev\": true,\n      \"funding\": [\n        {\n          \"type\": \"opencollective\",\n          \"url\": \"https://opencollective.com/postcss/\"\n        },\n        {\n          \"type\": \"tidelift\",\n          \"url\": \"https://tidelift.com/funding/github/npm/postcss\"\n        },\n        {\n          \"type\": \"github\",\n          \"url\": \"https://github.com/sponsors/ai\"\n        }\n      ],\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"nanoid\": \"^3.3.11\",\n        \"picocolors\": \"^1.1.1\",\n        \"source-map-js\": \"^1.2.1\"\n      },\n      \"engines\": {\n        \"node\": \"^10 || ^12 || >=14\"\n      }\n    },\n    \"node_modules/rollup\": {\n      \"version\": \"4.57.1\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"@types/estree\": \"1.0.8\"\n      },\n      \"bin\": {\n        \"rollup\": \"dist/bin/rollup\"\n      },\n      \"engines\": {\n        \"node\": \">=18.0.0\",\n        \"npm\": \">=8.0.0\"\n      },\n      \"optionalDependencies\": {\n        \"@rollup/rollup-android-arm-eabi\": \"4.57.1\",\n        \"@rollup/rollup-android-arm64\": \"4.57.1\",\n        \"@rollup/rollup-darwin-arm64\": \"4.57.1\",\n        \"@rollup/rollup-darwin-x64\": \"4.57.1\",\n        \"@rollup/rollup-freebsd-arm64\": \"4.57.1\",\n        \"@rollup/rollup-freebsd-x64\": \"4.57.1\",\n        \"@rollup/rollup-linux-arm-gnueabihf\": \"4.57.1\",\n        \"@rollup/rollup-linux-arm-musleabihf\": \"4.57.1\",\n        \"@rollup/rollup-linux-arm64-gnu\": \"4.57.1\",\n        \"@rollup/rollup-linux-arm64-musl\": \"4.57.1\",\n        \"@rollup/rollup-linux-loong64-gnu\": \"4.57.1\",\n        \"@rollup/rollup-linux-loong64-musl\": \"4.57.1\",\n        \"@rollup/rollup-linux-ppc64-gnu\": \"4.57.1\",\n        \"@rollup/rollup-linux-ppc64-musl\": \"4.57.1\",\n        \"@rollup/rollup-linux-riscv64-gnu\": \"4.57.1\",\n        \"@rollup/rollup-linux-riscv64-musl\": \"4.57.1\",\n        \"@rollup/rollup-linux-s390x-gnu\": \"4.57.1\",\n        \"@rollup/rollup-linux-x64-gnu\": \"4.57.1\",\n        \"@rollup/rollup-linux-x64-musl\": \"4.57.1\",\n        \"@rollup/rollup-openbsd-x64\": \"4.57.1\",\n        \"@rollup/rollup-openharmony-arm64\": \"4.57.1\",\n        \"@rollup/rollup-win32-arm64-msvc\": \"4.57.1\",\n        \"@rollup/rollup-win32-ia32-msvc\": \"4.57.1\",\n        \"@rollup/rollup-win32-x64-gnu\": \"4.57.1\",\n        \"@rollup/rollup-win32-x64-msvc\": \"4.57.1\",\n        \"fsevents\": \"~2.3.2\"\n      }\n    },\n    \"node_modules/semver\": {\n      \"version\": \"7.7.4\",\n      \"dev\": true,\n      \"license\": \"ISC\",\n      \"bin\": {\n        \"semver\": \"bin/semver.js\"\n      },\n      \"engines\": {\n        \"node\": \">=10\"\n      }\n    },\n    \"node_modules/shebang-command\": {\n      \"version\": \"2.0.0\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"shebang-regex\": \"^3.0.0\"\n      },\n      \"engines\": {\n        \"node\": \">=8\"\n      }\n    },\n    \"node_modules/shebang-regex\": {\n      \"version\": \"3.0.0\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">=8\"\n      }\n    },\n    \"node_modules/siginfo\": {\n      \"version\": \"2.0.0\",\n      \"dev\": true,\n      \"license\": \"ISC\"\n    },\n    \"node_modules/signal-exit\": {\n      \"version\": \"4.1.0\",\n      \"dev\": true,\n      \"license\": \"ISC\",\n      \"engines\": {\n        \"node\": \">=14\"\n      },\n      \"funding\": {\n        \"url\": \"https://github.com/sponsors/isaacs\"\n      }\n    },\n    \"node_modules/source-map-js\": {\n      \"version\": \"1.2.1\",\n      \"dev\": true,\n      \"license\": \"BSD-3-Clause\",\n      \"engines\": {\n        \"node\": \">=0.10.0\"\n      }\n    },\n    \"node_modules/sql.js\": {\n      \"version\": \"1.13.0\",\n      \"license\": \"MIT\"\n    },\n    \"node_modules/stackback\": {\n      \"version\": \"0.0.2\",\n      \"dev\": true,\n      \"license\": \"MIT\"\n    },\n    \"node_modules/std-env\": {\n      \"version\": \"3.10.0\",\n      \"dev\": true,\n      \"license\": \"MIT\"\n    },\n    \"node_modules/string-width\": {\n      \"version\": \"5.1.2\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"eastasianwidth\": \"^0.2.0\",\n        \"emoji-regex\": \"^9.2.2\",\n        \"strip-ansi\": \"^7.0.1\"\n      },\n      \"engines\": {\n        \"node\": \">=12\"\n      },\n      \"funding\": {\n        \"url\": \"https://github.com/sponsors/sindresorhus\"\n      }\n    },\n    \"node_modules/string-width-cjs\": {\n      \"name\": \"string-width\",\n      \"version\": \"4.2.3\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"emoji-regex\": \"^8.0.0\",\n        \"is-fullwidth-code-point\": \"^3.0.0\",\n        \"strip-ansi\": \"^6.0.1\"\n      },\n      \"engines\": {\n        \"node\": \">=8\"\n      }\n    },\n    \"node_modules/string-width-cjs/node_modules/ansi-regex\": {\n      \"version\": \"5.0.1\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">=8\"\n      }\n    },\n    \"node_modules/string-width-cjs/node_modules/emoji-regex\": {\n      \"version\": \"8.0.0\",\n      \"dev\": true,\n      \"license\": \"MIT\"\n    },\n    \"node_modules/string-width-cjs/node_modules/strip-ansi\": {\n      \"version\": \"6.0.1\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"ansi-regex\": \"^5.0.1\"\n      },\n      \"engines\": {\n        \"node\": \">=8\"\n      }\n    },\n    \"node_modules/strip-ansi\": {\n      \"version\": \"7.1.2\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"ansi-regex\": \"^6.0.1\"\n      },\n      \"engines\": {\n        \"node\": \">=12\"\n      },\n      \"funding\": {\n        \"url\": \"https://github.com/chalk/strip-ansi?sponsor=1\"\n      }\n    },\n    \"node_modules/strip-ansi-cjs\": {\n      \"name\": \"strip-ansi\",\n      \"version\": \"6.0.1\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"ansi-regex\": \"^5.0.1\"\n      },\n      \"engines\": {\n        \"node\": \">=8\"\n      }\n    },\n    \"node_modules/strip-ansi-cjs/node_modules/ansi-regex\": {\n      \"version\": \"5.0.1\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">=8\"\n      }\n    },\n    \"node_modules/supports-color\": {\n      \"version\": \"7.2.0\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"has-flag\": \"^4.0.0\"\n      },\n      \"engines\": {\n        \"node\": \">=8\"\n      }\n    },\n    \"node_modules/test-exclude\": {\n      \"version\": \"7.0.1\",\n      \"dev\": true,\n      \"license\": \"ISC\",\n      \"dependencies\": {\n        \"@istanbuljs/schema\": \"^0.1.2\",\n        \"glob\": \"^10.4.1\",\n        \"minimatch\": \"^9.0.4\"\n      },\n      \"engines\": {\n        \"node\": \">=18\"\n      }\n    },\n    \"node_modules/tinybench\": {\n      \"version\": \"2.9.0\",\n      \"dev\": true,\n      \"license\": \"MIT\"\n    },\n    \"node_modules/tinyexec\": {\n      \"version\": \"0.3.2\",\n      \"dev\": true,\n      \"license\": \"MIT\"\n    },\n    \"node_modules/tinypool\": {\n      \"version\": \"1.1.1\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \"^18.0.0 || >=20.0.0\"\n      }\n    },\n    \"node_modules/tinyrainbow\": {\n      \"version\": \"1.2.0\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">=14.0.0\"\n      }\n    },\n    \"node_modules/tinyspy\": {\n      \"version\": \"3.0.2\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">=14.0.0\"\n      }\n    },\n    \"node_modules/typescript\": {\n      \"version\": \"5.9.3\",\n      \"dev\": true,\n      \"license\": \"Apache-2.0\",\n      \"bin\": {\n        \"tsc\": \"bin/tsc\",\n        \"tsserver\": \"bin/tsserver\"\n      },\n      \"engines\": {\n        \"node\": \">=14.17\"\n      }\n    },\n    \"node_modules/undici-types\": {\n      \"version\": \"6.21.0\",\n      \"dev\": true,\n      \"license\": \"MIT\"\n    },\n    \"node_modules/vite\": {\n      \"version\": \"5.4.21\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"esbuild\": \"^0.21.3\",\n        \"postcss\": \"^8.4.43\",\n        \"rollup\": \"^4.20.0\"\n      },\n      \"bin\": {\n        \"vite\": \"bin/vite.js\"\n      },\n      \"engines\": {\n        \"node\": \"^18.0.0 || >=20.0.0\"\n      },\n      \"funding\": {\n        \"url\": \"https://github.com/vitejs/vite?sponsor=1\"\n      },\n      \"optionalDependencies\": {\n        \"fsevents\": \"~2.3.3\"\n      },\n      \"peerDependencies\": {\n        \"@types/node\": \"^18.0.0 || >=20.0.0\",\n        \"less\": \"*\",\n        \"lightningcss\": \"^1.21.0\",\n        \"sass\": \"*\",\n        \"sass-embedded\": \"*\",\n        \"stylus\": \"*\",\n        \"sugarss\": \"*\",\n        \"terser\": \"^5.4.0\"\n      },\n      \"peerDependenciesMeta\": {\n        \"@types/node\": {\n          \"optional\": true\n        },\n        \"less\": {\n          \"optional\": true\n        },\n        \"lightningcss\": {\n          \"optional\": true\n        },\n        \"sass\": {\n          \"optional\": true\n        },\n        \"sass-embedded\": {\n          \"optional\": true\n        },\n        \"stylus\": {\n          \"optional\": true\n        },\n        \"sugarss\": {\n          \"optional\": true\n        },\n        \"terser\": {\n          \"optional\": true\n        }\n      }\n    },\n    \"node_modules/vite-node\": {\n      \"version\": \"2.1.9\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"cac\": \"^6.7.14\",\n        \"debug\": \"^4.3.7\",\n        \"es-module-lexer\": \"^1.5.4\",\n        \"pathe\": \"^1.1.2\",\n        \"vite\": \"^5.0.0\"\n      },\n      \"bin\": {\n        \"vite-node\": \"vite-node.mjs\"\n      },\n      \"engines\": {\n        \"node\": \"^18.0.0 || >=20.0.0\"\n      },\n      \"funding\": {\n        \"url\": \"https://opencollective.com/vitest\"\n      }\n    },\n    \"node_modules/vitest\": {\n      \"version\": \"2.1.9\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"@vitest/expect\": \"2.1.9\",\n        \"@vitest/mocker\": \"2.1.9\",\n        \"@vitest/pretty-format\": \"^2.1.9\",\n        \"@vitest/runner\": \"2.1.9\",\n        \"@vitest/snapshot\": \"2.1.9\",\n        \"@vitest/spy\": \"2.1.9\",\n        \"@vitest/utils\": \"2.1.9\",\n        \"chai\": \"^5.1.2\",\n        \"debug\": \"^4.3.7\",\n        \"expect-type\": \"^1.1.0\",\n        \"magic-string\": \"^0.30.12\",\n        \"pathe\": \"^1.1.2\",\n        \"std-env\": \"^3.8.0\",\n        \"tinybench\": \"^2.9.0\",\n        \"tinyexec\": \"^0.3.1\",\n        \"tinypool\": \"^1.0.1\",\n        \"tinyrainbow\": \"^1.2.0\",\n        \"vite\": \"^5.0.0\",\n        \"vite-node\": \"2.1.9\",\n        \"why-is-node-running\": \"^2.3.0\"\n      },\n      \"bin\": {\n        \"vitest\": \"vitest.mjs\"\n      },\n      \"engines\": {\n        \"node\": \"^18.0.0 || >=20.0.0\"\n      },\n      \"funding\": {\n        \"url\": \"https://opencollective.com/vitest\"\n      },\n      \"peerDependencies\": {\n        \"@edge-runtime/vm\": \"*\",\n        \"@types/node\": \"^18.0.0 || >=20.0.0\",\n        \"@vitest/browser\": \"2.1.9\",\n        \"@vitest/ui\": \"2.1.9\",\n        \"happy-dom\": \"*\",\n        \"jsdom\": \"*\"\n      },\n      \"peerDependenciesMeta\": {\n        \"@edge-runtime/vm\": {\n          \"optional\": true\n        },\n        \"@types/node\": {\n          \"optional\": true\n        },\n        \"@vitest/browser\": {\n          \"optional\": true\n        },\n        \"@vitest/ui\": {\n          \"optional\": true\n        },\n        \"happy-dom\": {\n          \"optional\": true\n        },\n        \"jsdom\": {\n          \"optional\": true\n        }\n      }\n    },\n    \"node_modules/which\": {\n      \"version\": \"2.0.2\",\n      \"dev\": true,\n      \"license\": \"ISC\",\n      \"dependencies\": {\n        \"isexe\": \"^2.0.0\"\n      },\n      \"bin\": {\n        \"node-which\": \"bin/node-which\"\n      },\n      \"engines\": {\n        \"node\": \">= 8\"\n      }\n    },\n    \"node_modules/why-is-node-running\": {\n      \"version\": \"2.3.0\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"siginfo\": \"^2.0.0\",\n        \"stackback\": \"0.0.2\"\n      },\n      \"bin\": {\n        \"why-is-node-running\": \"cli.js\"\n      },\n      \"engines\": {\n        \"node\": \">=8\"\n      }\n    },\n    \"node_modules/wrap-ansi\": {\n      \"version\": \"8.1.0\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"ansi-styles\": \"^6.1.0\",\n        \"string-width\": \"^5.0.1\",\n        \"strip-ansi\": \"^7.0.1\"\n      },\n      \"engines\": {\n        \"node\": \">=12\"\n      },\n      \"funding\": {\n        \"url\": \"https://github.com/chalk/wrap-ansi?sponsor=1\"\n      }\n    },\n    \"node_modules/wrap-ansi-cjs\": {\n      \"name\": \"wrap-ansi\",\n      \"version\": \"7.0.0\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"ansi-styles\": \"^4.0.0\",\n        \"string-width\": \"^4.1.0\",\n        \"strip-ansi\": \"^6.0.0\"\n      },\n      \"engines\": {\n        \"node\": \">=10\"\n      },\n      \"funding\": {\n        \"url\": \"https://github.com/chalk/wrap-ansi?sponsor=1\"\n      }\n    },\n    \"node_modules/wrap-ansi-cjs/node_modules/ansi-regex\": {\n      \"version\": \"5.0.1\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">=8\"\n      }\n    },\n    \"node_modules/wrap-ansi-cjs/node_modules/emoji-regex\": {\n      \"version\": \"8.0.0\",\n      \"dev\": true,\n      \"license\": \"MIT\"\n    },\n    \"node_modules/wrap-ansi-cjs/node_modules/string-width\": {\n      \"version\": \"4.2.3\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"emoji-regex\": \"^8.0.0\",\n        \"is-fullwidth-code-point\": \"^3.0.0\",\n        \"strip-ansi\": \"^6.0.1\"\n      },\n      \"engines\": {\n        \"node\": \">=8\"\n      }\n    },\n    \"node_modules/wrap-ansi-cjs/node_modules/strip-ansi\": {\n      \"version\": \"6.0.1\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"ansi-regex\": \"^5.0.1\"\n      },\n      \"engines\": {\n        \"node\": \">=8\"\n      }\n    },\n    \"node_modules/wrap-ansi/node_modules/ansi-styles\": {\n      \"version\": \"6.2.3\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">=12\"\n      },\n      \"funding\": {\n        \"url\": \"https://github.com/chalk/ansi-styles?sponsor=1\"\n      }\n    }\n  }\n}\n\nFile v2.0.3:package.json\n\n{\n  \"name\": \"memory-tools\",\n  \"version\": \"2.0.3\",\n  \"description\": \"Memory-as-Tools plugin for OpenClaw - Agent-controlled persistent memory with QMD-powered search\",\n  \"type\": \"module\",\n  \"main\": \"dist/index.js\",\n  \"types\": \"dist/index.d.ts\",\n  \"scripts\": {\n    \"clean\": \"rm -rf dist\",\n    \"build\": \"npm run clean && tsc\",\n    \"test\": \"vitest run\",\n    \"test:watch\": \"vitest\",\n    \"test:coverage\": \"vitest run --coverage\",\n    \"lint\": \"oxlint\",\n    \"typecheck\": \"tsc --noEmit\",\n    \"verify:release\": \"node scripts/verify-release.mjs\",\n    \"prepublishOnly\": \"npm run build && npm run verify:release\"\n  },\n  \"dependencies\": {\n    \"@sinclair/typebox\": \"0.34.48\",\n    \"sql.js\": \"^1.13.0\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^22.0.0\",\n    \"@types/sql.js\": \"^1.4.9\",\n    \"@vitest/coverage-v8\": \"^2.1.0\",\n    \"typescript\": \"^5.7.0\",\n    \"vitest\": \"^2.1.0\"\n  },\n  \"peerDependencies\": {\n    \"openclaw\": \">=2026.0.0\"\n  },\n  \"peerDependenciesMeta\": {\n    \"openclaw\": {\n      \"optional\": true\n    }\n  },\n  \"openclaw\": {\n    \"extensions\": [\n      \"./dist/index.js\"\n    ]\n  },\n  \"files\": [\n    \"dist\",\n    \"README.md\"\n  ],\n  \"keywords\": [\n    \"openclaw\",\n    \"memory\",\n    \"ai-agent\",\n    \"plugin\",\n    \"vector-search\",\n    \"qmd\",\n    \"local-llm\"\n  ],\n  \"author\": \"Purple Horizons\",\n  \"license\": \"MIT\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/Purple-Horizons/memory-tools.git\"\n  }\n}\n\nFile v2.0.3:tsconfig.json\n\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"lib\": [\"ES2022\"],\n    \"outDir\": \"dist\",\n    \"rootDir\": \"src\",\n    \"declaration\": true,\n    \"declarationMap\": true,\n    \"sourceMap\": true,\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": true,\n    \"noEmit\": false\n  },\n  \"include\": [\"src/**/*\"],\n  \"exclude\": [\"node_modules\", \"dist\", \"**/*.test.ts\"]\n}\n\nFile v2.0.3:test/docker/docker-compose.yml\n\nversion: '3.8'\n\nservices:\n  migration-test:\n    build:\n      context: ../..\n      dockerfile: test/docker/Dockerfile\n    volumes:\n      - ../..:/app/memory-tools:ro\n      - test-data:/home/testuser/.openclaw\n    environment:\n      - HOME=/home/testuser\n      - NODE_ENV=test\n\nvolumes:\n  test-data:\n\nArchive v2.0.2: 26 files, 48213 bytes\n\nFiles: CLAUDE.md (2126b), clawdbot.plugin.json (1424b), openclaw.plugin.json (1424b), package-lock.json (32215b), package.json (1410b), README.md (13127b), scripts/verify-release.mjs (1199b), SKILL.md (5727b), src/config.ts (2055b), src/file-manager.ts (12565b), src/index.ts (13377b), src/migration.ts (11904b), src/plugin-types.ts (1447b), src/qmd.ts (10399b), src/store.test.ts (10457b), src/store.ts (8459b), src/tools.test.ts (7005b), src/tools.ts (21256b), src/types.ts (2386b), test/docker/docker-compose.yml (298b), test/docker/run-tests.sh (423b), test/docker/seed-v1-data.js (4109b), test/docker/test-migration.sh (4817b), tsconfig.json (540b), vitest.config.ts (404b), _meta.json (131b)\n\nFile v2.0.2:SKILL.md\n\n---\nname: memory-tools\ndescription: Agent-controlled memory plugin for OpenClaw with confidence scoring, decay, and semantic search. The agent decides WHEN to store/retrieve memories — no auto-capture noise. v2 uses file-based storage with optional QMD search (no external APIs required).\nhomepage: https://github.com/Purple-Horizons/memory-tools\nmetadata:\n  openclaw:\n    emoji: 🧠\n    kind: plugin\n---\n\n# Memory Tools v2\n\nAgent-controlled persistent memory for OpenClaw.\n\n## What's New in v2\n\n- **File-based storage** — Memories stored as readable markdown files\n- **No external APIs** — No OpenAI dependency, everything runs locally\n- **QMD search (optional)** — BM25 + vector + reranking via local GGUF models\n- **Auto-migration** — Seamlessly upgrades from v1 SQLite/LanceDB storage\n\n## Why Memory-as-Tools?\n\nTraditional memory systems auto-capture everything, flooding context with irrelevant information. Memory Tools follows the [AgeMem](https://arxiv.org/abs/2409.02634) approach: **the agent decides** when to store and retrieve memories.\n\n## Features\n\n- **6 Memory Tools**: `memory_store`, `memory_update`, `memory_forget`, `memory_search`, `memory_summarize`, `memory_list`\n- **Confidence Scoring**: Track how certain you are (1.0 = explicit, 0.5 = inferred)\n- **Importance Scoring**: Prioritize critical instructions over nice-to-know facts\n- **Decay/Expiration**: Temporal memories automatically become stale\n- **Human-readable storage**: Markdown files with YAML frontmatter\n- **Conflict Resolution**: New info auto-supersedes old (no contradictions)\n\n## Installation\n\n### Step 1: Install from ClawHub\n\n```bash\nclawhub install memory-tools\n```\n\n### Step 2: Build the plugin\n\n```bash\ncd skills/memory-tools\nnpm install\nnpm run build\n```\n\n### Step 3: Activate the plugin\n\n```bash\nopenclaw plugins install --link .\nopenclaw plugins enable memory-tools\n```\n\n### Step 4: Restart the gateway\n\n```bash\nopenclaw gateway restart\n```\n\n### Optional: Install QMD for better search\n\n```bash\nnpm install -g @tobilu/qmd\n```\n\nWithout QMD, basic filtering works. With QMD, you get semantic search (BM25 + vector + reranking).\n\n## Security Model\n\n- No API keys or external credentials are required.\n- Data is stored locally in `~/.openclaw/memories` (or configured `memoriesPath`).\n- The plugin can inject `systemPrompt` and `prependContext` at `before_agent_start` when `autoInjectInstructions=true`.\n- The plugin can auto-migrate legacy v1 data from `~/.openclaw/memory/tools/memory.db` when `autoMigrateLegacy=true`.\n- Disable injection with `autoInjectInstructions=false` if you want stricter control.\n- Disable migration with `autoMigrateLegacy=false` if you do not want startup migration behavior.\n\n## Storage Format\n\nMemories are stored as markdown files in `~/.openclaw/memories/`:\n\n```\n~/.openclaw/memories/\n├── facts/\n│   └── abc123-def4-5678-90ab-cdef12345678.md\n├── preferences/\n│   └── def456-7890-abcd-ef12-345678901234.md\n├── instructions/\n│   └── ghi789-0abc-def1-2345-678901234567.md\n└── .deleted/\n    └── old-memory.md\n```\n\nEach memory file:\n\n```markdown\n---\nid: abc123-def4-5678-90ab-cdef12345678\ncategory: preference\nconfidence: 0.9\nimportance: 0.7\ncreated_at: 2024-01-15T10:30:00Z\ntags: [ui, settings]\n---\n\nUser prefers dark mode in all applications.\n```\n\n## Memory Categories\n\n| Category | Use For | Example |\n|----------|---------|---------|\n| fact | Static information | \"User's dog is named Rex\" |\n| preference | Likes/dislikes | \"User prefers dark mode\" |\n| event | Temporal things | \"Dentist Tuesday 3pm\" |\n| relationship | People connections | \"Sarah is user's wife\" |\n| instruction | Standing orders | \"Always respond in Spanish\" |\n| decision | Choices made | \"We decided to use PostgreSQL\" |\n| context | Situational info | \"User is job hunting\" |\n| entity | Named things | \"Project Apollo is their startup\" |\n\n## Tool Reference\n\n### memory_store\n```\nmemory_store({\n  content: \"User prefers bullet points\",\n  category: \"preference\",\n  confidence: 0.9,\n  importance: 0.7,\n  tags: [\"formatting\", \"communication\"]\n})\n```\n\n### memory_search\n```\nmemory_search({\n  query: \"formatting preferences\",\n  category: \"preference\",\n  limit: 10\n})\n```\n\n### memory_update\n```\nmemory_update({\n  id: \"abc123\",\n  content: \"User now prefers numbered lists\",\n  confidence: 1.0\n})\n```\n\n### memory_forget\n```\nmemory_forget({\n  query: \"bullet points\",\n  reason: \"User corrected preference\"\n})\n```\n\n### memory_summarize\n```\nmemory_summarize({\n  topic: \"user's work projects\",\n  maxMemories: 20\n})\n```\n\n### memory_list\n```\nmemory_list({\n  category: \"instruction\",\n  sortBy: \"importance\",\n  limit: 20\n})\n```\n\n## CLI Commands\n\n```bash\n# Show memory statistics\nopenclaw memory-tools stats\n\n# List memories\nopenclaw memory-tools list\nopenclaw memory-tools list --category fact\n\n# Search memories (requires QMD)\nopenclaw memory-tools search \"dark mode\"\n\n# Export all memories as JSON\nopenclaw memory-tools export\n\n# Force re-index with QMD\nopenclaw memory-tools reindex\n\n# Show storage path\nopenclaw memory-tools path\n```\n\n## Debugging\n\nMemories are plain markdown files — just read them:\n\n```bash\ncat ~/.openclaw/memories/facts/*.md\nls ~/.openclaw/memories/\n```\n\nExport all memories:\n\n```bash\nopenclaw memory-tools export > memories.json\n```\n\n## Migration from v1\n\nv2 automatically detects v1 databases and migrates them:\n\n1. On startup, v2 checks for `~/.openclaw/memory/tools/memory.db`\n2. If found, exports all memories to markdown files\n3. Original database preserved as backup\n4. No manual action required\n\nTo disable auto-migration, set `autoMigrateLegacy: false` in plugin config.\n\n## License\n\nMIT — [Purple Horizons](https://github.com/Purple-Horizons)\n\nFile v2.0.2:README.md\n\n<p align=\"center\">\n  <img src=\"header.png\" alt=\"memory-tools\" width=\"100%\">\n</p>\n\n# OpenClaw Memory Tools v2\n\nAgent-controlled memory plugin for OpenClaw with confidence scoring, decay, and semantic search.\n\n## What's New in v2\n\n- **File-based storage** - Memories stored as readable markdown files\n- **No external APIs** - No OpenAI dependency, everything runs locally\n- **QMD search (optional)** - BM25 + vector + reranking via local GGUF models\n- **Auto-migration** - Seamlessly upgrades from v1 SQLite/LanceDB storage\n\n## Why Memory-as-Tools?\n\nTraditional AI memory systems auto-capture everything, flooding context with irrelevant information. **Memory-as-Tools** follows the [AgeMem](https://arxiv.org/abs/2409.02634) approach: the agent decides **when** to store and retrieve memories.\n\n```\nTraditional: Agent -> always retrieves -> context flooded\nMemory-as-Tools: Agent -> decides IF/WHAT to remember -> uses tools explicitly\n```\n\n## Features\n\n- **6 Memory Tools**: `memory_store`, `memory_update`, `memory_forget`, `memory_search`, `memory_summarize`, `memory_list`\n- **Confidence Scoring**: Track how certain you are about each memory (1.0 = explicit, 0.5 = inferred)\n- **Importance Scoring**: Prioritize critical instructions over nice-to-know facts\n- **Decay/Expiration**: Temporal memories (events) automatically become stale\n- **Human-readable storage**: Markdown files with YAML frontmatter\n- **Semantic Search**: Optional QMD-powered hybrid search (BM25 + vector + reranking)\n- **Zero External Dependencies**: Everything runs locally, no API keys needed\n- **Standing Instructions**: Auto-inject category=\"instruction\" memories at conversation start\n\n## Installation\n\n### Step 1: Install from ClawHub\n\n```bash\nclawhub install memory-tools\n```\n\n### Step 2: Build the plugin\n\n```bash\ncd skills/memory-tools\nnpm install\nnpm run build\n```\n\n### Step 3: Activate the plugin\n\n```bash\nopenclaw plugins install --link .\nopenclaw plugins enable memory-tools\n```\n\n### Step 4: Restart the gateway\n\n```bash\nopenclaw gateway restart\n```\n\n### Optional: Install QMD for better search\n\n```bash\nnpm install -g @tobilu/qmd\n```\n\nWithout QMD, basic category/tag filtering works. With QMD, you get semantic search (BM25 + vector + reranking using local GGUF models).\n\n## Configuration\n\nAdd to `~/.openclaw/openclaw.json`:\n\n```json\n{\n  \"plugins\": {\n    \"slots\": {\n      \"memory\": \"memory-tools\"\n    },\n    \"entries\": {\n      \"memory-tools\": {\n        \"enabled\": true,\n        \"config\": {\n          \"memoriesPath\": \"~/.openclaw/memories\",\n          \"autoInjectInstructions\": true,\n          \"autoMigrateLegacy\": true\n        }\n      }\n    }\n  },\n  \"tools\": {\n    \"alsoAllow\": [\"group:plugins\"]\n  }\n}\n```\n\n### Security Model\n\n- No API keys or external credentials are required by this plugin.\n- Data is stored locally in `~/.openclaw/memories` (or your configured `memoriesPath`).\n- The plugin can inject `systemPrompt` and `prependContext` at `before_agent_start` when `autoInjectInstructions=true`.\n- The plugin can auto-migrate legacy v1 data from `~/.openclaw/memory/tools/memory.db` when `autoMigrateLegacy=true`.\n- Set `autoInjectInstructions=false` if you do not want startup prompt/context injection.\n- Set `autoMigrateLegacy=false` if you do not want automatic migration reads/writes.\n\n### Verify Installation\n\n```bash\n# Restart gateway\nopenclaw gateway stop && openclaw gateway run\n\n# Check plugin loaded\nopenclaw plugins list\n\n# Test CLI\nopenclaw memory-tools stats\n```\n\n## Storage Format\n\nMemories are stored as markdown files in `~/.openclaw/memories/`:\n\n```\n~/.openclaw/memories/\n├── facts/\n│   └── abc123-def4-5678-90ab-cdef12345678.md\n├── preferences/\n│   └── def456-7890-abcd-ef12-345678901234.md\n├── instructions/\n│   └── ghi789-0abc-def1-2345-678901234567.md\n└── .deleted/\n    └── old-memory.md\n```\n\nEach memory file contains YAML frontmatter with metadata:\n\n```markdown\n---\nid: abc123-def4-5678-90ab-cdef12345678\ncategory: preference\nconfidence: 0.9\nimportance: 0.7\ncreated_at: 2024-01-15T10:30:00Z\ntags: [ui, settings]\n---\n\nUser prefers dark mode in all applications.\n```\n\n## Memory Categories\n\n| Category | Use For | Example |\n|----------|---------|---------|\n| `fact` | Static information | \"User's dog is named Rex\" |\n| `preference` | Likes/dislikes | \"User prefers dark mode\" |\n| `event` | Temporal things | \"Dentist appointment Tuesday 3pm\" |\n| `relationship` | People connections | \"User's sister is Sarah\" |\n| `context` | Current work | \"Working on React project\" |\n| `instruction` | Standing orders | \"Always respond in Spanish\" |\n| `decision` | Choices made | \"We decided to use PostgreSQL\" |\n| `entity` | Contact info | \"User's email is x@y.com\" |\n\n## Tool Reference\n\n### memory_store\n\nStore a new memory.\n\n```typescript\nmemory_store({\n  content: \"User prefers bullet points\",\n  category: \"preference\",\n  confidence: 0.9,      // How sure (0-1)\n  importance: 0.7,      // How critical (0-1)\n  decayDays: null,      // null = permanent\n  tags: [\"formatting\"]\n})\n```\n\n### memory_update\n\nUpdate an existing memory.\n\n```typescript\nmemory_update({\n  id: \"abc-123\",\n  content: \"User prefers numbered lists\",  // Optional\n  confidence: 0.95                          // Optional\n})\n```\n\n### memory_forget\n\nDelete a memory.\n\n```typescript\nmemory_forget({\n  id: \"abc-123\",           // If known\n  query: \"bullet points\",  // Or search\n  reason: \"User corrected\"\n})\n```\n\n### memory_search\n\nSemantic search (uses QMD if installed, otherwise basic filtering).\n\n```typescript\nmemory_search({\n  query: \"formatting preferences\",\n  category: \"preference\",      // Optional filter\n  minConfidence: 0.7,          // Optional filter\n  limit: 10\n})\n```\n\n### memory_summarize\n\nGet topic summary.\n\n```typescript\nmemory_summarize({\n  topic: \"user's work\",\n  maxMemories: 20\n})\n```\n\n### memory_list\n\nBrowse all memories.\n\n```typescript\nmemory_list({\n  category: \"instruction\",\n  sortBy: \"importance\",\n  limit: 20\n})\n```\n\n## CLI Commands\n\n```bash\n# Show statistics\nopenclaw memory-tools stats\n\n# List memories\nopenclaw memory-tools list --category preference\n\n# Search memories (uses QMD if installed)\nopenclaw memory-tools search \"dark mode\"\n\n# Export all memories as JSON\nopenclaw memory-tools export\n\n# Force re-index with QMD\nopenclaw memory-tools reindex\n\n# Show storage path\nopenclaw memory-tools path\n```\n\n## Debugging\n\nMemories are plain markdown files - just read them:\n\n```bash\ncat ~/.openclaw/memories/facts/*.md\nls ~/.openclaw/memories/\n```\n\nExport all memories:\n\n```bash\nopenclaw memory-tools export > memories.json\n```\n\n## Architecture\n\n```\n┌─────────────────────────────────────────────────────────┐\n│                    OpenClaw Agent                       │\n│                                                         │\n│  Agent decides: \"This is worth remembering\"             │\n│         ↓                                               │\n│  Calls: memory_store(...)                               │\n└─────────────────────────────────────────────────────────┘\n                          ↓\n┌─────────────────────────────────────────────────────────┐\n│                   Memory Tools                          │\n├─────────────────────────────────────────────────────────┤\n│  store │ update │ forget │ search │ summarize │ list   │\n└─────────────────────────────────────────────────────────┘\n                          ↓\n┌─────────────────────────────────────────────────────────┐\n│                 Storage Layer                           │\n│  ┌──────────────────────────────────────────────────┐  │\n│  │           Markdown Files (YAML frontmatter)       │  │\n│  │           ~/.openclaw/memories/{category}/*.md    │  │\n│  └──────────────────────────────────────────────────┘  │\n│                          ↓                              │\n│  ┌──────────────────────────────────────────────────┐  │\n│  │        QMD Search (optional)                      │  │\n│  │        BM25 + Vector + Reranking                  │  │\n│  └──────────────────────────────────────────────────┘  │\n└─────────────────────────────────────────────────────────┘\n```\n\n## Migration from v1\n\nv2 automatically detects v1 databases and migrates them:\n\n1. On startup, v2 checks for `~/.openclaw/memory/tools/memory.db`\n2. If found, exports all memories to markdown files\n3. Original database preserved as backup\n4. No manual action required\n\nTo disable auto-migration, set `\"autoMigrateLegacy\": false` in plugin config.\n\n## Development\n\n```bash\n# Install dependencies\nnpm install\n\n# Run tests\nnpm test\n\n# Run tests with coverage\nnpm test:coverage\n\n# Type check\nnpm run typecheck\n\n# Build\nnpm run build\n```\n\n### Environment Variables\n\n- `MEMORY_TOOLS_DISABLE_QMD=true` - Disable QMD for testing\n\nNo environment variables are required for credentials.\n\n## Comparison with Other Memory Systems\n\n| Feature | [memU](https://github.com/NevaMind-AI/memU) | [claude-mem](https://github.com/thedotmack/claude-mem) | **memory-tools** |\n|---------|------|------------|--------------|\n| **Architecture** | 3-tier hierarchical (Resource -> Item -> Category) | Hook-based observer with lifecycle events | Tool-based agent control |\n| **Storage Trigger** | Automatic extraction during background processing | Lifecycle hooks (SessionStart, PostToolUse, etc.) | Agent explicitly decides when to store |\n| **Storage Backend** | Custom hierarchical | Custom | Markdown files + optional QMD |\n| **External APIs** | Varies | Varies | None required |\n| **Conflict Handling** | None - relies on proactive pattern detection | None - auto-capture model | Auto-supersede + explicit forget |\n| **Context Injection** | Proactive - predicts and pre-loads context | Progressive disclosure (3-layer filtering) | On-demand via memory_search |\n| **Token Efficiency** | Compression via fact extraction | ~10x savings via progressive disclosure | Semantic search with configurable limits |\n| **Auditability** | Background processing | Hook-based capture | Human-readable markdown files |\n| **User Corrections** | Accumulates conflicting facts | Accumulates conflicting facts | Replaces old with new automatically |\n| **Best For** | 24/7 agents with predictable patterns | Automatic session continuity | Personal assistants with ongoing relationships |\n\n### Design Philosophy\n\nDifferent memory systems optimize for different things:\n\n- **Automatic systems** (memU, claude-mem) minimize agent cognitive load by extracting memories in the background. Trade-off: less control over what's captured, conflicts accumulate.\n\n- **Agent-controlled systems** (memory-tools) put the agent in charge of what matters. Trade-off: requires active management, but memories are deliberate choices.\n\nFor agents that maintain ongoing relationships with users - where someone might say \"no, my favorite color is purple, not blue\" - explicit conflict handling prevents contradictory memories from accumulating. Every memory has a clear provenance: the agent decided it was worth remembering, and corrections replace rather than compete with old information.\n\nThe file-based storage means you can always `ls ~/.openclaw/memories/` and read exactly what your agent knows. Each memory is a plain markdown file you can edit, delete, or backup.\n\n## References\n\n- [AgeMem Paper](https://arxiv.org/abs/2409.02634) - Memory operations as first-class tools\n- [QMD](https://github.com/tobilu/qmd) - Local hybrid search with GGUF models\n- [memU](https://github.com/NevaMind-AI/memU) - Hierarchical memory with proactive context\n- [claude-mem](https://github.com/thedotmack/claude-mem) - Hook-based automatic memory\n- [Mem0](https://github.com/mem0ai/mem0) - AI memory layer\n- [OpenClaw](https://github.com/openclaw/openclaw) - Personal AI assistant\n\n## License\n\nMIT - [Purple Horizons](https://github.com/Purple-Horizons)\n\nFile v2.0.2:_meta.json\n\n{\n  \"ownerId\": \"kn7ajybsnj998tbfcgvrc7731s803brp\",\n  \"slug\": \"memory-tools\",\n  \"version\": \"2.0.2\",\n  \"publishedAt\": 1771435507858\n}\n\nFile v2.0.2:CLAUDE.md\n\n# CLAUDE.md\n\nProject context for Claude Code.\n\n## Project\n\n**memory-tools v2** - Agent-controlled memory plugin for OpenClaw/ClawHub.\n\n- **Repo**: `Purple-Horizons/memory-tools`\n- **ClawHub slug**: `memory-tools`\n- **Owner**: gianni-dalerta\n\n## Architecture (v2)\n\n- **File-based storage** - Memories stored as markdown files with YAML frontmatter\n- **QMD search** - Optional BM25 + vector + reranking via local GGUF models\n- **No external APIs** - No OpenAI dependency, everything runs locally\n- **Auto-migration** - Seamlessly upgrades from v1 SQLite/LanceDB storage\n\n### Storage Structure\n```\n~/.openclaw/memories/\n├── facts/\n│   └── abc123.md\n├── preferences/\n│   └── def456.md\n├── instructions/\n│   └── ghi789.md\n└── .deleted/\n    └── old-memory.md\n```\n\n### Memory File Format\n```markdown\n---\nid: abc123-def4-5678-90ab-cdef12345678\ncategory: preference\nconfidence: 0.9\nimportance: 0.7\ncreated_at: 2024-01-15T10:30:00Z\ntags: [ui, settings]\n---\n\nUser prefers dark mode in all applications.\n```\n\n## Key Decisions\n\n- **v2 rewrote storage layer**: Switched from SQLite + LanceDB + OpenAI to file-based + QMD\n- **QMD is optional**: Works without QMD (basic file listing), better search with QMD installed\n- **Auto-migration**: v2 detects v1 databases and automatically exports to markdown files\n- **Backward compatible API**: Tools interface unchanged, existing integrations work\n\n## QMD Integration\n\nQMD provides hybrid search (BM25 + vector + reranking) using local GGUF models:\n- `npm install -g @tobilu/qmd` to install\n- Models download on first use (~2GB total)\n- Without QMD: basic category/tag filtering only\n- With QMD: semantic search across all memories\n\n## Publishing to ClawHub\n\n```bash\nclawhub publish . --slug memory-tools --version X.Y.Z --changelog \"description\"\n```\n\nAlways use `--slug memory-tools` to update the correct skill.\n\n## Build & Test\n\n```bash\nnpm run build    # TypeScript compile\nnpm test         # Run vitest (uses MEMORY_TOOLS_DISABLE_QMD=true in CI)\n```\n\n## Environment Variables\n\n- `MEMORY_TOOLS_DISABLE_QMD=true` - Disable QMD for testing\n\nFile v2.0.2:clawdbot.plugin.json\n\n{\n  \"id\": \"memory-tools\",\n  \"kind\": \"memory\",\n  \"name\": \"Memory Tools\",\n  \"description\": \"Agent-controlled memory with file-based storage and optional QMD search. No external APIs required.\",\n  \"version\": \"2.0.2\",\n  \"uiHints\": {\n    \"memoriesPath\": {\n      \"label\": \"Memories Path\",\n      \"placeholder\": \"~/.clawdbot/memories\",\n      \"advanced\": true,\n      \"help\": \"Directory for storing memory files\"\n    },\n    \"autoInjectInstructions\": {\n      \"label\": \"Auto-Inject Instructions\",\n      \"help\": \"Inject standing instructions (category='instruction') at conversation start\"\n    },\n    \"autoMigrateLegacy\": {\n      \"label\": \"Auto-Migrate Legacy DB\",\n      \"advanced\": true,\n      \"help\": \"Automatically migrate v1 database to markdown files on startup\"\n    },\n    \"qmdCollection\": {\n      \"label\": \"QMD Collection\",\n      \"advanced\": true,\n      \"help\": \"QMD collection name for semantic search index\"\n    }\n  },\n  \"configSchema\": {\n    \"type\": \"object\",\n    \"additionalProperties\": false,\n    \"properties\": {\n      \"memoriesPath\": {\n        \"type\": \"string\",\n        \"description\": \"Directory for storing memory markdown files\"\n      },\n      \"autoInjectInstructions\": {\n        \"type\": \"boolean\",\n        \"default\": true\n      },\n      \"autoMigrateLegacy\": {\n        \"type\": \"boolean\",\n        \"default\": true\n      },\n      \"qmdCollection\": {\n        \"type\": \"string\",\n        \"default\": \"memories\"\n      }\n    }\n  }\n}\n\nFile v2.0.2:openclaw.plugin.json\n\n{\n  \"id\": \"memory-tools\",\n  \"kind\": \"memory\",\n  \"name\": \"Memory Tools\",\n  \"description\": \"Agent-controlled memory with file-based storage and optional QMD search. No external APIs required.\",\n  \"version\": \"2.0.2\",\n  \"uiHints\": {\n    \"memoriesPath\": {\n      \"label\": \"Memories Path\",\n      \"placeholder\": \"~/.openclaw/memories\",\n      \"advanced\": true,\n      \"help\": \"Directory for storing memory files\"\n    },\n    \"autoInjectInstructions\": {\n      \"label\": \"Auto-Inject Instructions\",\n      \"help\": \"Inject standing instructions (category='instruction') at conversation start\"\n    },\n    \"autoMigrateLegacy\": {\n      \"label\": \"Auto-Migrate Legacy DB\",\n      \"advanced\": true,\n      \"help\": \"Automatically migrate v1 database to markdown files on startup\"\n    },\n    \"qmdCollection\": {\n      \"label\": \"QMD Collection\",\n      \"advanced\": true,\n      \"help\": \"QMD collection name for semantic search index\"\n    }\n  },\n  \"configSchema\": {\n    \"type\": \"object\",\n    \"additionalProperties\": false,\n    \"properties\": {\n      \"memoriesPath\": {\n        \"type\": \"string\",\n        \"description\": \"Directory for storing memory markdown files\"\n      },\n      \"autoInjectInstructions\": {\n        \"type\": \"boolean\",\n        \"default\": true\n      },\n      \"autoMigrateLegacy\": {\n        \"type\": \"boolean\",\n        \"default\": true\n      },\n      \"qmdCollection\": {\n        \"type\": \"string\",\n        \"default\": \"memories\"\n      }\n    }\n  }\n}\n\nFile v2.0.2:package-lock.json\n\n{\n  \"name\": \"memory-tools\",\n  \"version\": \"2.0.1\",\n  \"lockfileVersion\": 3,\n  \"requires\": true,\n  \"packages\": {\n    \"\": {\n      \"name\": \"memory-tools\",\n      \"version\": \"2.0.1\",\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"@sinclair/typebox\": \"0.34.48\",\n        \"sql.js\": \"^1.13.0\"\n      },\n      \"devDependencies\": {\n        \"@types/node\": \"^22.0.0\",\n        \"@types/sql.js\": \"^1.4.9\",\n        \"@vitest/coverage-v8\": \"^2.1.0\",\n        \"typescript\": \"^5.7.0\",\n        \"vitest\": \"^2.1.0\"\n      },\n      \"peerDependencies\": {\n        \"openclaw\": \">=2026.0.0\"\n      },\n      \"peerDependenciesMeta\": {\n        \"openclaw\": {\n          \"optional\": true\n        }\n      }\n    },\n    \"node_modules/@ampproject/remapping\": {\n      \"version\": \"2.3.0\",\n      \"dev\": true,\n      \"license\": \"Apache-2.0\",\n      \"dependencies\": {\n        \"@jridgewell/gen-mapping\": \"^0.3.5\",\n        \"@jridgewell/trace-mapping\": \"^0.3.24\"\n      },\n      \"engines\": {\n        \"node\": \">=6.0.0\"\n      }\n    },\n    \"node_modules/@babel/helper-string-parser\": {\n      \"version\": \"7.27.1\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">=6.9.0\"\n      }\n    },\n    \"node_modules/@babel/helper-validator-identifier\": {\n      \"version\": \"7.28.5\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"engines\": {\n        \"node\": \">=6.9.0\"\n      }\n    },\n    \"node_modules/@babel/parser\": {\n      \"version\": \"7.29.0\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"@babel/types\": \"^7.29.0\"\n      },\n      \"bin\": {\n        \"parser\": \"bin/babel-parser.js\"\n      },\n      \"engines\": {\n        \"node\": \">=6.0.0\"\n      }\n    },\n    \"node_modules/@babel/types\": {\n      \"version\": \"7.29.0\",\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"dependencies\": {\n        \"@babel/helper-string-parser\": \"^7.27.1\",\n        \"@babel/helper-validator-identifier\": \"^7.28.5\"\n      },\n      \"engines\": {\n        \"node\": \">=6.9.0\"\n      }\n    },\n    \"node_modules/@bcoe/v8-coverage\": {\n      \"version\": \"0.2.3\",\n      \"dev\": true,\n      \"license\": \"MIT\"\n    },\n    \"node_modules/@esbuild/darwin-arm64\": {\n      \"version\": \"0.21.5\",\n      \"cpu\": [\n        \"arm64\"\n      ],\n      \"dev\": true,\n      \"license\": \"MIT\",\n      \"optional\": true,\n      \"os\": [\n        \"darwin\"\n      ],\n      \"engines\": {\n        \"node\": \">=12\"\n   \n\nArchive v2.0.1: 26 files, 154702 bytes\n\nFiles: CLAUDE.md (2126b), clawdbot.plugin.json (1896b), openclaw.plugin.json (1885b), package-lock.json (91759b), package.json (1243b), pnpm-lock.yaml (256815b), README.md (9889b), SKILL.md (5073b), src/config.ts (1895b), src/file-manager.ts (12565b), src/index.ts (13114b), src/migration.ts (11904b), src/plugin-types.ts (1447b), src/qmd.ts (8996b), src/store.test.ts (10457b), src/store.ts (6657b), src/tools.test.ts (7005b), src/tools.ts (21256b), src/types.ts (2844b), test/docker/docker-compose.yml (298b), test/docker/run-tests.sh (423b), test/docker/seed-v1-data.js (4109b), test/docker/test-migration.sh (4817b), tsconfig.json (540b), vitest.config.ts (404b), _meta.json (131b)\n\nArchive v2.0.0: 27 files, 154838 bytes\n\nFiles: CLAUDE.md (2126b), clawdbot.plugin.json (1896b), openclaw.plugin.json (1885b), package-lock.json (91759b), package.json (1335b), pnpm-lock.yaml (256815b), README.md (9889b), SKILL.md (3906b), src/config.ts (1895b), src/embeddings.ts (863b), src/file-manager.ts (12565b), src/index.ts (13114b), src/migration.ts (11904b), src/plugin-types.ts (1447b), src/qmd.ts (8996b), src/store.test.ts (10457b), src/store.ts (6657b), src/tools.test.ts (7005b), src/tools.ts (21256b), src/types.ts (2844b), test/docker/docker-compose.yml (298b), test/docker/run-tests.sh (423b), test/docker/seed-v1-data.js (4109b), test/docker/test-migration.sh (4817b), tsconfig.json (540b), vitest.config.ts (404b), _meta.json (131b)\n\nArchive v1.1.3: 34 files, 164233 bytes\n\nFiles: _meta.json (131b), CLAUDE.md (1003b), clawdbot.plugin.json (1896b), dist/config.d.ts (1456b), dist/config.js (1918b), dist/embeddings.d.ts (353b), dist/embeddings.js (888b), dist/index.d.ts (968b), dist/index.js (11121b), dist/plugin-types.d.ts (1640b), dist/plugin-types.js (192b), dist/store.d.ts (3159b), dist/store.js (17347b), dist/tools.d.ts (10837b), dist/tools.js (23719b), dist/types.d.ts (2085b), dist/types.js (872b), openclaw.plugin.json (1885b), package-lock.json (91489b), package.json (1324b), pnpm-lock.yaml (256815b), README.md (9889b), SKILL.md (3906b), src/config.ts (2100b), src/embeddings.ts (863b), src/index.ts (10839b), src/plugin-types.ts (1447b), src/store.test.ts (12424b), src/store.ts (17638b), src/tools.test.ts (12777b), src/tools.ts (21256b), src/types.ts (2844b), tsconfig.json (540b), vitest.config.ts (404b)\n\nArchive v1.1.2: 20 files, 144382 bytes\n\nFiles: CLAUDE.md (1003b), clawdbot.plugin.json (1896b), openclaw.plugin.json (1885b), package-lock.json (91759b), package.json (1285b), pnpm-lock.yaml (256815b), README.md (9889b), SKILL.md (3906b), src/config.ts (2100b), src/embeddings.ts (863b), src/index.ts (10839b), src/plugin-types.ts (1447b), src/store.test.ts (12424b), src/store.ts (17638b), src/tools.test.ts (12777b), src/tools.ts (21256b), src/types.ts (2844b), tsconfig.json (540b), vitest.config.ts (404b), _meta.json (131b)\n\nArchive v1.1.1: 20 files, 144286 bytes\n\nFiles: CLAUDE.md (1003b), clawdbot.plugin.json (1896b), openclaw.plugin.json (1885b), package-lock.json (91759b), package.json (1285b), pnpm-lock.yaml (256815b), README.md (9807b), SKILL.md (3906b), src/config.ts (2100b), src/embeddings.ts (863b), src/index.ts (10652b), src/plugin-types.ts (1447b), src/store.test.ts (12424b), src/store.ts (17641b), src/tools.test.ts (12777b), src/tools.ts (21212b), src/types.ts (2844b), tsconfig.json (540b), vitest.config.ts (404b), _meta.json (131b)\n\nArchive v1.1.0: 19 files, 143114 bytes\n\nFiles: clawdbot.plugin.json (1896b), openclaw.plugin.json (1885b), package-lock.json (91759b), package.json (1294b), pnpm-lock.yaml (256815b), README.md (9807b), SKILL.md (3906b), src/config.ts (2100b), src/embeddings.ts (863b), src/index.ts (10652b), src/plugin-types.ts (1447b), src/store.test.ts (10890b), src/store.ts (17329b), src/tools.test.ts (12777b), src/tools.ts (21212b), src/types.ts (2844b), tsconfig.json (540b), vitest.config.ts (404b), _meta.json (131b)\n\nArchive v1.0.5: 19 files, 146161 bytes\n\nFiles: clawdbot.plugin.json (1896b), openclaw.plugin.json (1885b), package-lock.json (106960b), package.json (1311b), pnpm-lock.yaml (256815b), README.md (9710b), SKILL.md (3906b), src/config.ts (2100b), src/embeddings.ts (863b), src/index.ts (10652b), src/plugin-types.ts (1447b), src/store.test.ts (10821b), src/store.ts (12229b), src/tools.test.ts (12708b), src/tools.ts (21212b), src/types.ts (2844b), tsconfig.json (540b), vitest.config.ts (404b), _meta.json (131b)","readmeExcerpt":"Skill: Memory Tools Owner: gianni-dalerta Summary: Agent-controlled memory plugin for OpenClaw with confidence scoring, decay, and semantic search. The agent decides WHEN to store/retrieve memories — no auto-... Tags: latest:2.0.4 Version history: v2.0.4 | 2026-02-18T19:20:20.054Z | user Security hardening: changed high-impact behaviors to opt-in defaults (autoInjectInstructions=false, autoMigrateLegacy=false), remov","codeSnippets":[],"executableExamples":[{"language":"bash","snippet":"clawhub install memory-tools"},{"language":"bash","snippet":"cd skills/memory-tools\nnpm install\nnpm run build"},{"language":"bash","snippet":"openclaw plugins install --link .\nopenclaw plugins enable memory-tools"},{"language":"bash","snippet":"openclaw gateway restart"},{"language":"bash","snippet":"npm install -g @tobilu/qmd"},{"language":"text","snippet":"~/.openclaw/memories/\n├── facts/\n│   └── abc123-def4-5678-90ab-cdef12345678.md\n├── preferences/\n│   └── def456-7890-abcd-ef12-345678901234.md\n├── instructions/\n│   └── ghi789-0abc-def1-2345-678901234567.md\n└── .deleted/\n    └── old-memory.md"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: memory-tools\ndescription: Agent-controlled memory plugin for OpenClaw with confidence scoring, decay, and semantic search. The agent decides WHEN to store/retrieve memories — no auto-capture noise. v2 uses file-based storage with optional QMD search (no external APIs required).\nhomepage: https://github.com/Purple-Horizons/memory-tools\nmetadata:\n  openclaw:\n    emoji: 🧠\n    kind: plugin\n---\n\n# Memory Tools v2\n\nAgent-controlled persistent memory for OpenClaw.\n\n## What's New in v2\n\n- **File-based storage** — Memories stored as readable markdown files\n- **No external APIs** — No OpenAI dependency, everything runs locally\n- **QMD search (optional)** — BM25 + vector + reranking via local GGUF models\n- **Auto-migration** — Seamlessly upgrades from v1 SQLite/LanceDB storage\n\n## Why Memory-as-Tools?\n\nTraditional memory systems auto-capture everything, flooding context with irrelevant information. Memory Tools follows the [AgeMem](https://arxiv.org/abs/2409.02634) approach: **the agent decides** when to store and retrieve memories.\n\n## Features\n\n- **6 Memory Tools**: `memory_store`, `memory_update`, `memory_forget`, `memory_search`, `memory_summarize`, `memory_list`\n- **Confidence Scoring**: Track how certain you are (1.0 = explicit, 0.5 = inferred)\n- **Importance Scoring**: Prioritize critical instructions over nice-to-know facts\n- **Decay/Expiration**: Temporal memories automatically become stale\n- **Human-readable storage**: Markdown files with YAML frontmatter\n- **Conflict Resolution**: New info auto-supersedes old (no contradictions)\n\n## Installation\n\n### Step 1: Install from ClawHub\n\n```bash\nclawhub install memory-tools\n```\n\n### Step 2: Build the plugin\n\n```bash\ncd skills/memory-tools\nnpm install\nnpm run build\n```\n\n### Step 3: Activate the plugin\n\n```bash\nopenclaw plugins install --link .\nopenclaw plugins enable memory-tools\n```\n\n### Step 4: Restart the gateway\n\n```bash\nopenclaw gateway restart\n```\n\n### Optional: Install QMD for better search\n\n```bash\nnpm install -g @tobilu/qmd\n```\n\nWithout QMD, basic filtering works. With QMD, you get semantic search (BM25 + vector + reranking).\n\n### Node Compatibility (QMD)\n\n- QMD may not be compatible with the newest Node ABI immediately.\n- If QMD fails (for example `NODE_MODULE_VERSION` mismatch), memory-tools falls back to basic mode.\n- To force basic mode: `MEMORY_TOOLS_DISABLE_QMD=true`.\n- For best QMD stability, use a Node LTS version supported by your installed QMD build.\n\n## Security Model\n\n- No API keys or external credentials are required.\n- Data is stored locally in `~/.openclaw/memories` (or configured `memoriesPath`).\n- The plugin can prepend standing-instruction context at `before_agent_start` when `autoInjectInstructions=true`.\n- The plugin can auto-migrate legacy v1 data from `~/.openclaw/memory/tools/memory.db` when `autoMigrateLegacy=true`.\n- Defaults are conservative: both `autoInjectInstructions` and `autoMigrateLegacy` are `false`.\n\n## Storage Format\n\nMemories are stored as markdown "},{"path":"README.md","content":"<p align=\"center\">\n  <img src=\"header.png\" alt=\"memory-tools\" width=\"100%\">\n</p>\n\n# OpenClaw Memory Tools v2\n\nAgent-controlled memory plugin for OpenClaw with confidence scoring, decay, and semantic search.\n\n## What's New in v2\n\n- **File-based storage** - Memories stored as readable markdown files\n- **No external APIs** - No OpenAI dependency, everything runs locally\n- **QMD search (optional)** - BM25 + vector + reranking via local GGUF models\n- **Auto-migration** - Seamlessly upgrades from v1 SQLite/LanceDB storage\n\n## Why Memory-as-Tools?\n\nTraditional AI memory systems auto-capture everything, flooding context with irrelevant information. **Memory-as-Tools** follows the [AgeMem](https://arxiv.org/abs/2409.02634) approach: the agent decides **when** to store and retrieve memories.\n\n```\nTraditional: Agent -> always retrieves -> context flooded\nMemory-as-Tools: Agent -> decides IF/WHAT to remember -> uses tools explicitly\n```\n\n## Features\n\n- **6 Memory Tools**: `memory_store`, `memory_update`, `memory_forget`, `memory_search`, `memory_summarize`, `memory_list`\n- **Confidence Scoring**: Track how certain you are about each memory (1.0 = explicit, 0.5 = inferred)\n- **Importance Scoring**: Prioritize critical instructions over nice-to-know facts\n- **Decay/Expiration**: Temporal memories (events) automatically become stale\n- **Human-readable storage**: Markdown files with YAML frontmatter\n- **Semantic Search**: Optional QMD-powered hybrid search (BM25 + vector + reranking)\n- **Zero External Dependencies**: Everything runs locally, no API keys needed\n- **Standing Instructions**: Auto-inject category=\"instruction\" memories at conversation start\n\n## Installation\n\n### Step 1: Install from ClawHub\n\n```bash\nclawhub install memory-tools\n```\n\n### Step 2: Build the plugin\n\n```bash\ncd skills/memory-tools\nnpm install\nnpm run build\n```\n\n### Step 3: Activate the plugin\n\n```bash\nopenclaw plugins install --link .\nopenclaw plugins enable memory-tools\n```\n\n### Step 4: Restart the gateway\n\n```bash\nopenclaw gateway restart\n```\n\n### Optional: Install QMD for better search\n\n```bash\nnpm install -g @tobilu/qmd\n```\n\nWithout QMD, basic category/tag filtering works. With QMD, you get semantic search (BM25 + vector + reranking using local GGUF models).\n\n### Node Compatibility (QMD)\n\n- `memory-tools` works without QMD on modern Node versions.\n- QMD dependencies (notably `better-sqlite3`) may lag behind the latest Node ABI.\n- If QMD fails on startup (for example `NODE_MODULE_VERSION` mismatch on Node v25), the plugin now falls back to basic mode.\n- To force basic mode explicitly, set `MEMORY_TOOLS_DISABLE_QMD=true`.\n- Recommended for full QMD stability: use a Node LTS version supported by your installed QMD build.\n\n## Configuration\n\nAdd to `~/.openclaw/openclaw.json`:\n\n```json\n{\n  \"plugins\": {\n    \"slots\": {\n      \"memory\": \"memory-tools\"\n    },\n    \"entries\": {\n      \"memory-tools\": {\n        \"enabled\": true,\n        \"config\": {\n          \"memoriesPath\": \"~/.openclaw/memories\",\n"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn7ajybsnj998tbfcgvrc7731s803brp\",\n  \"slug\": \"memory-tools\",\n  \"version\": \"2.0.4\",\n  \"publishedAt\": 1771442420054\n}"},{"path":"CLAUDE.md","content":"# CLAUDE.md\n\nProject context for Claude Code.\n\n## Project\n\n**memory-tools v2** - Agent-controlled memory plugin for OpenClaw/ClawHub.\n\n- **Repo**: `Purple-Horizons/memory-tools`\n- **ClawHub slug**: `memory-tools`\n- **Owner**: gianni-dalerta\n\n## Architecture (v2)\n\n- **File-based storage** - Memories stored as markdown files with YAML frontmatter\n- **QMD search** - Optional BM25 + vector + reranking via local GGUF models\n- **No external APIs** - No OpenAI dependency, everything runs locally\n- **Auto-migration** - Seamlessly upgrades from v1 SQLite/LanceDB storage\n\n### Storage Structure\n```\n~/.openclaw/memories/\n├── facts/\n│   └── abc123.md\n├── preferences/\n│   └── def456.md\n├── instructions/\n│   └── ghi789.md\n└── .deleted/\n    └── old-memory.md\n```\n\n### Memory File Format\n```markdown\n---\nid: abc123-def4-5678-90ab-cdef12345678\ncategory: preference\nconfidence: 0.9\nimportance: 0.7\ncreated_at: 2024-01-15T10:30:00Z\ntags: [ui, settings]\n---\n\nUser prefers dark mode in all applications.\n```\n\n## Key Decisions\n\n- **v2 rewrote storage layer**: Switched from SQLite + LanceDB + OpenAI to file-based + QMD\n- **QMD is optional**: Works without QMD (basic file listing), better search with QMD installed\n- **Auto-migration**: v2 detects v1 databases and automatically exports to markdown files\n- **Backward compatible API**: Tools interface unchanged, existing integrations work\n\n## QMD Integration\n\nQMD provides hybrid search (BM25 + vector + reranking) using local GGUF models:\n- `npm install -g @tobilu/qmd` to install\n- Models download on first use (~2GB total)\n- Without QMD: basic category/tag filtering only\n- With QMD: semantic search across all memories\n\n## Publishing to ClawHub\n\n```bash\nclawhub publish . --slug memory-tools --version X.Y.Z --changelog \"description\"\n```\n\nAlways use `--slug memory-tools` to update the correct skill.\n\n## Build & Test\n\n```bash\nnpm run build    # TypeScript compile\nnpm test         # Run vitest (uses MEMORY_TOOLS_DISABLE_QMD=true in CI)\n```\n\n## Environment Variables\n\n- `MEMORY_TOOLS_DISABLE_QMD=true` - Disable QMD for testing"},{"path":"clawdbot.plugin.json","content":"{\n  \"id\": \"memory-tools\",\n  \"kind\": \"memory\",\n  \"name\": \"Memory Tools\",\n  \"description\": \"Agent-controlled memory with file-based storage and optional QMD search. No external APIs required.\",\n  \"version\": \"2.0.4\",\n  \"uiHints\": {\n    \"memoriesPath\": {\n      \"label\": \"Memories Path\",\n      \"placeholder\": \"~/.clawdbot/memories\",\n      \"advanced\": true,\n      \"help\": \"Directory for storing memory files\"\n    },\n    \"autoInjectInstructions\": {\n      \"label\": \"Auto-Inject Instructions\",\n      \"help\": \"Inject standing instructions (category='instruction') at conversation start\"\n    },\n    \"autoMigrateLegacy\": {\n      \"label\": \"Auto-Migrate Legacy DB\",\n      \"advanced\": true,\n      \"help\": \"Automatically migrate v1 database to markdown files on startup\"\n    },\n    \"qmdCollection\": {\n      \"label\": \"QMD Collection\",\n      \"advanced\": true,\n      \"help\": \"QMD collection name for semantic search index\"\n    }\n  },\n  \"configSchema\": {\n    \"type\": \"object\",\n    \"additionalProperties\": false,\n    \"properties\": {\n      \"memoriesPath\": {\n        \"type\": \"string\",\n        \"description\": \"Directory for storing memory markdown files\"\n      },\n      \"autoInjectInstructions\": {\n        \"type\": \"boolean\",\n        \"default\": false\n      },\n      \"autoMigrateLegacy\": {\n        \"type\": \"boolean\",\n        \"default\": false\n      },\n      \"qmdCollection\": {\n        \"type\": \"string\",\n        \"default\": \"memories\"\n      }\n    }\n  }\n}"}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":null,"editorialQuality":{"score":100,"threshold":65,"status":"thin","wordCount":1411,"uniquenessScore":43,"reasons":["uniqueness-below-45"]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-09T07:47:19.347Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-09T07:47:19.347Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-09T11:56:21.233Z","emptyReason":null},"items":[{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-10T18:48:31.762Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}