yourmemory 1.4.2__tar.gz → 1.4.4__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.
- {yourmemory-1.4.2 → yourmemory-1.4.4}/PKG-INFO +3 -3
- {yourmemory-1.4.2 → yourmemory-1.4.4}/memory_mcp.py +131 -11
- {yourmemory-1.4.2 → yourmemory-1.4.4}/pyproject.toml +4 -2
- {yourmemory-1.4.2 → yourmemory-1.4.4}/yourmemory.egg-info/PKG-INFO +3 -3
- {yourmemory-1.4.2 → yourmemory-1.4.4}/LICENSE +0 -0
- {yourmemory-1.4.2 → yourmemory-1.4.4}/README.md +0 -0
- {yourmemory-1.4.2 → yourmemory-1.4.4}/setup.cfg +0 -0
- {yourmemory-1.4.2 → yourmemory-1.4.4}/src/__init__.py +0 -0
- {yourmemory-1.4.2 → yourmemory-1.4.4}/src/app.py +0 -0
- {yourmemory-1.4.2 → yourmemory-1.4.4}/src/db/connection.py +0 -0
- {yourmemory-1.4.2 → yourmemory-1.4.4}/src/db/duckdb_schema.sql +0 -0
- {yourmemory-1.4.2 → yourmemory-1.4.4}/src/db/migrate.py +0 -0
- {yourmemory-1.4.2 → yourmemory-1.4.4}/src/db/schema.sql +0 -0
- {yourmemory-1.4.2 → yourmemory-1.4.4}/src/db/sqlite_schema.sql +0 -0
- {yourmemory-1.4.2 → yourmemory-1.4.4}/src/graph/__init__.py +0 -0
- {yourmemory-1.4.2 → yourmemory-1.4.4}/src/graph/backend.py +0 -0
- {yourmemory-1.4.2 → yourmemory-1.4.4}/src/graph/graph_store.py +0 -0
- {yourmemory-1.4.2 → yourmemory-1.4.4}/src/graph/neo4j_backend.py +0 -0
- {yourmemory-1.4.2 → yourmemory-1.4.4}/src/graph/networkx_backend.py +0 -0
- {yourmemory-1.4.2 → yourmemory-1.4.4}/src/graph/svo_extract.py +0 -0
- {yourmemory-1.4.2 → yourmemory-1.4.4}/src/jobs/decay_job.py +0 -0
- {yourmemory-1.4.2 → yourmemory-1.4.4}/src/routes/__init__.py +0 -0
- {yourmemory-1.4.2 → yourmemory-1.4.4}/src/routes/agents.py +0 -0
- {yourmemory-1.4.2 → yourmemory-1.4.4}/src/routes/memories.py +0 -0
- {yourmemory-1.4.2 → yourmemory-1.4.4}/src/routes/retrieve.py +0 -0
- {yourmemory-1.4.2 → yourmemory-1.4.4}/src/routes/ui.py +0 -0
- {yourmemory-1.4.2 → yourmemory-1.4.4}/src/services/__init__.py +0 -0
- {yourmemory-1.4.2 → yourmemory-1.4.4}/src/services/agent_registry.py +0 -0
- {yourmemory-1.4.2 → yourmemory-1.4.4}/src/services/api_keys.py +0 -0
- {yourmemory-1.4.2 → yourmemory-1.4.4}/src/services/decay.py +0 -0
- {yourmemory-1.4.2 → yourmemory-1.4.4}/src/services/embed.py +0 -0
- {yourmemory-1.4.2 → yourmemory-1.4.4}/src/services/extract.py +0 -0
- {yourmemory-1.4.2 → yourmemory-1.4.4}/src/services/extract_fallback.py +0 -0
- {yourmemory-1.4.2 → yourmemory-1.4.4}/src/services/resolve.py +0 -0
- {yourmemory-1.4.2 → yourmemory-1.4.4}/src/services/resolve_fallback.py +0 -0
- {yourmemory-1.4.2 → yourmemory-1.4.4}/src/services/retrieve.py +0 -0
- {yourmemory-1.4.2 → yourmemory-1.4.4}/src/services/utils.py +0 -0
- {yourmemory-1.4.2 → yourmemory-1.4.4}/yourmemory.egg-info/SOURCES.txt +0 -0
- {yourmemory-1.4.2 → yourmemory-1.4.4}/yourmemory.egg-info/dependency_links.txt +0 -0
- {yourmemory-1.4.2 → yourmemory-1.4.4}/yourmemory.egg-info/entry_points.txt +0 -0
- {yourmemory-1.4.2 → yourmemory-1.4.4}/yourmemory.egg-info/requires.txt +2 -2
- {yourmemory-1.4.2 → yourmemory-1.4.4}/yourmemory.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: yourmemory
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.4
|
|
4
4
|
Summary: Persistent memory for Claude — Ebbinghaus forgetting curve, semantic deduplication, MCP-native
|
|
5
5
|
Author-email: Sachit Misra <mishrasachit1@gmail.com>
|
|
6
6
|
License-Expression: CC-BY-NC-4.0
|
|
@@ -24,12 +24,12 @@ Requires-Dist: duckdb>=0.10.0
|
|
|
24
24
|
Requires-Dist: apscheduler
|
|
25
25
|
Requires-Dist: spacy<4.0,>=3.8.13
|
|
26
26
|
Requires-Dist: networkx>=3.0
|
|
27
|
+
Requires-Dist: fastapi
|
|
28
|
+
Requires-Dist: uvicorn[standard]
|
|
27
29
|
Provides-Extra: postgres
|
|
28
30
|
Requires-Dist: psycopg2-binary; extra == "postgres"
|
|
29
31
|
Requires-Dist: pgvector; extra == "postgres"
|
|
30
32
|
Provides-Extra: sse
|
|
31
|
-
Requires-Dist: fastapi; extra == "sse"
|
|
32
|
-
Requires-Dist: uvicorn[standard]; extra == "sse"
|
|
33
33
|
Requires-Dist: httpx; extra == "sse"
|
|
34
34
|
Provides-Extra: neo4j
|
|
35
35
|
Requires-Dist: neo4j>=5.0; extra == "neo4j"
|
|
@@ -555,6 +555,32 @@ async def call_tool(name: str, arguments: dict) -> list[types.TextContent]:
|
|
|
555
555
|
return [types.TextContent(type="text", text=json.dumps({"error": f"Unknown tool: {name}"}))]
|
|
556
556
|
|
|
557
557
|
|
|
558
|
+
def _start_dashboard(port: int) -> None:
|
|
559
|
+
"""Start the memory dashboard HTTP server in a background daemon thread.
|
|
560
|
+
|
|
561
|
+
Binds to 127.0.0.1 only — local access, not exposed to the network.
|
|
562
|
+
Prints the URL to stderr so it doesn't pollute the MCP stdio stream.
|
|
563
|
+
"""
|
|
564
|
+
try:
|
|
565
|
+
import uvicorn
|
|
566
|
+
from src.app import app as dashboard_app
|
|
567
|
+
|
|
568
|
+
config = uvicorn.Config(
|
|
569
|
+
dashboard_app,
|
|
570
|
+
host="127.0.0.1",
|
|
571
|
+
port=port,
|
|
572
|
+
log_level="error",
|
|
573
|
+
access_log=False,
|
|
574
|
+
)
|
|
575
|
+
server = uvicorn.Server(config)
|
|
576
|
+
|
|
577
|
+
t = threading.Thread(target=server.run, daemon=True, name="dashboard")
|
|
578
|
+
t.start()
|
|
579
|
+
print(f" Dashboard → http://127.0.0.1:{port}/ui", file=sys.stderr)
|
|
580
|
+
except Exception as exc:
|
|
581
|
+
print(f" Dashboard unavailable: {exc}", file=sys.stderr)
|
|
582
|
+
|
|
583
|
+
|
|
558
584
|
def _start_decay_scheduler():
|
|
559
585
|
"""Run the decay job once immediately, then every 24 hours in a background thread."""
|
|
560
586
|
from src.jobs.decay_job import run as run_decay
|
|
@@ -828,29 +854,68 @@ def setup():
|
|
|
828
854
|
|
|
829
855
|
# ── 4. Inject memory rules into global agent instructions ───────────────
|
|
830
856
|
print("\n[4/4] Injecting memory rules into global agent instructions…")
|
|
831
|
-
|
|
857
|
+
|
|
858
|
+
# Resolve user_id: env var → saved file → prompt
|
|
859
|
+
uid_path = os.path.join(home, ".yourmemory", "user_id")
|
|
860
|
+
user_id = os.getenv("YOURMEMORY_USER", "").strip()
|
|
861
|
+
if not user_id and os.path.exists(uid_path):
|
|
862
|
+
with open(uid_path) as f:
|
|
863
|
+
user_id = f.read().strip()
|
|
864
|
+
if not user_id:
|
|
865
|
+
try:
|
|
866
|
+
user_id = input(" Your name (used as memory user_id, e.g. 'alice'): ").strip()
|
|
867
|
+
except (EOFError, OSError):
|
|
868
|
+
user_id = ""
|
|
869
|
+
if not user_id:
|
|
870
|
+
user_id = "user"
|
|
871
|
+
os.makedirs(os.path.dirname(uid_path), exist_ok=True)
|
|
872
|
+
with open(uid_path, "w") as f:
|
|
873
|
+
f.write(user_id)
|
|
874
|
+
print(f" user_id → {user_id}")
|
|
875
|
+
|
|
876
|
+
_inject_memory_rules(home, user_id)
|
|
832
877
|
|
|
833
878
|
print("\n✓ Setup complete. Restart your AI client to load YourMemory.\n")
|
|
834
879
|
|
|
835
880
|
|
|
836
|
-
def _inject_memory_rules(home: str) -> None:
|
|
837
|
-
"""Append
|
|
838
|
-
|
|
881
|
+
def _inject_memory_rules(home: str, user_id: str = "user") -> None:
|
|
882
|
+
"""Append memory rules to every detected global agent instruction file.
|
|
883
|
+
Replaces <your_name> with the actual user_id. Skips if already present.
|
|
839
884
|
"""
|
|
885
|
+
rules = _MEMORY_RULES.replace("<your_name>", user_id)
|
|
886
|
+
|
|
840
887
|
candidates = [
|
|
841
|
-
# Claude Code
|
|
888
|
+
# Claude Code — all platforms
|
|
842
889
|
os.path.join(home, ".claude", "CLAUDE.md"),
|
|
843
|
-
# Cursor
|
|
890
|
+
# Cursor — all platforms
|
|
844
891
|
os.path.join(home, ".cursor", "rules", "memory.mdc"),
|
|
845
|
-
# Windsurf
|
|
892
|
+
# Windsurf — all platforms
|
|
846
893
|
os.path.join(home, ".codeium", "windsurf", "memories", "memory_rules.md"),
|
|
894
|
+
# OpenCode — all platforms
|
|
895
|
+
os.path.join(home, ".config", "opencode", "instructions.md"),
|
|
847
896
|
]
|
|
848
897
|
|
|
898
|
+
# Cline (VS Code) — platform-specific globalStorage path
|
|
899
|
+
if sys.platform == "darwin":
|
|
900
|
+
vscode_global = os.path.join(home, "Library", "Application Support",
|
|
901
|
+
"Code", "User", "globalStorage")
|
|
902
|
+
elif sys.platform == "win32":
|
|
903
|
+
vscode_global = os.path.join(os.getenv("APPDATA", ""), "Code",
|
|
904
|
+
"User", "globalStorage")
|
|
905
|
+
else:
|
|
906
|
+
vscode_global = os.path.join(home, ".config", "Code", "User", "globalStorage")
|
|
907
|
+
|
|
908
|
+
if os.path.isdir(vscode_global):
|
|
909
|
+
for entry in os.listdir(vscode_global):
|
|
910
|
+
if "claude-dev" in entry or "cline" in entry.lower():
|
|
911
|
+
candidates.append(os.path.join(vscode_global, entry, "settings", "instructions.md"))
|
|
912
|
+
break
|
|
913
|
+
|
|
849
914
|
wrote_any = False
|
|
850
915
|
for path in candidates:
|
|
851
916
|
dir_ = os.path.dirname(path)
|
|
852
917
|
if not os.path.isdir(dir_):
|
|
853
|
-
continue
|
|
918
|
+
continue
|
|
854
919
|
try:
|
|
855
920
|
existing = ""
|
|
856
921
|
if os.path.exists(path):
|
|
@@ -860,22 +925,75 @@ def _inject_memory_rules(home: str) -> None:
|
|
|
860
925
|
print(f" ✓ Already present → {path}")
|
|
861
926
|
wrote_any = True
|
|
862
927
|
continue
|
|
928
|
+
os.makedirs(dir_, exist_ok=True)
|
|
863
929
|
with open(path, "a") as f:
|
|
864
930
|
if existing and not existing.endswith("\n"):
|
|
865
931
|
f.write("\n")
|
|
866
|
-
f.write("\n" +
|
|
867
|
-
print(f" ✓ Memory rules
|
|
932
|
+
f.write("\n" + rules)
|
|
933
|
+
print(f" ✓ Memory rules injected → {path}")
|
|
868
934
|
wrote_any = True
|
|
869
935
|
except Exception as exc:
|
|
870
936
|
print(f" ✗ Could not write to {path}: {exc}")
|
|
871
937
|
|
|
872
938
|
if not wrote_any:
|
|
873
|
-
print(" (No global instruction files detected —
|
|
939
|
+
print(" (No global instruction files detected — copy sample_CLAUDE.md to your project's CLAUDE.md manually.)")
|
|
940
|
+
|
|
941
|
+
|
|
942
|
+
def _first_run_setup() -> None:
|
|
943
|
+
"""Silently run first-time setup when the MCP server starts for the first time.
|
|
944
|
+
|
|
945
|
+
Triggered when ~/.yourmemory/user_id does not exist.
|
|
946
|
+
All output goes to stderr — stdout is reserved for the MCP stdio stream.
|
|
947
|
+
spaCy download runs in a background thread so it doesn't delay server startup.
|
|
948
|
+
"""
|
|
949
|
+
home = os.path.expanduser("~")
|
|
950
|
+
uid_path = os.path.join(home, ".yourmemory", "user_id")
|
|
951
|
+
|
|
952
|
+
if os.path.exists(uid_path):
|
|
953
|
+
return # already set up
|
|
954
|
+
|
|
955
|
+
print(" [YourMemory] First run detected — running setup…", file=sys.stderr)
|
|
956
|
+
|
|
957
|
+
# Resolve user_id: env var → system login → fallback
|
|
958
|
+
user_id = os.getenv("YOURMEMORY_USER", "").strip()
|
|
959
|
+
if not user_id:
|
|
960
|
+
try:
|
|
961
|
+
import getpass
|
|
962
|
+
user_id = getpass.getuser()
|
|
963
|
+
except Exception:
|
|
964
|
+
user_id = "user"
|
|
965
|
+
|
|
966
|
+
os.makedirs(os.path.join(home, ".yourmemory"), exist_ok=True)
|
|
967
|
+
with open(uid_path, "w") as f:
|
|
968
|
+
f.write(user_id)
|
|
969
|
+
print(f" [YourMemory] user_id → {user_id}", file=sys.stderr)
|
|
970
|
+
|
|
971
|
+
# Inject memory rules into detected client instruction files
|
|
972
|
+
_inject_memory_rules(home, user_id)
|
|
973
|
+
|
|
974
|
+
# Fire install ping
|
|
975
|
+
_ping_install()
|
|
976
|
+
|
|
977
|
+
# Download spaCy model in background — don't block server startup
|
|
978
|
+
def _download_spacy():
|
|
979
|
+
try:
|
|
980
|
+
import subprocess
|
|
981
|
+
subprocess.run(
|
|
982
|
+
[sys.executable, "-m", "spacy", "download", "en_core_web_sm"],
|
|
983
|
+
check=False, capture_output=True,
|
|
984
|
+
)
|
|
985
|
+
except Exception:
|
|
986
|
+
pass
|
|
987
|
+
|
|
988
|
+
threading.Thread(target=_download_spacy, daemon=True, name="spacy-dl").start()
|
|
989
|
+
|
|
990
|
+
print(" [YourMemory] Setup complete. Memory rules injected into your AI client.", file=sys.stderr)
|
|
874
991
|
|
|
875
992
|
|
|
876
993
|
def run():
|
|
877
994
|
from src.db.migrate import migrate
|
|
878
995
|
migrate()
|
|
996
|
+
_first_run_setup()
|
|
879
997
|
_start_decay_scheduler()
|
|
880
998
|
|
|
881
999
|
# SSE mode: --sse flag, PORT env var, or Windows default (stdio pipes unreliable on Windows)
|
|
@@ -892,6 +1010,8 @@ def run():
|
|
|
892
1010
|
# Default to SSE on Windows — stdio pipes break intermittently on Windows
|
|
893
1011
|
_run_sse(int(os.getenv("PORT", 3033)))
|
|
894
1012
|
else:
|
|
1013
|
+
dashboard_port = int(os.getenv("YOURMEMORY_DASHBOARD_PORT", 3033))
|
|
1014
|
+
_start_dashboard(dashboard_port)
|
|
895
1015
|
asyncio.run(main())
|
|
896
1016
|
|
|
897
1017
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "yourmemory"
|
|
7
|
-
version = "1.4.
|
|
7
|
+
version = "1.4.4"
|
|
8
8
|
description = "Persistent memory for Claude — Ebbinghaus forgetting curve, semantic deduplication, MCP-native"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -30,11 +30,13 @@ dependencies = [
|
|
|
30
30
|
"apscheduler",
|
|
31
31
|
"spacy>=3.8.13,<4.0",
|
|
32
32
|
"networkx>=3.0",
|
|
33
|
+
"fastapi",
|
|
34
|
+
"uvicorn[standard]",
|
|
33
35
|
]
|
|
34
36
|
|
|
35
37
|
[project.optional-dependencies]
|
|
36
38
|
postgres = ["psycopg2-binary", "pgvector"]
|
|
37
|
-
sse = ["
|
|
39
|
+
sse = ["httpx"]
|
|
38
40
|
neo4j = ["neo4j>=5.0"]
|
|
39
41
|
all = ["yourmemory[postgres,sse,neo4j]"]
|
|
40
42
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: yourmemory
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.4
|
|
4
4
|
Summary: Persistent memory for Claude — Ebbinghaus forgetting curve, semantic deduplication, MCP-native
|
|
5
5
|
Author-email: Sachit Misra <mishrasachit1@gmail.com>
|
|
6
6
|
License-Expression: CC-BY-NC-4.0
|
|
@@ -24,12 +24,12 @@ Requires-Dist: duckdb>=0.10.0
|
|
|
24
24
|
Requires-Dist: apscheduler
|
|
25
25
|
Requires-Dist: spacy<4.0,>=3.8.13
|
|
26
26
|
Requires-Dist: networkx>=3.0
|
|
27
|
+
Requires-Dist: fastapi
|
|
28
|
+
Requires-Dist: uvicorn[standard]
|
|
27
29
|
Provides-Extra: postgres
|
|
28
30
|
Requires-Dist: psycopg2-binary; extra == "postgres"
|
|
29
31
|
Requires-Dist: pgvector; extra == "postgres"
|
|
30
32
|
Provides-Extra: sse
|
|
31
|
-
Requires-Dist: fastapi; extra == "sse"
|
|
32
|
-
Requires-Dist: uvicorn[standard]; extra == "sse"
|
|
33
33
|
Requires-Dist: httpx; extra == "sse"
|
|
34
34
|
Provides-Extra: neo4j
|
|
35
35
|
Requires-Dist: neo4j>=5.0; extra == "neo4j"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|