loop-memory 0.4.12__tar.gz → 0.4.14__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.
- {loop_memory-0.4.12 → loop_memory-0.4.14}/PKG-INFO +5 -1
- {loop_memory-0.4.12 → loop_memory-0.4.14}/README.md +4 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/cli/commands/diag.py +11 -88
- loop_memory-0.4.14/loop_memory/cli/commands/doctor.py +144 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/cli/commands/read.py +44 -7
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/cli/main.py +3 -3
- loop_memory-0.4.14/loop_memory/doctor.py +678 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/mcp/__init__.py +21 -1
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/sdk.py +19 -2
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/serve/routes/system.py +48 -2
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/storage/sqlite_store.py +314 -2
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory.egg-info/PKG-INFO +5 -1
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory.egg-info/SOURCES.txt +4 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/pyproject.toml +1 -1
- loop_memory-0.4.14/tests/test_doctor_2026_10_12.py +319 -0
- loop_memory-0.4.14/tests/test_recall_budget_2026_10_05.py +407 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/LICENSE +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/__init__.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/backends/__init__.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/backends/embedding.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/backends/sentence_embedder.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/backends/vector_store.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/cli/__init__.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/cli/_common.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/cli/commands/__init__.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/cli/commands/cognitive.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/cli/commands/graph.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/cli/commands/hooks.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/cli/commands/rules.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/cli/commands/serve.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/cli/commands/write.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/engine/__init__.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/engine/loop.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/engine/reflect.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/examples/__init__.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/examples/demo.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/export/__init__.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/export/memory_md.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/graph/__init__.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/graph/build.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/graph/extract.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/ingest/__init__.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/ingest/loader.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/ingest/pipeline.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/jobs/__init__.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/jobs/cognitive.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/jobs/compact.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/jobs/consolidate.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/jobs/contradiction.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/jobs/evolution.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/jobs/graph.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/jobs/llm_compact_pass.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/jobs/llm_consolidate.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/jobs/scheduler.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/llm/__init__.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/llm/base.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/llm/openai_adapter.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/llm/providers.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/memory/__init__.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/memory/types.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/privacy/__init__.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/privacy/private.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/privacy/redact.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/py.typed +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/sdk_extensions.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/security/__init__.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/security/secrets.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/serve/__init__.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/serve/app.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/serve/handlers.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/serve/routes/_shared.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/serve/routes/admin.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/serve/routes/cognitive.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/serve/routes/export.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/serve/routes/graph.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/serve/routes/insights.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/serve/routes/memories.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/serve/routes/sessions.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/serve/routes/wiki.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/serve/static/__init__.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/serve/static/index.html +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/serve/watcher.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/storage/__init__.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/storage/retrieval.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/storage/snapshot.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/wiki/__init__.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/wiki/backfill.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/wiki/classifier.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/wiki/prompts.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory/wiki/scope.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory.egg-info/dependency_links.txt +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory.egg-info/entry_points.txt +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory.egg-info/requires.txt +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/loop_memory.egg-info/top_level.txt +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/setup.cfg +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_admin_ingest_route.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_agent_memory_api.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_agent_memory_sdk.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_agents_init.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_audit_triggers_2026_09_27.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_auth_token_rotate.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_busy_timeout_2026_09_24.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_cache_cap_2026_09_23.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_cli_audit_supersede.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_cli_export_okf.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_cli_init.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_cli_memory_stats.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_cli_recall_as_of.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_cli_recall_paths.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_cli_recall_verbose.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_cli_rules.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_cli_snapshot.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_cli_v7.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_cli_version.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_contradictions.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_evolution.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_evolution_quality.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_expanduser.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_export_ask.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_export_okf.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_graph.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_healthz_readyz_2026_09_24.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_import_okf_2026_09_27.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_ingest.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_llm_consolidator.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_llm_fingerprint_not_persisted.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_llm_providers.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_llm_test_endpoint.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_loop.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_mcp.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_memories_pagination.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_memory_stats.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_openclaw_loader.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_package_version.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_path_safety_2026_09_23.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_recall_as_of.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_recall_paths.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_recall_provenance.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_reflection.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_repo_framing.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_routes_audit_2026_09_13.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_routes_audit_2026_09_20.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_score_api.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_scoring_v2.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_secrets.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_serve_app.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_serve_handlers.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_session_order.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_short_query.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_snapshot.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_store.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_subgraph_hops_2026_09_23.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_summarization.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_supersession_chain.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_universal_memory.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_vector_store.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_watcher.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_wiki_classifier.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/tests/test_wiki_export_escape.py +0 -0
- {loop_memory-0.4.12 → loop_memory-0.4.14}/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.
|
|
3
|
+
Version: 0.4.14
|
|
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,10 @@ Dynamic: license-file
|
|
|
66
66
|
|
|
67
67
|
---
|
|
68
68
|
|
|
69
|
+
> **What's new in 0.4.14** — **`loop-memory doctor` deep store-health check** (audit 2026-10-12). Ten diagnostic checks — `db_exists`, `db_integrity`, `schema_version`, `audit_triggers`, `audit_log_writable`, `audit_log_size`, `hooks_installed`, `version_consistent`, `wiki_no_orphans`, `recall_paths_works` — report `ok`/`info`/`warn`/`error` for the live `MemoryStore`. `--fix` auto-repairs the `audit_triggers` check. `--json` emits a stable shape for CI. `--list` prints the check function names without touching the store. `--verbose` shows `info`-level checks. Exit code `1` on any `error` status, `0` otherwise. Source: `cortexkit/magic-context doctor` auto-diagnostic pattern (MIT, 2026-10-12) + `dsh-memento` write-approval-gate pattern (Apache-2.0, 2026-10-12). Stdlib-only — we re-implement from scratch against our own `MemoryStore`. Also fixed a Python 3.14 bug: chained `store._conn().__enter__()` immediately triggers the contextmanager's `finally` and closes the connection mid-query — both call sites in `doctor.py` now use explicit `with` form. 27 new regression cases. [Full CHANGELOG →](./CHANGELOG.md#0414---2026-10-12)
|
|
70
|
+
|
|
71
|
+
> **What's new in 0.4.13** — **recall token / char budget cap** + **unified `level=0|1|2` tiered-loader knob** (audit 2026-10-05). New `max_chars` parameter on `MemoryStore.recall()` / `recall_paths()` / `recall_hybrid()` / `recall_as_of()` caps the *total* payload across all returned hits — when the budget is exceeded the lowest-ranked hit shrinks first so the top-scoring hits always keep their full body. `recall()` / `recall_paths()` / `recall_as_of()` now also accept `level=0|1|2` so a caller can ask for the L0 abstract ladder rung inline (titles + tags + abstract only, never the full `text` / `body`) without routing through `recall_paths()` separately. Both knobs are wired through the HTTP routes (`GET /api/recall?max_chars=&level=`, `GET /api/recall/outline?max_chars=`), the CLI (`loop-memory recall --max-chars N --level 0|1|2`, `recall-paths --max-chars N`), the SDK (`LoopMemoryClient.recall(max_chars=, level=)`), and the MCP `tool_recall` server. Source: `vectorize-io/hindsight v0.10.2` "concise extraction by default" (Apache-2.0, 2026-09-29) + `aiming-lab/SimpleMem` ICML'26 semantic-lossless-compression (Apache-2.0, 2026-10-04) + `volcengine/OpenViking` tiered-loader (AGPLv3, 2026-10-02 — *pattern only, no code copied*). 26 new regression cases. [Full CHANGELOG →](./CHANGELOG.md#0413---2026-10-05)
|
|
72
|
+
|
|
69
73
|
> **What's new in 0.4.12** — **OKF bundle import** + **DB-level audit enforcement** (audit 2026-09-27). The new `loop-memory import-okf <in_dir>` (and `POST /api/import/okf`) is the symmetric counterpart to `export-okf` (0.4.9) — bring an OKF v0.2 bundle back into Loop Memory as wiki pages, with idempotent upsert on `(scope, slug)`, optional `--dry-run` and `--skip-conflicts`. Source: `thecolourfoundation/rune` HN launch (MIT, 2026-09-25) + `okf-memory/okf-agent-memory` Issues #12-#15 + `Deja-Vu` (MIT, 2026-09-24) + Google OKF v0.2 spec (Apache-2.0, 2026-09-01). The new `MemoryStore._install_audit_triggers()` installs 12 SQLite triggers on `memories` / `wiki_pages` / `relations` / `consolidation_runs` so the `audit_log` table cannot be skipped — even a raw `sqlite3` writer that bypasses the Python wrapper still appends an audit row with `actor='db_trigger'`. New `MemoryStore.list_audit_log()` reads the log; `GET /api/stats` reports `audit_log` + `audit_triggers` counts. Source: `cogstate-eng/memory-eternal v0.4.3` `enforceAudit()` pattern (MIT, 2026-09-23). 31 new regression cases. [Full CHANGELOG →](./CHANGELOG.md#0412---2026-09-27)
|
|
70
74
|
|
|
71
75
|
> **What's new in 0.4.11** — **operational probes** +
|
|
@@ -22,6 +22,10 @@
|
|
|
22
22
|
|
|
23
23
|
---
|
|
24
24
|
|
|
25
|
+
> **What's new in 0.4.14** — **`loop-memory doctor` deep store-health check** (audit 2026-10-12). Ten diagnostic checks — `db_exists`, `db_integrity`, `schema_version`, `audit_triggers`, `audit_log_writable`, `audit_log_size`, `hooks_installed`, `version_consistent`, `wiki_no_orphans`, `recall_paths_works` — report `ok`/`info`/`warn`/`error` for the live `MemoryStore`. `--fix` auto-repairs the `audit_triggers` check. `--json` emits a stable shape for CI. `--list` prints the check function names without touching the store. `--verbose` shows `info`-level checks. Exit code `1` on any `error` status, `0` otherwise. Source: `cortexkit/magic-context doctor` auto-diagnostic pattern (MIT, 2026-10-12) + `dsh-memento` write-approval-gate pattern (Apache-2.0, 2026-10-12). Stdlib-only — we re-implement from scratch against our own `MemoryStore`. Also fixed a Python 3.14 bug: chained `store._conn().__enter__()` immediately triggers the contextmanager's `finally` and closes the connection mid-query — both call sites in `doctor.py` now use explicit `with` form. 27 new regression cases. [Full CHANGELOG →](./CHANGELOG.md#0414---2026-10-12)
|
|
26
|
+
|
|
27
|
+
> **What's new in 0.4.13** — **recall token / char budget cap** + **unified `level=0|1|2` tiered-loader knob** (audit 2026-10-05). New `max_chars` parameter on `MemoryStore.recall()` / `recall_paths()` / `recall_hybrid()` / `recall_as_of()` caps the *total* payload across all returned hits — when the budget is exceeded the lowest-ranked hit shrinks first so the top-scoring hits always keep their full body. `recall()` / `recall_paths()` / `recall_as_of()` now also accept `level=0|1|2` so a caller can ask for the L0 abstract ladder rung inline (titles + tags + abstract only, never the full `text` / `body`) without routing through `recall_paths()` separately. Both knobs are wired through the HTTP routes (`GET /api/recall?max_chars=&level=`, `GET /api/recall/outline?max_chars=`), the CLI (`loop-memory recall --max-chars N --level 0|1|2`, `recall-paths --max-chars N`), the SDK (`LoopMemoryClient.recall(max_chars=, level=)`), and the MCP `tool_recall` server. Source: `vectorize-io/hindsight v0.10.2` "concise extraction by default" (Apache-2.0, 2026-09-29) + `aiming-lab/SimpleMem` ICML'26 semantic-lossless-compression (Apache-2.0, 2026-10-04) + `volcengine/OpenViking` tiered-loader (AGPLv3, 2026-10-02 — *pattern only, no code copied*). 26 new regression cases. [Full CHANGELOG →](./CHANGELOG.md#0413---2026-10-05)
|
|
28
|
+
|
|
25
29
|
> **What's new in 0.4.12** — **OKF bundle import** + **DB-level audit enforcement** (audit 2026-09-27). The new `loop-memory import-okf <in_dir>` (and `POST /api/import/okf`) is the symmetric counterpart to `export-okf` (0.4.9) — bring an OKF v0.2 bundle back into Loop Memory as wiki pages, with idempotent upsert on `(scope, slug)`, optional `--dry-run` and `--skip-conflicts`. Source: `thecolourfoundation/rune` HN launch (MIT, 2026-09-25) + `okf-memory/okf-agent-memory` Issues #12-#15 + `Deja-Vu` (MIT, 2026-09-24) + Google OKF v0.2 spec (Apache-2.0, 2026-09-01). The new `MemoryStore._install_audit_triggers()` installs 12 SQLite triggers on `memories` / `wiki_pages` / `relations` / `consolidation_runs` so the `audit_log` table cannot be skipped — even a raw `sqlite3` writer that bypasses the Python wrapper still appends an audit row with `actor='db_trigger'`. New `MemoryStore.list_audit_log()` reads the log; `GET /api/stats` reports `audit_log` + `audit_triggers` counts. Source: `cogstate-eng/memory-eternal v0.4.3` `enforceAudit()` pattern (MIT, 2026-09-23). 31 new regression cases. [Full CHANGELOG →](./CHANGELOG.md#0412---2026-09-27)
|
|
26
30
|
|
|
27
31
|
> **What's new in 0.4.11** — **operational probes** +
|
|
@@ -133,95 +133,18 @@ def _detect_watcher() -> bool:
|
|
|
133
133
|
|
|
134
134
|
|
|
135
135
|
def run_doctor(_args) -> int:
|
|
136
|
-
"""
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
136
|
+
"""`loop-memory doctor` — deep store-health check.
|
|
137
|
+
|
|
138
|
+
Audit 2026-10-12. Delegates to :mod:`loop_memory.doctor` which runs
|
|
139
|
+
a small library of health checks against the live
|
|
140
|
+
`MemoryStore` and renders a human-readable report. Exits
|
|
141
|
+
non-zero if any check is in 'error' state. Source:
|
|
142
|
+
cortexkit/magic-context doctor (MIT, 2026-10-12) +
|
|
143
|
+
PerryLink/dsh-memento dsh-plugin-doctor (Apache-2.0,
|
|
144
|
+
2026-10-12) — pattern only.
|
|
140
145
|
"""
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
cli_path = shutil.which("loop-memory")
|
|
144
|
-
print(_dot(cli_path is not None,
|
|
145
|
-
f"CLI on PATH: {'yes (' + cli_path + ')' if cli_path else 'no'}"))
|
|
146
|
-
# 2) Database
|
|
147
|
-
db_path = Path(DEFAULT_DB)
|
|
148
|
-
print(_dot(db_path.exists(),
|
|
149
|
-
f"database: {db_path}" + ("" if db_path.exists() else " (will be created on first run)")))
|
|
150
|
-
# 3) Server
|
|
151
|
-
server_running = False
|
|
152
|
-
try:
|
|
153
|
-
import urllib.request
|
|
154
|
-
with urllib.request.urlopen("http://127.0.0.1:7767/api/stats", timeout=1) as r:
|
|
155
|
-
server_running = r.status == 200
|
|
156
|
-
except Exception:
|
|
157
|
-
server_running = False
|
|
158
|
-
print(_dot(server_running,
|
|
159
|
-
"web UI server: http://127.0.0.1:7767" + (" (running)" if server_running else " (not running — start with `loop-memory serve &`)")))
|
|
160
|
-
|
|
161
|
-
# 4) Clients
|
|
162
|
-
print()
|
|
163
|
-
print("clients:")
|
|
164
|
-
clients = _detect_clients()
|
|
165
|
-
for name in ("codex", "claude", "hermes", "openclaw"):
|
|
166
|
-
info = clients[name]
|
|
167
|
-
if name == "openclaw":
|
|
168
|
-
print(_dot(info["installed"],
|
|
169
|
-
f" openclaw: {'installed' if info['installed'] else 'not installed'}"))
|
|
170
|
-
if info["installed"]:
|
|
171
|
-
paths = ", ".join(Path(p).name for p in info["watch_paths"]) or "no transcript paths found"
|
|
172
|
-
print(f" {paths}")
|
|
173
|
-
print(_dot(_detect_watcher(),
|
|
174
|
-
" watcher running" if _detect_watcher() else " watcher not running — start with `loop-memory openclaw-setup`"))
|
|
175
|
-
else:
|
|
176
|
-
cfg = info["config"]
|
|
177
|
-
installed = info["installed"]
|
|
178
|
-
cfg_str = f"@ {cfg}" if installed else ""
|
|
179
|
-
print(_dot(installed,
|
|
180
|
-
f" {name}: {'installed' if installed else 'not installed'} {cfg_str}"))
|
|
181
|
-
if installed:
|
|
182
|
-
print(_dot(info["mcp_configured"],
|
|
183
|
-
f" MCP server wired: {'yes' if info['mcp_configured'] else 'no — run `loop-memory install-hooks`'}"))
|
|
184
|
-
|
|
185
|
-
# 5) LLM provider
|
|
186
|
-
print()
|
|
187
|
-
print("LLM provider:")
|
|
188
|
-
try:
|
|
189
|
-
from ...storage.sqlite_store import MemoryStore
|
|
190
|
-
from ...llm.providers import default_config
|
|
191
|
-
from ...security import backend_display_name, has_secret
|
|
192
|
-
store = MemoryStore(DEFAULT_DB)
|
|
193
|
-
cfg = store.get_setting("llm_consolidator", default_config())
|
|
194
|
-
provider = cfg.get("provider") or "echo"
|
|
195
|
-
print(f" provider: {provider}")
|
|
196
|
-
print(f" model: {cfg.get('model', '—')}")
|
|
197
|
-
print(f" secret backend: {backend_display_name()}")
|
|
198
|
-
if provider != "echo":
|
|
199
|
-
from ...security import account_for
|
|
200
|
-
account = cfg.get("api_key_account") or account_for(provider)
|
|
201
|
-
has = has_secret(account)
|
|
202
|
-
print(_dot(has,
|
|
203
|
-
f" API key: {'configured' if has else 'MISSING — open the web UI → ⚙ Model → paste your key'}"))
|
|
204
|
-
except Exception as e:
|
|
205
|
-
print(_dot(False, f" could not read LLM config: {e}"))
|
|
206
|
-
|
|
207
|
-
# 6) Data summary
|
|
208
|
-
print()
|
|
209
|
-
print("data:")
|
|
210
|
-
try:
|
|
211
|
-
from ...storage.sqlite_store import MemoryStore
|
|
212
|
-
store = MemoryStore(DEFAULT_DB)
|
|
213
|
-
n_mem = store.count_memories()
|
|
214
|
-
n_sess = store.count_sessions()
|
|
215
|
-
n_wiki = store.count_wiki_pages()
|
|
216
|
-
n_ent = store.count_entities()
|
|
217
|
-
print(f" {n_mem} memories · {n_sess} sessions · {n_wiki} wiki pages · {n_ent} entities")
|
|
218
|
-
except Exception as e:
|
|
219
|
-
print(f" could not read counters: {e}")
|
|
220
|
-
|
|
221
|
-
print()
|
|
222
|
-
print(_DIM + "Tip: run `loop-memory status` for a one-screen summary, "
|
|
223
|
-
"or `loop-memory install-hooks` to auto-configure your CLIs." + _RESET)
|
|
224
|
-
return 0
|
|
146
|
+
from . import doctor as _doctor_cli
|
|
147
|
+
return _doctor_cli.run_doctor(list(_args))
|
|
225
148
|
|
|
226
149
|
|
|
227
150
|
def run_status(_args) -> int:
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"""``loop-memory doctor`` subcommand.
|
|
2
|
+
|
|
3
|
+
Audit 2026-10-12. Wraps :mod:`loop_memory.doctor` and renders the
|
|
4
|
+
result for a human or as JSON. See ``loop_memory/doctor.py`` for
|
|
5
|
+
the check library and the source attribution.
|
|
6
|
+
|
|
7
|
+
Usage examples::
|
|
8
|
+
|
|
9
|
+
loop-memory doctor # human-readable report
|
|
10
|
+
loop-memory doctor --json # machine-readable report
|
|
11
|
+
loop-memory doctor --verbose # also show INFO-level checks
|
|
12
|
+
loop-memory doctor --fix # auto-repair auto_fixable checks
|
|
13
|
+
loop-memory doctor --db /path/to/store.db # run against a specific DB
|
|
14
|
+
"""
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import argparse
|
|
18
|
+
import sys
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
from typing import Any
|
|
21
|
+
|
|
22
|
+
from .._common import die
|
|
23
|
+
from ... import doctor as _doctor
|
|
24
|
+
from ...storage.sqlite_store import MemoryStore
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _build_parser() -> argparse.ArgumentParser:
|
|
28
|
+
p = argparse.ArgumentParser(
|
|
29
|
+
prog="loop-memory doctor",
|
|
30
|
+
description=(
|
|
31
|
+
"Run a small library of health checks against the loop-memory "
|
|
32
|
+
"store. Reports ok / info / warn / error per check and exits "
|
|
33
|
+
"non-zero if any check is in 'error' state. Source: cortexkit/"
|
|
34
|
+
"magic-context doctor (MIT, 2026-10-12) + PerryLink/dsh-memento "
|
|
35
|
+
"dsh-plugin-doctor (Apache-2.0, 2026-10-12) — pattern only."
|
|
36
|
+
),
|
|
37
|
+
)
|
|
38
|
+
p.add_argument(
|
|
39
|
+
"--db",
|
|
40
|
+
default=None,
|
|
41
|
+
help="path to the SQLite file (default: $LOOP_MEMORY_DB or ~/.loop_memory/loop_memory.db)",
|
|
42
|
+
)
|
|
43
|
+
p.add_argument(
|
|
44
|
+
"--json",
|
|
45
|
+
action="store_true",
|
|
46
|
+
help="emit the result as JSON for scripting",
|
|
47
|
+
)
|
|
48
|
+
p.add_argument(
|
|
49
|
+
"--verbose",
|
|
50
|
+
action="store_true",
|
|
51
|
+
help="also show INFO-level checks in human output",
|
|
52
|
+
)
|
|
53
|
+
p.add_argument(
|
|
54
|
+
"--fix",
|
|
55
|
+
action="store_true",
|
|
56
|
+
help="auto-repair any auto_fixable check that fails (idempotent; safe to re-run)",
|
|
57
|
+
)
|
|
58
|
+
p.add_argument(
|
|
59
|
+
"--list",
|
|
60
|
+
action="store_true",
|
|
61
|
+
help="list every check the doctor would run and exit (no DB access)",
|
|
62
|
+
)
|
|
63
|
+
return p
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _resolve_db_path(arg: str | None) -> Path:
|
|
67
|
+
"""Pick the store path: ``--db`` wins, else ``$LOOP_MEMORY_DB``,
|
|
68
|
+
else the default ``~/.loop_memory/loop_memory.db``."""
|
|
69
|
+
if arg:
|
|
70
|
+
return Path(arg).expanduser()
|
|
71
|
+
import os
|
|
72
|
+
env = os.environ.get("LOOP_MEMORY_DB")
|
|
73
|
+
if env:
|
|
74
|
+
return Path(env).expanduser()
|
|
75
|
+
from .._common import default_db_path
|
|
76
|
+
return Path(default_db_path())
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def run_doctor(args: list[str]) -> int:
|
|
80
|
+
parser = _build_parser()
|
|
81
|
+
parsed = parser.parse_args(args)
|
|
82
|
+
|
|
83
|
+
if parsed.list:
|
|
84
|
+
for fn in _doctor.CHECKS:
|
|
85
|
+
print(fn.__name__)
|
|
86
|
+
return 0
|
|
87
|
+
|
|
88
|
+
db_path = _resolve_db_path(parsed.db)
|
|
89
|
+
if not db_path.exists():
|
|
90
|
+
msg = (
|
|
91
|
+
f"loop-memory doctor: store file not found at {db_path}. "
|
|
92
|
+
"Run `loop-memory init` first, or pass --db to point at an existing store."
|
|
93
|
+
)
|
|
94
|
+
if parsed.json:
|
|
95
|
+
print(_doctor.render_json([
|
|
96
|
+
_doctor.DoctorCheck(
|
|
97
|
+
name="db_exists",
|
|
98
|
+
status=_doctor.STATUS_ERROR,
|
|
99
|
+
message=msg,
|
|
100
|
+
fix_hint="run `loop-memory init` to create the store",
|
|
101
|
+
),
|
|
102
|
+
]))
|
|
103
|
+
return 1
|
|
104
|
+
return die(msg)
|
|
105
|
+
|
|
106
|
+
# ``MemoryStore(<missing_path>)`` creates a fresh DB on open.
|
|
107
|
+
# We want doctor to FAIL when the path is missing rather than
|
|
108
|
+
# silently materialise an empty store, so the missing-path
|
|
109
|
+
# check above is the contract.
|
|
110
|
+
try:
|
|
111
|
+
store = MemoryStore(str(db_path))
|
|
112
|
+
except Exception as e:
|
|
113
|
+
msg = f"loop-memory doctor: could not open store at {db_path}: {e}"
|
|
114
|
+
if parsed.json:
|
|
115
|
+
print(_doctor.render_json([
|
|
116
|
+
_doctor.DoctorCheck(
|
|
117
|
+
name="db_exists",
|
|
118
|
+
status=_doctor.STATUS_ERROR,
|
|
119
|
+
message=msg,
|
|
120
|
+
),
|
|
121
|
+
]))
|
|
122
|
+
return 1
|
|
123
|
+
return die(msg)
|
|
124
|
+
|
|
125
|
+
checks = _doctor.run_checks(store)
|
|
126
|
+
|
|
127
|
+
if parsed.fix:
|
|
128
|
+
# Apply auto-fixes in a single pass. We re-run the checks
|
|
129
|
+
# so the user sees the post-fix state in the same command.
|
|
130
|
+
for c in checks:
|
|
131
|
+
if c.status in (_doctor.STATUS_ERROR, _doctor.STATUS_WARN) and c.auto_fixable:
|
|
132
|
+
post = _doctor.apply_fix(store, c.name)
|
|
133
|
+
# Replace the failing check with the post-fix result
|
|
134
|
+
# so the human / JSON output reflects reality.
|
|
135
|
+
idx = checks.index(c)
|
|
136
|
+
checks[idx] = post
|
|
137
|
+
checks = _doctor.run_checks(store)
|
|
138
|
+
|
|
139
|
+
if parsed.json:
|
|
140
|
+
sys.stdout.write(_doctor.render_json(checks))
|
|
141
|
+
else:
|
|
142
|
+
sys.stdout.write(_doctor.render_human(checks, verbose=parsed.verbose))
|
|
143
|
+
|
|
144
|
+
return _doctor.exit_code(checks)
|
|
@@ -51,7 +51,7 @@ def run_stats(_args) -> int:
|
|
|
51
51
|
|
|
52
52
|
|
|
53
53
|
def run_recall(args) -> int:
|
|
54
|
-
"""Run ``loop-memory recall <query> [--verbose] [--outline] [--as-of T] [--limit N]``.
|
|
54
|
+
"""Run ``loop-memory recall <query> [--verbose] [--outline] [--as-of T] [--limit N] [--max-chars N] [--level 0|1|2]``.
|
|
55
55
|
|
|
56
56
|
With ``--verbose`` each memory hit is annotated with the
|
|
57
57
|
``why: [...]`` provenance labels produced by ``MemoryStore.recall``
|
|
@@ -73,6 +73,8 @@ def run_recall(args) -> int:
|
|
|
73
73
|
outline = False
|
|
74
74
|
limit = 10
|
|
75
75
|
as_of: float | None = None
|
|
76
|
+
max_chars: int | None = None
|
|
77
|
+
level = 1
|
|
76
78
|
qargs: list[str] = []
|
|
77
79
|
i = 0
|
|
78
80
|
while i < len(args):
|
|
@@ -104,6 +106,29 @@ def run_recall(args) -> int:
|
|
|
104
106
|
f"--as-of must be float epoch or ISO-8601; got {raw!r}"
|
|
105
107
|
)
|
|
106
108
|
i += 2
|
|
109
|
+
elif a == "--max-chars" and i + 1 < len(args):
|
|
110
|
+
# Audit 2026-10-05 (vectorize-io/hindsight v0.10.2 +
|
|
111
|
+
# aiming-lab/SimpleMem ICML'26) — cap the total payload
|
|
112
|
+
# across all hits so an agent loop never has to hand-trim
|
|
113
|
+
# a giant response. ``0`` / negative = no cap.
|
|
114
|
+
try:
|
|
115
|
+
max_chars = int(args[i + 1])
|
|
116
|
+
if max_chars <= 0:
|
|
117
|
+
max_chars = None
|
|
118
|
+
except ValueError:
|
|
119
|
+
return die(f"--max-chars must be an integer, got {args[i + 1]!r}")
|
|
120
|
+
i += 2
|
|
121
|
+
elif a == "--level" and i + 1 < len(args):
|
|
122
|
+
# Audit 2026-10-05 (volcengine/OpenViking tiered-loader
|
|
123
|
+
# pattern) — 0 = L0 abstract ladder rung, 1 = L1 default,
|
|
124
|
+
# 2 = L2 full body.
|
|
125
|
+
try:
|
|
126
|
+
level = int(args[i + 1])
|
|
127
|
+
if level not in (0, 1, 2):
|
|
128
|
+
return die("--level must be 0, 1, or 2")
|
|
129
|
+
except ValueError:
|
|
130
|
+
return die(f"--level must be 0, 1, or 2, got {args[i + 1]!r}")
|
|
131
|
+
i += 2
|
|
107
132
|
elif a == "--limit" and i + 1 < len(args):
|
|
108
133
|
try:
|
|
109
134
|
limit = int(args[i + 1])
|
|
@@ -116,18 +141,20 @@ def run_recall(args) -> int:
|
|
|
116
141
|
qargs.append(a)
|
|
117
142
|
i += 1
|
|
118
143
|
if not qargs:
|
|
119
|
-
return die("usage: loop-memory recall <query> [--verbose] [--outline] [--as-of <ISO|epoch>] [--limit N]")
|
|
144
|
+
return die("usage: loop-memory recall <query> [--verbose] [--outline] [--as-of <ISO|epoch>] [--limit N] [--max-chars N] [--level 0|1|2]")
|
|
120
145
|
store = MemoryStore(default_db_path())
|
|
121
146
|
query = " ".join(qargs)
|
|
122
147
|
if as_of is not None:
|
|
123
148
|
try:
|
|
124
|
-
r = store.recall_as_of(query, as_of, limit=limit
|
|
149
|
+
r = store.recall_as_of(query, as_of, limit=limit,
|
|
150
|
+
max_chars=max_chars, level=level)
|
|
125
151
|
except ValueError as e:
|
|
126
152
|
return die(str(e))
|
|
127
153
|
elif outline:
|
|
128
|
-
r = store.recall_paths(query, limit=limit)
|
|
154
|
+
r = store.recall_paths(query, limit=limit, max_chars=max_chars)
|
|
129
155
|
else:
|
|
130
|
-
r = store.recall(query, limit=limit
|
|
156
|
+
r = store.recall(query, limit=limit,
|
|
157
|
+
max_chars=max_chars, level=level)
|
|
131
158
|
has = False
|
|
132
159
|
if r["wiki"]:
|
|
133
160
|
has = True
|
|
@@ -458,6 +485,7 @@ def run_recall_paths(args) -> int:
|
|
|
458
485
|
if not args:
|
|
459
486
|
return die("usage: loop-memory recall-paths <query> [--limit N]")
|
|
460
487
|
limit = 12
|
|
488
|
+
max_chars: int | None = None
|
|
461
489
|
qargs: list[str] = []
|
|
462
490
|
i = 0
|
|
463
491
|
while i < len(args):
|
|
@@ -468,16 +496,25 @@ def run_recall_paths(args) -> int:
|
|
|
468
496
|
except ValueError:
|
|
469
497
|
return die(f"--limit must be an integer, got {args[i + 1]!r}")
|
|
470
498
|
i += 2
|
|
499
|
+
elif a == "--max-chars" and i + 1 < len(args):
|
|
500
|
+
# Audit 2026-10-05 — cap the abstract chip-stream size.
|
|
501
|
+
try:
|
|
502
|
+
max_chars = int(args[i + 1])
|
|
503
|
+
if max_chars <= 0:
|
|
504
|
+
max_chars = None
|
|
505
|
+
except ValueError:
|
|
506
|
+
return die(f"--max-chars must be an integer, got {args[i + 1]!r}")
|
|
507
|
+
i += 2
|
|
471
508
|
elif a.startswith("--"):
|
|
472
509
|
return die(f"unknown flag: {a}")
|
|
473
510
|
else:
|
|
474
511
|
qargs.append(a)
|
|
475
512
|
i += 1
|
|
476
513
|
if not qargs:
|
|
477
|
-
return die("usage: loop-memory recall-paths <query> [--limit N]")
|
|
514
|
+
return die("usage: loop-memory recall-paths <query> [--limit N] [--max-chars N]")
|
|
478
515
|
store = MemoryStore(default_db_path())
|
|
479
516
|
query = " ".join(qargs)
|
|
480
|
-
r = store.recall_paths(query, limit=limit)
|
|
517
|
+
r = store.recall_paths(query, limit=limit, max_chars=max_chars)
|
|
481
518
|
has = False
|
|
482
519
|
if r["memories"]:
|
|
483
520
|
has = True
|
|
@@ -149,7 +149,7 @@ COMMAND_HELP: dict[str, str] = {
|
|
|
149
149
|
"consolidate": "loop-memory consolidate # rescore + GC + dedupe.",
|
|
150
150
|
"consolidate-now": "loop-memory consolidate-now # ask the running server to trigger a pass right now.",
|
|
151
151
|
"digest": "loop-memory digest [--out PATH] # compact knowledge digest for AGENTS.md.",
|
|
152
|
-
"doctor": "loop-memory doctor #
|
|
152
|
+
"doctor": "loop-memory doctor [--json] [--verbose] [--fix] [--db PATH] # deep store-health check (db integrity + audit triggers + hooks + version + wiki orphans). Auto-repair with --fix (audit 2026-10-12; pattern adopted from cortexkit/magic-context + dsh-memento).",
|
|
153
153
|
"export": "loop-memory export [--out FILE | <out_dir>] # markdown dump or v7 bundle export.",
|
|
154
154
|
"export-bundle": "loop-memory export-bundle <out_dir> # explicit v7 bundle alias.",
|
|
155
155
|
"flush": "loop-memory flush # drop volatile caches; keep persisted data.",
|
|
@@ -164,7 +164,7 @@ COMMAND_HELP: dict[str, str] = {
|
|
|
164
164
|
"install-hooks": "loop-memory install-hooks # auto-write MCP + SessionStart hooks for known clients.",
|
|
165
165
|
"mcp": "loop-memory mcp # stdio MCP server (for codex/claude/hermes). Requires ``[serve]`` for HTTP transport.",
|
|
166
166
|
"openclaw-setup": "loop-memory openclaw-setup # install the openclaw/clawx auto-ingest watcher (launchd on macOS).",
|
|
167
|
-
"recall": "loop-memory recall <text> [--as-of <ISO|epoch>] # show top memories (--as-of = bi-temporal recall).",
|
|
167
|
+
"recall": "loop-memory recall <text> [--as-of <ISO|epoch>] [--max-chars N] [--level 0|1|2] # show top memories (--as-of = bi-temporal recall; --max-chars = total payload cap; --level 0 = L0 abstract ladder rung; audit 2026-10-05).",
|
|
168
168
|
"rescore": "loop-memory rescore [--half-life 30] # recompute memory scores.",
|
|
169
169
|
"serve": "loop-memory serve [--port 7767] [--no-browser] # start the local web UI. Requires the ``[serve]`` extra (fastapi + uvicorn).",
|
|
170
170
|
"stats": "loop-memory stats # counters.",
|
|
@@ -178,7 +178,7 @@ COMMAND_HELP: dict[str, str] = {
|
|
|
178
178
|
"import-okf": "loop-memory import-okf <in_dir> [--scope S] [--dry-run] [--skip-conflicts] # ingest an OKF v0.2 bundle as wiki pages (audit 2026-09-27).",
|
|
179
179
|
"restore": "loop-memory restore <in.memory.sqlite> # re-hydrate a portable SQLite snapshot.",
|
|
180
180
|
# Audit 2026-09-13 — L0 outline recall (tigerless-labs/agent-memory v0.3.0).
|
|
181
|
-
"recall-paths": "loop-memory recall-paths <query> [--limit N] # cheap L0 outline (id+abstract+score) instead of full text (audit 2026-09-13).",
|
|
181
|
+
"recall-paths": "loop-memory recall-paths <query> [--limit N] [--max-chars N] # cheap L0 outline (id+abstract+score) instead of full text (audit 2026-09-13; --max-chars caps the chip stream, audit 2026-10-05).",
|
|
182
182
|
# Audit 2026-09-13 — per-agent identity bootstrap (Mem0 CLI init --agent pattern).
|
|
183
183
|
"init": "loop-memory init --agent <name> [--install-hooks] # register an agent + (optionally) install hooks.",
|
|
184
184
|
"rules": "loop-memory rules [--agent codex|claude|hermes|openclaw] [--write] [--force]\n Print, or append into the agent's rule file, the three-phase memory discipline (task start / mid-task / wrap-up). Never overwrites user content.",
|