handoff-mcp-server 0.15.0 → 0.15.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/Cargo.lock CHANGED
@@ -136,7 +136,7 @@ dependencies = [
136
136
 
137
137
  [[package]]
138
138
  name = "handoff-mcp"
139
- version = "0.15.0"
139
+ version = "0.15.1"
140
140
  dependencies = [
141
141
  "anyhow",
142
142
  "chrono",
package/Cargo.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "handoff-mcp"
3
- version = "0.15.0"
3
+ version = "0.15.1"
4
4
  edition = "2021"
5
5
  description = "MCP server that gives AI coding agents persistent memory across sessions"
6
6
  license = "MIT"
package/README.md CHANGED
@@ -215,6 +215,7 @@ rename) so a concurrent reader never sees a partially-written file.
215
215
  | `handoff_memory_delete` | Delete a memory by id (full id or unique prefix) |
216
216
  | `handoff_memory_cleanup` | Housekeeping (for SessionStart): silently merge exact duplicates, return near-duplicate/stale recommendations, gc old injection sidecars |
217
217
 
218
+ For usage best practices (granularity, scope_paths, conflict handling, cleanup), see `skills/handoff-memory/SKILL.md`.
218
219
  See [Project Memory](#project-memory-1) below for what it is and how to wire automatic injection.
219
220
 
220
221
  ### Task Data Model
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "handoff-mcp-server",
3
- "version": "0.15.0",
3
+ "version": "0.15.1",
4
4
  "description": "MCP server that gives AI coding agents persistent memory across sessions",
5
5
  "license": "MIT",
6
6
  "author": "AlphaElements <66808803+alphaelements@users.noreply.github.com>",
@@ -0,0 +1,139 @@
1
+ ---
2
+ name: handoff-memory
3
+ description: "Project memory — save, query, merge, and clean up durable project knowledge (lessons, rules, conventions, gotchas). Triggers on 'メモリ保存', 'これ覚えて', '知見を残して', '過去の知見', 'memory save', 'memory query', 'remember this', 'recall', 'cleanup memories', or when recording post-incident learnings, recurring NG patterns, or project-specific conventions."
4
+ ---
5
+
6
+ # Handoff Memory Skill
7
+
8
+ ## When to use
9
+
10
+ - The user says "メモリ保存", "これ覚えて", "知見を残して", "remember this", "save this as a memory"
11
+ - The user asks "過去の知見を確認", "recall", "what do we know about X"
12
+ - You discover a reusable lesson, recurring NG pattern, or project-specific convention worth persisting across sessions
13
+ - Post-incident feedback or investigation results should be captured
14
+ - Existing memories need merging, updating, or pruning
15
+ - Session start — run cleanup to keep the memory store healthy
16
+
17
+ ## Granularity Rule
18
+
19
+ **One memory = one piece of knowledge.** Do not bundle multiple unrelated lessons
20
+ into a single memory. Each memory should be independently searchable and
21
+ independently deletable. If two ideas always travel together, save them together;
22
+ if they could be relevant in different contexts, split them.
23
+
24
+ ## Saving a Memory
25
+
26
+ Call `handoff_memory_save` with:
27
+
28
+ | Param | Required | Description |
29
+ |---|---|---|
30
+ | `text` | yes | The memory content. Be specific and actionable — "always use X because Y", not "X is important" |
31
+ | `kind` | no (default: `lesson`) | One of: `lesson` (something learned), `rule` (a mandated practice), `convention` (an agreed pattern), `gotcha` (a non-obvious trap) |
32
+ | `scope_paths` | no | Path prefixes this memory applies to (e.g. `["src/storage/", "src/mcp/handlers/"]`). Memories with matching scope_paths get a relevance boost when the user edits files under those paths |
33
+ | `tags` | no | Free-form tags for searchability (e.g. `["atomic-write", "config"]`). Tags are included in the similarity index |
34
+ | `force` | no | `true` to skip near-duplicate detection and save unconditionally |
35
+ | `merge_into` | no | ID of an existing memory to overwrite with merged content (see Merging below) |
36
+ | `absorb_ids` | no | IDs of memories to delete after merging into the target |
37
+
38
+ ### scope_paths Best Practices
39
+
40
+ - Use directory-level substrings, not full file paths: `"src/storage/"` not `"src/storage/config.rs"`. The matching is substring-based (`file_path.contains(scope)`), so `"storage/"` will match any file whose path contains that segment
41
+ - Scope broadly enough to catch related files, narrowly enough to avoid noise
42
+ - A memory with no scope_paths relies purely on text similarity for injection — fine for project-wide rules, but file-specific gotchas benefit from scoping
43
+
44
+ ### tags Best Practices
45
+
46
+ - Use lowercase, hyphenated terms: `"atomic-write"`, `"json-rpc"`, `"config-toml"`
47
+ - Tags supplement the body text for search — add tags for synonyms or concepts not explicitly mentioned in the body
48
+
49
+ ## Handling Near-Duplicate Conflicts
50
+
51
+ When `handoff_memory_save` returns `status: "conflict"`, it means the new memory
52
+ is similar to one or more existing memories (Jaccard similarity >= threshold). The
53
+ response includes both the new text and the similar existing memories.
54
+
55
+ **Decision flow:**
56
+
57
+ 1. **Read both texts carefully.** Are they expressing the same knowledge?
58
+ 2. **If yes — merge:** Write a combined text that captures both perspectives, then call `handoff_memory_save` again with:
59
+ - `text`: the merged content
60
+ - `merge_into`: ID of the existing memory to keep
61
+ - `absorb_ids`: IDs of any other similar memories to absorb
62
+ - Update `kind`, `tags`, `scope_paths` as needed
63
+ 3. **If no — force-save:** The memories are genuinely distinct despite textual similarity. Call `handoff_memory_save` with `force: true` to save the new one separately.
64
+
65
+ Do not ignore conflicts — they indicate the memory store may have redundancy that degrades injection quality.
66
+
67
+ ## Querying Memories
68
+
69
+ Call `handoff_memory_query` with:
70
+
71
+ | Param | Description |
72
+ |---|---|
73
+ | `text` | The prompt or question to match against (BM25 relevance ranking) |
74
+ | `file_paths` | Files being worked on — memories scoped to these paths get a boost |
75
+ | `session_id` | Current session ID — suppresses re-injection of memories already seen this session |
76
+ | `limit` | Max memories to return (default from config, typically 5) |
77
+ | `tool_name` | Tool being used (adds context tokens for matching) |
78
+ | `mark_injected` | Whether to record injection for dedup (default: true) |
79
+
80
+ The query engine uses BM25 text similarity plus a scope_path bonus. Passing
81
+ `session_id` enables per-session diff injection: a memory already injected this
82
+ session (same content hash) is filtered out, but an edited memory (new hash) is
83
+ re-injected.
84
+
85
+ ## Cleanup
86
+
87
+ ### When to Run
88
+
89
+ Run `handoff_memory_cleanup` at the start of each session (the SessionStart hook
90
+ does this automatically if configured). Optional arguments:
91
+
92
+ | Param | Default | Description |
93
+ |---|---|---|
94
+ | `apply_exact_merges` | `true` | Set `false` to skip auto-merging and only return recommendations |
95
+ | `stale_days` | from config (default 60) | Override the staleness threshold in days |
96
+
97
+ It performs three passes:
98
+
99
+ 1. **Exact duplicates** — silently auto-merged (lossless; oldest entry kept, others absorbed). Skipped when `apply_exact_merges` is `false`
100
+ 2. **Near-duplicate clusters** — returned as recommendations for AI-driven merge
101
+ 3. **Stale memories** — memories not referenced for `stale_days`, returned as recommendations
102
+
103
+ ### Acting on Cleanup Recommendations
104
+
105
+ - **similar_clusters**: Review each cluster. If the memories are truly redundant, merge them with `handoff_memory_save(merge_into=..., absorb_ids=[...])`. If distinct, leave them.
106
+ - **stale**: Consider whether the memory is obsolete (delete with `handoff_memory_delete`) or simply rarely triggered (leave it — low hit_count doesn't mean low value).
107
+
108
+ ### Manual Deletion
109
+
110
+ Call `handoff_memory_delete` with the memory `id` (full ID or unique prefix). Use
111
+ this for memories that are confirmed obsolete, wrong, or superseded by a code
112
+ change.
113
+
114
+ ## Memory Hooks (Optional Auto-Injection)
115
+
116
+ Memory tools can be called manually, but for automatic injection without AI
117
+ initiative, configure Claude Code hooks:
118
+
119
+ | Hook | Tool Call | Purpose |
120
+ |---|---|---|
121
+ | `UserPromptSubmit` | `handoff_memory_query` (prompt text) | Inject memories relevant to each user prompt |
122
+ | `PreToolUse` (`Edit\|Write\|MultiEdit`) | `handoff_memory_query` (file path) | Inject memories scoped to the file being edited |
123
+ | `SessionStart` | `handoff_memory_cleanup` | Auto-merge exact duplicates, surface recommendations |
124
+
125
+ Run `handoff-mcp setup` to install these hooks automatically, or
126
+ `handoff-mcp setup --uninstall` to remove them. See the README for the full hook
127
+ JSON configuration.
128
+
129
+ ## Memory vs Session vs CLAUDE.md
130
+
131
+ | Layer | Lifespan | Purpose |
132
+ |---|---|---|
133
+ | Sessions (`.handoff/sessions/`) | Per-conversation | "What was I doing last time?" |
134
+ | Memory (`.handoff/memory/`) | Cross-session, long-lived | "What has this project learned?" |
135
+ | `CLAUDE.md` | Permanent | Foundational rules, build commands, repo structure |
136
+ | `.claude/skills/` | Permanent | Operational procedures triggered by intent |
137
+
138
+ Rule changes: discover via memory → codify in skills/CLAUDE.md. Memory is the
139
+ source of evidence; skills and CLAUDE.md are the source of authority.