hmem-mcp 6.5.0 → 6.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hmem-mcp",
3
- "version": "6.5.0",
3
+ "version": "6.5.1",
4
4
  "description": "Humanlike memory for AI agents — MCP server with 5-level lazy-loaded SQLite memory",
5
5
  "author": "Bumblebiber",
6
6
  "license": "MIT",
@@ -15,39 +15,26 @@ If `write_memory` is not available:
15
15
 
16
16
  ## Syntax
17
17
 
18
- ```
19
- write_memory(
20
- prefix: "E",
21
- content: "Short Title (~50 chars)\n\nL1 body — detailed explanation, can span multiple lines\nsecond body line with more context\n\tL2 node title\n\n\tL2 body text (supports newlines)\n\tmore L2 body\n\t\tL3 detail (2 tabs)\n\t\t\tL4 raw data (3 tabs — rarely needed)"
22
- )
23
- ```
18
+ Every node has a **title** (short navigation label, shown in listings) and an optional **body** (detail shown on drill-down). Use explicit parameters — avoid blank-line tricks in `content`:
24
19
 
25
- **Title + Body convention (git-commit style):** Every node has a **title** (short navigation label) and an optional **body** (detailed content loaded on drill-down). Separate them with a **blank line** — just like a git commit message.
20
+ ```python
21
+ # Preferred: explicit title + body
22
+ write_memory(prefix="E", title="Short Title (~50 chars)", body="Full explanation here.\nCan span multiple lines.", content="\tL2 section\n\t\tL3 detail")
26
23
 
27
- - **Title:** The first line (L1) or first line at a given indent level (L2+). ~50 chars, like a chapter title.
28
- - **Body:** Everything after the blank line at the same indent level. Freetext, no special prefix needed. Shown only when the node is drilled into, not in listings.
29
- - **Legacy `> ` prefix:** Still works for backward compatibility, but blank-line separation is preferred.
30
- - **Without body:** The full text is stored as `content` and the title is auto-extracted from the first `maxTitleChars` characters.
24
+ # Title only (no body)
25
+ write_memory(prefix="L", title="FTS5 needs rowid-map for contentless tables", content="\tDetails\n\t\tImplication")
31
26
 
32
- **L1 example with body:**
27
+ # Legacy (still works, but avoid for new entries)
28
+ write_memory(prefix="E", content="Short Title\n\nBody text here.\n\tL2 section\n\t\tL3 detail")
33
29
  ```
34
- Short Error Title
35
30
 
36
- SQLite connection failed because .mcp.json used a relative path.
37
- The fix was to use an absolute path in the HMEM_PATH env var.
38
- Details about reproduction
31
+ **Parameters:**
32
+ - **`title`** Short label (~50 chars). Think "chapter title in a book". Shown in all listings.
33
+ - **`body`** — Freetext detail (any length, newlines OK). Shown only on drill-down.
34
+ - **`content`** — Tab-indented sub-nodes (L2+). When `title` is given, `content` holds only sub-nodes. In legacy mode (no `title`), `content` holds everything.
39
35
 
40
- Steps: 1. Set HMEM_PATH=./hmem 2. Run hmem serve 3. Observe SQLITE_CANTOPEN
41
- ```
42
-
43
- **L1 example without body (still works):**
44
- ```
45
- SQLite connection failed due to wrong path in .mcp.json
46
- Fix: use absolute path in env var
47
- ```
36
+ **Sub-node indentation:** 1 tab = 1 level deeper. Never use tabs for text formatting inside body — tabs are structural.
48
37
 
49
- **Indentation:** 1 tab = 1 level. Alternatively: 2 or 4 spaces per level (auto-detected).
50
- **Warning:** A tab at the start of any line always means "go one level deeper" — it is structural, not content. If you need to store code or text that contains leading tabs, use spaces instead.
51
38
  **IDs and timestamps** are assigned automatically — never write them yourself.
52
39
 
53
40
  ---
@@ -190,16 +177,18 @@ The MCP server validates that L2 nodes start with one of these names. Minimum fo
190
177
 
191
178
  **Complete P-entry example (WeatherBot):**
192
179
 
193
- ```
180
+ ```python
194
181
  write_memory(
195
182
  prefix="P",
196
- content="WeatherBot | New | Python/Discord.py | GH: user/weatherbot\n\nDiscord bot for weather forecasts — slash commands for current weather and multi-day forecasts\n\tOverview\n\t\tCurrent state\n\n\t\tScaffolding done, no commands yet. Bot connects to Discord but has no slash commands registered.\n\t\tGoals\n\n\t\tDaily/hourly forecasts via slash commands, multi-city support, embed formatting\n\t\tArchitecture\n\n\t\tDiscord slash command → OpenWeatherMap API → formatted embed. Single-file cog pattern.\n\t\tEnvironment\n\n\t\t/home/user/weatherbot, python bot.py, needs DISCORD_TOKEN + WEATHER_API_KEY in .env\n\tCodebase\n\t\tEntry point — bot.py, start: python bot.py\n\t\tCore modules\n\t\t\tweather_cog.py — WeatherCog(Cog); fetch_forecast(city: str) → discord.Embed\n\t\t\tformatter.py — format_embed(data: dict) → discord.Embed\n\t\tHelpers / Utilities\n\t\t\tapi_client.py — get_weather(city: str) → dict; wraps HTTP to OpenWeatherMap\n\t\tConfig / Constants — .env: DISCORD_TOKEN, WEATHER_API_KEY, DEFAULT_CITY\n\t\tTests — pytest, test_weather_cog.py (3 tests)\n\tUsage\n\t\tInstallation / Setup — pip install -r requirements.txt, cp .env.example .env\n\t\tCLI / API — /weather <city>, /forecast <city> (planned)\n\tContext\n\t\tInitiator — personal project, Mar 2026\n\t\tTarget audience — personal Discord server\n\t\tDependencies — discord.py, OpenWeatherMap API, aiohttp\n\tOpen tasks\n\t\tImplement /forecast command\n\n\t\tMulti-day view with daily highs/lows and weather icons per day\n\t\tAdd city autocomplete",
183
+ title="WeatherBot | New | Python/Discord.py | GH: user/weatherbot",
184
+ body="Discord bot for weather forecasts — slash commands for current weather and multi-day forecasts",
185
+ content="\tOverview\n\t\tCurrent state\n\t\t> Scaffolding done, no commands yet. Bot connects to Discord but has no slash commands registered.\n\t\tGoals\n\t\t> Daily/hourly forecasts via slash commands, multi-city support, embed formatting\n\t\tArchitecture\n\t\t> Discord slash command → OpenWeatherMap API → formatted embed. Single-file cog pattern.\n\t\tEnvironment\n\t\t> /home/user/weatherbot, python bot.py, needs DISCORD_TOKEN + WEATHER_API_KEY in .env\n\tCodebase\n\t\tEntry point — bot.py, start: python bot.py\n\t\tCore modules\n\t\t\tweather_cog.py — WeatherCog(Cog); fetch_forecast(city: str) → discord.Embed\n\t\t\tformatter.py — format_embed(data: dict) → discord.Embed\n\t\tHelpers / Utilities\n\t\t\tapi_client.py — get_weather(city: str) → dict; wraps HTTP to OpenWeatherMap\n\t\tConfig / Constants — .env: DISCORD_TOKEN, WEATHER_API_KEY, DEFAULT_CITY\n\t\tTests — pytest, test_weather_cog.py (3 tests)\n\tUsage\n\t\tInstallation / Setup — pip install -r requirements.txt, cp .env.example .env\n\t\tCLI / API — /weather <city>, /forecast <city> (planned)\n\tContext\n\t\tInitiator — personal project, Mar 2026\n\t\tTarget audience — personal Discord server\n\t\tDependencies — discord.py, OpenWeatherMap API, aiohttp\n\tNext Steps\n\t\tImplement /forecast command\n\t\t> Multi-day view with daily highs/lows and weather icons per day\n\t\tAdd city autocomplete",
197
186
  tags=["#discord", "#python", "#weather", "#bot"],
198
187
  links=[]
199
188
  )
200
189
  ```
201
190
 
202
- Note: L2 nodes use 1 tab, L3 uses 2 tabs, L4 uses 3 tabs. Separate title from body with a blank line at the same indent level. Skip empty sections — no need for placeholder text.
191
+ Note: L2 nodes use 1 tab, L3 uses 2 tabs, L4 uses 3 tabs. Use `title`+`body` for the root entry. For body text on sub-nodes inside `content`, use the `> ` prefix (unambiguous, no blank-line tricks). Skip empty sections — no need for placeholder text.
203
192
 
204
193
  ### E-Entry Schema (auto-scaffolded)
205
194
 
@@ -291,15 +280,19 @@ write_memory(
291
280
  - Not "Fixed a bug" — instead explain root cause, fix, and impact
292
281
 
293
282
  **With title + body (recommended):**
294
- ```
295
- write_memory(prefix="L", content="hmem.py Performance: Bulk-Queries statt N+1\n\nAlle Nodes in 2 Bulk-Queries laden, nicht pro Entry einzeln.\nVorher: load_nodes() pro Entry = N+1 SQLite-Connections.\n\tImplementation detail\n\n\tChanged read() to batch-fetch all nodes for visible entries in one query")
283
+ ```python
284
+ write_memory(
285
+ prefix="L",
286
+ title="hmem.py Performance: Bulk-Queries statt N+1",
287
+ body="Alle Nodes in 2 Bulk-Queries laden, nicht pro Entry einzeln.\nVorher: load_nodes() pro Entry = N+1 SQLite-Connections.",
288
+ content="\tImplementation detail\n\t\tChanged read() to batch-fetch all nodes for visible entries in one query"
289
+ )
296
290
  ```
297
291
 
298
- **Without body (simple entries, backward-compatible):**
292
+ **Without body (simple entries, still works):**
293
+ ```python
294
+ write_memory(prefix="E", title="SQLite connection failed due to wrong path in .mcp.json", content="\tFix: use absolute path in env var")
299
295
  ```
300
- write_memory(prefix="E", content="SQLite connection failed due to wrong path in .mcp.json\n\tFix: use absolute path in env var")
301
- ```
302
- Title auto-extracted: `"SQLite connection failed due to wrong path in .mc"`
303
296
 
304
297
  ---
305
298
 
@@ -403,10 +396,21 @@ Use `update_memory` and `append_memory` to modify entries without deleting and r
403
396
 
404
397
  Updates the text of a single node. Children are **not** touched.
405
398
 
406
- ```
407
- update_memory(id="L0003", content="Corrected L1 summary — new wording")
408
- update_memory(id="L0003.2", content="Fixed L2 detail")
409
- update_memory(id="D0010", content="New L1", links=["E0042"]) # also update links
399
+ ```python
400
+ # Update title only
401
+ update_memory(id="L0003", content="Corrected summary — new wording")
402
+
403
+ # Update body only (title preserved automatically)
404
+ update_memory(id="L0003", body="New detailed explanation here.")
405
+
406
+ # Update both title and body
407
+ update_memory(id="L0003", content="New short title", body="New detailed body text.")
408
+
409
+ # Update sub-node
410
+ update_memory(id="L0003.2", content="Fixed sub-node title", body="Sub-node body.")
411
+
412
+ # Also update links
413
+ update_memory(id="D0010", content="New title", links=["E0042"])
410
414
  ```
411
415
 
412
416
  Use when: the wording is wrong, outdated, or needs clarification.
@@ -415,34 +419,21 @@ Use when: the wording is wrong, outdated, or needs clarification.
415
419
 
416
420
  Appends new child nodes under an existing root or node. Existing children are preserved.
417
421
 
418
- Content indentation is **relative to the parent** — 0 tabs = direct child of `id`.
419
- Body works the same as in `write_memory` — blank line separates title from body.
422
+ ```python
423
+ # Preferred: explicit title + body
424
+ append_memory(id="L0003", title="New finding", body="Detailed explanation of what was found.\nCan span multiple lines.")
420
425
 
421
- > **Schema enforcement:** For entries with a defined schema (e.g., all P-entries), appending
422
- > to the root (e.g., `id="P0029"`) is **blocked** — that would create a new L2 section outside
423
- > the schema. You must target a specific section: `append_memory(id="P0029.3", content="...")`.
424
- > For entries without a schema (L, D, E, etc. by default), root appends are allowed.
426
+ # With sub-nodes (complex mode)
427
+ append_memory(id="L0003", content="New finding\n\tSub-detail\n\t\tDeep detail")
425
428
 
429
+ # Append to a specific section node
430
+ append_memory(id="P0029.3", title="New usage example", body="Run: hmem serve --port 3100")
426
431
  ```
427
- append_memory(
428
- id="L0003",
429
- content="New finding discovered later\n\nDetailed explanation of what was found and why it matters.\nThis can span multiple lines.\n\tSub-detail about it"
430
- )
431
- # → adds L0003.N (L2 with title + body) and L0003.N.1 (L3)
432
- # ↑ only works if L has no schema defined; use L0003.N for schema-constrained entries
433
432
 
434
- append_memory(
435
- id="P0029.3",
436
- content="New detail in the Usage section"
437
- )
438
- # → adds P0029.3.M (L3 under section .3) — correct way for schema-constrained entries
439
-
440
- append_memory(
441
- id="L0003.2",
442
- content="Extra note under L0003.2"
443
- )
444
- # → adds L0003.2.M (L3)
445
- ```
433
+ > **Schema enforcement:** For entries with a defined schema (e.g., all P-entries), appending
434
+ > to the root (e.g., `id="P0029"`) is **blocked** — that would create a new L2 section outside
435
+ > the schema. You must target a specific section: `append_memory(id="P0029.3", ...)`.
436
+ > For entries without a schema (L, D, E, etc. by default), root appends are allowed.
446
437
 
447
438
  Use when: you have new context to add without replacing what's there.
448
439