claude-total-memory 11.2.2__py3-none-any.whl

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 (179) hide show
  1. claude_total_memory/__init__.py +3 -0
  2. claude_total_memory/lookup.py +183 -0
  3. claude_total_memory/server.py +25 -0
  4. claude_total_memory-11.2.2.dist-info/METADATA +1309 -0
  5. claude_total_memory-11.2.2.dist-info/RECORD +179 -0
  6. claude_total_memory-11.2.2.dist-info/WHEEL +5 -0
  7. claude_total_memory-11.2.2.dist-info/entry_points.txt +4 -0
  8. claude_total_memory-11.2.2.dist-info/licenses/LICENSE +21 -0
  9. claude_total_memory-11.2.2.dist-info/top_level.txt +2 -0
  10. src/__init__.py +0 -0
  11. src/active_context.py +205 -0
  12. src/ai_layer/__init__.py +77 -0
  13. src/ai_layer/answerability.py +386 -0
  14. src/ai_layer/contradiction_detector.py +37 -0
  15. src/ai_layer/coref_resolver.py +21 -0
  16. src/ai_layer/enrichment_jobs.py +129 -0
  17. src/ai_layer/enrichment_worker.py +44 -0
  18. src/ai_layer/iterative_retriever.py +469 -0
  19. src/ai_layer/keyword_extractor.py +51 -0
  20. src/ai_layer/quality_gate.py +23 -0
  21. src/ai_layer/query_rewriter.py +22 -0
  22. src/ai_layer/question_generator.py +53 -0
  23. src/ai_layer/reflection.py +30 -0
  24. src/ai_layer/relation_extractor.py +64 -0
  25. src/ai_layer/reranker.py +28 -0
  26. src/ai_layer/self_improve.py +30 -0
  27. src/ai_layer/summarizer.py +39 -0
  28. src/ai_layer/verifier.py +506 -0
  29. src/analogy.py +157 -0
  30. src/associative/__init__.py +0 -0
  31. src/associative/activation.py +244 -0
  32. src/associative/composition.py +338 -0
  33. src/associative/recall.py +383 -0
  34. src/ast_ingest/__init__.py +5 -0
  35. src/ast_ingest/ingester.py +401 -0
  36. src/auto_episode_capture.py +417 -0
  37. src/auto_extract_active.py +217 -0
  38. src/auto_self_improve.py +314 -0
  39. src/auto_session_save.py +101 -0
  40. src/autofilter.py +191 -0
  41. src/cache.py +237 -0
  42. src/cache_layer.py +528 -0
  43. src/canonical_tags.py +390 -0
  44. src/choose_embed.py +201 -0
  45. src/cognitive/__init__.py +1 -0
  46. src/cognitive/engine.py +979 -0
  47. src/config.py +896 -0
  48. src/content_filter.py +270 -0
  49. src/context_expander.py +179 -0
  50. src/contradiction_detector.py +476 -0
  51. src/coref_resolver.py +302 -0
  52. src/dashboard.py +4557 -0
  53. src/dashboard_v6.py +1417 -0
  54. src/decisions.py +320 -0
  55. src/deep_enricher.py +286 -0
  56. src/deep_enrichment_queue.py +169 -0
  57. src/embed_provider.py +441 -0
  58. src/enrichment_filter.py +108 -0
  59. src/enrichment_worker.py +483 -0
  60. src/entity_dedup.py +354 -0
  61. src/episodic.py +328 -0
  62. src/error_capture.py +248 -0
  63. src/eval_harness.py +234 -0
  64. src/extract_transcript.py +408 -0
  65. src/fact_index.py +510 -0
  66. src/fact_merger.py +245 -0
  67. src/fact_synthesizer.py +375 -0
  68. src/file_context.py +338 -0
  69. src/fusion.py +138 -0
  70. src/graph/__init__.py +8 -0
  71. src/graph/auto_link.py +81 -0
  72. src/graph/enricher.py +505 -0
  73. src/graph/indexer.py +872 -0
  74. src/graph/query.py +470 -0
  75. src/graph/store.py +731 -0
  76. src/graph_expander.py +393 -0
  77. src/ingestion/__init__.py +13 -0
  78. src/ingestion/chunker.py +271 -0
  79. src/ingestion/enricher.py +249 -0
  80. src/ingestion/extractor.py +541 -0
  81. src/ingestion/file_watcher.py +320 -0
  82. src/ingestion/gateway.py +345 -0
  83. src/ingestion/ocr.py +264 -0
  84. src/intents.py +194 -0
  85. src/llm_provider.py +404 -0
  86. src/memory_core/__init__.py +33 -0
  87. src/memory_core/answer_router.py +359 -0
  88. src/memory_core/cache.py +123 -0
  89. src/memory_core/calibration.py +401 -0
  90. src/memory_core/chunker.py +438 -0
  91. src/memory_core/classifier.py +406 -0
  92. src/memory_core/dedup.py +87 -0
  93. src/memory_core/embedding_cache.py +232 -0
  94. src/memory_core/embedding_spaces.py +127 -0
  95. src/memory_core/embeddings.py +173 -0
  96. src/memory_core/entity_resolver.py +601 -0
  97. src/memory_core/episodes/__init__.py +27 -0
  98. src/memory_core/episodes/extractor.py +469 -0
  99. src/memory_core/episodes/retriever.py +383 -0
  100. src/memory_core/episodes/schema.py +90 -0
  101. src/memory_core/graph_links.py +131 -0
  102. src/memory_core/health.py +77 -0
  103. src/memory_core/idk_router.py +214 -0
  104. src/memory_core/negative_retrieval.py +510 -0
  105. src/memory_core/storage.py +64 -0
  106. src/memory_core/telemetry.py +91 -0
  107. src/memory_core/temporal/__init__.py +80 -0
  108. src/memory_core/temporal/allen.py +406 -0
  109. src/memory_core/temporal/arithmetic.py +281 -0
  110. src/memory_core/temporal/normalizer.py +581 -0
  111. src/memory_core/vector_store.py +254 -0
  112. src/memory_systems/__init__.py +0 -0
  113. src/memory_systems/episode_store.py +278 -0
  114. src/memory_systems/self_model.py +476 -0
  115. src/memory_systems/signals.py +246 -0
  116. src/memory_systems/skill_store.py +391 -0
  117. src/metrics/__init__.py +0 -0
  118. src/migrate_knowledge_to_graph.py +335 -0
  119. src/models.py +1296 -0
  120. src/multi_repr_search.py +334 -0
  121. src/multi_repr_store.py +202 -0
  122. src/outbox.py +325 -0
  123. src/privacy_filter.py +19 -0
  124. src/procedural.py +356 -0
  125. src/project_wiki.py +434 -0
  126. src/quality_gate.py +460 -0
  127. src/query_rewriter.py +300 -0
  128. src/query_router.py +285 -0
  129. src/recall_modes.py +278 -0
  130. src/reembed.py +307 -0
  131. src/reflection/__init__.py +1 -0
  132. src/reflection/agent.py +688 -0
  133. src/reflection/digest.py +484 -0
  134. src/reflection/scheduler.py +2202 -0
  135. src/reflection/synthesize.py +463 -0
  136. src/representations.py +231 -0
  137. src/representations_queue.py +204 -0
  138. src/reranker.py +672 -0
  139. src/server.py +6799 -0
  140. src/session_continuity.py +413 -0
  141. src/subject_predicate_retriever.py +184 -0
  142. src/task_classifier.py +181 -0
  143. src/task_phases.py +299 -0
  144. src/temporal_filter.py +199 -0
  145. src/temporal_index.py +368 -0
  146. src/temporal_kg.py +348 -0
  147. src/tools/__init__.py +0 -0
  148. src/tools/analyze_project.py +396 -0
  149. src/tools/backfill_orphan_edges.py +159 -0
  150. src/tools/backfill_v6.py +82 -0
  151. src/tools/benchmark.py +940 -0
  152. src/tools/brain_autonomy.py +614 -0
  153. src/tools/brain_health.py +485 -0
  154. src/tools/check_updates.py +166 -0
  155. src/tools/context_layers.py +472 -0
  156. src/tools/cross_project.py +1021 -0
  157. src/tools/dependency_monitor.py +285 -0
  158. src/tools/export_knowledge.py +314 -0
  159. src/tools/git_observer.py +968 -0
  160. src/tools/graph_enrichment.py +1100 -0
  161. src/tools/idea_engine.py +1215 -0
  162. src/tools/import_projects_now.py +312 -0
  163. src/tools/improve_search.py +877 -0
  164. src/tools/llm_router.py +397 -0
  165. src/tools/merge_duplicate_nodes.py +491 -0
  166. src/tools/obsidian_sync.py +399 -0
  167. src/tools/predictive.py +1176 -0
  168. src/tools/run_reflection.py +191 -0
  169. src/tools/task_manager.py +816 -0
  170. src/tools/tech_radar.py +275 -0
  171. src/tools/version_status.py +141 -0
  172. src/triple_extraction_queue.py +208 -0
  173. src/v11_handlers.py +236 -0
  174. src/validator.py +235 -0
  175. src/verbosity.py +49 -0
  176. src/version.py +10 -0
  177. src/workers/__init__.py +34 -0
  178. src/workers/consolidation_daemon.py +849 -0
  179. src/workers/project_activity.py +193 -0
@@ -0,0 +1,3 @@
1
+ """total-agent-memory — Persistent memory MCP server for Claude Code & Codex CLI."""
2
+
3
+ __version__ = "9.0.0-alpha"
@@ -0,0 +1,183 @@
1
+ """v9.0 D9 — `ctm-lookup` CLI: bash-friendly memory search for sub-agents.
2
+
3
+ Replaces the legacy `~/claude-memory-server/ollama/lookup_memory.sh` script
4
+ that was *only* distributed through manual setup. This module ships in the
5
+ pip package so any client that did `pip install claude-total-memory` (or
6
+ `uv pip install …`) gets a working `ctm-lookup` binary on PATH.
7
+
8
+ Design goals:
9
+ * **Zero extra deps** — uses only what claude_total_memory.server already
10
+ pulls in (mcp[cli], chromadb, sentence-transformers, sqlite3 stdlib).
11
+ * **No Ollama / RAG / LLM call** — pure retrieval. Sub-agents that need
12
+ a chat model wrap us with their own.
13
+ * **Same DB the running MCP server uses** — reads `$CLAUDE_MEMORY_DIR/memory.db`,
14
+ so results match what the parent agent sees through MCP tools.
15
+
16
+ Usage:
17
+ ctm-lookup "query"
18
+ ctm-lookup --project myproj "query"
19
+ ctm-lookup --limit 5 --json "query"
20
+ ctm-lookup --tag reusable --type solution "query"
21
+
22
+ Output: human-readable bullets by default; `--json` for structured stdout
23
+ (stable schema for machine consumption by agents).
24
+ """
25
+
26
+ from __future__ import annotations
27
+
28
+ import argparse
29
+ import json
30
+ import os
31
+ import sqlite3
32
+ import sys
33
+ from pathlib import Path
34
+
35
+ DEFAULT_LIMIT = 8
36
+ DEFAULT_PROJECT_FILTER = None
37
+
38
+
39
+ def _resolve_db_path() -> Path:
40
+ """Honor CLAUDE_MEMORY_DIR (same env the server reads) → fall back to ~/.claude-memory."""
41
+ base = os.environ.get("CLAUDE_MEMORY_DIR") or os.path.expanduser("~/.claude-memory")
42
+ p = Path(base) / "memory.db"
43
+ return p
44
+
45
+
46
+ def _open_db(db_path: Path) -> sqlite3.Connection:
47
+ if not db_path.exists():
48
+ sys.stderr.write(
49
+ f"[ctm-lookup] memory.db not found at {db_path}\n"
50
+ " Run the MCP server once (or set CLAUDE_MEMORY_DIR) so the DB initialises.\n"
51
+ )
52
+ sys.exit(2)
53
+ conn = sqlite3.connect(str(db_path))
54
+ conn.row_factory = sqlite3.Row
55
+ return conn
56
+
57
+
58
+ def _has_fts(conn: sqlite3.Connection) -> bool:
59
+ """v8+ ships an FTS5 virtual table `knowledge_fts`. Fall back to LIKE if absent."""
60
+ try:
61
+ conn.execute("SELECT 1 FROM knowledge_fts LIMIT 1")
62
+ return True
63
+ except sqlite3.OperationalError:
64
+ return False
65
+
66
+
67
+ def search(
68
+ conn: sqlite3.Connection,
69
+ query: str,
70
+ *,
71
+ project: str | None = None,
72
+ types: list[str] | None = None,
73
+ tags: list[str] | None = None,
74
+ limit: int = DEFAULT_LIMIT,
75
+ ) -> list[dict]:
76
+ """Hybrid BM25 (FTS5) + LIKE fallback. Filters: project, type, tags."""
77
+ use_fts = _has_fts(conn)
78
+
79
+ where: list[str] = ["k.status = 'active'"]
80
+ params: list = []
81
+
82
+ if project:
83
+ where.append("k.project = ?")
84
+ params.append(project)
85
+ if types:
86
+ placeholders = ",".join("?" * len(types))
87
+ where.append(f"k.type IN ({placeholders})")
88
+ params.extend(types)
89
+ if tags:
90
+ # tags is JSON in DB; LIKE on substring is sufficient for the lookup CLI.
91
+ for t in tags:
92
+ where.append("k.tags LIKE ?")
93
+ params.append(f'%"{t}"%')
94
+
95
+ if use_fts:
96
+ # FTS5 BM25 ranking — uses the virtual table on `content`.
97
+ sql = (
98
+ "SELECT k.id, k.project, k.type, k.content, k.tags, k.created_at, "
99
+ " bm25(knowledge_fts) AS score "
100
+ "FROM knowledge_fts "
101
+ "JOIN knowledge k ON k.id = knowledge_fts.rowid "
102
+ "WHERE knowledge_fts MATCH ? "
103
+ f"AND {' AND '.join(where)} "
104
+ "ORDER BY score LIMIT ?"
105
+ )
106
+ rows = conn.execute(sql, (_fts_query(query), *params, limit)).fetchall()
107
+ else:
108
+ sql = (
109
+ "SELECT k.id, k.project, k.type, k.content, k.tags, k.created_at, "
110
+ " 0.0 AS score "
111
+ "FROM knowledge k "
112
+ f"WHERE {' AND '.join(where)} AND k.content LIKE ? "
113
+ "ORDER BY k.created_at DESC LIMIT ?"
114
+ )
115
+ rows = conn.execute(sql, (*params, f"%{query}%", limit)).fetchall()
116
+
117
+ return [dict(r) for r in rows]
118
+
119
+
120
+ def _fts_query(q: str) -> str:
121
+ """Quote bare tokens for FTS5 so punctuation in user input doesn't break parsing."""
122
+ parts = []
123
+ for tok in q.split():
124
+ tok = tok.replace('"', '""')
125
+ parts.append(f'"{tok}"')
126
+ return " ".join(parts) or '""'
127
+
128
+
129
+ def render_human(rows: list[dict]) -> str:
130
+ if not rows:
131
+ return "(no matches)"
132
+ out: list[str] = []
133
+ for i, r in enumerate(rows, 1):
134
+ content = (r.get("content") or "").strip()
135
+ snippet = content if len(content) <= 280 else content[:277] + "..."
136
+ meta = f"[{r.get('type', '?')}|{r.get('project', '?')}]"
137
+ out.append(f"{i}. {meta} {snippet}")
138
+ return "\n".join(out)
139
+
140
+
141
+ def main(argv: list[str] | None = None) -> int:
142
+ p = argparse.ArgumentParser(
143
+ prog="ctm-lookup",
144
+ description="Search claude-total-memory DB from the shell.",
145
+ )
146
+ p.add_argument("query", nargs="+", help="Search query (free text).")
147
+ p.add_argument("-p", "--project", default=DEFAULT_PROJECT_FILTER,
148
+ help="Restrict to a single project.")
149
+ p.add_argument("-l", "--limit", type=int, default=DEFAULT_LIMIT,
150
+ help=f"Max results (default {DEFAULT_LIMIT}).")
151
+ p.add_argument("-t", "--type", action="append",
152
+ help="Filter by knowledge type. Repeat for multiple.")
153
+ p.add_argument("--tag", action="append",
154
+ help="Require this tag. Repeat for multiple (AND).")
155
+ p.add_argument("--json", dest="json_out", action="store_true",
156
+ help="Emit machine-readable JSON instead of bullets.")
157
+ p.add_argument("--db", type=Path, default=None,
158
+ help="Path to memory.db (default: $CLAUDE_MEMORY_DIR/memory.db).")
159
+ args = p.parse_args(argv)
160
+
161
+ db_path = args.db or _resolve_db_path()
162
+ conn = _open_db(db_path)
163
+ try:
164
+ rows = search(
165
+ conn,
166
+ " ".join(args.query),
167
+ project=args.project,
168
+ types=args.type,
169
+ tags=args.tag,
170
+ limit=args.limit,
171
+ )
172
+ finally:
173
+ conn.close()
174
+
175
+ if args.json_out:
176
+ print(json.dumps(rows, ensure_ascii=False, indent=2, default=str))
177
+ else:
178
+ print(render_human(rows))
179
+ return 0
180
+
181
+
182
+ if __name__ == "__main__":
183
+ raise SystemExit(main())
@@ -0,0 +1,25 @@
1
+ """Entry point for pip-installed package. Re-exports from src/server.py."""
2
+
3
+ import sys
4
+ import os
5
+ import asyncio
6
+
7
+ # Add parent directory to path so we can import the actual server
8
+ _root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
9
+ _server_path = os.path.join(_root, "src", "server.py")
10
+
11
+ if os.path.exists(_server_path):
12
+ import importlib.util
13
+ spec = importlib.util.spec_from_file_location("_server", _server_path)
14
+ _mod = importlib.util.module_from_spec(spec)
15
+ spec.loader.exec_module(_mod)
16
+ main = _mod.main
17
+ else:
18
+ async def main():
19
+ print("Error: server.py not found", file=sys.stderr)
20
+ sys.exit(1)
21
+
22
+
23
+ def main_sync():
24
+ """Synchronous entry point for console_scripts."""
25
+ asyncio.run(main())