loop-memory 0.4.1__tar.gz → 0.4.3__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 (127) hide show
  1. {loop_memory-0.4.1 → loop_memory-0.4.3}/PKG-INFO +193 -33
  2. {loop_memory-0.4.1 → loop_memory-0.4.3}/README.md +192 -32
  3. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/jobs/cognitive.py +153 -19
  4. loop_memory-0.4.3/loop_memory/llm/openai_adapter.py +64 -0
  5. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/llm/providers.py +74 -6
  6. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/sdk_extensions.py +7 -0
  7. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/serve/routes/cognitive.py +7 -0
  8. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/storage/sqlite_store.py +35 -1
  9. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory.egg-info/PKG-INFO +193 -33
  10. {loop_memory-0.4.1 → loop_memory-0.4.3}/pyproject.toml +1 -1
  11. {loop_memory-0.4.1 → loop_memory-0.4.3}/tests/test_graph.py +52 -0
  12. {loop_memory-0.4.1 → loop_memory-0.4.3}/tests/test_llm_providers.py +111 -0
  13. {loop_memory-0.4.1 → loop_memory-0.4.3}/tests/test_repo_framing.py +89 -0
  14. {loop_memory-0.4.1 → loop_memory-0.4.3}/tests/test_universal_memory.py +210 -0
  15. loop_memory-0.4.1/loop_memory/llm/openai_adapter.py +0 -31
  16. {loop_memory-0.4.1 → loop_memory-0.4.3}/LICENSE +0 -0
  17. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/__init__.py +0 -0
  18. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/backends/__init__.py +0 -0
  19. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/backends/embedding.py +0 -0
  20. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/backends/sentence_embedder.py +0 -0
  21. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/backends/vector_store.py +0 -0
  22. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/cli/__init__.py +0 -0
  23. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/cli/_common.py +0 -0
  24. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/cli/commands/__init__.py +0 -0
  25. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/cli/commands/cognitive.py +0 -0
  26. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/cli/commands/diag.py +0 -0
  27. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/cli/commands/graph.py +0 -0
  28. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/cli/commands/hooks.py +0 -0
  29. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/cli/commands/read.py +0 -0
  30. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/cli/commands/serve.py +0 -0
  31. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/cli/commands/write.py +0 -0
  32. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/cli/main.py +0 -0
  33. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/engine/__init__.py +0 -0
  34. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/engine/loop.py +0 -0
  35. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/engine/reflect.py +0 -0
  36. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/examples/__init__.py +0 -0
  37. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/examples/demo.py +0 -0
  38. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/export/__init__.py +0 -0
  39. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/export/memory_md.py +0 -0
  40. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/graph/__init__.py +0 -0
  41. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/graph/build.py +0 -0
  42. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/graph/extract.py +0 -0
  43. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/ingest/__init__.py +0 -0
  44. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/ingest/loader.py +0 -0
  45. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/ingest/pipeline.py +0 -0
  46. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/jobs/__init__.py +0 -0
  47. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/jobs/compact.py +0 -0
  48. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/jobs/consolidate.py +0 -0
  49. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/jobs/contradiction.py +0 -0
  50. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/jobs/evolution.py +0 -0
  51. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/jobs/graph.py +0 -0
  52. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/jobs/llm_compact_pass.py +0 -0
  53. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/jobs/llm_consolidate.py +0 -0
  54. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/jobs/scheduler.py +0 -0
  55. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/llm/__init__.py +0 -0
  56. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/llm/base.py +0 -0
  57. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/mcp/__init__.py +0 -0
  58. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/memory/__init__.py +0 -0
  59. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/memory/types.py +0 -0
  60. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/privacy/__init__.py +0 -0
  61. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/privacy/private.py +0 -0
  62. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/privacy/redact.py +0 -0
  63. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/py.typed +0 -0
  64. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/sdk.py +0 -0
  65. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/security/__init__.py +0 -0
  66. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/security/secrets.py +0 -0
  67. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/serve/__init__.py +0 -0
  68. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/serve/app.py +0 -0
  69. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/serve/handlers.py +0 -0
  70. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/serve/routes/_shared.py +0 -0
  71. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/serve/routes/admin.py +0 -0
  72. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/serve/routes/export.py +0 -0
  73. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/serve/routes/graph.py +0 -0
  74. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/serve/routes/insights.py +0 -0
  75. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/serve/routes/memories.py +0 -0
  76. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/serve/routes/sessions.py +0 -0
  77. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/serve/routes/system.py +0 -0
  78. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/serve/routes/wiki.py +0 -0
  79. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/serve/static/__init__.py +0 -0
  80. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/serve/static/index.html +0 -0
  81. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/serve/watcher.py +0 -0
  82. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/storage/__init__.py +0 -0
  83. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/storage/retrieval.py +0 -0
  84. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/wiki/__init__.py +0 -0
  85. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/wiki/backfill.py +0 -0
  86. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/wiki/classifier.py +0 -0
  87. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/wiki/prompts.py +0 -0
  88. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory/wiki/scope.py +0 -0
  89. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory.egg-info/SOURCES.txt +0 -0
  90. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory.egg-info/dependency_links.txt +0 -0
  91. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory.egg-info/entry_points.txt +0 -0
  92. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory.egg-info/requires.txt +0 -0
  93. {loop_memory-0.4.1 → loop_memory-0.4.3}/loop_memory.egg-info/top_level.txt +0 -0
  94. {loop_memory-0.4.1 → loop_memory-0.4.3}/setup.cfg +0 -0
  95. {loop_memory-0.4.1 → loop_memory-0.4.3}/tests/test_admin_ingest_route.py +0 -0
  96. {loop_memory-0.4.1 → loop_memory-0.4.3}/tests/test_agent_memory_api.py +0 -0
  97. {loop_memory-0.4.1 → loop_memory-0.4.3}/tests/test_agent_memory_sdk.py +0 -0
  98. {loop_memory-0.4.1 → loop_memory-0.4.3}/tests/test_auth_token_rotate.py +0 -0
  99. {loop_memory-0.4.1 → loop_memory-0.4.3}/tests/test_cli_v7.py +0 -0
  100. {loop_memory-0.4.1 → loop_memory-0.4.3}/tests/test_cli_version.py +0 -0
  101. {loop_memory-0.4.1 → loop_memory-0.4.3}/tests/test_contradictions.py +0 -0
  102. {loop_memory-0.4.1 → loop_memory-0.4.3}/tests/test_evolution.py +0 -0
  103. {loop_memory-0.4.1 → loop_memory-0.4.3}/tests/test_evolution_quality.py +0 -0
  104. {loop_memory-0.4.1 → loop_memory-0.4.3}/tests/test_expanduser.py +0 -0
  105. {loop_memory-0.4.1 → loop_memory-0.4.3}/tests/test_export_ask.py +0 -0
  106. {loop_memory-0.4.1 → loop_memory-0.4.3}/tests/test_ingest.py +0 -0
  107. {loop_memory-0.4.1 → loop_memory-0.4.3}/tests/test_llm_consolidator.py +0 -0
  108. {loop_memory-0.4.1 → loop_memory-0.4.3}/tests/test_llm_fingerprint_not_persisted.py +0 -0
  109. {loop_memory-0.4.1 → loop_memory-0.4.3}/tests/test_llm_test_endpoint.py +0 -0
  110. {loop_memory-0.4.1 → loop_memory-0.4.3}/tests/test_loop.py +0 -0
  111. {loop_memory-0.4.1 → loop_memory-0.4.3}/tests/test_mcp.py +0 -0
  112. {loop_memory-0.4.1 → loop_memory-0.4.3}/tests/test_memories_pagination.py +0 -0
  113. {loop_memory-0.4.1 → loop_memory-0.4.3}/tests/test_openclaw_loader.py +0 -0
  114. {loop_memory-0.4.1 → loop_memory-0.4.3}/tests/test_reflection.py +0 -0
  115. {loop_memory-0.4.1 → loop_memory-0.4.3}/tests/test_score_api.py +0 -0
  116. {loop_memory-0.4.1 → loop_memory-0.4.3}/tests/test_scoring_v2.py +0 -0
  117. {loop_memory-0.4.1 → loop_memory-0.4.3}/tests/test_secrets.py +0 -0
  118. {loop_memory-0.4.1 → loop_memory-0.4.3}/tests/test_serve_app.py +0 -0
  119. {loop_memory-0.4.1 → loop_memory-0.4.3}/tests/test_serve_handlers.py +0 -0
  120. {loop_memory-0.4.1 → loop_memory-0.4.3}/tests/test_session_order.py +0 -0
  121. {loop_memory-0.4.1 → loop_memory-0.4.3}/tests/test_store.py +0 -0
  122. {loop_memory-0.4.1 → loop_memory-0.4.3}/tests/test_summarization.py +0 -0
  123. {loop_memory-0.4.1 → loop_memory-0.4.3}/tests/test_vector_store.py +0 -0
  124. {loop_memory-0.4.1 → loop_memory-0.4.3}/tests/test_watcher.py +0 -0
  125. {loop_memory-0.4.1 → loop_memory-0.4.3}/tests/test_wiki_classifier.py +0 -0
  126. {loop_memory-0.4.1 → loop_memory-0.4.3}/tests/test_wiki_export_escape.py +0 -0
  127. {loop_memory-0.4.1 → loop_memory-0.4.3}/tests/test_wiki_prompts.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: loop-memory
3
- Version: 0.4.1
3
+ Version: 0.4.3
4
4
  Summary: A general-purpose, local memory system for every AI agent you run. Loop Memory auto-captures conversations from Codex / Claude / Hermes / OpenClaw, scores them by importance × recency × usage × feedback, distils them into a curated wiki, and serves everything from a single web UI.
5
5
  Author: Loop Memory contributors <loop-memory@users.noreply.github.com>
6
6
  License-Expression: MIT
@@ -66,6 +66,40 @@ Dynamic: license-file
66
66
 
67
67
  ---
68
68
 
69
+ > **What's new in 0.4.1** — CLI dispatch hardened so every subcommand's
70
+ > `--help` / `--version` exits 0 cleanly (no more `ValueError: unknown
71
+ > source: '--help'` on a zero-deps install). Added a static
72
+ > `COMMAND_HELP` table guarded by 10 new regression cases in
73
+ > `tests/test_cli_version.py`, plus GitHub `About` / README lead now
74
+ > surface for "agent loop" searches.
75
+ > [Full changelog →](CHANGELOG.md)
76
+
77
+ ---
78
+
79
+ ## Table of contents
80
+
81
+ - [What it does](#what-it-does)
82
+ - [Install](#install)
83
+ - [Quickstart](#quickstart)
84
+ - [Why Loop Memory vs. every other agent-memory project](#why-loop-memory-vs-every-other-agent-memory-project)
85
+ - [Architecture & docs](#architecture--docs)
86
+ - [After install: 30-second setup](#after-install-30-second-setup)
87
+ - [Auto-capture (after every conversation)](#auto-capture-after-every-conversation)
88
+ - [Dashboard + Evolution consolidator](#dashboard--evolution-consolidator-看板--进化式蒸馏)
89
+ - [Auto-feedback into every LLM client](#auto-feedback-into-every-llm-client-反哺)
90
+ - [Web UI](#web-ui)
91
+ - [Programmatic use](#programmatic-use)
92
+ - [The four-stage loop](#the-four-stage-loop)
93
+ - [Project layout](#project-layout)
94
+ - [Security & auth token](#security--auth-token)
95
+ - [Wiki scope auto-classification](#wiki-scope-auto-classification)
96
+ - [FAQ & troubleshooting](#faq--troubleshooting)
97
+ - [Run the tests](#run-the-tests)
98
+ - [Using distilled knowledge in your clients](#using-distilled-knowledge-in-your-clients)
99
+ - [License](#license)
100
+
101
+ ---
102
+
69
103
  ## What it does
70
104
 
71
105
  **Loop Memory** gives every agent you use a single, persistent brain
@@ -108,6 +142,21 @@ via MCP / hooks]
108
142
 
109
143
  *One loop, many agents, one evolving wiki.*
110
144
 
145
+ **Supported agents:**
146
+
147
+ | Agent | Capture path | Hook shipped? | Notes |
148
+ | -------------- | ----------------------------------- | :-----------: | ----- |
149
+ | Codex CLI | `~/.codex/sessions/*.json` | ✅ | MCP + SessionStart auto-wired by `install-hooks` |
150
+ | Claude Code | `~/.claude/**/*.jsonl` | ✅ | MCP + SessionStart auto-wired by `install-hooks` |
151
+ | Hermes | `~/.hermes/**/*.jsonl` | ✅ | MCP + SessionStart auto-wired by `install-hooks` |
152
+ | OpenClaw/clawx | `~/.openclaw/agents/main/sessions` + `workspace/memory/*.md` | ✅ | watcher only (no MCP yet); `openclaw-setup` enables launchd |
153
+ | Anything else | any on-disk transcript dir | — | use `loop-memory hook --source <name> --watch <dir>` (see [docs/auto-capture.md](docs/auto-capture.md)) |
154
+
155
+ The shipped hooks are the four popular agents we maintain in-tree.
156
+ The generic watcher CLI is the supported extension point for every
157
+ other agent — Aider, Cursor, Copilot, Cline, Continue, Goose, your
158
+ own home-grown CLI, anything that drops JSON/JSONL on disk.
159
+
111
160
  ---
112
161
 
113
162
  ## Install
@@ -229,6 +278,7 @@ flavors:
229
278
  | Claude Code | `loop-memory hook --source claude --watch ~/.claude` |
230
279
  | Hermes | `loop-memory hook --source hermes --watch ~/.hermes` |
231
280
  | OpenClaw (clawx) | `loop-memory hook --source openclaw --watch ~/.openclaw/agents/main/sessions` — also ingests `workspace/memory/*.md` daily logs |
281
+ | Anything else (Aider, Cursor, Copilot, Cline, Continue, Goose, …) | `loop-memory hook --source <name> --watch <path/to/transcripts>` — see [docs/auto-capture.md](docs/auto-capture.md) for loader requirements |
232
282
 
233
283
  Three of these in a `tmux` session, or persisted via launchd, keeps
234
284
  your memory store fresh without any clicks. Run `loop-memory
@@ -335,6 +385,43 @@ User signals close the loop:
335
385
  - Every `recall()` / search bumps `recall_count` on the returned
336
386
  rows so the next Stage-1 ranks them higher.
337
387
 
388
+ ### Cognitive sleep (v7)
389
+
390
+ `loop-memory cognitive-sleep [--apply]` runs an **auditable cleanup
391
+ pass** over the store:
392
+
393
+ - Surfaces contradictions between memories (e.g. "user prefers X"
394
+ vs. "user prefers Y") so you can resolve them in one click rather
395
+ than chasing them across sessions.
396
+ - Drops items that are below the configurable floor (`min_score`) and
397
+ older than the floor age.
398
+ - Merges near-duplicate memories (cosine ≥ 0.95 with `MergeableBy` rules).
399
+ - Emits a full audit row per action — visible in the Dashboard →
400
+ **Audit** tab and reachable via the MCP `audit` tool, so every
401
+ byte the consolidator ever touches is traceable.
402
+
403
+ Dry-run by default; pass `--apply` to commit.
404
+
405
+ **Observability (since 0.4.3).** The report carries per-stage
406
+ timings (``scan``, ``stale``, ``merge``, ``contradict``, ``apply``,
407
+ ``audit``) and an explicit ``aborted`` flag with an ``abort_reason``
408
+ that names the stage the budget fired in. Pass
409
+ ``--deadline-seconds <N>`` (HTTP: ``POST /api/v1/cognitive/sleep``
410
+ with ``{"deadline_seconds": N}``; SDK: ``client.cognitive_sleep(deadline_seconds=N)``)
411
+ to bound the sweep — useful for nightly cron, where a stuck
412
+ sweep should leave a loud trace instead of a silent spinner.
413
+
414
+ ### Knowledge graph
415
+
416
+ `loop-memory graph-rebuild` extracts entities from every distilled
417
+ wiki page and every long-term memory, then materialises a typed
418
+ relation graph:
419
+
420
+ - Visible as the **Knowledge graph** globe tab in the web UI.
421
+ - Queryable via the MCP `subgraph` and `remember_edge` tools.
422
+ - Re-built by the Evolution Consolidator's Stage-5 evolution memo, so
423
+ the graph evolves alongside the wiki.
424
+
338
425
  ## Auto-feedback into every LLM client (反哺)
339
426
 
340
427
  Distilled knowledge is only useful if your LLM tools can actually
@@ -391,21 +478,6 @@ configuration, scheduling, language switching, and light/dark themes.
391
478
 
392
479
  ---
393
480
 
394
- ## Time-weighted scoring
395
-
396
- Every memory carries a `score ∈ [0, 1]` recomputed from:
397
-
398
- ```
399
- score = 0.35 · importance + 0.65 · recency
400
- recency = ½ ^ (age / half_life)
401
- ```
402
-
403
- `half_life` defaults to 30 days, configurable via
404
- `consolidate(half_life_days=...)`. The UI shows the score as a
405
- percentage; use `?min_score=0.85` to see only high-relevance memories.
406
-
407
- ---
408
-
409
481
  ## Programmatic use
410
482
 
411
483
  ```python
@@ -459,26 +531,35 @@ Even though v0.2 is built around local storage, the original
459
531
  ```
460
532
  loop_memory/
461
533
  loop_memory/
534
+ cli/main.py # CLI entrypoint + COMMAND_HELP table + `--version`
535
+ ingest/ # Codex / Claude / Hermes / OpenClaw / generic loaders
536
+ wiki/ # distillation, classifier, scope auto-promotion
537
+ graph/ # entity extraction + knowledge-graph build
538
+ jobs/ # consolidate / evolve / cognitive-sleep / scheduler / contradiction / graph
539
+ llm/ # provider protocol + OpenAI / Anthropic / Ollama / rule-based
540
+ backends/ # embedding (hashing / sentence-transformers) + vector store (memory / chroma)
541
+ storage/ # SQLite-backed MemoryStore + migrations
542
+ privacy/ # <private> stripping + regex redaction
543
+ security/ # Keychain / 0600-file secrets wrapper
544
+ mcp/ # stdio JSON-RPC MCP server
545
+ serve/ # FastAPI app, watcher, web UI (Timeline / Dashboard / Wiki / Graph)
546
+ export/ # markdown + v7 portable bundle export/import
547
+ sdk.py # four-verb stable API: remember / recall / forget / feedback
548
+ sdk_extensions.py # optional high-level helpers (graph edges, wiki pages)
549
+ engine/loop.py # Retrieve → Generate → Reflect → Store loop
462
550
  memory/types.py # MemoryItem + 4 tiers
463
- backends/embedding.py # BaseEmbedder, HashingEmbedder, IdentityEmbedder
464
- backends/vector_store.py # VectorStore protocol + InMemory / Chroma
465
- backends/sentence_embedder.py # optional sentence-transformers
466
- llm/base.py # LLMClient protocol + EchoLLM + helpers
467
- llm/openai_adapter.py # optional OpenAI client
468
- engine/loop.py # the Retrieve → Generate → Reflect → Store loop
469
- engine/reflect.py # reflection & summarization passes
470
- storage/sqlite_store.py # persistent SQLite-backed MemoryStore
471
- ingest/loader.py # CodexLoader, ClaudeLoader, HermesLoader
472
- ingest/pipeline.py # session → MemoryStore
473
- jobs/consolidate.py # background rescore + GC + dedupe
474
- serve/app.py # FastAPI app for the local web UI
475
- serve/static/index.html # the page
476
- serve/watcher.py # filesystem watcher for auto-capture
477
- cli/main.py # CLI entrypoint (chat / stats / ingest / consolidate / serve / hook)
478
551
  examples/demo.py # runnable, zero-API-key demo
479
552
  py.typed
480
- tests/ # 92 unit tests, zero deps
481
- docs/auto-capture.md # launchd / systemd / cron recipes
553
+ tests/ # 475 unit tests across memory / SDK / serve / CLI / scripts
554
+ docs/
555
+ auto-capture.md # launchd / systemd / cron recipes
556
+ architecture.md # layered view + 5-stage evolution pipeline
557
+ api.md # HTTP API reference
558
+ agent-memory-api.md # four-verb SDK / HTTP / MCP contract
559
+ universal-agent-memory.md # v7 graph memory + cognitive sleep + bundles
560
+ providers.md # LLM provider reference
561
+ settings.md # settings table + secrets file
562
+ weekly-research-automation.md # how the project auto-evolves from upstream research
482
563
  ```
483
564
 
484
565
  ---
@@ -560,6 +641,85 @@ classifier is local and makes no model or network request on a wiki write.
560
641
 
561
642
  ---
562
643
 
644
+ ### LLM env-var overrides
645
+
646
+ The OpenAI-compat / Anthropic / Ollama providers (and the optional
647
+ ``openai`` adapter) honour two env-var knobs so you can pin
648
+ distillation deterministically without touching the behaviour
649
+ config:
650
+
651
+ - ``LLM_TEMPERATURE`` — float, defaults to ``0.3`` (or the explicit
652
+ ``kwargs.temperature``). Invalid values are ignored with a warning.
653
+ - ``LLM_SEED`` — int, sent as ``seed`` for OpenAI / Anthropic /
654
+ Ollama where supported. Omitting it preserves the existing
655
+ "no seed" behaviour so older call sites do not need to migrate.
656
+
657
+ Both env vars are read at every ``complete()`` call, so a single
658
+ ``export LLM_SEED=42`` plus a nightly cron makes wiki distillation
659
+ reproducible. Pinned by 11 cases in
660
+ ``tests/test_llm_providers.py::LLMEnvVarTests``.
661
+
662
+ ## FAQ & troubleshooting
663
+
664
+ **Q: `pip install loop-memory` succeeds but `loop-memory serve` says `ModuleNotFoundError: No module named 'fastapi'`.**
665
+ A: `fastapi` is the optional `[serve]` extra. Install it explicitly:
666
+ `pip install 'loop-memory[serve]'` (or `'loop-memory[all]'` for everything).
667
+
668
+ **Q: My `~/.codex/sessions/` is empty / nothing appears in the UI.**
669
+ A: Run `loop-memory doctor` — it prints per-source paths, last-seen
670
+ mtime, and whether the watcher is running. Then check
671
+ `loop-memory hook --source codex --watch ~/.codex/sessions` is alive
672
+ in another shell (or via launchd — see [docs/auto-capture.md](docs/auto-capture.md)).
673
+
674
+ **Q: Distillation never finishes / wiki stays empty.**
675
+ A: You need an LLM provider configured. Open the web UI → ⚙ Model,
676
+ pick a provider, paste an API key, and click **Save**. Then either
677
+ wait for the scheduler or hit **� Run now**. Zero-deps installs ship
678
+ with a rule-based provider as a placeholder so the loop never blocks
679
+ on a missing key.
680
+
681
+ **Q: `loop-memory install-hooks` warns that the token file already exists.**
682
+ A: That's expected — it's idempotent. To force a rewrite, delete the
683
+ target files (`~/.codex/config.toml`, `~/.claude/mcp.json`,
684
+ `~/.hermes/mcp.json`) and re-run. The tool also refuses to touch
685
+ non-loop-memory config keys.
686
+
687
+ **Q: How big can the SQLite store get before I should worry?**
688
+ A: Practical floor: 100k memories / 10k wiki pages stays under ~80 MB
689
+ and `recall()` returns in <100 ms. The Evolution Consolidator is
690
+ designed to keep the wiki tight (~hundreds of pages) rather than let
691
+ it grow unbounded. Run `loop-memory cognitive-sleep --apply` weekly
692
+ to drop the long tail.
693
+
694
+ **Q: Can I sync the store across machines?**
695
+ A: The SQLite file is git-friendly and copy-friendly. The `MEMORY.md`
696
+ + graph + memories + metadata **bundle** (`loop-memory export
697
+ <dir>`) is a portable v7 artefact you can commit, share, or
698
+ back-up. There is no first-class sync daemon — by design — so the
699
+ local-first guarantee is never violated.
700
+
701
+ **Q: Is there a hosted / cloud version?**
702
+ A: No. Loop Memory is MIT-licensed and 100% local; the SQLite file
703
+ lives under `~/.loop_memory/`. The web UI is bound to loopback by
704
+ default; binding to `0.0.0.0` prints a security warning and requires
705
+ an auth token.
706
+
707
+ **Q: Where do secrets / API keys live?**
708
+ A: Two places. Provider keys you set in the **⚙ Model** UI are
709
+ written to `~/.loop_memory/secrets.json` (mode 0600) via the
710
+ `loop_memory.security.secrets` wrapper, which prefers the macOS
711
+ Keychain on Darwin and falls back to the encrypted file on Linux.
712
+ The auth token used by the web UI is hashed in the SQLite settings
713
+ table — never stored in plaintext.
714
+
715
+ **Q: I see "no version" / "package not found" on the PyPI badge.**
716
+ A: shields.io pulls from a separate data source that lags PyPI by a
717
+ few minutes after a new release. Re-publish the badge warmer step
718
+ in `.github/workflows/publish.yml` to force a refresh, or wait ~30
719
+ minutes for shields.io to catch up.
720
+
721
+ ---
722
+
563
723
  ## Run the tests
564
724
 
565
725
  ```bash
@@ -22,6 +22,40 @@
22
22
 
23
23
  ---
24
24
 
25
+ > **What's new in 0.4.1** — CLI dispatch hardened so every subcommand's
26
+ > `--help` / `--version` exits 0 cleanly (no more `ValueError: unknown
27
+ > source: '--help'` on a zero-deps install). Added a static
28
+ > `COMMAND_HELP` table guarded by 10 new regression cases in
29
+ > `tests/test_cli_version.py`, plus GitHub `About` / README lead now
30
+ > surface for "agent loop" searches.
31
+ > [Full changelog →](CHANGELOG.md)
32
+
33
+ ---
34
+
35
+ ## Table of contents
36
+
37
+ - [What it does](#what-it-does)
38
+ - [Install](#install)
39
+ - [Quickstart](#quickstart)
40
+ - [Why Loop Memory vs. every other agent-memory project](#why-loop-memory-vs-every-other-agent-memory-project)
41
+ - [Architecture & docs](#architecture--docs)
42
+ - [After install: 30-second setup](#after-install-30-second-setup)
43
+ - [Auto-capture (after every conversation)](#auto-capture-after-every-conversation)
44
+ - [Dashboard + Evolution consolidator](#dashboard--evolution-consolidator-看板--进化式蒸馏)
45
+ - [Auto-feedback into every LLM client](#auto-feedback-into-every-llm-client-反哺)
46
+ - [Web UI](#web-ui)
47
+ - [Programmatic use](#programmatic-use)
48
+ - [The four-stage loop](#the-four-stage-loop)
49
+ - [Project layout](#project-layout)
50
+ - [Security & auth token](#security--auth-token)
51
+ - [Wiki scope auto-classification](#wiki-scope-auto-classification)
52
+ - [FAQ & troubleshooting](#faq--troubleshooting)
53
+ - [Run the tests](#run-the-tests)
54
+ - [Using distilled knowledge in your clients](#using-distilled-knowledge-in-your-clients)
55
+ - [License](#license)
56
+
57
+ ---
58
+
25
59
  ## What it does
26
60
 
27
61
  **Loop Memory** gives every agent you use a single, persistent brain
@@ -64,6 +98,21 @@ via MCP / hooks]
64
98
 
65
99
  *One loop, many agents, one evolving wiki.*
66
100
 
101
+ **Supported agents:**
102
+
103
+ | Agent | Capture path | Hook shipped? | Notes |
104
+ | -------------- | ----------------------------------- | :-----------: | ----- |
105
+ | Codex CLI | `~/.codex/sessions/*.json` | ✅ | MCP + SessionStart auto-wired by `install-hooks` |
106
+ | Claude Code | `~/.claude/**/*.jsonl` | ✅ | MCP + SessionStart auto-wired by `install-hooks` |
107
+ | Hermes | `~/.hermes/**/*.jsonl` | ✅ | MCP + SessionStart auto-wired by `install-hooks` |
108
+ | OpenClaw/clawx | `~/.openclaw/agents/main/sessions` + `workspace/memory/*.md` | ✅ | watcher only (no MCP yet); `openclaw-setup` enables launchd |
109
+ | Anything else | any on-disk transcript dir | — | use `loop-memory hook --source <name> --watch <dir>` (see [docs/auto-capture.md](docs/auto-capture.md)) |
110
+
111
+ The shipped hooks are the four popular agents we maintain in-tree.
112
+ The generic watcher CLI is the supported extension point for every
113
+ other agent — Aider, Cursor, Copilot, Cline, Continue, Goose, your
114
+ own home-grown CLI, anything that drops JSON/JSONL on disk.
115
+
67
116
  ---
68
117
 
69
118
  ## Install
@@ -185,6 +234,7 @@ flavors:
185
234
  | Claude Code | `loop-memory hook --source claude --watch ~/.claude` |
186
235
  | Hermes | `loop-memory hook --source hermes --watch ~/.hermes` |
187
236
  | OpenClaw (clawx) | `loop-memory hook --source openclaw --watch ~/.openclaw/agents/main/sessions` — also ingests `workspace/memory/*.md` daily logs |
237
+ | Anything else (Aider, Cursor, Copilot, Cline, Continue, Goose, …) | `loop-memory hook --source <name> --watch <path/to/transcripts>` — see [docs/auto-capture.md](docs/auto-capture.md) for loader requirements |
188
238
 
189
239
  Three of these in a `tmux` session, or persisted via launchd, keeps
190
240
  your memory store fresh without any clicks. Run `loop-memory
@@ -291,6 +341,43 @@ User signals close the loop:
291
341
  - Every `recall()` / search bumps `recall_count` on the returned
292
342
  rows so the next Stage-1 ranks them higher.
293
343
 
344
+ ### Cognitive sleep (v7)
345
+
346
+ `loop-memory cognitive-sleep [--apply]` runs an **auditable cleanup
347
+ pass** over the store:
348
+
349
+ - Surfaces contradictions between memories (e.g. "user prefers X"
350
+ vs. "user prefers Y") so you can resolve them in one click rather
351
+ than chasing them across sessions.
352
+ - Drops items that are below the configurable floor (`min_score`) and
353
+ older than the floor age.
354
+ - Merges near-duplicate memories (cosine ≥ 0.95 with `MergeableBy` rules).
355
+ - Emits a full audit row per action — visible in the Dashboard →
356
+ **Audit** tab and reachable via the MCP `audit` tool, so every
357
+ byte the consolidator ever touches is traceable.
358
+
359
+ Dry-run by default; pass `--apply` to commit.
360
+
361
+ **Observability (since 0.4.3).** The report carries per-stage
362
+ timings (``scan``, ``stale``, ``merge``, ``contradict``, ``apply``,
363
+ ``audit``) and an explicit ``aborted`` flag with an ``abort_reason``
364
+ that names the stage the budget fired in. Pass
365
+ ``--deadline-seconds <N>`` (HTTP: ``POST /api/v1/cognitive/sleep``
366
+ with ``{"deadline_seconds": N}``; SDK: ``client.cognitive_sleep(deadline_seconds=N)``)
367
+ to bound the sweep — useful for nightly cron, where a stuck
368
+ sweep should leave a loud trace instead of a silent spinner.
369
+
370
+ ### Knowledge graph
371
+
372
+ `loop-memory graph-rebuild` extracts entities from every distilled
373
+ wiki page and every long-term memory, then materialises a typed
374
+ relation graph:
375
+
376
+ - Visible as the **Knowledge graph** globe tab in the web UI.
377
+ - Queryable via the MCP `subgraph` and `remember_edge` tools.
378
+ - Re-built by the Evolution Consolidator's Stage-5 evolution memo, so
379
+ the graph evolves alongside the wiki.
380
+
294
381
  ## Auto-feedback into every LLM client (反哺)
295
382
 
296
383
  Distilled knowledge is only useful if your LLM tools can actually
@@ -347,21 +434,6 @@ configuration, scheduling, language switching, and light/dark themes.
347
434
 
348
435
  ---
349
436
 
350
- ## Time-weighted scoring
351
-
352
- Every memory carries a `score ∈ [0, 1]` recomputed from:
353
-
354
- ```
355
- score = 0.35 · importance + 0.65 · recency
356
- recency = ½ ^ (age / half_life)
357
- ```
358
-
359
- `half_life` defaults to 30 days, configurable via
360
- `consolidate(half_life_days=...)`. The UI shows the score as a
361
- percentage; use `?min_score=0.85` to see only high-relevance memories.
362
-
363
- ---
364
-
365
437
  ## Programmatic use
366
438
 
367
439
  ```python
@@ -415,26 +487,35 @@ Even though v0.2 is built around local storage, the original
415
487
  ```
416
488
  loop_memory/
417
489
  loop_memory/
490
+ cli/main.py # CLI entrypoint + COMMAND_HELP table + `--version`
491
+ ingest/ # Codex / Claude / Hermes / OpenClaw / generic loaders
492
+ wiki/ # distillation, classifier, scope auto-promotion
493
+ graph/ # entity extraction + knowledge-graph build
494
+ jobs/ # consolidate / evolve / cognitive-sleep / scheduler / contradiction / graph
495
+ llm/ # provider protocol + OpenAI / Anthropic / Ollama / rule-based
496
+ backends/ # embedding (hashing / sentence-transformers) + vector store (memory / chroma)
497
+ storage/ # SQLite-backed MemoryStore + migrations
498
+ privacy/ # <private> stripping + regex redaction
499
+ security/ # Keychain / 0600-file secrets wrapper
500
+ mcp/ # stdio JSON-RPC MCP server
501
+ serve/ # FastAPI app, watcher, web UI (Timeline / Dashboard / Wiki / Graph)
502
+ export/ # markdown + v7 portable bundle export/import
503
+ sdk.py # four-verb stable API: remember / recall / forget / feedback
504
+ sdk_extensions.py # optional high-level helpers (graph edges, wiki pages)
505
+ engine/loop.py # Retrieve → Generate → Reflect → Store loop
418
506
  memory/types.py # MemoryItem + 4 tiers
419
- backends/embedding.py # BaseEmbedder, HashingEmbedder, IdentityEmbedder
420
- backends/vector_store.py # VectorStore protocol + InMemory / Chroma
421
- backends/sentence_embedder.py # optional sentence-transformers
422
- llm/base.py # LLMClient protocol + EchoLLM + helpers
423
- llm/openai_adapter.py # optional OpenAI client
424
- engine/loop.py # the Retrieve → Generate → Reflect → Store loop
425
- engine/reflect.py # reflection & summarization passes
426
- storage/sqlite_store.py # persistent SQLite-backed MemoryStore
427
- ingest/loader.py # CodexLoader, ClaudeLoader, HermesLoader
428
- ingest/pipeline.py # session → MemoryStore
429
- jobs/consolidate.py # background rescore + GC + dedupe
430
- serve/app.py # FastAPI app for the local web UI
431
- serve/static/index.html # the page
432
- serve/watcher.py # filesystem watcher for auto-capture
433
- cli/main.py # CLI entrypoint (chat / stats / ingest / consolidate / serve / hook)
434
507
  examples/demo.py # runnable, zero-API-key demo
435
508
  py.typed
436
- tests/ # 92 unit tests, zero deps
437
- docs/auto-capture.md # launchd / systemd / cron recipes
509
+ tests/ # 475 unit tests across memory / SDK / serve / CLI / scripts
510
+ docs/
511
+ auto-capture.md # launchd / systemd / cron recipes
512
+ architecture.md # layered view + 5-stage evolution pipeline
513
+ api.md # HTTP API reference
514
+ agent-memory-api.md # four-verb SDK / HTTP / MCP contract
515
+ universal-agent-memory.md # v7 graph memory + cognitive sleep + bundles
516
+ providers.md # LLM provider reference
517
+ settings.md # settings table + secrets file
518
+ weekly-research-automation.md # how the project auto-evolves from upstream research
438
519
  ```
439
520
 
440
521
  ---
@@ -516,6 +597,85 @@ classifier is local and makes no model or network request on a wiki write.
516
597
 
517
598
  ---
518
599
 
600
+ ### LLM env-var overrides
601
+
602
+ The OpenAI-compat / Anthropic / Ollama providers (and the optional
603
+ ``openai`` adapter) honour two env-var knobs so you can pin
604
+ distillation deterministically without touching the behaviour
605
+ config:
606
+
607
+ - ``LLM_TEMPERATURE`` — float, defaults to ``0.3`` (or the explicit
608
+ ``kwargs.temperature``). Invalid values are ignored with a warning.
609
+ - ``LLM_SEED`` — int, sent as ``seed`` for OpenAI / Anthropic /
610
+ Ollama where supported. Omitting it preserves the existing
611
+ "no seed" behaviour so older call sites do not need to migrate.
612
+
613
+ Both env vars are read at every ``complete()`` call, so a single
614
+ ``export LLM_SEED=42`` plus a nightly cron makes wiki distillation
615
+ reproducible. Pinned by 11 cases in
616
+ ``tests/test_llm_providers.py::LLMEnvVarTests``.
617
+
618
+ ## FAQ & troubleshooting
619
+
620
+ **Q: `pip install loop-memory` succeeds but `loop-memory serve` says `ModuleNotFoundError: No module named 'fastapi'`.**
621
+ A: `fastapi` is the optional `[serve]` extra. Install it explicitly:
622
+ `pip install 'loop-memory[serve]'` (or `'loop-memory[all]'` for everything).
623
+
624
+ **Q: My `~/.codex/sessions/` is empty / nothing appears in the UI.**
625
+ A: Run `loop-memory doctor` — it prints per-source paths, last-seen
626
+ mtime, and whether the watcher is running. Then check
627
+ `loop-memory hook --source codex --watch ~/.codex/sessions` is alive
628
+ in another shell (or via launchd — see [docs/auto-capture.md](docs/auto-capture.md)).
629
+
630
+ **Q: Distillation never finishes / wiki stays empty.**
631
+ A: You need an LLM provider configured. Open the web UI → ⚙ Model,
632
+ pick a provider, paste an API key, and click **Save**. Then either
633
+ wait for the scheduler or hit **� Run now**. Zero-deps installs ship
634
+ with a rule-based provider as a placeholder so the loop never blocks
635
+ on a missing key.
636
+
637
+ **Q: `loop-memory install-hooks` warns that the token file already exists.**
638
+ A: That's expected — it's idempotent. To force a rewrite, delete the
639
+ target files (`~/.codex/config.toml`, `~/.claude/mcp.json`,
640
+ `~/.hermes/mcp.json`) and re-run. The tool also refuses to touch
641
+ non-loop-memory config keys.
642
+
643
+ **Q: How big can the SQLite store get before I should worry?**
644
+ A: Practical floor: 100k memories / 10k wiki pages stays under ~80 MB
645
+ and `recall()` returns in <100 ms. The Evolution Consolidator is
646
+ designed to keep the wiki tight (~hundreds of pages) rather than let
647
+ it grow unbounded. Run `loop-memory cognitive-sleep --apply` weekly
648
+ to drop the long tail.
649
+
650
+ **Q: Can I sync the store across machines?**
651
+ A: The SQLite file is git-friendly and copy-friendly. The `MEMORY.md`
652
+ + graph + memories + metadata **bundle** (`loop-memory export
653
+ <dir>`) is a portable v7 artefact you can commit, share, or
654
+ back-up. There is no first-class sync daemon — by design — so the
655
+ local-first guarantee is never violated.
656
+
657
+ **Q: Is there a hosted / cloud version?**
658
+ A: No. Loop Memory is MIT-licensed and 100% local; the SQLite file
659
+ lives under `~/.loop_memory/`. The web UI is bound to loopback by
660
+ default; binding to `0.0.0.0` prints a security warning and requires
661
+ an auth token.
662
+
663
+ **Q: Where do secrets / API keys live?**
664
+ A: Two places. Provider keys you set in the **⚙ Model** UI are
665
+ written to `~/.loop_memory/secrets.json` (mode 0600) via the
666
+ `loop_memory.security.secrets` wrapper, which prefers the macOS
667
+ Keychain on Darwin and falls back to the encrypted file on Linux.
668
+ The auth token used by the web UI is hashed in the SQLite settings
669
+ table — never stored in plaintext.
670
+
671
+ **Q: I see "no version" / "package not found" on the PyPI badge.**
672
+ A: shields.io pulls from a separate data source that lags PyPI by a
673
+ few minutes after a new release. Re-publish the badge warmer step
674
+ in `.github/workflows/publish.yml` to force a refresh, or wait ~30
675
+ minutes for shields.io to catch up.
676
+
677
+ ---
678
+
519
679
  ## Run the tests
520
680
 
521
681
  ```bash