claude_memory 0.10.0 → 0.12.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 (72) hide show
  1. checksums.yaml +4 -4
  2. data/.claude/memory.sqlite3 +0 -0
  3. data/.claude/rules/claude_memory.generated.md +42 -64
  4. data/.claude/skills/release/SKILL.md +44 -6
  5. data/.claude/skills/study-repo/SKILL.md +15 -0
  6. data/.claude-plugin/commands/audit-memory.md +68 -0
  7. data/.claude-plugin/marketplace.json +1 -1
  8. data/.claude-plugin/plugin.json +1 -1
  9. data/CHANGELOG.md +70 -0
  10. data/CLAUDE.md +20 -5
  11. data/README.md +64 -2
  12. data/db/migrations/018_add_otel_telemetry.rb +81 -0
  13. data/docs/1_0_punchlist.md +522 -89
  14. data/docs/GETTING_STARTED.md +3 -1
  15. data/docs/api_stability.md +341 -0
  16. data/docs/architecture.md +3 -3
  17. data/docs/audit_runbook.md +209 -0
  18. data/docs/claude_monitoring.md +956 -0
  19. data/docs/dashboard.md +23 -3
  20. data/docs/improvements.md +329 -5
  21. data/docs/influence/ai-memory-systems-2026.md +403 -0
  22. data/docs/memory_audit_2026-05-21.md +303 -0
  23. data/docs/plugin.md +1 -1
  24. data/docs/quality_review.md +35 -0
  25. data/lib/claude_memory/audit/checks.rb +239 -0
  26. data/lib/claude_memory/audit/finding.rb +33 -0
  27. data/lib/claude_memory/audit/runner.rb +73 -0
  28. data/lib/claude_memory/commands/audit_command.rb +117 -0
  29. data/lib/claude_memory/commands/dashboard_command.rb +2 -1
  30. data/lib/claude_memory/commands/digest_command.rb +95 -3
  31. data/lib/claude_memory/commands/hook_command.rb +27 -2
  32. data/lib/claude_memory/commands/import_auto_memory_command.rb +180 -0
  33. data/lib/claude_memory/commands/initializers/hooks_configurator.rb +7 -4
  34. data/lib/claude_memory/commands/otel_command.rb +240 -0
  35. data/lib/claude_memory/commands/registry.rb +5 -1
  36. data/lib/claude_memory/commands/show_command.rb +90 -0
  37. data/lib/claude_memory/commands/stats_command.rb +94 -2
  38. data/lib/claude_memory/configuration.rb +60 -0
  39. data/lib/claude_memory/core/fact_query_builder.rb +1 -0
  40. data/lib/claude_memory/dashboard/api.rb +8 -0
  41. data/lib/claude_memory/dashboard/index.html +140 -1
  42. data/lib/claude_memory/dashboard/prompt_journey.rb +48 -0
  43. data/lib/claude_memory/dashboard/server.rb +86 -0
  44. data/lib/claude_memory/dashboard/telemetry.rb +156 -0
  45. data/lib/claude_memory/dashboard/trust.rb +180 -11
  46. data/lib/claude_memory/deprecations.rb +106 -0
  47. data/lib/claude_memory/distill/bare_conclusion_detector.rb +71 -0
  48. data/lib/claude_memory/distill/reference_material_detector.rb +37 -4
  49. data/lib/claude_memory/hook/auto_memory_mirror.rb +7 -3
  50. data/lib/claude_memory/hook/context_injector.rb +11 -2
  51. data/lib/claude_memory/hook/handler.rb +142 -1
  52. data/lib/claude_memory/mcp/tool_definitions.rb +3 -3
  53. data/lib/claude_memory/otel/attributes.rb +118 -0
  54. data/lib/claude_memory/otel/constants.rb +32 -0
  55. data/lib/claude_memory/otel/ingestor.rb +54 -0
  56. data/lib/claude_memory/otel/otlp_json_envelope.rb +254 -0
  57. data/lib/claude_memory/otel/prompt_scope.rb +108 -0
  58. data/lib/claude_memory/otel/settings_writer.rb +122 -0
  59. data/lib/claude_memory/otel/status.rb +58 -0
  60. data/lib/claude_memory/recall/staleness_annotator.rb +73 -0
  61. data/lib/claude_memory/resolve/predicate_policy.rb +17 -1
  62. data/lib/claude_memory/resolve/resolver.rb +30 -3
  63. data/lib/claude_memory/shortcuts.rb +61 -18
  64. data/lib/claude_memory/store/prompt_journey_query.rb +87 -0
  65. data/lib/claude_memory/store/schema_manager.rb +1 -1
  66. data/lib/claude_memory/store/sqlite_store.rb +136 -0
  67. data/lib/claude_memory/sweep/maintenance.rb +31 -1
  68. data/lib/claude_memory/sweep/sweeper.rb +6 -0
  69. data/lib/claude_memory/templates/hooks.example.json +5 -0
  70. data/lib/claude_memory/version.rb +1 -1
  71. data/lib/claude_memory.rb +20 -0
  72. metadata +28 -1
@@ -593,8 +593,10 @@ Now that you're up and running:
593
593
  | `claude-memory changes` | Recent updates |
594
594
  | `claude-memory conflicts` | Show contradictions |
595
595
  | `claude-memory dashboard` | Open the local web UI (0.10.0+) |
596
- | `claude-memory digest --since 7` | Markdown report of the last 7 days (0.10.0+) |
596
+ | `claude-memory digest --since 7` | Markdown report of the last 7 days (0.10.0+; gains Context cost + Quality sections in 0.11.0) |
597
+ | `claude-memory show [--pending] [--source]` | Print what memory would inject at next SessionStart (0.11.0+) |
597
598
  | `claude-memory stats --stale` | List facts not recalled recently (0.10.0+) |
599
+ | `claude-memory stats --tokens [--since DAYS]` | SessionStart context-token budget histogram (0.11.0+) |
598
600
  | `claude-memory stats --tools` | MCP tool-call telemetry (0.9.0+) |
599
601
  | `claude-memory census` | Privacy-safe predicate audit across projects (0.10.0+) |
600
602
  | `claude-memory dedupe-conflicts --dry-run` | Preview historical conflict-row dedup (0.10.0+) |
@@ -0,0 +1,341 @@
1
+ # API Stability
2
+
3
+ > Authoritative reference for what ClaudeMemory promises to keep stable
4
+ > across releases. If a surface is listed here as **stable**, breaking
5
+ > it without a deprecation cycle is a bug. If it's listed as **internal**
6
+ > or simply not listed, no compatibility is implied.
7
+
8
+ **Last updated:** 2026-05-01 (initial publication for 0.12.0). **Applies to:** `claude_memory` ≥ 0.12.0.
9
+
10
+ This doc is the contract `claude-memory` semver depends on. The 1.0.0 release will lock the **stable** surfaces below; subsequent minor releases (`1.x`) may grow the stable set but won't shrink it without a deprecation cycle. Earlier 0.x releases also followed semver in spirit, but the absence of this doc made it un-arbitrable. From 0.12 onward, this is the single source of truth.
11
+
12
+ ---
13
+
14
+ ## 1. Versioning policy
15
+
16
+ ClaudeMemory follows [SemVer 2.0](https://semver.org):
17
+
18
+ - **MAJOR** (`1.0.0`, `2.0.0`): breaking changes to **stable** surfaces below.
19
+ - **MINOR** (`0.X.0`, `1.X.0`): new features and additions; existing **stable** surfaces remain compatible.
20
+ - **PATCH** (`0.X.Y`): bug fixes only; no new features and no behavior changes to **stable** surfaces.
21
+
22
+ ### Deprecation cycle
23
+
24
+ When we want to break or rename a **stable** surface in a future major:
25
+
26
+ 1. Pick a `removed_in` version (typically `(N+1).0.0`).
27
+ 2. Wire a runtime warning via `ClaudeMemory::Deprecations.warn(name:, replacement:, removed_in:)`. Continue accepting the old form.
28
+ 3. Document in CHANGELOG under "Deprecated".
29
+ 4. Keep the old surface working for **at least one minor cycle**.
30
+ 5. Remove no earlier than the `removed_in` version.
31
+
32
+ Suppress deprecation noise in CI/tests with `CLAUDE_MEMORY_NO_DEPRECATIONS=1`.
33
+
34
+ ### Stability tiers
35
+
36
+ Throughout this doc each surface carries one tier:
37
+
38
+ | Tier | Meaning |
39
+ |---|---|
40
+ | **stable** | Covered by semver. Breaking change requires deprecation cycle. |
41
+ | **experimental** | May change in any minor without deprecation. Use at your own risk. |
42
+ | **internal** | No guarantees. May change in any patch. Don't rely on it from external code. |
43
+
44
+ When ambiguous, default is **internal** — easier to promote later than demote.
45
+
46
+ ---
47
+
48
+ ## 2. Public CLI surface
49
+
50
+ All commands listed in `Commands::Registry::COMMANDS` are reachable via `claude-memory <subcommand>`. The full registered set (34 commands as of 0.12.0) is canonically stored in `lib/claude_memory/commands/registry.rb`. Stability:
51
+
52
+ ### Stable commands (covered by semver)
53
+
54
+ These commands and their **documented** flags are stable. Adding new commands or new flags is non-breaking; renaming or removing requires a deprecation cycle.
55
+
56
+ | Command | Notes |
57
+ |---|---|
58
+ | `claude-memory init` | Project + global initialization. |
59
+ | `claude-memory uninstall` | Removes `.claude/settings.json` hooks and rules. |
60
+ | `claude-memory doctor` | Health check. New checks may be added; the JSON-summary mode is also stable. |
61
+ | `claude-memory dashboard [--port N] [--no-open]` | Local web UI. The dashboard's **JSON HTTP API is internal** — see §7. |
62
+ | `claude-memory recall <query>` | Fact retrieval. |
63
+ | `claude-memory promote <fact_id>` | Promote project → global. |
64
+ | `claude-memory reject <id_or_docid>` | Reject + close associated conflicts. |
65
+ | `claude-memory restore --predicate NAME` | Recover supersession from obsolete single-value classifications. |
66
+ | `claude-memory explain <fact_id>` | Provenance receipts. |
67
+ | `claude-memory recover` | Database recovery. |
68
+ | `claude-memory compact` | VACUUM + FTS rebuild. |
69
+ | `claude-memory export` | Dump facts to JSON. |
70
+ | `claude-memory ingest` / `sweep` / `publish` | Pipeline entrypoints. Hook commands stable as listed in §4. |
71
+ | `claude-memory hook <ingest\|sweep\|publish\|context\|nudge>` | Hook entrypoints; stdin JSON contract in §4. |
72
+ | `claude-memory serve-mcp` | MCP server. Argument schemas in §3. |
73
+ | `claude-memory stats [--scope SCOPE] [--tools] [--tokens] [--stale] [--since DAYS] [--stale-days N]` | Statistics. |
74
+ | `claude-memory show [--source SOURCE] [--pending]` | Print would-be-injected context (0.11.0+). |
75
+ | `claude-memory digest [--since DAYS] [--output FILE]` | Markdown rollup (0.10.0+). |
76
+ | `claude-memory census [--root DIR]` | Cross-project predicate audit (0.10.0+). |
77
+ | `claude-memory conflicts` / `changes` | Inspection. |
78
+ | `claude-memory db:init` | Initialize a single DB at a path. |
79
+ | `claude-memory completion <bash\|zsh\|fish>` | Shell completions. |
80
+ | `claude-memory version` / `help` | Inspection. |
81
+
82
+ ### Experimental commands
83
+
84
+ May change in any minor; treat with care.
85
+
86
+ | Command | Notes |
87
+ |---|---|
88
+ | `claude-memory dedupe-conflicts [--dry-run] [--apply]` | One-shot historical cleanup. The output format (preview rows, count summary) may change. |
89
+ | `claude-memory reclassify-references [--dry-run] [--apply]` | Same shape; introduced 0.10.0. |
90
+ | `claude-memory recall --semantic` / `--mode=hybrid` | Semantic-recall flags depend on the embedding backend; `tfidf` is stable, `fastembed`/`api` may change configuration knobs. |
91
+ | `claude-memory embeddings` | Embedding-backend inspection; the JSON shape evolves with provider work. |
92
+ | `claude-memory import-auto-memory [--dry-run]` | Imports Claude Code auto-memory markdown files into the project DB as facts. Introduced 0.12.0 from the 2026-05-21 audit; argument shape and idempotency contract are stable but the heuristic for predicate mapping may evolve. |
93
+
94
+ ### Internal / not for external automation
95
+
96
+ - `claude-memory index --vec` (rebuild operation) — semantics may shift with the embeddings overhaul.
97
+ - `claude-memory git-lfs` — installation helper; output shape not guaranteed.
98
+ - `claude-memory install-skill <name>` — skill plumbing.
99
+
100
+ ### Exit codes (stable)
101
+
102
+ `Hook::ExitCodes`:
103
+
104
+ | Code | Meaning |
105
+ |---|---|
106
+ | `0` | Success or graceful degradation. |
107
+ | `1` | Non-blocking warning (shown to user; session continues). |
108
+ | `2` | Blocking error (fed to Claude for processing). |
109
+
110
+ Renaming or repurposing a code is a major-version change.
111
+
112
+ ---
113
+
114
+ ## 3. Public MCP tool surface
115
+
116
+ All 23 tools registered via `MCP::ToolDefinitions.all`. Argument schemas, return shapes (both `content` and `structuredContent`), and tool-annotation hints (`readOnlyHint`, `idempotentHint`, `destructiveHint`) are **stable** for the listed tools.
117
+
118
+ ### Stable MCP tools
119
+
120
+ | Tool | Group | Stability notes |
121
+ |---|---|---|
122
+ | `memory.recall` | Query | Argument schema + return shape stable. New optional fields may be added. |
123
+ | `memory.recall_index` | Query | Stable. |
124
+ | `memory.recall_details` | Query | Stable. |
125
+ | `memory.recall_semantic` | Query | Stable since 0.9.0. |
126
+ | `memory.search_concepts` | Query | Stable. |
127
+ | `memory.explain` | Provenance | Stable. |
128
+ | `memory.fact_graph` | Provenance | Stable. |
129
+ | `memory.decisions` | Shortcut | Stable. |
130
+ | `memory.conventions` | Shortcut | Stable. |
131
+ | `memory.architecture` | Shortcut | Stable. |
132
+ | `memory.facts_by_tool` | Context | Stable. |
133
+ | `memory.facts_by_context` | Context | Stable. |
134
+ | `memory.promote` | Management | Stable. |
135
+ | `memory.reject_fact` | Management | Stable since 0.10.0. |
136
+ | `memory.store_extraction` | Management | Argument schema (`facts`, `entities`, `decisions`) stable. |
137
+ | `memory.undistilled` | Distillation | Stable since 0.10.0. |
138
+ | `memory.mark_distilled` | Distillation | Stable since 0.10.0. |
139
+ | `memory.status` | Monitoring | Stable. |
140
+ | `memory.stats` | Monitoring | Stable. |
141
+ | `memory.changes` | Monitoring | Stable. |
142
+ | `memory.conflicts` | Monitoring | Stable. |
143
+ | `memory.activity` | Monitoring | Stable since 0.10.0. |
144
+ | `memory.sweep_now` | Maintenance | Stable. |
145
+ | `memory.check_setup` | Discovery | Stable. |
146
+ | `memory.list_projects` | Discovery | Stable since 0.10.0. |
147
+
148
+ ### Stability of tool responses
149
+
150
+ Both response shapes are stable:
151
+
152
+ - **Text content**: a human-readable summary in `content[0].text`. Content text format may evolve, but always remains valid Markdown.
153
+ - **Structured content**: machine-parseable JSON in `structuredContent`. Top-level keys for each tool are stable; new keys may be added.
154
+ - **Compact mode** (`compact: true` argument where supported): the compact representation is stable but explicitly omits receipts. Decision is documented per-tool.
155
+
156
+ ### What is NOT promised about MCP tools
157
+
158
+ - Tool descriptions (the prose strings in `tool_definitions.rb`) may be tuned for prompt quality.
159
+ - Tool annotations (`readOnlyHint` etc.) may flip if a tool's behavior changes — annotation flips count as a deprecation event.
160
+ - Server-internal pagination cursors are opaque to clients.
161
+
162
+ ---
163
+
164
+ ## 4. Public hook contract
165
+
166
+ ClaudeMemory ships hooks for **5 events** as listed in `Commands::Checks::HooksCheck::EXPECTED_HOOKS`: `Stop`, `StopFailure`, `SessionStart`, `PreCompact`, `SessionEnd`. The `init` command also writes hooks for `TaskCompleted`, `TeammateIdle`, and `Notification` in projects that opt in. **Adding or removing the events that `init` writes is a stable-surface change.**
167
+
168
+ ### Hook subcommands (stable since 0.10.0)
169
+
170
+ `claude-memory hook <ingest|sweep|publish|context|nudge>` reads JSON from stdin. The `nudge` subcommand was added 0.11.0.
171
+
172
+ ### Stable stdin payload fields
173
+
174
+ | Field | Type | Required | Notes |
175
+ |---|---|---|---|
176
+ | `session_id` | string | yes for `ingest`, `context`, `nudge` | Claude Code session id. |
177
+ | `transcript_path` | string | yes for `ingest` | Path to the session transcript JSONL. |
178
+ | `project_path` | string | no | Defaults to `cwd`. |
179
+ | `cwd` | string | no | Working directory. |
180
+ | `source` | string | no | Hook fresh-session source (`startup`, `resume`, `clear`, etc.). Affects `context` injector behavior. |
181
+ | `mode` | string | no | For `publish` — `shared`, `local`, `home`. |
182
+
183
+ Unknown payload fields are **ignored** rather than rejected — this lets Claude Code add new fields without breaking older gem versions.
184
+
185
+ ### Stable stdout response
186
+
187
+ For `claude-memory hook context` only:
188
+
189
+ ```json
190
+ {"hookSpecificOutput": {"hookEventName": "SessionStart", "additionalContext": "<markdown>"}}
191
+ ```
192
+
193
+ The shape and key names are stable. `additionalContext` content format (Markdown sections) is stable as listed in §6.
194
+
195
+ ### Stable `activity_events.detail_json` field set
196
+
197
+ Each hook records an `activity_events` row whose `detail_json` carries telemetry. The **stable** field set per `event_type` is enumerated in [`spec/smoke/expected_fields.yml`](../spec/smoke/expected_fields.yml) — that file is the manifest, and `bin/pre-release-smoke` enforces it as a release gate.
198
+
199
+ Adding a new field to `detail_json` is a stable-surface addition (non-breaking). Removing or renaming a listed field requires a deprecation cycle. The smoke gate refuses to ship a release if any listed field is unexpectedly null.
200
+
201
+ Current covered events (0.11.0):
202
+
203
+ - `hook_context`: `context_length`, `context_tokens` (since 0.11.0), `top_fact_ids`, `fact_count`.
204
+ - `roi_nudge`: `n`, `used`, `pct`, `prior_count` (all since 0.11.0).
205
+
206
+ `hook_ingest`, `hook_sweep`, `hook_publish` event detail fields are currently **internal** (not on the smoke-gate manifest). Promoting them to stable is a 0.12.x or later task.
207
+
208
+ ---
209
+
210
+ ## 5. Public Ruby API surface
211
+
212
+ External Ruby callers (benchmark adapters, scripts, and downstream gems) may rely on these classes and methods. Default for everything else: **internal**.
213
+
214
+ ### Stable classes
215
+
216
+ | Class | Public surface |
217
+ |---|---|
218
+ | `ClaudeMemory::Recall` | `#initialize(manager)`, `#query(query, limit:, scope:, intent:)`, `#query_index(...)`, `#query_semantic(...)`, return-shape: array of `{fact:, receipts:, source:}`. |
219
+ | `ClaudeMemory::Configuration` | `#initialize(env = ENV)` and instance methods returning paths/flags. **Note:** instance methods only — no class-level helpers (e.g. `Configuration.global_db_path` does not exist; use `Configuration.new.global_db_path`). |
220
+ | `ClaudeMemory::Store::StoreManager` | `#initialize(global_db_path:, project_db_path:, project_path:, env:)`, `#ensure_both!`, `#close`, `#default_store`, `#store_if_exists(scope)`, accessors `global_store`, `project_store`. |
221
+ | `ClaudeMemory::Domain::Fact` | Read-only attribute accessors and predicate methods (`active?`, `superseded?`, `rejected?`). Frozen / immutable. |
222
+ | `ClaudeMemory::Domain::Entity` | Same shape — frozen value object. Predicates: `database?`, `framework?`, etc. |
223
+ | `ClaudeMemory::Domain::Provenance` | Frozen value object; `stated?`, `inferred?` predicates. |
224
+ | `ClaudeMemory::Domain::Conflict` | Frozen value object; `open?`, `resolved?` predicates. |
225
+ | `ClaudeMemory::Deprecations` | The deprecation-warning helper itself; `.warn(name:, replacement:, removed_in:, message:)`. |
226
+ | `ClaudeMemory::VERSION` | Semver string constant. |
227
+
228
+ ### Experimental
229
+
230
+ | Class | Why |
231
+ |---|---|
232
+ | `ClaudeMemory::Hook::ContextInjector` | Used by `claude-memory show` and benchmark fixtures, but its emitted_* accessors evolve as the injector is tuned. Method signatures stable; private internals not. |
233
+ | `ClaudeMemory::Distill::Extraction` | Value object the LLM-distillation path produces. Field set may grow. |
234
+ | `ClaudeMemory::Core::TokenEstimator` | Estimation heuristic may sharpen; returned counts are approximations regardless. |
235
+
236
+ ### Internal (do not rely on from external code)
237
+
238
+ Everything else under `lib/claude_memory/`. Specifically:
239
+
240
+ - All of `Resolve::*` (truth maintenance internals).
241
+ - All of `Sweep::*` (maintenance internals).
242
+ - All of `Index::*` (indexing internals — `LexicalFTS`, `VectorIndex`).
243
+ - All of `Hook::Handler` and `Hook::DistillationRunner` (use the CLI hook subcommands instead).
244
+ - All of `MCP::*` except via the public MCP-tool protocol (use `claude-memory serve-mcp` and the JSON-RPC interface).
245
+ - All of `Commands::*` except via the CLI (don't call command classes directly from external Ruby).
246
+ - All of `Dashboard::*` (treat the dashboard as a black box; don't import its panel classes).
247
+ - `Distill::NullDistiller`, `Distill::ReferenceMaterialDetector`, `Distill::BareConclusionDetector` — these are pluggable internals; treat as "may change in any patch."
248
+
249
+ If you need a feature from one of the internal classes, **open an issue** so we can promote it deliberately or expose it through a stable adapter.
250
+
251
+ ---
252
+
253
+ ## 6. Schema & predicate vocabulary
254
+
255
+ ### Schema migrations
256
+
257
+ Schema is at v18 as of 0.12.0 with 18 migrations under `db/migrations/`. Migrations remain forward-compatible per the round-trip-spec convention (`feedback_round_trip_migration_specs.md`): each release's specs verify that DBs from the prior 3 schema boundaries can be migrated into the current schema without data loss.
258
+
259
+ **What's stable:**
260
+
261
+ - Existing **table names**: `content_items`, `entities`, `entity_aliases`, `facts`, `provenance`, `fact_links`, `conflicts`, `mcp_tool_calls`, `activity_events`, `moment_feedback`, `delta_cursors`, plus `content_fts` (FTS5) and `facts_vec` (sqlite-vec).
262
+ - Existing **column names** on the above tables.
263
+ - The **predicate vocabulary** in `Resolve::PredicatePolicy::POLICIES`: `convention`, `decision`, `architecture`, `reference`, `uses_framework`, `uses_language`, `uses_database`, `deployment_platform`, `auth_method`. Adding new predicates is non-breaking; renaming or removing an existing predicate requires a deprecation cycle (see `SYNONYMS` for prior canonicalizations).
264
+ - **Cardinality** of each predicate (single vs multi). Reclassifying a predicate's cardinality is a breaking change — see the 0.9.0 `uses_framework` reclassification incident for context.
265
+
266
+ **What's experimental:**
267
+
268
+ - The `vec0` virtual-table internals — sqlite-vec evolution may shift representation.
269
+ - `mcp_tool_calls` retention behavior (currently 90 days, configurable); the column set is stable, the retention default is not.
270
+
271
+ **What's internal:**
272
+
273
+ - Auxiliary FTS shadow tables (e.g. `content_fts_data`, `content_fts_idx`) — managed by SQLite, treat as opaque.
274
+ - `schema_info` / `schema_migrations` housekeeping tables — managed by Sequel::Migrator.
275
+ - Specific SQL indexes and triggers — may be added/dropped without notice as long as the user-visible columns and behaviors stay the same.
276
+
277
+ ### Removing a column or predicate
278
+
279
+ Always a major-version change. Process:
280
+
281
+ 1. Mark the surface deprecated via `Deprecations.warn` in the next minor.
282
+ 2. Keep reading the column / accepting the predicate for ≥ 1 minor cycle.
283
+ 3. Migration to drop the column ships in the major bump.
284
+
285
+ ---
286
+
287
+ ## 7. Database signal-health audit (since 0.12.0)
288
+
289
+ The memory database itself has stability contracts that, when violated, indicate either a regression in the distillation/resolve pipeline or contamination of the source documentation. These contracts are enforced at two layers:
290
+
291
+ ### `bin/memory-audit` (runtime audit script)
292
+
293
+ Reports per-DB statistics and exits non-zero on threshold breach. Stable surface:
294
+
295
+ - Output JSON shape (`--json` flag): `{project_path, global: {active_facts, predicate_counts}, project: {active_facts, predicate_counts, open_conflicts, pending_distillation}, single_cardinality_violations, warnings, failures, ok}`.
296
+ - Exit code: `0` on `failures.empty?`, `1` otherwise. `--no-exit` always returns 0 (informational mode).
297
+
298
+ Run before tagging a release; wire into CI on the project's own DB to catch in-conversation contamination.
299
+
300
+ ### `spec/benchmarks/health/database_signal_spec.rb`
301
+
302
+ `:benchmark`-tagged RSpec suite that codifies the contracts:
303
+
304
+ 1. Zero open conflicts in both stores.
305
+ 2. At most one active fact per single-cardinality predicate (`uses_database`, `deployment_platform`, `auth_method`).
306
+ 3. `memory.conventions` returns at least one project-scope fact when project conventions exist (regression guard against the pre-0.12 global-only filter).
307
+ 4. `memory.decisions` returns only `decision`-predicate facts (no `uses_*` leakage).
308
+ 5. `memory.architecture` returns only predicates in `Shortcuts::SHORTCUTS[:architecture][:predicates]`.
309
+ 6. Distillation backlog < 100 (hard fail) / < 25 (warning).
310
+ 7. Project active facts ≥ 5 (sanity floor — catches over-aggressive rejection).
311
+
312
+ Run via `bundle exec rspec spec/benchmarks/health/ --tag benchmark`.
313
+
314
+ ---
315
+
316
+ ## 7. What is explicitly NOT public
317
+
318
+ Listed here for honesty — these surfaces look public but are not.
319
+
320
+ - **Dashboard JSON HTTP API.** The `claude-memory dashboard` server's endpoints are an internal interface for the bundled UI. Don't build scripts against `GET /api/trust` etc. — endpoints, response shapes, and even URL paths may change without notice.
321
+ - **`activity_events.detail_json` fields not in `spec/smoke/expected_fields.yml`.** Inspecting a missing field during debugging is fine; relying on it in scripts is not.
322
+ - **The exact text of `additionalContext`.** The Markdown sections (`## Decisions`, `## Conventions`, `## Architecture`, `## Pending Knowledge Extraction`, `## Auto-Memory Mirror`) and their order are stable; the per-fact rendering format inside each section is tuned for prompt quality and may change.
323
+ - **Internal env vars** (anything not listed in `Configuration` instance methods or in this doc). Examples that exist but are internal: `CLAUDE_MEMORY_LOG_LEVEL`, debug flags surfaced during development.
324
+ - **Test/spec/fixture infrastructure.** `spec/benchmarks/`, `spec/evals/`, `spec/support/` are not public APIs.
325
+ - **Plugin-format paths.** `.claude-plugin/`, `scripts/serve-mcp.sh`, etc. are part of the Claude Code plugin format integration; treat them as opaque.
326
+
327
+ ---
328
+
329
+ ## 8. Reporting a stability concern
330
+
331
+ If you depended on a surface that changed without a deprecation cycle, file an issue at [github.com/codenamev/claude_memory/issues](https://github.com/codenamev/claude_memory/issues) with:
332
+
333
+ 1. The surface (class, method, flag, tool, field).
334
+ 2. The version it worked in and the version that broke.
335
+ 3. The use case (so we can decide whether to revert or add a stable replacement).
336
+
337
+ Surfaces listed here as **stable** that broke without warning are bugs and will be fixed in a patch release. Surfaces listed as **internal** or **experimental** may or may not be fixed — we'll triage based on reach.
338
+
339
+ ---
340
+
341
+ *This doc is the contract; `lib/claude_memory/commands/registry.rb`, `lib/claude_memory/mcp/tool_definitions.rb`, `lib/claude_memory/resolve/predicate_policy.rb`, and `spec/smoke/expected_fields.yml` are the implementation. When they disagree, the manifest files in code are authoritative — but disagreement is itself a bug; keep them in sync.*
data/docs/architecture.md CHANGED
@@ -40,7 +40,7 @@ ClaudeMemory is architected using Domain-Driven Design (DDD) principles with cle
40
40
 
41
41
  **Components:**
42
42
  - **CLI** (`cli.rb`): Thin router that dispatches to command classes
43
- - **Commands** (`commands/`): 32 command classes, each handling one CLI command
43
+ - **Commands** (`commands/`): 34 command classes, each handling one CLI command
44
44
  - **Configuration** (`configuration.rb`): Centralized ENV access and path calculation
45
45
 
46
46
  **Key Principles:**
@@ -205,7 +205,7 @@ end
205
205
  - **Server**: WEBrick HTTP server (default port 3377), starts via `claude-memory dashboard`
206
206
  - **API**: HTTP-shape glue + per-endpoint formatting; routes/delegates to panel classes
207
207
  - **Panels** (each backed by a dedicated class with focused responsibility):
208
- - `Trust`: weekly moments, fingerprint, utilization, feedback ratio, needs-review
208
+ - `Trust`: weekly moments, fingerprint, utilization, feedback ratio, needs-review, **token_budget** (p50/p95/avg over 30d, 0.11.0+), **quality_score** (live 30-day window + historical baseline, 0.11.0+)
209
209
  - `Moments`: feed-first activity stream with kind classification
210
210
  - `Knowledge`: predicate-grouped fact summary (incl. References section)
211
211
  - `Conflicts`: display-layer dedup with bulk-reject helper
@@ -361,7 +361,7 @@ FileSystem (write)
361
361
  - Value objects (SessionId, TranscriptPath, FactId)
362
362
  - Centralized Configuration
363
363
  - 4 domain models with business logic
364
- - 32 command classes
364
+ - 34 command classes
365
365
  - 25 MCP tools
366
366
  - Semantic search with local embeddings (FastEmbed + TF-IDF fallback)
367
367
  - Schema v17 with WAL mode
@@ -0,0 +1,209 @@
1
+ # Memory Audit Runbook
2
+
3
+ This runbook explains every check the audit runs, why it matters, and how to remediate findings. It is the human-readable companion to `claude-memory audit` and the `/audit-memory` skill.
4
+
5
+ ## When to run
6
+
7
+ - **After a release** — before tagging, confirm no contracts were silently broken.
8
+ - **When `memory.recall` feels noisy** — if you ask for conventions and get unrelated stack facts, the shortcut filters may have regressed.
9
+ - **When ingest seems slow** — a large distillation backlog or repeating contamination loop will compound over weeks.
10
+ - **In CI on `main`** — wire `claude-memory audit --no-exit --json` into a workflow and post the output to a dashboard.
11
+
12
+ ## Quick start
13
+
14
+ ```bash
15
+ claude-memory audit # human-readable, exits non-zero on error
16
+ claude-memory audit --json # machine-readable JSON
17
+ claude-memory audit --severity=error # only blocking findings
18
+ /audit-memory # interactive walkthrough via Claude Code
19
+ ```
20
+
21
+ ## Output shape
22
+
23
+ JSON payload:
24
+
25
+ ```json
26
+ {
27
+ "ok": true,
28
+ "checks_run": 10,
29
+ "counts": {"error": 0, "warn": 1, "info": 2},
30
+ "stats": {
31
+ "global": {"active_facts": 4, "predicate_counts": {"convention": 4}},
32
+ "project": {"active_facts": 68, "predicate_counts": {...}}
33
+ },
34
+ "findings": [
35
+ {
36
+ "id": "C003",
37
+ "severity": "warn",
38
+ "title": "27 content items not yet deeply distilled",
39
+ "detail": "...",
40
+ "suggestion": "claude-memory sweep --mark-all-distilled OR /distill-transcripts",
41
+ "fact_ids": []
42
+ }
43
+ ]
44
+ }
45
+ ```
46
+
47
+ Exit code is `0` when `ok: true`, `1` otherwise. `--no-exit` always returns `0`.
48
+
49
+ ## Checks
50
+
51
+ ### C001 — Open conflicts
52
+
53
+ **Severity:** error
54
+
55
+ **Triggered when:** the project or global DB has any row in `conflicts` with `status='open'`.
56
+
57
+ **Why it matters:** Conflicts pause supersession. Until they close, single-cardinality predicates can't reach a clean state. Every re-ingest of the contested content potentially adds noise.
58
+
59
+ **Remediation:**
60
+ 1. List with `claude-memory conflicts`.
61
+ 2. For each pair, run `claude-memory explain <fact_a>` and `claude-memory explain <fact_b>` to inspect provenance.
62
+ 3. Reject the wrong claim with `claude-memory reject <fact_id> --reason "<why>"`. Rejection closes any conflict the fact was party to in the same transaction.
63
+
64
+ ### C002 — Single-cardinality multiplicity
65
+
66
+ **Severity:** error
67
+
68
+ **Triggered when:** `uses_database`, `deployment_platform`, or `auth_method` has more than one active fact.
69
+
70
+ **Why it matters:** The single-cardinality contract is "at most one active value per predicate." Multiple actives mean either the resolver dropped a supersession or distillation produced contradictions. Downstream tools (snapshot publishing, `memory.architecture`) will list mutually exclusive values.
71
+
72
+ **Remediation:**
73
+ 1. Identify the right value (the one the project actually uses).
74
+ 2. `claude-memory reject <fact_id>` on the others.
75
+ 3. Re-audit to confirm; if it keeps recurring, look at C010 (churn) and find the contamination source.
76
+
77
+ ### C003 — Distillation backlog
78
+
79
+ **Severity:** warn (≥ 25) or error (≥ 100)
80
+
81
+ **Triggered when:** content items are not present in `ingestion_metrics`, indicating they haven't been deep-distilled (Layer 2/3).
82
+
83
+ **Why it matters:** Backlog grows when SessionStart distillation prompts don't get acknowledged via `memory.mark_distilled`. The same transcript text keeps getting re-extracted across sessions, multiplying hallucination opportunities.
84
+
85
+ **Remediation:**
86
+ - **Triage path (preserves signal):** `/distill-transcripts --limit 10` repeatedly until cleared. Slow, but extracts genuine facts.
87
+ - **Bulk-clear path (accepts backlog is noise):** `claude-memory sweep --mark-all-distilled`. Use when the backlog is old transcripts unlikely to add value.
88
+
89
+ ### C004 — `memory.decisions` predicate leak
90
+
91
+ **Severity:** error
92
+
93
+ **Triggered when:** the `memory.decisions` MCP shortcut returns facts whose predicate is not `decision`.
94
+
95
+ **Why it matters:** The shortcut should be a clean `predicate=decision` filter. Pre-2026-05-21, it ran an FTS text search on "decision constraint rule requirement" which matched `uses_database`/`uses_framework` rows. Any leakage means the shortcut has regressed.
96
+
97
+ **Remediation:**
98
+ - Open `lib/claude_memory/shortcuts.rb` and verify `SHORTCUTS[:decisions][:predicates]` is `%w[decision]`.
99
+ - Run `bundle exec rspec spec/claude_memory/shortcuts_spec.rb`.
100
+ - File a bug if the spec passes but real output leaks.
101
+
102
+ ### C005 — `memory.conventions` scope regression
103
+
104
+ **Severity:** warn
105
+
106
+ **Triggered when:** `memory.conventions` returns zero project-scoped facts despite the project DB containing active conventions.
107
+
108
+ **Why it matters:** Pre-2026-05-21, `memory.conventions` was hardcoded to `scope=global` only. Project conventions were invisible to coding agents calling the shortcut. Resurfacing this regression means losing project knowledge.
109
+
110
+ **Remediation:**
111
+ - Inspect `Shortcuts.collect_facts` in `lib/claude_memory/shortcuts.rb` — it must query both `manager.project_store` and `manager.global_store`.
112
+ - Re-run the shortcut spec.
113
+
114
+ ### C006 — Duplicate global conventions
115
+
116
+ **Severity:** info
117
+
118
+ **Triggered when:** the global DB has multiple `convention` facts whose object text normalizes to the same phrasing (after lowercasing, stripping `uses`/`prefers`/punctuation).
119
+
120
+ **Why it matters:** Duplicates pollute the global convention list and inflate the apparent size of your memory. They don't break correctness, but they waste tokens.
121
+
122
+ **Remediation:**
123
+ 1. Pick the cleanest phrasing.
124
+ 2. `claude-memory reject <duplicate_id>` on the rest.
125
+
126
+ ### C007 — Bare-conclusion rate
127
+
128
+ **Severity:** info
129
+
130
+ **Triggered when:** ≥ 30% of active `decision`/`convention` facts lack a reason clause ("because", "so that", "to avoid", etc.).
131
+
132
+ **Why it matters:** Facts without justification are dead weight when the original context fades. A high bare-conclusion ratio means the LLM distillation is shipping low-quality extractions.
133
+
134
+ **Remediation:**
135
+ - Low-value bare facts: reject.
136
+ - Important bare facts: rewrite via `memory.store_extraction` with a `quote` that embeds the reason, then reject the bare original.
137
+ - See `Distill::BareConclusionDetector` for the canonical signal patterns.
138
+
139
+ ### C008 — Project starvation
140
+
141
+ **Severity:** warn
142
+
143
+ **Triggered when:** the project DB has fewer than 5 active facts.
144
+
145
+ **Why it matters:** A nearly-empty DB suggests either a fresh install (ignore) or a broken ingest pipeline / overzealous cleanup. Distinguishing requires looking at ingest history.
146
+
147
+ **Remediation:**
148
+ - `claude-memory doctor` — verify hooks are firing.
149
+ - `claude-memory stats` — check `content_items.total` vs `facts.active`; if many content items but few facts, distillation isn't running.
150
+ - Check `.claude/settings.json` for hook configuration.
151
+
152
+ ### C009 — Auto-memory unimported
153
+
154
+ **Severity:** info
155
+
156
+ **Triggered when:** `~/.claude/projects/<slug>/memory/*.md` contains more files than the project DB has `content_items` with `source='auto_memory_import'`.
157
+
158
+ **Why it matters:** Claude Code's auto-memory markdown files are durable user-curated knowledge. Until imported, they only surface transiently via `AutoMemoryMirror` at SessionStart — they're invisible to `memory.recall` and to the shortcut tools.
159
+
160
+ **Remediation:**
161
+ - Preview: `claude-memory import-auto-memory --dry-run`.
162
+ - Apply: `claude-memory import-auto-memory`.
163
+
164
+ ### C010 — Single-cardinality churn
165
+
166
+ **Severity:** warn
167
+
168
+ **Triggered when:** any single-cardinality predicate has ≥ 5 historical non-active facts (superseded + disputed + rejected).
169
+
170
+ **Why it matters:** Repeated supersession on a "must be exactly one" predicate is the signature of a persistent contamination source. Common culprits:
171
+ - Example text in `CLAUDE.md` ("e.g., this app uses PostgreSQL") triggers extraction every session.
172
+ - Comments in code/docs naming alternative stacks.
173
+ - Audit/discussion documents (like this one) mentioning the contaminating value.
174
+
175
+ **Remediation:**
176
+ 1. Find the trigger: `claude-memory recall "<bad_value>" --scope=project`. Inspect the matching content items and their source.
177
+ 2. Wrap the trigger text in `<no-memory>` tags at the source.
178
+ 3. Clean up: `claude-memory reject` the historical disputed/superseded rows (or accept them as historical record).
179
+ 4. Re-audit.
180
+
181
+ ## Adding a new check
182
+
183
+ The audit is extensible by design.
184
+
185
+ 1. Add a method to `ClaudeMemory::Audit::Checks` returning `Array<Finding>`. Convention: pure read-only access to the StoreManager.
186
+ 2. Append the method name to `Audit::Runner::CHECK_METHODS`.
187
+ 3. Document the check in this runbook (this file) with the same `C###` ID.
188
+ 4. Write a spec at `spec/claude_memory/audit/checks_spec.rb`.
189
+
190
+ ## Integrating with CI
191
+
192
+ A minimal GitHub Actions step:
193
+
194
+ ```yaml
195
+ - name: ClaudeMemory health audit
196
+ run: bundle exec claude-memory audit --json | tee audit.json
197
+ - uses: actions/upload-artifact@v4
198
+ with:
199
+ name: memory-audit
200
+ path: audit.json
201
+ ```
202
+
203
+ Treat error-severity findings as build failures. Warnings can route to a Slack channel for periodic triage.
204
+
205
+ ## Related
206
+
207
+ - `docs/memory_audit_2026-05-21.md` — the original audit and 4-phase remediation pipeline that established this workflow.
208
+ - `docs/api_stability.md` Section 7 — stable surface of the audit script and benchmark spec.
209
+ - `spec/benchmarks/health/database_signal_spec.rb` — runtime contract checks that mirror C001/C002/C004/C005.