graph-mind-memory 0.5.0__tar.gz → 0.5.2__tar.gz

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 (33) hide show
  1. {graph_mind_memory-0.5.0/graph_mind_memory.egg-info → graph_mind_memory-0.5.2}/PKG-INFO +10 -4
  2. {graph_mind_memory-0.5.0 → graph_mind_memory-0.5.2}/README.md +8 -3
  3. {graph_mind_memory-0.5.0 → graph_mind_memory-0.5.2}/automatic_capture.py +30 -1
  4. {graph_mind_memory-0.5.0 → graph_mind_memory-0.5.2}/conversation_memory.py +9 -0
  5. {graph_mind_memory-0.5.0 → graph_mind_memory-0.5.2}/graph_mind_mcp_server.py +20 -1
  6. {graph_mind_memory-0.5.0 → graph_mind_memory-0.5.2/graph_mind_memory.egg-info}/PKG-INFO +10 -4
  7. {graph_mind_memory-0.5.0 → graph_mind_memory-0.5.2}/pyproject.toml +2 -1
  8. {graph_mind_memory-0.5.0 → graph_mind_memory-0.5.2}/LICENSE +0 -0
  9. {graph_mind_memory-0.5.0 → graph_mind_memory-0.5.2}/associative_memory.py +0 -0
  10. {graph_mind_memory-0.5.0 → graph_mind_memory-0.5.2}/automatic_capture_cli.py +0 -0
  11. {graph_mind_memory-0.5.0 → graph_mind_memory-0.5.2}/brain_log.py +0 -0
  12. {graph_mind_memory-0.5.0 → graph_mind_memory-0.5.2}/clock.py +0 -0
  13. {graph_mind_memory-0.5.0 → graph_mind_memory-0.5.2}/coding_memory.py +0 -0
  14. {graph_mind_memory-0.5.0 → graph_mind_memory-0.5.2}/development_memory.py +0 -0
  15. {graph_mind_memory-0.5.0 → graph_mind_memory-0.5.2}/development_paths.py +0 -0
  16. {graph_mind_memory-0.5.0 → graph_mind_memory-0.5.2}/embedding_warmup.py +0 -0
  17. {graph_mind_memory-0.5.0 → graph_mind_memory-0.5.2}/entity_timeline.py +0 -0
  18. {graph_mind_memory-0.5.0 → graph_mind_memory-0.5.2}/forget.py +0 -0
  19. {graph_mind_memory-0.5.0 → graph_mind_memory-0.5.2}/graph_mind_memory.egg-info/SOURCES.txt +0 -0
  20. {graph_mind_memory-0.5.0 → graph_mind_memory-0.5.2}/graph_mind_memory.egg-info/dependency_links.txt +0 -0
  21. {graph_mind_memory-0.5.0 → graph_mind_memory-0.5.2}/graph_mind_memory.egg-info/entry_points.txt +0 -0
  22. {graph_mind_memory-0.5.0 → graph_mind_memory-0.5.2}/graph_mind_memory.egg-info/requires.txt +0 -0
  23. {graph_mind_memory-0.5.0 → graph_mind_memory-0.5.2}/graph_mind_memory.egg-info/top_level.txt +0 -0
  24. {graph_mind_memory-0.5.0 → graph_mind_memory-0.5.2}/install.py +0 -0
  25. {graph_mind_memory-0.5.0 → graph_mind_memory-0.5.2}/local_brain.py +0 -0
  26. {graph_mind_memory-0.5.0 → graph_mind_memory-0.5.2}/local_embedder.py +0 -0
  27. {graph_mind_memory-0.5.0 → graph_mind_memory-0.5.2}/semantic_llm_extractor.py +0 -0
  28. {graph_mind_memory-0.5.0 → graph_mind_memory-0.5.2}/semantic_memory.py +0 -0
  29. {graph_mind_memory-0.5.0 → graph_mind_memory-0.5.2}/semantic_recall.py +0 -0
  30. {graph_mind_memory-0.5.0 → graph_mind_memory-0.5.2}/setup.cfg +0 -0
  31. {graph_mind_memory-0.5.0 → graph_mind_memory-0.5.2}/temporal_resolver.py +0 -0
  32. {graph_mind_memory-0.5.0 → graph_mind_memory-0.5.2}/universal_personal_memory.py +0 -0
  33. {graph_mind_memory-0.5.0 → graph_mind_memory-0.5.2}/vector_cache.py +0 -0
@@ -1,11 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: graph-mind-memory
3
- Version: 0.5.0
3
+ Version: 0.5.2
4
4
  Summary: Local-first memory for AI coding assistants: verbatim, on your own PC, no LLM calls at write time.
5
5
  Author-email: Yohan Ko <goyohan0611@gmail.com>
6
6
  License-Expression: AGPL-3.0-only
7
7
  Project-URL: Homepage, https://github.com/goyohan0611-png/graph-mind
8
8
  Project-URL: Issues, https://github.com/goyohan0611-png/graph-mind/issues
9
+ Project-URL: Changelog, https://github.com/goyohan0611-png/graph-mind/blob/main/CHANGELOG.md
9
10
  Keywords: mcp,memory,claude,codex,llm,longmemeval,local-first
10
11
  Classifier: Development Status :: 3 - Alpha
11
12
  Classifier: Programming Language :: Python :: 3
@@ -120,6 +121,8 @@ Requires Python 3.10+ (64-bit). Windows, macOS or Linux. Hosting a brain that ot
120
121
  needs Python 3.12 or older on that one PC (its Postgres helper, pgserver, has no newer build yet);
121
122
  everything else, joining included, works on 3.13 and 3.14 too.
122
123
 
124
+ What changed in each release: [CHANGELOG.md](CHANGELOG.md).
125
+
123
126
  ```bash
124
127
  pip install graph-mind-memory
125
128
  graph-mind-install
@@ -180,9 +183,12 @@ random 20-64 character tokens caught; in 246,750 ordinary chat turns it fired 92
180
183
  all on real ids and tokens). Commit ids, hashes and UUIDs are kept, since you recall those on
181
184
  purpose.
182
185
 
183
- There is no switch to keep keys: a recalled memory goes to your model's provider with the question,
184
- so a stored key would leave your PC the first time it is useful. To have Graph-MIND remember a key,
185
- tell it **where the key is**, not the key: *"my OpenAI key is in 1Password, under Dev"*.
186
+ Keep masking on if you use a cloud model: a recalled memory goes to your model's provider with the
187
+ question, so a stored key would leave your PC the first time it is useful. To have Graph-MIND
188
+ remember a key, tell it **where the key is**, not the key: *"my OpenAI key is in 1Password, under
189
+ Dev"*. If your model runs on your own machines and you want keys remembered as typed, add
190
+ `"mask_secrets": false` to `~/.graph-mind/config.json` (applies from the next message; already
191
+ masked text stays masked).
186
192
 
187
193
  Only what you actually send is captured: the service reads each app's transcript, which is written
188
194
  after you press Enter, so a paste you delete before sending never reaches it. A plain password
@@ -93,6 +93,8 @@ Requires Python 3.10+ (64-bit). Windows, macOS or Linux. Hosting a brain that ot
93
93
  needs Python 3.12 or older on that one PC (its Postgres helper, pgserver, has no newer build yet);
94
94
  everything else, joining included, works on 3.13 and 3.14 too.
95
95
 
96
+ What changed in each release: [CHANGELOG.md](CHANGELOG.md).
97
+
96
98
  ```bash
97
99
  pip install graph-mind-memory
98
100
  graph-mind-install
@@ -153,9 +155,12 @@ random 20-64 character tokens caught; in 246,750 ordinary chat turns it fired 92
153
155
  all on real ids and tokens). Commit ids, hashes and UUIDs are kept, since you recall those on
154
156
  purpose.
155
157
 
156
- There is no switch to keep keys: a recalled memory goes to your model's provider with the question,
157
- so a stored key would leave your PC the first time it is useful. To have Graph-MIND remember a key,
158
- tell it **where the key is**, not the key: *"my OpenAI key is in 1Password, under Dev"*.
158
+ Keep masking on if you use a cloud model: a recalled memory goes to your model's provider with the
159
+ question, so a stored key would leave your PC the first time it is useful. To have Graph-MIND
160
+ remember a key, tell it **where the key is**, not the key: *"my OpenAI key is in 1Password, under
161
+ Dev"*. If your model runs on your own machines and you want keys remembered as typed, add
162
+ `"mask_secrets": false` to `~/.graph-mind/config.json` (applies from the next message; already
163
+ masked text stays masked).
159
164
 
160
165
  Only what you actually send is captured: the service reads each app's transcript, which is written
161
166
  after you press Enter, so a paste you delete before sending never reaches it. A plain password
@@ -234,10 +234,39 @@ class AutomaticCaptureService:
234
234
  "conversation_sources": conversation, "semantic": semantic,
235
235
  "semantic_llm": semantic_llm,
236
236
  "associative": associative,
237
- "errors": errors}
237
+ "errors": errors,
238
+ "warnings": self._stall_warnings(conversation)}
238
239
  self._write_status(result)
239
240
  return result
240
241
 
242
+ STALL_ROWS = 2000
243
+
244
+ def _stall_warnings(self, conversation):
245
+ """A source whose transcripts keep growing while no conversation comes out of them: the
246
+ app most likely changed its transcript format, and capture would otherwise stop without
247
+ a word. Counted across passes in capture-health.json; reset by the next turn found."""
248
+ path = self.state_dir / "capture-health.json"
249
+ try:
250
+ health = json.loads(path.read_text(encoding="utf-8"))
251
+ except (OSError, ValueError):
252
+ health = {}
253
+ warnings = []
254
+ for name, outcome in conversation.items():
255
+ if not isinstance(outcome, dict) or "scanned_rows" not in outcome:
256
+ continue
257
+ entry = health.setdefault(name, {"rows_without_turns": 0, "last_turn_at": None})
258
+ if outcome.get("recorded_turns"):
259
+ entry.update(rows_without_turns=0, last_turn_at=self.now())
260
+ else:
261
+ entry["rows_without_turns"] += outcome["scanned_rows"]
262
+ if entry["rows_without_turns"] >= self.STALL_ROWS:
263
+ warnings.append(
264
+ f"{name}: {entry['rows_without_turns']} new transcript lines and no "
265
+ f"conversation found in them since {entry['last_turn_at'] or 'capture began'}"
266
+ " - the app may have changed its format; update Graph-MIND or report it")
267
+ _atomic_json(path, health)
268
+ return warnings
269
+
241
270
  def _write_status(self, result):
242
271
  _atomic_json(self.status_path, {**result, "pid": os.getpid(),
243
272
  "config_db": str(self.db_path)})
@@ -79,8 +79,17 @@ AGENT_INSTRUCTIONS = re.compile(
79
79
  r"(?:#\s*AGENTS\.md instructions[^\n]*\s*)?<INSTRUCTIONS>.*?</INSTRUCTIONS>", flags=re.DOTALL)
80
80
 
81
81
 
82
+ def masking_on():
83
+ """On unless ~/.graph-mind/config.json says "mask_secrets": false: someone running a model on
84
+ their own machines may want keys kept in memory verbatim."""
85
+ from brain_log import _config
86
+ return _config().get("mask_secrets", True) is not False
87
+
88
+
82
89
  def _redact(value):
83
90
  cleaned = AGENT_INSTRUCTIONS.sub("", AUTOMATIC_BLOCKS.sub("", value))
91
+ if not masking_on():
92
+ return cleaned.strip(), 0
84
93
  count = 0
85
94
  for pattern, replacement in SECRET_PATTERNS:
86
95
  cleaned, replacements = pattern.subn(replacement, cleaned)
@@ -4,6 +4,7 @@ from __future__ import annotations
4
4
  from datetime import datetime, timedelta
5
5
  from pathlib import Path
6
6
  from typing import Any, Literal
7
+ import json
7
8
  import os
8
9
  import sys
9
10
  import threading
@@ -346,6 +347,17 @@ def gather(database, query, *, scopes=None, as_of, knowledge_cutoff=None, limit=
346
347
  return result
347
348
 
348
349
 
350
+ def capture_warnings() -> list[str]:
351
+ """What the capture service last reported as wrong (a source that stopped yielding turns)."""
352
+ try:
353
+ from automatic_capture import default_service_state_dir
354
+ status = json.loads((default_service_state_dir() / "status.json")
355
+ .read_text(encoding="utf-8"))
356
+ return list(status.get("warnings") or [])
357
+ except Exception:
358
+ return []
359
+
360
+
349
361
  def build_server(db_path=None):
350
362
  database = Path(db_path).expanduser() if db_path is not None else configured_db_path()
351
363
  server = MCPServer(
@@ -368,7 +380,8 @@ def build_server(db_path=None):
368
380
  "project, file or symbol, use code_activity. brain_folder shows or changes where the "
369
381
  "memory lives and shares it with the user's other PCs. When the user asks to "
370
382
  "delete something from memory, use brain_forget: list first, delete only what the "
371
- "user picks. Preserve provenance."
383
+ "user picks. If a result carries capture_warnings, tell the user once, plainly: "
384
+ "conversations from that app are no longer being saved. Preserve provenance."
372
385
  ),
373
386
  version=SERVER_VERSION,
374
387
  )
@@ -557,6 +570,9 @@ def build_server(db_path=None):
557
570
  packet = build_context_pack(recalled, max_chars=max_chars,
558
571
  order="time" if recent else "relevance")
559
572
  packet["route"] = route
573
+ warnings = capture_warnings()
574
+ if warnings:
575
+ packet["capture_warnings"] = warnings
560
576
  if route["mode"] == "EXECUTE":
561
577
  packet.setdefault("warnings", []).append(
562
578
  "STRUCTURED_EXECUTION_REQUIRED_FOR_COMPLETE_SCOPE_CLAIMS")
@@ -626,6 +642,9 @@ def build_server(db_path=None):
626
642
  result = {} if shared_out is None else {
627
643
  "connection_code": shared_out["connection_code"],
628
644
  "reachable_at": shared_out["addresses"], "firewall": shared_out["firewall"]}
645
+ warnings = capture_warnings()
646
+ if warnings:
647
+ result["capture_warnings"] = warnings
629
648
  return {**result, "folder": where, "this_device": device_name(),
630
649
  "devices": devices(shared),
631
650
  "imported_from_other_devices": imported["imported"],
@@ -1,11 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: graph-mind-memory
3
- Version: 0.5.0
3
+ Version: 0.5.2
4
4
  Summary: Local-first memory for AI coding assistants: verbatim, on your own PC, no LLM calls at write time.
5
5
  Author-email: Yohan Ko <goyohan0611@gmail.com>
6
6
  License-Expression: AGPL-3.0-only
7
7
  Project-URL: Homepage, https://github.com/goyohan0611-png/graph-mind
8
8
  Project-URL: Issues, https://github.com/goyohan0611-png/graph-mind/issues
9
+ Project-URL: Changelog, https://github.com/goyohan0611-png/graph-mind/blob/main/CHANGELOG.md
9
10
  Keywords: mcp,memory,claude,codex,llm,longmemeval,local-first
10
11
  Classifier: Development Status :: 3 - Alpha
11
12
  Classifier: Programming Language :: Python :: 3
@@ -120,6 +121,8 @@ Requires Python 3.10+ (64-bit). Windows, macOS or Linux. Hosting a brain that ot
120
121
  needs Python 3.12 or older on that one PC (its Postgres helper, pgserver, has no newer build yet);
121
122
  everything else, joining included, works on 3.13 and 3.14 too.
122
123
 
124
+ What changed in each release: [CHANGELOG.md](CHANGELOG.md).
125
+
123
126
  ```bash
124
127
  pip install graph-mind-memory
125
128
  graph-mind-install
@@ -180,9 +183,12 @@ random 20-64 character tokens caught; in 246,750 ordinary chat turns it fired 92
180
183
  all on real ids and tokens). Commit ids, hashes and UUIDs are kept, since you recall those on
181
184
  purpose.
182
185
 
183
- There is no switch to keep keys: a recalled memory goes to your model's provider with the question,
184
- so a stored key would leave your PC the first time it is useful. To have Graph-MIND remember a key,
185
- tell it **where the key is**, not the key: *"my OpenAI key is in 1Password, under Dev"*.
186
+ Keep masking on if you use a cloud model: a recalled memory goes to your model's provider with the
187
+ question, so a stored key would leave your PC the first time it is useful. To have Graph-MIND
188
+ remember a key, tell it **where the key is**, not the key: *"my OpenAI key is in 1Password, under
189
+ Dev"*. If your model runs on your own machines and you want keys remembered as typed, add
190
+ `"mask_secrets": false` to `~/.graph-mind/config.json` (applies from the next message; already
191
+ masked text stays masked).
186
192
 
187
193
  Only what you actually send is captured: the service reads each app's transcript, which is written
188
194
  after you press Enter, so a paste you delete before sending never reaches it. A plain password
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "graph-mind-memory"
7
- version = "0.5.0"
7
+ version = "0.5.2"
8
8
  description = "Local-first memory for AI coding assistants: verbatim, on your own PC, no LLM calls at write time."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -35,6 +35,7 @@ dependencies = [
35
35
  [project.urls]
36
36
  Homepage = "https://github.com/goyohan0611-png/graph-mind"
37
37
  Issues = "https://github.com/goyohan0611-png/graph-mind/issues"
38
+ Changelog = "https://github.com/goyohan0611-png/graph-mind/blob/main/CHANGELOG.md"
38
39
 
39
40
  [project.scripts]
40
41
  graph-mind = "graph_mind_mcp_server:main"