claude_memory 0.9.0 β†’ 0.10.0

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 (76) hide show
  1. checksums.yaml +4 -4
  2. data/.claude/memory.sqlite3 +0 -0
  3. data/.claude/rules/claude_memory.generated.md +63 -1
  4. data/.claude/skills/dashboard/SKILL.md +42 -0
  5. data/.claude/skills/release/SKILL.md +168 -0
  6. data/.claude-plugin/marketplace.json +1 -1
  7. data/.claude-plugin/plugin.json +1 -1
  8. data/CHANGELOG.md +92 -0
  9. data/CLAUDE.md +21 -5
  10. data/README.md +32 -2
  11. data/db/migrations/015_add_activity_events.rb +26 -0
  12. data/db/migrations/016_add_moment_feedback.rb +22 -0
  13. data/db/migrations/017_add_last_recalled_at.rb +15 -0
  14. data/docs/1_0_punchlist.md +190 -0
  15. data/docs/EXAMPLES.md +41 -2
  16. data/docs/GETTING_STARTED.md +31 -4
  17. data/docs/architecture.md +22 -7
  18. data/docs/audit-queries.md +131 -0
  19. data/docs/dashboard.md +172 -0
  20. data/docs/improvements.md +465 -9
  21. data/docs/influence/cq.md +187 -0
  22. data/docs/plugin.md +13 -6
  23. data/docs/quality_review.md +489 -172
  24. data/docs/reflection_memory_as_accumulating_judgment.md +67 -0
  25. data/lib/claude_memory/activity_log.rb +86 -0
  26. data/lib/claude_memory/commands/census_command.rb +210 -0
  27. data/lib/claude_memory/commands/completion_command.rb +3 -0
  28. data/lib/claude_memory/commands/dashboard_command.rb +54 -0
  29. data/lib/claude_memory/commands/dedupe_conflicts_command.rb +55 -0
  30. data/lib/claude_memory/commands/digest_command.rb +181 -0
  31. data/lib/claude_memory/commands/hook_command.rb +34 -0
  32. data/lib/claude_memory/commands/reclassify_references_command.rb +56 -0
  33. data/lib/claude_memory/commands/registry.rb +6 -1
  34. data/lib/claude_memory/commands/skills/distill-transcripts.md +13 -1
  35. data/lib/claude_memory/commands/stats_command.rb +38 -1
  36. data/lib/claude_memory/commands/sweep_command.rb +2 -0
  37. data/lib/claude_memory/configuration.rb +16 -0
  38. data/lib/claude_memory/core/relative_time.rb +9 -0
  39. data/lib/claude_memory/dashboard/api.rb +610 -0
  40. data/lib/claude_memory/dashboard/conflicts.rb +279 -0
  41. data/lib/claude_memory/dashboard/efficacy.rb +127 -0
  42. data/lib/claude_memory/dashboard/fact_presenter.rb +109 -0
  43. data/lib/claude_memory/dashboard/health.rb +175 -0
  44. data/lib/claude_memory/dashboard/index.html +2707 -0
  45. data/lib/claude_memory/dashboard/knowledge.rb +136 -0
  46. data/lib/claude_memory/dashboard/moments.rb +244 -0
  47. data/lib/claude_memory/dashboard/reuse.rb +97 -0
  48. data/lib/claude_memory/dashboard/scoped_fact_resolver.rb +95 -0
  49. data/lib/claude_memory/dashboard/server.rb +211 -0
  50. data/lib/claude_memory/dashboard/timeline.rb +68 -0
  51. data/lib/claude_memory/dashboard/trust.rb +285 -0
  52. data/lib/claude_memory/distill/reference_material_detector.rb +78 -0
  53. data/lib/claude_memory/hook/auto_memory_mirror.rb +112 -0
  54. data/lib/claude_memory/hook/context_injector.rb +97 -3
  55. data/lib/claude_memory/hook/handler.rb +50 -3
  56. data/lib/claude_memory/mcp/handlers/management_handlers.rb +8 -0
  57. data/lib/claude_memory/mcp/query_guide.rb +11 -0
  58. data/lib/claude_memory/mcp/server.rb +8 -2
  59. data/lib/claude_memory/mcp/text_summary.rb +29 -0
  60. data/lib/claude_memory/mcp/tool_definitions.rb +13 -0
  61. data/lib/claude_memory/mcp/tools.rb +148 -0
  62. data/lib/claude_memory/publish.rb +13 -21
  63. data/lib/claude_memory/recall/stale_detector.rb +67 -0
  64. data/lib/claude_memory/resolve/predicate_policy.rb +2 -0
  65. data/lib/claude_memory/resolve/resolver.rb +41 -11
  66. data/lib/claude_memory/store/llm_cache.rb +68 -0
  67. data/lib/claude_memory/store/metrics_aggregator.rb +96 -0
  68. data/lib/claude_memory/store/schema_manager.rb +1 -1
  69. data/lib/claude_memory/store/sqlite_store.rb +47 -143
  70. data/lib/claude_memory/store/store_manager.rb +29 -0
  71. data/lib/claude_memory/sweep/maintenance.rb +216 -0
  72. data/lib/claude_memory/sweep/recall_timestamp_refresher.rb +83 -0
  73. data/lib/claude_memory/sweep/sweeper.rb +2 -0
  74. data/lib/claude_memory/version.rb +1 -1
  75. data/lib/claude_memory.rb +22 -0
  76. metadata +50 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9b42d582ddd17dd325f8048268c889d6c80c1ca9c229732da1a8d619279201af
4
- data.tar.gz: 8853caacc212900483a4a3f9939e8261e18f53b886675f01b4c5a5b61a506d26
3
+ metadata.gz: a299c6ab2aeb95123dcb61f5c87a06b93d15a00a2ed9ff2c8343e7fde6b369cb
4
+ data.tar.gz: d09c02a2f5dcd4bd0dfcb625793505bd2218c7df04230411e813a7543e7e7382
5
5
  SHA512:
6
- metadata.gz: a65038105334c741d26c5e485da7565016ae670ed24f04d4c23b2bb00329d729ee3bfd91cf333ea36ad518937e40e4c95c4d0846bcb423984b0ec683fee59b5a
7
- data.tar.gz: d94e2ce5fbd1ed496a0c56f094b7f1fbb01b9eb255c819a95b2ffe6ecf79ea9c1706408fd658b2bcaee19d440a87d45a1185a7e471cb05fc7c003d433d6e5808
6
+ metadata.gz: 87fd7dab40cb2e5b190de071f99bcc1394e98e5f426951eedaff09b190fa66591b40f49580bca45f75819170ba939a0d3d9239f4825825b431fd4a83d388bb7d
7
+ data.tar.gz: ffb4ab50ba94a8f3c7bfb8129f01ea96fd27b981dd614f0addd7d65a9fc2b4b8562b9d23148bb5ea4ee90b5ae5a9fc183d1c82e68d3b009557967a00b96bfec1
Binary file
@@ -1,7 +1,7 @@
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-04-15T17:38:20Z
4
+ Generated: 2026-04-16T17:54:51Z
5
5
  -->
6
6
 
7
7
  # Project Memory
@@ -14,6 +14,14 @@
14
14
 
15
15
  ## Conventions
16
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.
17
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.
18
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.
19
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]'.
@@ -37,15 +45,69 @@
37
45
 
38
46
  ## Technical Constraints
39
47
 
48
+ - **Uses framework**: rails
49
+ - **Deployment platform**: aws
40
50
  - **Uses database**: sqlite
41
51
 
42
52
  ## Additional Knowledge
43
53
 
44
54
  ### Architecture
45
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.
46
57
  - MCP::Tools: Thin 104-line dispatcher that includes 6 handler modules in mcp/handlers/: QueryHandlers, ShortcutHandlers, ContextHandlers, ManagementHandlers, StatsHandlers, SetupHandlers
47
58
  - Recall: 94-line facade delegating to @engine (DualEngine or LegacyEngine), both include shared QueryCore module with all store-level query logic
48
59
  - SQLiteStore: 386-line CRUD class that includes RetryHandler (retry/connection logic) and SchemaManager (migrations/version sync) modules
49
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
50
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.
51
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
@@ -0,0 +1,42 @@
1
+ ---
2
+ name: dashboard
3
+ description: Launch a local web dashboard for ClaudeMemory debugging and observability
4
+ ---
5
+
6
+ # Dashboard
7
+
8
+ Launch the ClaudeMemory debugging dashboard to visualize memory system health, activity, and efficacy.
9
+
10
+ ## Task
11
+
12
+ Start the dashboard web server so the user can inspect what's happening behind the scenes.
13
+
14
+ ## Steps
15
+
16
+ 1. Run the dashboard command:
17
+
18
+ ```bash
19
+ claude-memory dashboard
20
+ ```
21
+
22
+ This starts a local web server (default port 3377) and opens it in the browser.
23
+
24
+ ## What the Dashboard Shows
25
+
26
+ - **Health Status**: Database health, hook configuration, vector index status
27
+ - **Overview**: Fact/entity/content counts, top predicates, entity type distribution, 30-day activity timeline
28
+ - **Activity**: Live event log of hook executions (ingest, context, sweep), memory recalls, and store extractions with timing and details
29
+ - **Facts**: Searchable fact explorer with status filtering, predicate/object search
30
+ - **Efficacy**: Recall hit rate, total results served, average results per query, top queries by result count
31
+
32
+ ## Options
33
+
34
+ - `--port PORT` - Use a different port (default: 3377)
35
+ - `--no-open` - Don't auto-open the browser
36
+
37
+ ## Notes
38
+
39
+ - Dashboard auto-refreshes every 30 seconds
40
+ - Activity events are recorded by hooks and MCP tools into the `activity_events` table
41
+ - The dashboard reads from both global and project databases
42
+ - Press Ctrl+C to stop the server
@@ -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.
@@ -7,7 +7,7 @@
7
7
  "plugins": [
8
8
  {
9
9
  "name": "claude-memory",
10
- "version": "0.9.0",
10
+ "version": "0.10.0",
11
11
  "source": "./",
12
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"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-memory",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
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",
data/CHANGELOG.md CHANGED
@@ -4,6 +4,98 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.10.0] - 2026-04-28
8
+
9
+ ### Added
10
+
11
+ **Dashboard β€” feed-first redesign with observability built in**
12
+
13
+ - New feed-first dashboard UI with scope-aware moments, fact detail modal, query tester, and activity drilldown. Reuse, Trust, Knowledge, Conflicts, and Moments panels each backed by a dedicated module (`Dashboard::{Reuse, Trust, Knowledge, Conflicts, Moments}`) under unit tests, replacing the prior all-in-API-class layout.
14
+ - πŸ‘/πŸ‘Ž feedback on individual moments with persisted verdicts (schema v16, `moment_feedback` table). Trust panel surfaces a 30-day up/down ratio so the dashboard can answer "when memory surfaces something, are users marking it useful?".
15
+ - Utilization ratio panel β€” of facts extracted in the last 30 days, how many has Claude actually used in a recall or context injection? Color-coded (green β‰₯40%, yellow β‰₯15%, red below). Hidden on fresh installs to avoid misleading zeros.
16
+ - Conflict deduping at the display layer: identical (subject, predicate, object_pair) detections collapse into one row with a `Γ—N` badge. Sidebar "Needs review" count now reflects distinct contradictions, not raw row count.
17
+ - Activity events drilldown: each moment opens a payload modal with prettified JSONL, recall trigger correlation (which user prompt motivated this lookup), and linked-fact resolution scoped per database.
18
+ - Vector index health threshold and clickable remediation hints in the health dashboard.
19
+
20
+ **CLI β€” observability surfaces and one-shot cleanups**
21
+
22
+ - `claude-memory digest [--since DAYS] [--output FILE]` β€” weekly markdown report. Sections: Activity, New knowledge by predicate, Utilization (extracted vs used), Conflicts, Feedback. No new schema; renders from existing aggregates.
23
+ - `claude-memory census [--root DIR]` β€” privacy-safe cross-project vocabulary scan. Aggregates per-DB predicate Γ— status counts, novel predicates, synonym candidates. Suppresses object literals, entity names, and paths; per-DB IDs are SHA256-prefixed.
24
+ - `claude-memory dedupe-conflicts [--scope SCOPE] [--dry-run]` β€” one-shot cleanup for historical conflict-row duplication that predates the Resolver dedup fix (commit f571ba4). Groups by (subject, predicate, normalized object pair), keeps the earliest, migrates provenance to the keeper.
25
+ - `claude-memory reclassify-references [--scope SCOPE] [--dry-run]` β€” retags active convention facts that the new `Distill::ReferenceMaterialDetector` flags as reference material (LOC counts, star counts, "X is a plugin..." templates, "by Firstname Lastname" attributions).
26
+
27
+ **Memory quality**
28
+
29
+ - Access-based staleness scoring (improvements.md #35). Schema v17 adds `last_recalled_at` to facts. `Sweep::RecallTimestampRefresher` derives the field periodically from activity_events; `claude-memory stats --stale [--stale-days N]` lists facts that haven't been recalled inside the threshold. Replaces the prior "active facts minus seen-in-recalls" approximation.
30
+ - Auto-memory mirror (improvements.md #36). On fresh sessions, the SessionStart context hook scans `~/.claude/projects/<slug>/memory/*.md` and surfaces new or changed entries as extraction candidates so users can promote auto-memory observations into claude_memory without manual copy-paste.
31
+ - Reasoning requirement enforced in distillation (improvements.md #34). The SessionStart prompt and the `/distill-transcripts` skill now require a why clause for `decision` and `convention` predicates ("because…", "so that…", etc.). Audit found ~75% of facts were bare conclusions before this change.
32
+ - `Distill::ReferenceMaterialDetector` reclassifies convention facts whose object text matches reference patterns. New `reference` predicate registered in `PredicatePolicy` with its own `:references` snapshot section. Detector runs at write time in `ManagementHandlers#store_extraction` so mislabeling can't persist.
33
+ - Predicate census command (#30) for cross-project vocabulary audits β€” see CLI section above.
34
+
35
+ **Benchmarks and observability**
36
+
37
+ - Repeat-correction benchmark harness (improvements.md #32). `spec/benchmarks/e2e/repeat_correction_spec.rb` pre-loads a past correction as a memory fact, runs the prompt through real Claude under `EVAL_MODE=real`, and reports pass rate (no violation patterns matched). Starter set of 2 scenarios drawn from this project's recurring gotchas.
38
+ - Relevance ratio metric (improvements.md #31). `Hook::ContextInjector#emitted_subjects` exposes the subjects injected at SessionStart; `BenchmarkHelpers::RelevanceMetrics` measures whether they appear in Claude's response. Trend signal for memory-application quality, integrated into `devmemeval_spec.rb`.
39
+ - MCP server embeds the V=R/C ("Verify before Recommend / Correct") mental model in agent instructions so memory recommendations come with built-in verification cues.
40
+
41
+ **Schema v15 β†’ v17 (additive only, automatic on first run)**
42
+
43
+ - Migration 015: adds `activity_events` table for hook/recall/context/sweep telemetry. Powers the dashboard timeline, moments feed, and efficacy reports.
44
+ - Migration 016: adds `moment_feedback` table (unique on event_id) for the dashboard πŸ‘/πŸ‘Ž surface.
45
+ - Migration 017: adds nullable `facts.last_recalled_at` for access-based staleness scoring.
46
+
47
+ **1.0 readiness track**
48
+
49
+ - New `docs/1_0_punchlist.md` opens the path to 1.0: token-budget telemetry, hallucination-rate metric, negative-fact harm benchmark, CLAUDE.md baseline publication, `claude-memory show`, benchmark scoreboard. Ten entries (#47-56) added to `docs/improvements.md` with concrete file:line plumbing notes.
50
+
51
+ ### Changed
52
+
53
+ - `Resolver#apply_conflict` no longer creates a duplicate disputed fact + conflict row when the same contradicting value is re-extracted. Looks up disputed facts in the same (subject, predicate) slot and reinforces with provenance instead.
54
+ - `Resolver` no longer treats the distiller's `scope_hint` as a scope override. `scope_hint` is advisory metadata; `fact.scope` must match the DB the row lives in. Earlier behavior caused scope leakage where global-hinted distillations landed in the project DB.
55
+ - `Hook::ContextInjector` adds `emitted_fact_ids` and `emitted_subjects` accessors so benchmark harnesses can attribute injection contributions per session.
56
+ - `SQLiteStore` decomposed via module inclusion: `LLMCache` and `MetricsAggregator` extracted into `lib/claude_memory/store/`. SQLiteStore back under 600 LOC.
57
+ - `Dashboard::API` decomposed: `FactPresenter`, `Conflicts`, `Efficacy::Reporter`, `Timeline`, `Health` extracted into dedicated classes following the boundary pattern. API now routes/delegates rather than aggregating.
58
+ - Dashboard releases DB connections after each HTTP request (was holding connections open for the lifetime of the WEBrick session).
59
+ - `Sweep::Maintenance` gains `dedupe_open_conflicts` and `reclassify_references` for the one-shot CLI commands above.
60
+ - Round-trip migration specs from v12, v13, v14 β†’ v17 (per-version migrations covered by `spec/claude_memory/store/migrations/`). Codifies the release-blocker convention: any schema bump must round-trip from each prior major-release boundary back ~3 releases.
61
+
62
+ ### Fixed
63
+
64
+ - Dashboard surfaces an actionable hint when Recall hits FTS5 corruption (run `claude-memory compact` rather than a generic error).
65
+ - Dashboard query tester unwraps the nested Recall result shape rather than printing the raw envelope.
66
+ - Dashboard health checks correctly detect the claude-memory hook installation across the two-level Claude Code hooks structure (was reporting false negatives when hooks were installed under a matcher block).
67
+ - Dashboard Efficacy "this session" correlation falls back to a time window when the recall event has no `session_id` (MCP tool calls don't thread session_id).
68
+ - Bulk-reject in the Conflicts modal now retries with an actionable message when the server-side state is stale.
69
+
70
+ ### Upgrade Notes
71
+
72
+ **Schema bump v14 β†’ v17.** Three migrations run automatically on first launch after upgrade. All three are additive (no existing data is rewritten):
73
+
74
+ 1. Migration 015 creates `activity_events` (hook/recall telemetry).
75
+ 2. Migration 016 creates `moment_feedback` (dashboard verdicts).
76
+ 3. Migration 017 adds `facts.last_recalled_at` (NULL by default; `Sweep::RecallTimestampRefresher` populates it on the next sweep cycle from existing activity_events).
77
+
78
+ The migration delta has round-trip spec coverage in `spec/claude_memory/store/migrations/`. Forward-compatibility: 0.10.0 databases cannot be opened by 0.9.x or earlier. Downgrade is destructive β€” back up `~/.claude/memory.sqlite3` and `.claude/memory.sqlite3` before downgrading.
79
+
80
+ **Optional historical cleanups.** Two new admin commands address data tails left by earlier bugs that have since been fixed at the source:
81
+
82
+ ```bash
83
+ claude-memory dedupe-conflicts --dry-run # preview duplicate conflict rows
84
+ claude-memory dedupe-conflicts # consolidate them
85
+ claude-memory reclassify-references --dry-run # preview reference-material mislabels
86
+ claude-memory reclassify-references # retag them
87
+ ```
88
+
89
+ Both are opt-in. Neither runs in the regular sweep cycle. Use `--scope global` to clean the global DB.
90
+
91
+ **Telemetry footprint.** The `activity_events` table grows with hook activity. The dashboard surfaces this by default and powers the timeline/moments/efficacy panels. Retention pruning is not yet automatic (planned for a follow-up); manual cleanup via `DELETE FROM activity_events WHERE occurred_at < ?` is safe β€” the dashboard tolerates missing history.
92
+
93
+ ## [0.9.1] - 2026-04-16
94
+
95
+ ### Fixed
96
+
97
+ - MCP server now conforms to JSON-RPC 2.0: notifications (messages without an `id`) never receive a response. Previously, `notifications/initialized` β€” which Claude Code sends after every handshake β€” triggered a spurious `Method not found` error frame, causing strict MCP clients to mark the server failed on `/mcp` reconnect after the initial connection.
98
+
7
99
  ## [0.9.0] - 2026-04-16
8
100
 
9
101
  ### Added
data/CLAUDE.md CHANGED
@@ -163,7 +163,7 @@ New MCP tools `memory.undistilled` and `memory.mark_distilled` support the pipel
163
163
  - Each command is a separate class (HelpCommand, DoctorCommand, etc.)
164
164
  - All commands inherit from BaseCommand
165
165
  - Dependency injection for I/O (stdout, stderr, stdin)
166
- - 28 commands total, each focused on single responsibility
166
+ - 32 commands total, each focused on single responsibility
167
167
 
168
168
  - **`Configuration`**: Centralized ENV access (`configuration.rb`)
169
169
  - Single source of truth for paths and environment variables
@@ -208,6 +208,8 @@ New MCP tools `memory.undistilled` and `memory.mark_distilled` support the pipel
208
208
  - **`Distill`**: Fact extraction interface (`distill/`)
209
209
  - Pluggable distiller design (current: NullDistiller stub)
210
210
  - Extracts entities, facts, scope hints from content
211
+ - `ReferenceMaterialDetector`: classifies "X is a plugin/library/tool" templates, LOC counts, "by Firstname Lastname" attributions as reference material. Runs in `ManagementHandlers#store_extraction` so mislabeling can't persist
212
+ - SessionStart distillation prompt enforces reason clauses ("because…", "so that…") for `decision` and `convention` predicates β€” bare conclusions are explicitly disallowed
211
213
 
212
214
  - **`Resolve`**: Truth maintenance and conflict resolution (`resolve/`)
213
215
  - Determines equivalence, supersession, or conflicts
@@ -226,7 +228,7 @@ New MCP tools `memory.undistilled` and `memory.mark_distilled` support the pipel
226
228
  - Modes: shared (repo), local (uncommitted), home (user directory)
227
229
 
228
230
  - **`MCP`**: Model Context Protocol server and tools (`mcp/`)
229
- - Exposes memory tools to Claude Code (24 tools total)
231
+ - Exposes memory tools to Claude Code (25 tools total)
230
232
  - `Telemetry`: Records tool invocations to `mcp_tool_calls` table for usage stats
231
233
  - Dual content/structuredContent responses with compact mode
232
234
 
@@ -234,6 +236,7 @@ New MCP tools `memory.undistilled` and `memory.mark_distilled` support the pipel
234
236
  - Reads stdin JSON from Claude Code hooks
235
237
  - Routes to ingest/sweep/publish commands
236
238
  - `DistillationRunner`: Manages context hook injection with undistilled content for LLM extraction
239
+ - `AutoMemoryMirror` (0.10.0): On fresh sessions, scans `~/.claude/projects/<slug>/memory/*.md` for new/changed entries and surfaces them as extraction candidates in the SessionStart context. State diffed by md5 in `.claude/auto_memory_mirror.json`; bounded to 5 candidates per session, 1500 chars each.
237
240
 
238
241
  ### Database Schema
239
242
 
@@ -246,16 +249,19 @@ Key tables (defined in `sqlite_store.rb`):
246
249
  - `fact_links`: Supersession and conflict relationships
247
250
  - `conflicts`: Open contradictions
248
251
  - `mcp_tool_calls`: MCP server tool invocation telemetry (schema v13)
252
+ - `activity_events`: Hook/recall/context/sweep telemetry (schema v15) β€” powers the dashboard timeline, moments feed, efficacy reports
253
+ - `moment_feedback`: Per-moment πŸ‘/πŸ‘Ž verdicts with optional notes (schema v16) β€” unique on event_id, repeat clicks upsert
249
254
 
250
255
  Facts include:
251
256
  - `scope`: "global" or "project" (determines applicability)
252
257
  - `project_path`: Set for project-scoped facts
253
258
  - `valid_from`/`valid_to`: Temporal validity window
259
+ - `last_recalled_at` (schema v17): Set by `Sweep::RecallTimestampRefresher` from activity_events; powers `claude-memory stats --stale` and the dashboard's "stale" needs-review count
254
260
 
255
261
  ### Scope System
256
262
 
257
263
  Facts are scoped to control where they apply:
258
- - **project**: Current project only (e.g., "this app uses PostgreSQL")
264
+ - **project**: Current project only (e.g., "claude_memory uses SQLite for storage")
259
265
  - **global**: All projects (e.g., "I prefer 4-space indentation")
260
266
 
261
267
  Distiller detects signals like "always", "in all projects", "my preference" and sets `scope_hint: "global"`. Users can manually promote facts via `claude-memory promote <fact_id>` or the `memory.promote` MCP tool.
@@ -340,14 +346,14 @@ Also update `SECTION_MAP` if the predicate should appear in a specific snapshot
340
346
 
341
347
  The gem includes an MCP server (`claude-memory serve-mcp`) that exposes memory operations as tools. Configuration should be in `.mcp.json` at project root.
342
348
 
343
- Available MCP tools (24 total):
349
+ Available MCP tools (25 total):
344
350
  - **Query & Recall**: `memory.recall`, `memory.recall_index`, `memory.recall_details`, `memory.recall_semantic`, `memory.search_concepts`
345
351
  - **Provenance**: `memory.explain`, `memory.fact_graph`
346
352
  - **Shortcuts**: `memory.decisions`, `memory.conventions`, `memory.architecture`
347
353
  - **Context**: `memory.facts_by_tool`, `memory.facts_by_context`
348
354
  - **Management**: `memory.promote`, `memory.reject_fact`, `memory.store_extraction`
349
355
  - **Distillation**: `memory.undistilled`, `memory.mark_distilled`
350
- - **Monitoring**: `memory.status`, `memory.stats`, `memory.changes`, `memory.conflicts`
356
+ - **Monitoring**: `memory.status`, `memory.stats`, `memory.changes`, `memory.conflicts`, `memory.activity`
351
357
  - **Maintenance**: `memory.sweep_now`
352
358
  - **Discovery**: `memory.check_setup`, `memory.list_projects`
353
359
 
@@ -369,6 +375,16 @@ ClaudeMemory integrates with Claude Code via hooks in `.claude/settings.json`:
369
375
 
370
376
  Hook commands read JSON payloads from stdin for robustness. Supports `--async` flag for non-blocking execution.
371
377
 
378
+ ## Dashboard
379
+
380
+ Local web UI for inspecting memory state. Started via `claude-memory dashboard` (default port 3377). Reads from both global and project databases; no write side effects from page loads.
381
+
382
+ The dashboard is a thin web layer over the same `Recall`/`Conflicts`/`Trust`/`Moments`/`Knowledge`/`Reuse`/`Health`/`Timeline` classes the MCP server uses. Each panel is backed by a dedicated module under `lib/claude_memory/dashboard/`; `Dashboard::API` holds HTTP-shape glue and per-endpoint formatting (delegating non-trivial logic to the panel classes).
383
+
384
+ Connections are released after each request β€” never holds a WAL writer lock open across page loads.
385
+
386
+ See [docs/dashboard.md](docs/dashboard.md) for the user-facing guide (panels, common workflows, related CLI commands).
387
+
372
388
  ## Code Style
373
389
 
374
390
  This project uses [Standard Ruby](https://github.com/standardrb/standard) for linting. Run `bundle exec rake standard:fix` before committing.
data/README.md CHANGED
@@ -140,6 +140,35 @@ File-searchable questions ("what version is this?") and one-shot code generation
140
140
  - **Claude-Powered**: Uses Claude's intelligence to extract facts (no API key needed)
141
141
  - **Token Efficient**: 10x reduction in memory queries with progressive disclosure
142
142
  - **Database Maintenance**: Compact, export, and backup commands
143
+ - **Built-in Observability** (0.10.0+): `claude-memory dashboard` opens a local web UI with a moments feed, trust panel, conflicts dedup, knowledge index, πŸ‘/πŸ‘Ž feedback, and a 30-day utilization ratio. See **[Dashboard guide β†’](docs/dashboard.md)**. `claude-memory digest` writes a weekly markdown report; `claude-memory census` audits the predicate vocabulary across projects.
144
+
145
+ ## What's New in 0.10.0
146
+
147
+ Three behavior changes worth knowing about β€” they affect what you'll see in
148
+ extracted facts and SessionStart context, even if you don't change anything:
149
+
150
+ - **Auto-memory mirror** β€” On fresh sessions, the SessionStart context hook
151
+ scans `~/.claude/projects/<slug>/memory/*.md` and surfaces new or changed
152
+ entries as candidates for extraction into ClaudeMemory. You'll see a
153
+ "Pending Knowledge Extraction" section in Claude's startup context citing
154
+ files from your auto-memory directory. Claude reviews these and calls
155
+ `memory.store_extraction` for the high-signal ones; you don't need to
156
+ copy-paste manually anymore.
157
+ - **Why-clause enforcement** β€” When Claude distills `decision` and
158
+ `convention` facts, it's now required to embed a reason ("…because…",
159
+ "…so that…", "…to avoid…"). A bare conclusion is dead weight; a fact with
160
+ a reason stays useful when the situation changes. You'll see this
161
+ reflected in fact text being longer and more justified.
162
+ - **Reference predicate** β€” Active facts that look like reference material
163
+ (LOC counts, "X is a plugin/library/tool" templates, "by Firstname
164
+ Lastname" attributions) are auto-tagged `predicate=reference` instead of
165
+ `convention`. Keeps the conventions list signal-rich. Browse them in the
166
+ dashboard's Knowledge β†’ References section, or run
167
+ `claude-memory reclassify-references --dry-run` to see candidates.
168
+
169
+ Plus: **staleness detection** (`claude-memory stats --stale`) lists active
170
+ facts that haven't been recalled in N days, so you can prune dead weight
171
+ explicitly. The dashboard's Trust β†’ Needs review panel surfaces the count.
143
172
 
144
173
  ## Privacy Control
145
174
 
@@ -241,7 +270,8 @@ The uninstall command removes:
241
270
 
242
271
  - πŸ“– [Getting Started](docs/GETTING_STARTED.md) - Step-by-step onboarding
243
272
  - πŸ’‘ [Examples](docs/EXAMPLES.md) - Use cases and workflows
244
- - πŸ”§ [Plugin Setup](docs/PLUGIN.md) - Claude Code integration
273
+ - πŸ“Š [Dashboard](docs/dashboard.md) - Local web UI for inspection and trust signals (0.10.0+)
274
+ - πŸ”§ [Plugin Setup](docs/plugin.md) - Claude Code integration
245
275
  - πŸ—οΈ [Architecture](docs/architecture.md) - Technical deep dive
246
276
  - πŸ“ [Changelog](CHANGELOG.md) - Release notes
247
277
 
@@ -292,7 +322,7 @@ The benchmark dataset draws from real CLAUDE.md patterns and is designed specifi
292
322
 
293
323
  - **Language:** Ruby 3.2+
294
324
  - **Storage:** SQLite3 (no external services)
295
- - **Testing:** 1477 examples (1375 unit/integration + 102 benchmarks/evals), 100% core coverage
325
+ - **Testing:** 1964 examples (~1700 unit/integration + ~250 benchmarks/evals), 100% core coverage
296
326
  - **Code Style:** Standard Ruby
297
327
 
298
328
  ```bash
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Migration v15: Add activity_events table for debugging and observability
4
+ # Tracks hook executions, memory recalls, context injections, and sweep operations.
5
+ # Powers the dashboard timeline and efficacy reports.
6
+ Sequel.migration do
7
+ up do
8
+ create_table?(:activity_events) do
9
+ primary_key :id
10
+ String :event_type, null: false # "hook_ingest", "hook_context", "hook_sweep", "recall", "store_extraction"
11
+ String :session_id # Claude session that triggered the event
12
+ String :status, null: false # "success", "skipped", "error"
13
+ Integer :duration_ms # How long the operation took
14
+ String :detail_json, text: true # Event-specific details (JSON)
15
+ String :occurred_at, null: false # ISO 8601 timestamp
16
+ end
17
+
18
+ run "CREATE INDEX IF NOT EXISTS idx_activity_events_type ON activity_events(event_type)"
19
+ run "CREATE INDEX IF NOT EXISTS idx_activity_events_occurred_at ON activity_events(occurred_at)"
20
+ run "CREATE INDEX IF NOT EXISTS idx_activity_events_session ON activity_events(session_id)"
21
+ end
22
+
23
+ down do
24
+ drop_table?(:activity_events)
25
+ end
26
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Migration v16: Per-moment feedback (improvements.md #43).
4
+ # Tracks a single thumbs-up/down verdict (+ optional note) per activity_event
5
+ # so the dashboard can surface a trust-calibration signal. Unique on event_id
6
+ # so a given moment has at most one current verdict; repeat clicks upsert.
7
+ Sequel.migration do
8
+ up do
9
+ create_table?(:moment_feedback) do
10
+ primary_key :id
11
+ Integer :event_id, null: false
12
+ String :verdict, null: false # "up" | "down"
13
+ String :note, text: true # optional freeform note
14
+ String :recorded_at, null: false
15
+ index :event_id, unique: true
16
+ end
17
+ end
18
+
19
+ down do
20
+ drop_table?(:moment_feedback)
21
+ end
22
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Migration v17: Access-based staleness scoring (improvements.md #35).
4
+ # Records the last time a fact was surfaced via memory.recall or context
5
+ # injection, derived periodically from activity_events. Sweep-derived rather
6
+ # than per-call so we avoid WAL write contention on the recall hot path.
7
+ Sequel.migration do
8
+ up do
9
+ add_column :facts, :last_recalled_at, String
10
+ end
11
+
12
+ down do
13
+ drop_column :facts, :last_recalled_at
14
+ end
15
+ end