hmem-mcp 6.3.0 → 6.3.2

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.
@@ -55,11 +55,18 @@ Check for new skills that weren't there before — inform the user about new cap
55
55
 
56
56
  Hooks are critical — without them, O-entries are never logged and auto-checkpoints never fire.
57
57
 
58
- Check the current hook configuration:
58
+ Check the current hook configuration. Use the platform-appropriate command:
59
+
59
60
  ```bash
61
+ # Linux / macOS
60
62
  cat ~/.claude/settings.json | grep -A5 hooks
61
63
  ```
62
64
 
65
+ ```powershell
66
+ # Windows (PowerShell)
67
+ Get-Content "$env:USERPROFILE\.claude\settings.json" | Select-String -Pattern "hooks" -Context 0,5
68
+ ```
69
+
63
70
  **Required hooks (for `checkpointMode: "auto"`):**
64
71
  - **UserPromptSubmit** — memory load + checkpoint reminder
65
72
  - **Stop** — exchange logging (`hmem log-exchange`) + O-entry title generation
@@ -73,6 +80,46 @@ cat ~/.claude/settings.json | grep -A5 hooks
73
80
  - Check that hook scripts exist and are executable
74
81
  - Verify they reference the current hmem installation path
75
82
 
83
+ ### Windows-specific hook checks (CRITICAL)
84
+
85
+ On Windows, two specific issues break hooks. Always run these checks when updating on Windows:
86
+
87
+ **Check 1 — `shell: powershell` present on every hook command?**
88
+
89
+ Each object in `hooks.*.hooks` and the `statusLine` object must contain `"shell": "powershell"`. Without it, Claude Code may route the command through Git Bash, whose MSYS2 runtime crashes transiently at startup (`bash.exe: *** fatal error - add_item ... errno 1`) before the command is even parsed. Every hook then fails with a generic error.
90
+
91
+ **Check 2 — No inline env-var syntax in commands?**
92
+
93
+ Commands must NOT contain `VAR=value` prefixes like `HMEM_PATH=C:/... node ...`. That's bash-only syntax; cmd.exe and PowerShell interpret `HMEM_PATH=...` as the command name and fail. All env vars must live in the top-level `env` block of settings.json.
94
+
95
+ **The correct Windows shape:**
96
+
97
+ ```json
98
+ {
99
+ "env": {
100
+ "HMEM_PATH": "C:/Users/<you>/.hmem/Agents/<AGENT>/<AGENT>.hmem"
101
+ },
102
+ "hooks": {
103
+ "Stop": [
104
+ {
105
+ "matcher": "",
106
+ "hooks": [
107
+ {
108
+ "type": "command",
109
+ "command": "node C:/Users/<you>/AppData/Roaming/npm/node_modules/hmem-mcp/dist/cli.js log-exchange",
110
+ "shell": "powershell"
111
+ }
112
+ ]
113
+ }
114
+ ]
115
+ }
116
+ }
117
+ ```
118
+
119
+ **If either check fails:** Offer to fix settings.json automatically. The fix is lossless on other platforms, so it's safe to apply even on shared configs synced across OSes. Point the user to the Windows hook section in `/hmem-config` for the full pattern (UserPromptSubmit, Stop, SessionStart, statusLine).
120
+
121
+ **After fixing:** Claude Code must be restarted so the `env` block is re-loaded and hooks are re-registered with the new shell.
122
+
76
123
  ---
77
124
 
78
125
  ## Step 2c: Check load_project Display Config
@@ -76,15 +76,17 @@ Do NOT attempt to run /clear yourself — it is a built-in CLI command only the
76
76
 
77
77
  ## What happens after /clear
78
78
 
79
- The `SessionStart[clear]` hook automatically:
79
+ Context is restored **automatically** by the `SessionStart[clear]` hook — no
80
+ agent action needed after /clear. Do **NOT** call `load_project` or `read_memory`
81
+ during or after this skill; the next session's first UserPromptSubmit hook will
82
+ trigger the normal hmem-read flow with a verified active project ID.
83
+
84
+ The hook:
80
85
  1. Resets the MCP session cache
81
86
  2. Injects recent conversation exchanges from the project's O-entry transcript
82
87
  3. Injects the active project briefing (overview expanded)
83
88
  4. Injects recent O-entry titles + rules
84
89
 
85
- The agent then calls `load_project` and has full context to continue working.
86
- No manual restoration needed.
87
-
88
90
  ## Why this flow works
89
91
 
90
92
  - **O-entries are covered.** The Stop hook logs every exchange to the active
@@ -131,10 +131,20 @@ append_memory(id="P0048.6", content="Auto-sync fails with multiple .hmem in CWD
131
131
  ```
132
132
  Custom prefixes are merged with the defaults — they don't replace them. Without registering, the system will reject the prefix.
133
133
 
134
- ### P-Entry Standard Schema (enforced by MCP server)
134
+ ### Schema-Enforced Entries (P and any prefix with a defined schema)
135
135
 
136
- Every project entry MUST follow this structure. The MCP server validates L2 nodes
137
- against the standard categories when `prefix="P"`.
136
+ The MCP server enforces schemas for any prefix that has a `schemas` entry in `hmem.config.json`.
137
+ For those prefixes, two rules apply:
138
+
139
+ 1. **`write_memory`**: L2 node names must match the defined section names (error otherwise).
140
+ 2. **`append_memory` to root entry (e.g. `P0029`, no dot)**: **blocked** — you cannot add new L2 sections.
141
+ You must append to a specific section: `append_memory(id="P0029.N", content="...")`.
142
+
143
+ By default, `P` has a schema. If `L`, `D`, or other prefixes are configured with schemas, the same rules apply.
144
+
145
+ ### P-Entry Standard Schema
146
+
147
+ Every project entry MUST follow this structure.
138
148
 
139
149
  **L1 Title:** `Name | Status | Tech Stack | GH: owner/repo | Short description`
140
150
  The GH field is optional — include it when a GitHub repo exists, omit otherwise.
@@ -327,7 +337,8 @@ read_memory(id="P0029") # shows root + all L2 titles
327
337
  ```
328
338
  Do any L2 titles match the sub-topic?
329
339
 
330
- - **No match** → `append_memory(id="P0029", content="...")` adds a new L2
340
+ - **No match (and no schema)** → `append_memory(id="P0029", content="...")` adds a new L2
341
+ - **No match (schema-constrained entry like P)** → find the closest existing section and append there (L2 additions are blocked)
331
342
  - **Match found (e.g. .15)** → continue to Step 3
332
343
 
333
344
  **Step 3 — Drill into that L2**
@@ -411,12 +422,24 @@ Appends new child nodes under an existing root or node. Existing children are pr
411
422
  Content indentation is **relative to the parent** — 0 tabs = direct child of `id`.
412
423
  Body works the same as in `write_memory` — blank line separates title from body.
413
424
 
425
+ > **Schema enforcement:** For entries with a defined schema (e.g., all P-entries), appending
426
+ > to the root (e.g., `id="P0029"`) is **blocked** — that would create a new L2 section outside
427
+ > the schema. You must target a specific section: `append_memory(id="P0029.3", content="...")`.
428
+ > For entries without a schema (L, D, E, etc. by default), root appends are allowed.
429
+
414
430
  ```
415
431
  append_memory(
416
432
  id="L0003",
417
433
  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"
418
434
  )
419
435
  # → adds L0003.N (L2 with title + body) and L0003.N.1 (L3)
436
+ # ↑ only works if L has no schema defined; use L0003.N for schema-constrained entries
437
+
438
+ append_memory(
439
+ id="P0029.3",
440
+ content="New detail in the Usage section"
441
+ )
442
+ # → adds P0029.3.M (L3 under section .3) — correct way for schema-constrained entries
420
443
 
421
444
  append_memory(
422
445
  id="L0003.2",
@@ -434,7 +457,7 @@ Use when: you have new context to add without replacing what's there.
434
457
  | L1 wording is wrong/outdated | `update_memory` |
435
458
  | A sub-node has wrong detail | `update_memory` |
436
459
  | You have new info to add | `append_memory` |
437
- | Entry is completely wrong | curator: `delete_agent_memory` + `write_memory` |
460
+ | Entry is completely wrong | mark obsolete with `[✓newId]`, then `write_memory` for the correction |
438
461
 
439
462
  ---
440
463
 
@@ -1,194 +0,0 @@
1
- ---
2
- name: hmem-self-curate
3
- description: Curate your own memory. Systematically review entries — mark obsolete, irrelevant, or favorite. Run periodically to keep memory clean. Use when asked to "aufräumen", "clean up memory", "alte Einträge prüfen", "memory review", "Speicher bereinigen", "curate", "tidy up", or when memory_health() shows issues.
4
- ---
5
-
6
- # Self-Curation: Review Your Own Memory
7
-
8
- You are curating **your own** memory. You know best which entries are still relevant.
9
-
10
- ---
11
-
12
- ## Step 0: Health Check First
13
-
14
- Before diving in, run an audit to get a prioritized list of issues:
15
-
16
- ```
17
- memory_health()
18
- ```
19
-
20
- This instantly shows:
21
- - **Broken links** — fix or remove them first (high impact, easy to miss manually)
22
- - **Orphaned entries** — root entries with no sub-nodes (likely draft stubs)
23
- - **Stale favorites/pinned** — favorites not accessed in >60 days (demote or verify)
24
- - **Broken obsolete chains** — `[✓ID]` pointing to deleted entries
25
-
26
- Also useful before starting:
27
- ```
28
- memory_stats() # overview: how many entries per prefix, stale count, etc.
29
- read_memory(stale_days=60) # entries not touched in 60 days — prime curation candidates
30
- ```
31
-
32
- ---
33
-
34
- ## Workflow: Prefix by Prefix
35
-
36
- Work through one prefix at a time. Load all entries of a prefix with full depth:
37
-
38
- ```
39
- read_memory(prefix="P", show_all=true)
40
- ```
41
-
42
- This bypasses the bulk-read algorithm and session cache — every entry is expanded with L2+L3 children visible. Review each entry in the output directly — no need to drill into individual entries.
43
-
44
- **Order:** Start with the prefix that has the most entries (usually P), then move to L, E, D, O, etc.
45
-
46
- If context overflows mid-prefix, continue with the remaining entries — your memory survives compression.
47
-
48
- ---
49
-
50
- ## O-Entries (Session Logs)
51
-
52
- O-entries accumulate automatically via the Stop hook — each session creates one per project. `load_project` injects the latest session's **checkpoint summary** (if available) plus the most recent raw exchanges.
53
-
54
- **Checkpoint summaries:** Auto-checkpoints write a `[CP]` prefixed summary node (tagged `#checkpoint-summary`) under the O-entry. These rolling summaries compress older exchanges so `load_project` stays compact. Older summaries are further compressed into 1-2 sentences by each new checkpoint.
55
-
56
- **Skill-dialog filtering:** Exchanges containing skill activations (brainstorming, TDD, debugging) are tagged `#skill-dialog` at the exchange-node level and automatically excluded from `load_project` / `/clear` output. The full content remains accessible via `read_memory(id="O0123")`.
57
-
58
- **Curation rules for O-entries:**
59
- - **Leave them alone.** Old O-entries don't cause harm — they're excluded from bulk reads and `load_project` only shows the most recent one.
60
- - **Don't mark them irrelevant or obsolete** — they serve as historical record and can be useful for checkpoint agents extracting L/D/E.
61
- - **Skip O-entries during curation.** Focus your time on L, E, D, P entries where curation has real impact.
62
-
63
- ---
64
-
65
- ## Bulk Operations
66
-
67
- For large-scale curation across many entries, use the bulk tools instead of updating one by one:
68
-
69
- | Tool | Purpose |
70
- |------|---------|
71
- | `update_many(updates=[...])` | Batch-update multiple entries at once (content, flags, etc.) |
72
- | `tag_bulk(ids=[...], add_tags=[...], remove_tags=[...])` | Add or remove tags across many entries in one call |
73
- | `tag_rename(old_tag="...", new_tag="...")` | Rename a tag globally across all entries |
74
-
75
- These are especially useful when a curation pass reveals a pattern (e.g., 10 entries that all need the same tag added, or a batch of stale entries to mark irrelevant).
76
-
77
- ---
78
-
79
- ## Title Quality Check
80
-
81
- Since v5.1, every node has a **title** (short navigation label, ~50 chars) and an optional **body** (detailed content shown on drill-down). During curation, check whether titles are good navigation labels:
82
-
83
- - **Vague title?** Update it: `update_memory(id="L0003", content="Better, specific title")`
84
- - **Title = full content?** Old entries without body separation have `title = autoExtract(content)`. If the content is valuable but the title is truncated gibberish, rewrite with explicit title + blank line + body.
85
- - **Long content in a leaf node?** Consider whether it would benefit from title/body separation: `update_memory(id, content="Clear title\n\nDetailed body text")`.
86
-
87
- ---
88
-
89
- ## For Each Entry: Decide and Act
90
-
91
- | Decision | Action |
92
- |----------|--------|
93
- | Still valid and useful | Skip (no action needed) |
94
- | Important reference I need every session | `update_memory(id="X", content="...", favorite=true)` |
95
- | Outdated — a better entry exists | Mark obsolete (see below) |
96
- | Just noise — not wrong, but irrelevant | `update_memory(id="X", content="...", irrelevant=true)` |
97
- | Title is vague or misleading | `update_memory(id="X", content="Better wording")` |
98
- | Sub-node has valuable reference info | `update_memory(id="X.N", content="...", favorite=true)` |
99
-
100
- ---
101
-
102
- ## Marking Obsolete
103
-
104
- Obsolete requires a correction reference. Three patterns:
105
-
106
- **A: Replacement exists already**
107
- ```
108
- update_memory(id="E0023", content="Wrong approach — see [✓E0076]", obsolete=true)
109
- ```
110
-
111
- **B: No replacement exists yet**
112
- ```
113
- write_memory(prefix="L", content="Correct approach is XYZ\n\tDetails...") # -> L0090
114
- update_memory(id="L0042", content="Superseded — see [✓L0090]", obsolete=true)
115
- ```
116
-
117
- **C: Just stale, no correction needed**
118
- If the entry is simply outdated with no replacement (e.g., a finished task, a past state):
119
- ```
120
- update_memory(id="T0005", content="...", irrelevant=true)
121
- ```
122
-
123
- ---
124
-
125
- ## Consolidate Duplicates
126
-
127
- Look for entries covering the same topic (common with P entries). Merge them:
128
-
129
- 1. Pick the **keeper** (the more complete one)
130
- 2. Copy unique info from the duplicate: `append_memory(id="P0029", content="Session from duplicate\n\tDetail carried over")`
131
- 3. Mark the duplicate obsolete with a correction reference: `update_memory(id="P0031", content="Merged into [✓P0029]", obsolete=true)`
132
-
133
- **Note:** Only curators (ceo role) can delete entries via `delete_agent_memory`. As a worker agent, use `obsolete=true` with `[✓ID]` to point to the keeper. Obsolete entries are hidden from bulk reads and won't cause confusion.
134
-
135
- ---
136
-
137
- ## Relocate Misplaced Nodes
138
-
139
- When a sub-node belongs under a different root or parent, use `move_memory` to cut and re-insert it. All IDs, links, and `[✓ID]` content references are updated automatically.
140
-
141
- ```
142
- # Move P0029.15 to become a child of L0074
143
- move_memory(source_id="P0029.15", target_parent_id="L0074")
144
- # → P0029.15 (+ all children) become L0074.N (new seq under L0074)
145
-
146
- # Move within the same root: P0029.15 → under P0029.20
147
- move_memory(source_id="P0029.15", target_parent_id="P0029.20")
148
- # → becomes P0029.20.N with all children re-keyed
149
- ```
150
-
151
- **Constraints:**
152
- - `source_id` must be a sub-node — cannot move root entries
153
- - Cannot move a node into its own subtree
154
- - Curator variant: `move_agent_memory(agent_name="THOR", source_id="...", target_parent_id="...")`
155
-
156
- ---
157
-
158
- ## Favorite Audit
159
-
160
- Check `[♥]` markers in the output.
161
-
162
- - **Too many?** If >10% are favorites, demote less important ones: `update_memory(id="X", content="...", favorite=false)`
163
- - **Missing?** Reference entries you always need (API endpoints, key decisions, patterns) should be favorited.
164
- - **Sub-nodes:** If a specific L2/L3 is the real reference, favorite the sub-node instead.
165
-
166
- ---
167
-
168
- ## Guidelines
169
-
170
- - **One prefix per batch.** Don't try all 200+ entries at once — focus on one prefix per `show_all` call.
171
- - **Preserve learning value.** Error entries (E) and lessons (L) about *why* something failed are valuable even if the bug is fixed. Only mark obsolete if the analysis is wrong.
172
- - **When in doubt, skip.** False irrelevant/obsolete is harder to undo than leaving an entry alone.
173
- - **Update stale L1 text.** A clear L1 is the most impactful improvement you can make.
174
-
175
- ---
176
-
177
- ## Quick Reference
178
-
179
- | Tool | When |
180
- |------|------|
181
- | `memory_health()` | **Start here** — broken links, orphans, stale favorites |
182
- | `memory_stats()` | Overview before starting |
183
- | `read_memory(stale_days=60)` | Prime curation targets |
184
- | `read_memory(prefix="X", show_all=true)` | Load entire prefix for review |
185
- | `update_memory(id, content, favorite=true)` | Mark as always-show reference |
186
- | `update_memory(id, content, irrelevant=true)` | Hide from bulk reads (noise) |
187
- | `update_memory(id, content, obsolete=true)` | Mark as wrong (needs [✓ID]) |
188
- | `append_memory(id, content)` | Merge info into keeper |
189
- | `move_memory(source_id, target_parent_id)` | Relocate misplaced sub-node (updates all refs) |
190
- | `update_memory(id, content="Merged into [✓X]", obsolete=true)` | Mark duplicate as obsolete (point to keeper) |
191
- | `update_many(updates=[...])` | Batch-update multiple entries at once |
192
- | `tag_bulk(ids=[...], add_tags, remove_tags)` | Add/remove tags across many entries |
193
- | `tag_rename(old_tag, new_tag)` | Rename a tag globally |
194
- | `read_memory(show_obsolete=true, prefix="X")` | Review already-obsolete entries |