claude_memory 0.8.0 → 0.9.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.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/.claude/memory.sqlite3 +0 -0
  3. data/.claude/rules/claude_memory.generated.md +94 -2
  4. data/.claude/settings.json +30 -52
  5. data/.claude/settings.local.json +3 -1
  6. data/.claude/skills/release/SKILL.md +168 -0
  7. data/.claude/skills/upgrade-dependencies/SKILL.md +154 -0
  8. data/.claude-plugin/marketplace.json +2 -2
  9. data/.claude-plugin/plugin.json +3 -3
  10. data/.claude-plugin/scripts/hook-runner.sh +14 -0
  11. data/.claude-plugin/scripts/serve-mcp.sh +14 -0
  12. data/.ruby-version +1 -1
  13. data/CHANGELOG.md +47 -0
  14. data/CLAUDE.md +31 -17
  15. data/README.md +35 -0
  16. data/db/migrations/013_add_mcp_tool_calls.rb +26 -0
  17. data/db/migrations/014_canonicalize_predicates.rb +30 -0
  18. data/docs/improvements.md +58 -20
  19. data/docs/influence/claude-mem.md +1 -0
  20. data/docs/influence/claude-supermemory.md +1 -0
  21. data/docs/influence/episodic-memory.md +1 -0
  22. data/docs/influence/grepai.md +1 -0
  23. data/docs/influence/kbs.md +1 -0
  24. data/docs/influence/lossless-claw.md +1 -0
  25. data/docs/influence/qmd.md +1 -0
  26. data/lib/claude_memory/commands/completion_command.rb +1 -31
  27. data/lib/claude_memory/commands/embeddings_command.rb +198 -0
  28. data/lib/claude_memory/commands/help_command.rb +8 -1
  29. data/lib/claude_memory/commands/registry.rb +47 -34
  30. data/lib/claude_memory/commands/reject_command.rb +62 -0
  31. data/lib/claude_memory/commands/restore_command.rb +77 -0
  32. data/lib/claude_memory/commands/skills/distill-transcripts.md +5 -1
  33. data/lib/claude_memory/commands/stats_command.rb +98 -2
  34. data/lib/claude_memory/configuration.rb +14 -1
  35. data/lib/claude_memory/distill/json_schema.md +8 -4
  36. data/lib/claude_memory/distill/null_distiller.rb +2 -0
  37. data/lib/claude_memory/domain/entity.rb +13 -1
  38. data/lib/claude_memory/domain/fact.rb +26 -2
  39. data/lib/claude_memory/embeddings/api_adapter.rb +5 -4
  40. data/lib/claude_memory/embeddings/fastembed_adapter.rb +43 -13
  41. data/lib/claude_memory/embeddings/inspector.rb +91 -0
  42. data/lib/claude_memory/embeddings/model_registry.rb +210 -0
  43. data/lib/claude_memory/embeddings/resolver.rb +32 -6
  44. data/lib/claude_memory/ingest/ingester.rb +17 -0
  45. data/lib/claude_memory/mcp/handlers/management_handlers.rb +24 -0
  46. data/lib/claude_memory/mcp/handlers/stats_handlers.rb +5 -2
  47. data/lib/claude_memory/mcp/instructions_builder.rb +17 -0
  48. data/lib/claude_memory/mcp/server.rb +30 -3
  49. data/lib/claude_memory/mcp/telemetry.rb +86 -0
  50. data/lib/claude_memory/mcp/tool_definitions.rb +86 -3
  51. data/lib/claude_memory/mcp/tools.rb +10 -0
  52. data/lib/claude_memory/publish.rb +40 -5
  53. data/lib/claude_memory/recall.rb +81 -0
  54. data/lib/claude_memory/resolve/predicate_policy.rb +63 -3
  55. data/lib/claude_memory/resolve/resolver.rb +43 -0
  56. data/lib/claude_memory/store/schema_manager.rb +1 -1
  57. data/lib/claude_memory/store/sqlite_store.rb +250 -1
  58. data/lib/claude_memory/store/store_manager.rb +50 -1
  59. data/lib/claude_memory/sweep/maintenance.rb +115 -1
  60. data/lib/claude_memory/sweep/sweeper.rb +3 -0
  61. data/lib/claude_memory/version.rb +1 -1
  62. data/lib/claude_memory.rb +5 -0
  63. metadata +27 -8
  64. data/.claude/memory.sqlite3-shm +0 -0
  65. data/.claude/memory.sqlite3-wal +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1483a3663c9c589abad58f80c71d772c592f13727d3fd1339418c2ba1a3db875
4
- data.tar.gz: 34beebdf5e3cc8a70d383757ffaf7e21fde0724f963532e2d2548ec2e63ba329
3
+ metadata.gz: b6df0a3f58a88c1bbec82ec20e26789d51ad2712408d058337a196c5eac90654
4
+ data.tar.gz: beb9c2ef59ef6a45430eeb03466e37f6b1f741ef1745b5303a1443b02a7c84b4
5
5
  SHA512:
6
- metadata.gz: 514022df68751e4421942d914c003a1e104a5c2b5ab4a639619ca05bb4d6bafd722d87009dc898a5b578f1b7efdae50df68b5b8232e1cf42a8bb5e88a06e66c3
7
- data.tar.gz: 68c5a36361d3048e4c92bba7127e7fa0bc9ff09f6de3779ae59f7799cd4152d63030386ea2b124a90b345063545028b0da0401c9144f284c7e34290b2d674ba7
6
+ metadata.gz: '06905bca1f77df5642caf0846cde7394ba9a1baf3c954138383ac39927fcaae2ef097ff79dd3c866e6930fa0eac0d0fb958366bded54a0616d8e356a316e616c'
7
+ data.tar.gz: 9a8e3c455c20ae616bc239b766e1d4e2aa4c6e5448f494294d9c6a646a8a613428e9b63218624c5cae7e30f389704dd3bee6b788e97a369cb719b115abffddd7
Binary file
@@ -1,21 +1,113 @@
1
- <!--
1
+ <!--
2
2
  This file is auto-generated by claude-memory.
3
3
  Do not edit manually - changes will be overwritten.
4
- Generated: 2026-02-05T18:27:44Z
4
+ Generated: 2026-04-16T17:54:51Z
5
5
  -->
6
6
 
7
7
  # Project Memory
8
8
 
9
9
  ## Current Decisions
10
10
 
11
+ - MCP tool-call telemetry stores minimal columns (tool_name, duration_ms, result_count, scope, error_class) — deliberately no query_text or query_hash. YAGNI: hashes are write-only without the raw text, and raw text adds privacy concerns without clear value beyond existing shortcut tools (memory.decisions, memory.conventions).
11
12
  - From QMD 2026-02-02 restudy: adopt Claude Code plugin format, MCP structured content pattern, MCP query guide prompt, inline status checks. Carry forward sqlite-vec, RRF, docids, smart expansion from 2026-01-26. Reject custom fine-tuned models, LLM reranking, YAML collections.
12
13
  - From claude-supermemory study: adopt SessionStart hook context injection (hookSpecificOutput.additionalContext), tool-specific observation compression, and relative time formatting. Reject cloud storage dependency and no-test approach.
13
14
 
14
15
  ## Conventions
15
16
 
17
+ - Curated predicate vocabulary has 8 entries: multi-value (convention, decision, architecture, uses_framework, uses_language) and single-value (uses_database, deployment_platform, auth_method). Pruned 7 dead predicates after multi-project survey confirmed zero usage.
18
+ - Before making design changes to schemas, vocabularies, or policies, survey actual usage data across multiple project databases under ~/src/ — single-project analysis can validate wrong assumptions. The uses_framework cardinality bug was only visible across multi-project data.
19
+ - A/B testing memory plugin: use 'claude --bare --mcp-config=/tmp/mcp-test.json -p' with serve-mcp.sh path. --plugin-dir doesn't work with --bare despite docs claiming it should. Architecture/convention/preference questions differentiate best; grep-able and one-shot code-gen questions don't.
20
+ - NullDistiller emits uses_language for language-type entities (added 0.9.0), alongside existing uses_database, uses_framework, deployment_platform. Migration v14 canonicalizes stale predicate names (has_convention → convention, primary_language → uses_language) in existing facts.
21
+ - CLAUDE.md scope-system example text ('this app uses PostgreSQL') causes recurring distiller hallucinations. Reject + re-ingest creates rejection churn because rejection metadata doesn't block re-insertion at content level. Open product gap — workaround: wrap example text in <no-memory> tags.
22
+ - claude-memory restore --predicate NAME recovers facts superseded by obsolete single-value classifications. Uses Jaccard token overlap (threshold 0.5) to distinguish bug-caused supersession from real corrections. Only operates on predicates currently classified multi-value. Opt-in per DB, supports --dry-run.
23
+ - claude-memory reject <id_or_docid> marks facts as rejected and resolves associated open conflicts in a single transaction. Accepts integer fact IDs or 8-char hex docids. memory.reject_fact MCP tool mirrors the CLI.
24
+ - The /release skill automates gem releases in three phases: prepare (version bump across 3 files, bundle install, MCP verify, tests, lint, CHANGELOG check, commit), publish (user-driven: git push + rake release), announce (fix GitHub Latest flags, create gh release from CHANGELOG). Never auto-pushes.
25
+ - Never use Sequel.sqlite for DB reads; this gem only depends on extralite. Use Sequel.connect("extralite://#{db_path}") or SQLiteStore.new. Sequel.sqlite requires the ungem'd sqlite3 adapter and fails at runtime.
26
+ - Two distinct tool_calls tables exist: tool_calls (v3) for transcript-observed Claude Code tool usage, and mcp_tool_calls (v13) for MCP server telemetry. Disjoint purposes, never join.
27
+ - MCP tool-call telemetry is recorded via MCP::Telemetry wrapping Server#handle_tools_call. Writes to mcp_tool_calls table in the project DB. Swallows DB errors so telemetry never breaks a real tool response. Viewable via 'claude-memory stats --tools [--since DAYS]'.
28
+ - mcp_tool_calls retention is 90 days, enforced by Sweep::Maintenance#prune_old_mcp_tool_calls wired into Sweeper#run!. Configurable via mcp_tool_call_retention_days in Maintenance DEFAULT_CONFIG.
29
+ - CLAUDE_CONFIG_DIR env var overrides the default ~/.claude location for Configuration#global_db_path. Access via Configuration#claude_config_dir. Additive, backwards compatible.
30
+ - Registry::COMMANDS stores {class:, description:} entries as the single source of truth for command name, class reference, and shell-completion description. Class constants stored directly (no const_get). Registry.descriptions feeds CompletionCommand; adding a new command requires updating only this hash.
31
+ - Prefer do...end over braces when a block has repeated argument names, multiple expressions, or non-trivial body. Single-expression simple blocks can still use braces.
32
+ - EXPECTED_HOOKS constant must stay in sync with events in HooksConfigurator#build_hooks_config. Adding a new hook event without updating EXPECTED_HOOKS causes false doctor warnings.
33
+ - Tests using --db for hook context only set the project DB path. StoreManager still connects to the real global DB. Must stub Configuration to return a temp global path for isolation.
34
+ - Version must be updated in three places: lib/claude_memory/version.rb, .claude-plugin/plugin.json, .claude-plugin/marketplace.json. Runtime code uses ClaudeMemory::VERSION dynamically.
35
+ - Use module inclusion (not class extraction) to break up god objects — preserves public API so zero tests need modification
36
+ - Configuration class has instance methods only — use Configuration.new.global_db_path, not Configuration.global_db_path. Stub with instance_double + allow(Configuration).to receive(:new).and_return(config)
37
+ - OperationTracker.reset_stuck_operations only resets operations older than 24 hours (STALE_THRESHOLD_SECONDS). Tests must backdate started_at to trigger resets.
38
+ - SCHEMA_VERSION constant lives in Store::SchemaManager module but is accessible as SQLiteStore::SCHEMA_VERSION via Ruby include-based constant lookup
16
39
  - MCP tools return dual content (text summary) + structuredContent (JSON) via TextSummary module and Server#handle_tools_call. Compact mode (compact: true) omits receipts for ~60% smaller responses.
17
40
  - ContentSanitizer strips system-reminder, local-command-caveat, command-message, command-name, command-args tags in addition to private/no-memory/secret/claude-memory-context.
18
41
  - Core::RelativeTime module provides progressive time formatting: just now → Xm ago → Xh ago → Xd ago → YYYY-MM-DD. Used in ResponseFormatter for *_ago fields.
19
42
  - MCP server registers memory_guide prompt via prompts/list and prompts/get endpoints. QueryGuide module holds prompt content.
20
43
  - Claude Code plugin with marketplace.json, skill definitions, MCP server bundling. 5,700+ stars, by Tobi Lütke. Custom fine-tuned query expansion (Qwen3-1.7B, SFT+GRPO). Dual content/structuredContent MCP pattern.
21
44
  - Cloud-backed Claude Code plugin (~1,195 LOC JavaScript) using Supermemory API for persistent memory across sessions. Uses hooks for SessionStart context injection and Stop transcript capture. No local database.
45
+
46
+ ## Technical Constraints
47
+
48
+ - **Uses framework**: rails
49
+ - **Deployment platform**: aws
50
+ - **Uses database**: sqlite
51
+
52
+ ## Additional Knowledge
53
+
54
+ ### Architecture
55
+
56
+ - repo: PredicatePolicy is the single source of truth for predicate vocabulary (POLICIES), cardinality, snapshot section mapping (SECTION_MAP), synonym canonicalization (SYNONYMS), and LLM guidance. tool_definitions.rb, publish.rb, and distill-transcripts.md all derive from PredicatePolicy. Never hardcode predicate names elsewhere.
57
+ - MCP::Tools: Thin 104-line dispatcher that includes 6 handler modules in mcp/handlers/: QueryHandlers, ShortcutHandlers, ContextHandlers, ManagementHandlers, StatsHandlers, SetupHandlers
58
+ - Recall: 94-line facade delegating to @engine (DualEngine or LegacyEngine), both include shared QueryCore module with all store-level query logic
59
+ - SQLiteStore: 386-line CRUD class that includes RetryHandler (retry/connection logic) and SchemaManager (migrations/version sync) modules
60
+ - Embeddings: Pluggable providers via Embeddings.resolve(name, env:). Three providers: tfidf (default), fastembed, api. Duck-typed contract: name, dimensions, generate(text). ENV: CLAUDE_MEMORY_EMBEDDING_PROVIDER
61
+ - Embeddings::DimensionCheck: Pure value object — DimensionCheck.call(store, provider) returns Data.define Result with :fresh/:match/:mismatch status. No side effects; caller decides how to handle mismatch.
62
+
63
+
64
+ ## Open Conflicts
65
+
66
+ The following facts are in conflict and need resolution:
67
+
68
+ - Conflict #12: Fact 21 vs Fact 43
69
+ - Conflict #13: Fact 21 vs Fact 44
70
+ - Conflict #14: Fact 45 vs Fact 46
71
+ - Conflict #15: Fact 45 vs Fact 47
72
+ - Conflict #16: Fact 48 vs Fact 49
73
+ - Conflict #17: Fact 45 vs Fact 50
74
+ - Conflict #18: Fact 21 vs Fact 51
75
+ - Conflict #19: Fact 48 vs Fact 52
76
+ - Conflict #20: Fact 21 vs Fact 53
77
+ - Conflict #21: Fact 21 vs Fact 54
78
+ - Conflict #22: Fact 21 vs Fact 55
79
+ - Conflict #23: Fact 21 vs Fact 56
80
+ - Conflict #24: Fact 21 vs Fact 57
81
+ - Conflict #25: Fact 48 vs Fact 58
82
+ - Conflict #26: Fact 48 vs Fact 59
83
+ - Conflict #27: Fact 48 vs Fact 60
84
+ - Conflict #28: Fact 21 vs Fact 61
85
+ - Conflict #29: Fact 21 vs Fact 62
86
+ - Conflict #30: Fact 21 vs Fact 63
87
+ - Conflict #31: Fact 45 vs Fact 64
88
+ - Conflict #32: Fact 21 vs Fact 65
89
+ - Conflict #33: Fact 21 vs Fact 66
90
+ - Conflict #34: Fact 21 vs Fact 67
91
+ - Conflict #35: Fact 45 vs Fact 68
92
+ - Conflict #36: Fact 45 vs Fact 69
93
+ - Conflict #37: Fact 48 vs Fact 70
94
+ - Conflict #38: Fact 48 vs Fact 71
95
+ - Conflict #39: Fact 21 vs Fact 72
96
+ - Conflict #40: Fact 21 vs Fact 73
97
+ - Conflict #41: Fact 21 vs Fact 74
98
+ - Conflict #42: Fact 21 vs Fact 75
99
+ - Conflict #43: Fact 21 vs Fact 76
100
+ - Conflict #44: Fact 45 vs Fact 77
101
+ - Conflict #45: Fact 45 vs Fact 78
102
+ - Conflict #46: Fact 45 vs Fact 79
103
+ - Conflict #47: Fact 45 vs Fact 80
104
+ - Conflict #48: Fact 45 vs Fact 81
105
+ - Conflict #49: Fact 48 vs Fact 82
106
+ - Conflict #50: Fact 48 vs Fact 83
107
+ - Conflict #51: Fact 48 vs Fact 84
108
+ - Conflict #52: Fact 48 vs Fact 85
109
+ - Conflict #53: Fact 48 vs Fact 86
110
+ - Conflict #54: Fact 48 vs Fact 87
111
+ - Conflict #55: Fact 48 vs Fact 88
112
+ - Conflict #56: Fact 48 vs Fact 89
113
+ - Conflict #57: Fact 48 vs Fact 90
@@ -5,17 +5,21 @@
5
5
  "hooks": [
6
6
  {
7
7
  "type": "command",
8
- "command": "claude-memory hook ingest",
9
- "timeout": 5
8
+ "command": "claude-memory hook ingest --db /Users/valentinostoll/src/claude_memory/.claude/memory.sqlite3",
9
+ "timeout": 5,
10
+ "statusMessage": "Saving memory..."
10
11
  }
11
12
  ]
12
- },
13
+ }
14
+ ],
15
+ "StopFailure": [
13
16
  {
14
17
  "hooks": [
15
18
  {
16
19
  "type": "command",
17
20
  "command": "claude-memory hook ingest --db /Users/valentinostoll/src/claude_memory/.claude/memory.sqlite3",
18
- "timeout": 5
21
+ "timeout": 5,
22
+ "statusMessage": "Saving memory..."
19
23
  }
20
24
  ]
21
25
  }
@@ -26,87 +30,56 @@
26
30
  {
27
31
  "type": "command",
28
32
  "command": "claude-memory hook context",
29
- "timeout": 5
33
+ "timeout": 5,
34
+ "statusMessage": "Loading memory..."
30
35
  }
31
36
  ]
32
37
  }
33
38
  ],
34
39
  "PreCompact": [
35
- {
36
- "hooks": [
37
- {
38
- "type": "command",
39
- "command": "claude-memory hook ingest",
40
- "timeout": 30
41
- },
42
- {
43
- "type": "command",
44
- "command": "claude-memory hook sweep",
45
- "timeout": 30
46
- }
47
- ]
48
- },
49
40
  {
50
41
  "hooks": [
51
42
  {
52
43
  "type": "command",
53
44
  "command": "claude-memory hook ingest --db /Users/valentinostoll/src/claude_memory/.claude/memory.sqlite3",
54
- "timeout": 30
45
+ "timeout": 30,
46
+ "statusMessage": "Saving memory..."
55
47
  },
56
48
  {
57
49
  "type": "command",
58
50
  "command": "claude-memory hook sweep --db /Users/valentinostoll/src/claude_memory/.claude/memory.sqlite3",
59
- "timeout": 30
51
+ "timeout": 30,
52
+ "statusMessage": "Sweeping memory..."
60
53
  }
61
54
  ]
62
55
  }
63
56
  ],
64
57
  "SessionEnd": [
65
- {
66
- "hooks": [
67
- {
68
- "type": "command",
69
- "command": "claude-memory hook ingest",
70
- "timeout": 30
71
- },
72
- {
73
- "type": "command",
74
- "command": "claude-memory hook sweep",
75
- "timeout": 30
76
- }
77
- ]
78
- },
79
58
  {
80
59
  "hooks": [
81
60
  {
82
61
  "type": "command",
83
62
  "command": "claude-memory hook ingest --db /Users/valentinostoll/src/claude_memory/.claude/memory.sqlite3",
84
- "timeout": 30
63
+ "timeout": 30,
64
+ "statusMessage": "Saving memory..."
85
65
  },
86
66
  {
87
67
  "type": "command",
88
68
  "command": "claude-memory hook sweep --db /Users/valentinostoll/src/claude_memory/.claude/memory.sqlite3",
89
- "timeout": 30
69
+ "timeout": 30,
70
+ "statusMessage": "Sweeping memory..."
90
71
  }
91
72
  ]
92
73
  }
93
74
  ],
94
75
  "TaskCompleted": [
95
- {
96
- "hooks": [
97
- {
98
- "type": "command",
99
- "command": "claude-memory hook ingest",
100
- "timeout": 10
101
- }
102
- ]
103
- },
104
76
  {
105
77
  "hooks": [
106
78
  {
107
79
  "type": "command",
108
80
  "command": "claude-memory hook ingest --db /Users/valentinostoll/src/claude_memory/.claude/memory.sqlite3",
109
- "timeout": 10
81
+ "timeout": 10,
82
+ "statusMessage": "Saving memory..."
110
83
  }
111
84
  ]
112
85
  }
@@ -116,17 +89,22 @@
116
89
  "hooks": [
117
90
  {
118
91
  "type": "command",
119
- "command": "claude-memory hook ingest",
120
- "timeout": 15
92
+ "command": "claude-memory hook ingest --db /Users/valentinostoll/src/claude_memory/.claude/memory.sqlite3",
93
+ "timeout": 15,
94
+ "statusMessage": "Saving memory..."
121
95
  }
122
96
  ]
123
- },
97
+ }
98
+ ],
99
+ "Notification": [
124
100
  {
101
+ "matcher": "idle_prompt",
125
102
  "hooks": [
126
103
  {
127
104
  "type": "command",
128
- "command": "claude-memory hook ingest --db /Users/valentinostoll/src/claude_memory/.claude/memory.sqlite3",
129
- "timeout": 15
105
+ "command": "claude-memory hook sweep --db /Users/valentinostoll/src/claude_memory/.claude/memory.sqlite3",
106
+ "timeout": 10,
107
+ "statusMessage": "Sweeping memory..."
130
108
  }
131
109
  ]
132
110
  }
@@ -48,7 +48,9 @@
48
48
  "Bash(claude-memory search:*)",
49
49
  "Bash(bundle exec:*)",
50
50
  "Skill(improve)",
51
- "Skill(improve:*)"
51
+ "Skill(improve:*)",
52
+ "WebFetch(domain:arxiv.org)",
53
+ "mcp__memory__memory_conflicts"
52
54
  ]
53
55
  },
54
56
  "enableAllProjectMcpServers": true,
@@ -0,0 +1,168 @@
1
+ ---
2
+ name: release
3
+ description: Prepare and publish a new gem release — bumps version across all required files, validates tests/linting/MCP server, commits, and creates the GitHub release. Use this skill when the user says "release", "publish a new version", "bump the version", "cut a release", "prepare for release", "ship it", or any variation of wanting to publish a new gem version. Also use when the user asks about the release process or what steps are needed to release.
4
+ agent: general-purpose
5
+ allowed-tools: Read, Grep, Edit, Write, Bash
6
+ arguments:
7
+ - name: version
8
+ description: "The new version number (e.g., '0.10.0'). If omitted, you'll be asked."
9
+ required: false
10
+ ---
11
+
12
+ # Release Workflow
13
+
14
+ Automate the full release lifecycle for the ClaudeMemory gem. This workflow was codified from the actual 0.9.0 release process.
15
+
16
+ The release has three phases: **prepare** (automated), **publish** (user-driven), and **announce** (automated). The middle phase requires user action because it pushes to a shared remote and publishes to RubyGems — destructive operations that must never happen without explicit confirmation.
17
+
18
+ ## Phase 1: Prepare
19
+
20
+ ### Step 1: Determine the new version
21
+
22
+ If a version was passed as an argument, use it. Otherwise, read the current version from `lib/claude_memory/version.rb` and ask the user what the new version should be.
23
+
24
+ ### Step 2: Find and update all version references
25
+
26
+ The version lives in exactly three files. Grep to confirm there are no others:
27
+
28
+ ```bash
29
+ grep -rn "CURRENT_VERSION" --include="*.rb" --include="*.json" --include="*.gemspec" . | grep -v "CHANGELOG\|node_modules\|vendor\|\.git/"
30
+ ```
31
+
32
+ Update all three:
33
+
34
+ 1. **`lib/claude_memory/version.rb`** — the `VERSION` constant (canonical source)
35
+ 2. **`.claude-plugin/plugin.json`** — the `"version"` field
36
+ 3. **`.claude-plugin/marketplace.json`** — the `"version"` field inside the plugins array
37
+
38
+ If grep reveals any additional hardcoded references, update those too and flag them to the user as something that should be DRYed up.
39
+
40
+ ### Step 3: Update Gemfile.lock
41
+
42
+ ```bash
43
+ bundle install
44
+ ```
45
+
46
+ Verify both `claude_memory (X.Y.Z)` entries in Gemfile.lock match the new version.
47
+
48
+ ### Step 4: Verify MCP server reports the new version
49
+
50
+ The MCP server reads `ClaudeMemory::VERSION` dynamically. Confirm it picks up the change:
51
+
52
+ ```bash
53
+ echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' | bundle exec claude-memory serve-mcp 2>/dev/null | grep -o '"version":"[^"]*"'
54
+ ```
55
+
56
+ Expected output: `"version":"X.Y.Z"` matching the new version. If it doesn't match, something is wrong with the require chain — investigate before proceeding.
57
+
58
+ ### Step 5: Run the full test suite
59
+
60
+ ```bash
61
+ bundle exec rspec
62
+ ```
63
+
64
+ All tests must pass. Do not proceed with any failures. Fix them first.
65
+
66
+ ### Step 6: Run the linter
67
+
68
+ ```bash
69
+ bundle exec rake standard:fix
70
+ ```
71
+
72
+ Ensure no remaining violations.
73
+
74
+ ### Step 7: Verify CHANGELOG.md
75
+
76
+ The CHANGELOG should already have a release section written during development (via `/improve`, manual commits, or other workflow). **Do not auto-generate release notes** — they should reflect the actual development narrative.
77
+
78
+ Check that:
79
+ - The `## [X.Y.Z] - YYYY-MM-DD` section exists with today's date
80
+ - It has Added, Changed, Fixed subsections as appropriate
81
+ - Upgrade Notes are included if there are breaking changes or manual migration steps
82
+ - The `## [Unreleased]` section above it is empty or ready for the next cycle
83
+
84
+ If the CHANGELOG section is missing or incomplete, **stop and ask the user**. Do not fabricate release notes.
85
+
86
+ ### Step 8: Commit the version bump
87
+
88
+ ```bash
89
+ git add lib/claude_memory/version.rb .claude-plugin/plugin.json .claude-plugin/marketplace.json Gemfile.lock
90
+ git commit -m "[Release] Bump version to X.Y.Z"
91
+ ```
92
+
93
+ Do NOT push yet. Report what was committed and proceed to Phase 2.
94
+
95
+ ## Phase 2: Publish (User-Driven)
96
+
97
+ This phase involves pushing to a shared remote and publishing to RubyGems. These are **irreversible shared-state operations** — never execute them automatically.
98
+
99
+ Tell the user:
100
+
101
+ > Version X.Y.Z is prepared and committed locally. To publish:
102
+ >
103
+ > ```bash
104
+ > git push origin main
105
+ > rake release
106
+ > ```
107
+ >
108
+ > `rake release` will create the git tag, build the gem, and push to RubyGems. Let me know when that's done and I'll create the GitHub release.
109
+
110
+ Wait for the user to confirm before proceeding to Phase 3.
111
+
112
+ ## Phase 3: Announce
113
+
114
+ ### Step 9: Fix any stale "Latest" flags on GitHub releases
115
+
116
+ Check current release state:
117
+
118
+ ```bash
119
+ gh release list --limit 5
120
+ ```
121
+
122
+ If an older release is incorrectly marked "Latest" (this happens when releases are created out of order or with `--latest` set manually):
123
+
124
+ ```bash
125
+ gh release edit v<old-version> --latest=false
126
+ ```
127
+
128
+ ### Step 10: Create the GitHub release
129
+
130
+ Extract the release notes from CHANGELOG.md — everything between `## [X.Y.Z]` and the next `## [` heading. Write to a temp file:
131
+
132
+ ```bash
133
+ # Extract the section between the new version header and the next version header
134
+ sed -n '/^## \[X\.Y\.Z\]/,/^## \[/{ /^## \[X\.Y\.Z\]/d; /^## \[/d; p; }' CHANGELOG.md > /tmp/release-notes.md
135
+ ```
136
+
137
+ Create the release:
138
+
139
+ ```bash
140
+ gh release create vX.Y.Z \
141
+ --title "vX.Y.Z — Short descriptive title" \
142
+ --latest \
143
+ --verify-tag \
144
+ --notes-file /tmp/release-notes.md
145
+ ```
146
+
147
+ The title should capture the theme of the release in a few words (e.g., "Predicate Design Overhaul, Reject/Restore, Telemetry"). Read the CHANGELOG to derive this — don't ask the user unless the theme isn't obvious.
148
+
149
+ ### Step 11: Verify the release
150
+
151
+ ```bash
152
+ gh release list --limit 5
153
+ ```
154
+
155
+ Confirm:
156
+ - The new release appears at the top
157
+ - It's marked "Latest"
158
+ - No older release is incorrectly marked "Latest"
159
+
160
+ Report the release URL to the user.
161
+
162
+ ## Error Handling
163
+
164
+ - **Tests fail**: Fix first. Never release with failing tests.
165
+ - **CHANGELOG missing**: Ask the user. Never fabricate release notes.
166
+ - **Version already tagged**: The tag may exist from a prior attempt. Ask the user whether to delete and recreate, or use a different version.
167
+ - **`gh` not available**: Tell the user to create the GitHub release manually, providing the release notes content.
168
+ - **`rake release` fails**: Common causes: not logged into RubyGems, tag already exists, uncommitted changes. Help the user diagnose but don't retry automatically.
@@ -0,0 +1,154 @@
1
+ ---
2
+ name: upgrade-dependencies
3
+ description: "Upgrade all Ruby gem dependencies to their latest versions with release note review and codebase alignment checks. Use this skill whenever the user asks to update, upgrade, or bump dependencies, gems, or packages — even casually like 'update my gems' or 'are my deps up to date?'"
4
+ agent: general-purpose
5
+ allowed-tools: Read, Grep, Glob, Bash, Edit, Write, Agent, WebFetch
6
+ ---
7
+
8
+ # Dependency Upgrade Skill
9
+
10
+ Systematically upgrade Ruby gem dependencies by researching latest versions, reviewing release notes for breaking changes, updating version constraints, verifying with tests, and confirming codebase alignment.
11
+
12
+ The goal is a *thoughtful* upgrade — not blindly bumping versions, but understanding what changed and ensuring the codebase is compatible. This matters because a silent API change can introduce bugs that tests don't catch if the tests don't exercise the affected code path.
13
+
14
+ ## Process Overview
15
+
16
+ 1. **Discover** current dependencies and their constraints
17
+ 2. **Research** latest versions and release notes (in parallel)
18
+ 3. **Analyze** breaking changes and codebase impact
19
+ 4. **Upgrade** version constraints and install
20
+ 5. **Verify** with the full test suite
21
+ 6. **Report** a summary table with upgrade details
22
+
23
+ ## Step 1: Discover Current Dependencies
24
+
25
+ Read the gemspec and Gemfile to build a complete dependency inventory.
26
+
27
+ ```
28
+ Read *.gemspec → runtime dependencies (add_dependency)
29
+ Read Gemfile → development dependencies (gem declarations)
30
+ Run: bundle outdated → current vs latest versions, which are constrained
31
+ ```
32
+
33
+ Build a working list with these columns:
34
+ - **Gem name**
35
+ - **Source** (gemspec or Gemfile)
36
+ - **Current constraint** (e.g., `~> 5.0`)
37
+ - **Installed version** (from `bundle outdated` or `Gemfile.lock`)
38
+ - **Latest version** (from `bundle outdated`)
39
+ - **Constrained?** (is the version constraint preventing upgrade?)
40
+
41
+ ## Step 2: Research Release Notes
42
+
43
+ For each gem that has a newer version available, research what changed. Launch these as parallel Agent subagents — one per gem — to avoid sequential delays.
44
+
45
+ Each research agent should:
46
+
47
+ 1. Run `gem search <name> --exact --versions` to confirm the latest version
48
+ 2. Fetch the changelog or release notes from GitHub (check CHANGELOG.md, CHANGES, HISTORY.md, or GitHub Releases)
49
+ 3. Summarize changes between the installed version and latest version
50
+ 4. Flag any **breaking changes**, **deprecations**, or **API changes**
51
+ 5. Note if it's a **major version bump** (higher risk)
52
+
53
+ For transitive dependencies (not directly declared but showing in `bundle outdated`), research is optional — focus on direct dependencies. Transitive deps are upgraded automatically when their parent gem allows it.
54
+
55
+ ### What to look for in release notes
56
+
57
+ - **Removed methods or classes** the codebase might use
58
+ - **Renamed options or changed defaults** that could silently alter behavior
59
+ - **New required arguments** to methods we call
60
+ - **Deprecated features** we rely on (working now, but will break later)
61
+ - **Changed return types** or data structures
62
+ - **Minimum Ruby version bumps** that could affect CI or deployment
63
+
64
+ ## Step 3: Analyze Codebase Impact
65
+
66
+ For each gem with breaking changes or API modifications:
67
+
68
+ 1. **Grep the codebase** for usage of affected APIs
69
+ 2. **Check test coverage** — are the affected code paths tested?
70
+ 3. **Determine if changes are needed** before or after the upgrade
71
+
72
+ Classify each upgrade:
73
+
74
+ - **Safe** — no breaking changes, or breaking changes don't affect our usage
75
+ - **Needs code changes** — our code uses a deprecated or removed API
76
+ - **Held back** — a transitive dependency constraint prevents the upgrade (explain which parent gem and why)
77
+
78
+ If code changes are needed, make them *before* bumping the version constraint so the upgrade commit is clean.
79
+
80
+ ## Step 4: Upgrade Dependencies
81
+
82
+ ### Gemspec dependencies (runtime)
83
+
84
+ Update version constraints to target the latest version. Use `~>` with the appropriate precision:
85
+
86
+ - For stable gems (1.0+): `~> X.Y` allows patch updates (e.g., `~> 5.102` allows 5.102.x)
87
+ - For pre-1.0 gems: `~> 0.X, ">= 0.X.Y"` to pin a minimum while allowing patches
88
+ - For gems where a specific fix matters: add `">= X.Y.Z"` as an additional constraint
89
+
90
+ ### Gemfile dependencies (development)
91
+
92
+ Same approach. If a major version bump is available (e.g., lefthook 1.x → 2.x), check the migration guide before bumping.
93
+
94
+ ### Install
95
+
96
+ ```bash
97
+ bundle update
98
+ ```
99
+
100
+ If `bundle update` fails due to dependency conflicts, resolve them. Common strategies:
101
+ - Relax an overly tight constraint
102
+ - Update the conflicting parent gem first
103
+ - Accept that a gem can't be upgraded yet and document why
104
+
105
+ ## Step 5: Verify with Tests
106
+
107
+ Run the full test suite:
108
+
109
+ ```bash
110
+ bundle exec rspec
111
+ ```
112
+
113
+ Also run the linter to catch any style issues:
114
+
115
+ ```bash
116
+ bundle exec rake standard
117
+ ```
118
+
119
+ If tests fail:
120
+ 1. Read the failure carefully — is it caused by the upgrade or pre-existing?
121
+ 2. If caused by the upgrade, fix the code to work with the new version
122
+ 3. If unfixable, revert that specific gem's upgrade and note it in the report
123
+
124
+ ## Step 6: Present Summary
125
+
126
+ Present a clear summary table of all changes:
127
+
128
+ ```markdown
129
+ | Gem | Old Version | New Version | Old Constraint | New Constraint | Notes |
130
+ |-----|------------|-------------|----------------|----------------|-------|
131
+ | sequel | 5.100.0 | 5.102.0 | ~> 5.0 | ~> 5.102 | No breaking changes |
132
+ | lefthook | 1.13.6 | 2.1.4 | ~> 1.6 | ~> 2.1 | Major version bump, reviewed migration guide |
133
+ ```
134
+
135
+ Follow the table with:
136
+
137
+ 1. **Breaking changes found** — what changed and how the codebase was updated
138
+ 2. **Gems held back** — which gems couldn't be upgraded and why (e.g., "diff-lcs 2.0 held back by rspec's ~> 1.4 constraint")
139
+ 3. **Notable new features** — anything worth adopting from the new versions
140
+ 4. **Test results** — confirmation that all tests pass
141
+
142
+ ## Edge Cases
143
+
144
+ ### Gems with no GitHub repository
145
+ Fall back to `gem info <name>` and the RubyGems page for release history. Note reduced confidence in the review.
146
+
147
+ ### Yanked versions
148
+ If `bundle update` fails because a version was yanked, try the next most recent version.
149
+
150
+ ### Pre-release versions
151
+ Do not upgrade to pre-release or alpha versions unless the user explicitly asks. Stick to stable releases.
152
+
153
+ ### Monorepo gems
154
+ Some gems (like rails components) are versioned together. Upgrade them as a group.
@@ -7,9 +7,9 @@
7
7
  "plugins": [
8
8
  {
9
9
  "name": "claude-memory",
10
- "version": "0.8.0",
10
+ "version": "0.9.1",
11
11
  "source": "./",
12
- "description": "Long-term self-managed memory for Claude Code with fact extraction, truth maintenance, and provenance tracking",
12
+ "description": "Long-term memory for Claude Code. Recalls architecture, conventions, and decisions across sessions — so Claude explains your codebase without file traversal, follows your patterns, and never re-asks what it already learned.",
13
13
  "repository": "https://github.com/codenamev/claude_memory"
14
14
  }
15
15
  ]
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "claude-memory",
3
- "version": "0.8.0",
4
- "description": "Long-term self-managed memory for Claude Code with fact extraction, truth maintenance, and provenance tracking",
3
+ "version": "0.9.1",
4
+ "description": "Long-term memory for Claude Code. Recalls architecture, conventions, and decisions across sessions — so Claude explains your codebase without file traversal, follows your patterns, and never re-asks what it already learned.",
5
5
  "author": {
6
6
  "name": "Valentino Stoll",
7
7
  "email": "v@codenamev.com"
@@ -9,7 +9,7 @@
9
9
  "homepage": "https://github.com/codenamev/claude_memory",
10
10
  "repository": "https://github.com/codenamev/claude_memory",
11
11
  "license": "MIT",
12
- "keywords": ["memory", "facts", "knowledge", "persistence", "long-term-memory"],
12
+ "keywords": ["memory", "architecture", "conventions", "decisions", "recall", "preferences", "long-term-memory"],
13
13
  "mcpServers": {
14
14
  "memory": {
15
15
  "command": "${CLAUDE_PLUGIN_ROOT}/scripts/serve-mcp.sh",
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env bash
2
+ # Generic hook delegate for claude-memory.
3
+ # Used by the Claude Code plugin to run hook subcommands.
4
+ # Usage: hook-runner.sh <subcommand> [args...]
5
+ # Exit 0 on missing binary to avoid blocking Claude Code.
6
+
7
+ set -uo pipefail
8
+
9
+ if command -v claude-memory > /dev/null 2>&1; then
10
+ exec claude-memory hook "$@"
11
+ else
12
+ echo "claude-memory gem not found. Install with: gem install claude_memory" >&2
13
+ exit 0
14
+ fi