levh 2.26.8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- levh-2.26.8.dist-info/METADATA +677 -0
- levh-2.26.8.dist-info/RECORD +178 -0
- levh-2.26.8.dist-info/WHEEL +5 -0
- levh-2.26.8.dist-info/entry_points.txt +2 -0
- levh-2.26.8.dist-info/licenses/LICENSE +21 -0
- levh-2.26.8.dist-info/top_level.txt +1 -0
- server/__init__.py +1 -0
- server/api.py +1475 -0
- server/cli.py +1666 -0
- server/configs.py +210 -0
- server/connectors/__init__.py +82 -0
- server/connectors/base.py +58 -0
- server/connectors/calendar.py +269 -0
- server/connectors/email_connector.py +274 -0
- server/connectors/github.py +307 -0
- server/connectors/local_files.py +275 -0
- server/connectors/notion.py +343 -0
- server/connectors/obsidian.py +194 -0
- server/connectors/transcript.py +204 -0
- server/core/__init__.py +1 -0
- server/core/admission.py +142 -0
- server/core/answerer.py +111 -0
- server/core/backup.py +76 -0
- server/core/benchmark.py +113 -0
- server/core/conflict.py +137 -0
- server/core/conflict_service.py +203 -0
- server/core/crypto.py +104 -0
- server/core/database.py +1145 -0
- server/core/demo_data.py +287 -0
- server/core/dogfood.py +287 -0
- server/core/embedder.py +209 -0
- server/core/engine_provider.py +41 -0
- server/core/entities.py +123 -0
- server/core/entity_index_service.py +112 -0
- server/core/episodic.py +65 -0
- server/core/evaluation.py +374 -0
- server/core/hscore.py +227 -0
- server/core/memory_engine.py +2542 -0
- server/core/onboarding.py +222 -0
- server/core/organizations.py +180 -0
- server/core/people.py +145 -0
- server/core/rate_limit.py +41 -0
- server/core/runtime_config.py +179 -0
- server/core/short_term.py +51 -0
- server/core/summarizer.py +98 -0
- server/core/trust.py +245 -0
- server/core/trust_service.py +202 -0
- server/core/types.py +126 -0
- server/core/vector_store.py +99 -0
- server/dashboard/.gitkeep +0 -0
- server/dashboard/404/index.html +1 -0
- server/dashboard/404.html +1 -0
- server/dashboard/_next/static/EZcdmRBfcJ0DYaaVxZUoA/_buildManifest.js +1 -0
- server/dashboard/_next/static/EZcdmRBfcJ0DYaaVxZUoA/_ssgManifest.js +1 -0
- server/dashboard/_next/static/chunks/172-374e517eabaafcd5.js +1 -0
- server/dashboard/_next/static/chunks/248-0c9b0a583e391364.js +1 -0
- server/dashboard/_next/static/chunks/255-d19a68d5cdf61c74.js +1 -0
- server/dashboard/_next/static/chunks/344-3be46b3334d4bc18.js +1 -0
- server/dashboard/_next/static/chunks/354-9411c560837c5643.js +1 -0
- server/dashboard/_next/static/chunks/356-5550b6a9746410aa.js +1 -0
- server/dashboard/_next/static/chunks/4bd1b696-409494caf8c83275.js +1 -0
- server/dashboard/_next/static/chunks/546-53d4e5ffa0741b01.js +1 -0
- server/dashboard/_next/static/chunks/558-9f3c6f8ed16a6154.js +1 -0
- server/dashboard/_next/static/chunks/619-f072ac750404f9da.js +1 -0
- server/dashboard/_next/static/chunks/710-d525d6a7457e5361.js +1 -0
- server/dashboard/_next/static/chunks/850-f246cebe0acecdde.js +1 -0
- server/dashboard/_next/static/chunks/993-0d39fec9aa3922aa.js +1 -0
- server/dashboard/_next/static/chunks/app/_not-found/page-bb8623766fc272ad.js +1 -0
- server/dashboard/_next/static/chunks/app/briefing/page-431da3d802906b86.js +1 -0
- server/dashboard/_next/static/chunks/app/conflicts/page-f310caecd3370eab.js +1 -0
- server/dashboard/_next/static/chunks/app/decisions/page-506a20f430b2d7e1.js +1 -0
- server/dashboard/_next/static/chunks/app/graph/page-9342ca8482acab35.js +1 -0
- server/dashboard/_next/static/chunks/app/layout-0887bec82bd4e181.js +1 -0
- server/dashboard/_next/static/chunks/app/meeting-prep/page-960d2dddc5228bdf.js +1 -0
- server/dashboard/_next/static/chunks/app/memories/page-14785c77921a05f7.js +1 -0
- server/dashboard/_next/static/chunks/app/organizations/page-530f19e026dfd476.js +1 -0
- server/dashboard/_next/static/chunks/app/page-9070d4eaaebc7f50.js +1 -0
- server/dashboard/_next/static/chunks/app/people/page-35fc9df360827250.js +1 -0
- server/dashboard/_next/static/chunks/app/projects/page-c084863047d2a1a6.js +1 -0
- server/dashboard/_next/static/chunks/app/review/page-2f2ac3f22a8e3698.js +1 -0
- server/dashboard/_next/static/chunks/app/sessions/page-efdac681166a9439.js +1 -0
- server/dashboard/_next/static/chunks/app/settings/page-8c0c28a283f49875.js +1 -0
- server/dashboard/_next/static/chunks/app/timeline/page-9436e6fa22ee3645.js +1 -0
- server/dashboard/_next/static/chunks/app/visualize/page-0d25c2374a0b6fce.js +1 -0
- server/dashboard/_next/static/chunks/framework-f52ebcb9f26a1e11.js +1 -0
- server/dashboard/_next/static/chunks/main-875cb23dc0a1f18e.js +1 -0
- server/dashboard/_next/static/chunks/main-app-181ccbd6eeeceb1e.js +1 -0
- server/dashboard/_next/static/chunks/pages/_app-5addca2b3b969fde.js +1 -0
- server/dashboard/_next/static/chunks/pages/_error-022e4ac7bbb9914f.js +1 -0
- server/dashboard/_next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
- server/dashboard/_next/static/chunks/webpack-681601bcc1224fcd.js +1 -0
- server/dashboard/_next/static/css/809d4951adcd5b63.css +3 -0
- server/dashboard/brand/levh-mark.png +0 -0
- server/dashboard/briefing/index.html +1 -0
- server/dashboard/briefing/index.txt +24 -0
- server/dashboard/conflicts/index.html +1 -0
- server/dashboard/conflicts/index.txt +24 -0
- server/dashboard/decisions/index.html +1 -0
- server/dashboard/decisions/index.txt +24 -0
- server/dashboard/graph/index.html +1 -0
- server/dashboard/graph/index.txt +24 -0
- server/dashboard/icon.svg +9 -0
- server/dashboard/index.html +1 -0
- server/dashboard/index.txt +24 -0
- server/dashboard/meeting-prep/index.html +1 -0
- server/dashboard/meeting-prep/index.txt +24 -0
- server/dashboard/memories/index.html +1 -0
- server/dashboard/memories/index.txt +24 -0
- server/dashboard/organizations/index.html +1 -0
- server/dashboard/organizations/index.txt +24 -0
- server/dashboard/people/index.html +1 -0
- server/dashboard/people/index.txt +24 -0
- server/dashboard/projects/index.html +1 -0
- server/dashboard/projects/index.txt +24 -0
- server/dashboard/review/index.html +1 -0
- server/dashboard/review/index.txt +24 -0
- server/dashboard/sessions/index.html +1 -0
- server/dashboard/sessions/index.txt +24 -0
- server/dashboard/settings/index.html +1 -0
- server/dashboard/settings/index.txt +24 -0
- server/dashboard/timeline/index.html +1 -0
- server/dashboard/timeline/index.txt +24 -0
- server/dashboard/visualize/index.html +1 -0
- server/dashboard/visualize/index.txt +24 -0
- server/fixtures/__init__.py +0 -0
- server/fixtures/evaluation/01_project_decision_superseded.json +30 -0
- server/fixtures/evaluation/02_meeting_deadline_changed.json +31 -0
- server/fixtures/evaluation/03_same_fact_independent_sources.json +41 -0
- server/fixtures/evaluation/04_same_source_duplicate.json +24 -0
- server/fixtures/evaluation/05_low_trust_imported_text.json +19 -0
- server/fixtures/evaluation/06_confirmed_human_memory.json +31 -0
- server/fixtures/evaluation/07_fading_important_memory.json +35 -0
- server/fixtures/evaluation/08_redacted_secret.json +18 -0
- server/fixtures/evaluation/09_conflict_false_positive_guard.json +28 -0
- server/mcp_sse.py +55 -0
- server/mcp_stdio.py +71 -0
- server/routes/__init__.py +1 -0
- server/tools/__init__.py +1 -0
- server/tools/admission.py +74 -0
- server/tools/ask.py +52 -0
- server/tools/backup.py +87 -0
- server/tools/briefing.py +57 -0
- server/tools/clear_short_term.py +19 -0
- server/tools/conflicts.py +90 -0
- server/tools/connector_sync.py +86 -0
- server/tools/connectors.py +126 -0
- server/tools/consolidate.py +25 -0
- server/tools/consolidate_memories.py +56 -0
- server/tools/context_file.py +31 -0
- server/tools/decisions.py +37 -0
- server/tools/dedupe.py +50 -0
- server/tools/entities.py +80 -0
- server/tools/export_import.py +43 -0
- server/tools/feedback.py +74 -0
- server/tools/forget.py +30 -0
- server/tools/get_context.py +35 -0
- server/tools/list_memories.py +55 -0
- server/tools/meeting_prep.py +61 -0
- server/tools/organizations.py +78 -0
- server/tools/people.py +69 -0
- server/tools/pin.py +42 -0
- server/tools/privacy.py +72 -0
- server/tools/profiles.py +137 -0
- server/tools/projects.py +42 -0
- server/tools/recall.py +49 -0
- server/tools/register.py +143 -0
- server/tools/reinforce.py +35 -0
- server/tools/related.py +28 -0
- server/tools/review.py +80 -0
- server/tools/search.py +41 -0
- server/tools/session.py +48 -0
- server/tools/set_importance.py +23 -0
- server/tools/stats.py +26 -0
- server/tools/store.py +65 -0
- server/tools/summarize.py +27 -0
- server/tools/timeline.py +34 -0
- server/tools/trust.py +72 -0
- server/tools/update.py +48 -0
|
@@ -0,0 +1,677 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: levh
|
|
3
|
+
Version: 2.26.8
|
|
4
|
+
Summary: Shared memory layer for AI coding tools — memory that forgets like you do, unless it matters
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Project-URL: Homepage, https://github.com/agiulucom42-del/stackmemory-new
|
|
7
|
+
Project-URL: Repository, https://github.com/agiulucom42-del/stackmemory-new
|
|
8
|
+
Keywords: mcp,memory,ai,claude,cursor,llm,forgetting-curve,spaced-repetition
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
15
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
16
|
+
Requires-Python: >=3.11
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Requires-Dist: fastapi>=0.115
|
|
20
|
+
Requires-Dist: uvicorn>=0.30
|
|
21
|
+
Requires-Dist: aiosqlite>=0.20
|
|
22
|
+
Requires-Dist: numpy>=2.0
|
|
23
|
+
Requires-Dist: mcp>=1.0
|
|
24
|
+
Requires-Dist: fastmcp>=2.0
|
|
25
|
+
Requires-Dist: python-dotenv>=1.0
|
|
26
|
+
Requires-Dist: httpx>=0.27
|
|
27
|
+
Requires-Dist: cryptography>=42
|
|
28
|
+
Provides-Extra: local
|
|
29
|
+
Requires-Dist: sentence-transformers>=3.0; extra == "local"
|
|
30
|
+
Requires-Dist: transformers>=4.40; extra == "local"
|
|
31
|
+
Requires-Dist: torch>=2.0; extra == "local"
|
|
32
|
+
Provides-Extra: openai
|
|
33
|
+
Provides-Extra: secure
|
|
34
|
+
Requires-Dist: cryptography>=42; extra == "secure"
|
|
35
|
+
Provides-Extra: dev
|
|
36
|
+
Requires-Dist: pytest; extra == "dev"
|
|
37
|
+
Requires-Dist: pytest-asyncio; extra == "dev"
|
|
38
|
+
Requires-Dist: build; extra == "dev"
|
|
39
|
+
Requires-Dist: twine; extra == "dev"
|
|
40
|
+
Dynamic: license-file
|
|
41
|
+
|
|
42
|
+
# LEVH
|
|
43
|
+
|
|
44
|
+
> **Brand transition:** LEVH is the product name. The PyPI package will be published as `levh`. The CLI command, environment variables, and database format remain `stackmemory` in this release for compatibility.
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
<p align="center">
|
|
48
|
+
<strong>StackMemory</strong><br>
|
|
49
|
+
Shared Memory Layer for AI Coding Workflows<br>
|
|
50
|
+
<em>Memory that forgets like you do — unless it matters.</em>
|
|
51
|
+
</p>
|
|
52
|
+
|
|
53
|
+
<p align="center">
|
|
54
|
+
<img src="https://img.shields.io/badge/MCP-Protocol-blue?logo=anthropic" alt="MCP">
|
|
55
|
+
<img src="https://img.shields.io/badge/Claude-Desktop%20%7C%20Code-7c3aed?logo=claude" alt="Claude">
|
|
56
|
+
<img src="https://img.shields.io/badge/Cursor-IDE-000?logo=cursor" alt="Cursor">
|
|
57
|
+
<img src="https://img.shields.io/badge/VS%20Code-Extension-007acc?logo=visualstudiocode" alt="VS Code">
|
|
58
|
+
<img src="https://img.shields.io/badge/SQLite-Embedded-003b57?logo=sqlite" alt="SQLite">
|
|
59
|
+
<img src="https://img.shields.io/badge/Python-3.11%2B-3776ab?logo=python" alt="Python">
|
|
60
|
+
<img src="https://img.shields.io/badge/License-MIT-green" alt="License">
|
|
61
|
+
</p>
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## What is StackMemory?
|
|
66
|
+
|
|
67
|
+
StackMemory gives your AI coding agents a **persistent, searchable memory** across sessions, projects, and tools. Instead of starting from scratch every time, your AI remembers what you discussed, decisions you made, and context from every workspace.
|
|
68
|
+
|
|
69
|
+
Most memory tools optimize for **perfect recall** — store everything, retrieve everything, let noise pile up forever. StackMemory instead models memory the way **human memory actually works**: every memory has its own decay curve; unused memories fade; memories you actually rely on get reinforced and become durable, automatically, with no manual curation. Signal rises to the top on its own.
|
|
70
|
+
|
|
71
|
+
It works as an **MCP (Model Context Protocol) server** — plug it into Claude Desktop, Cursor, Claude Code, VS Code (Cline), Windsurf, or any MCP-compatible client. It also exposes a **REST API + WebSocket** for custom integrations and ships with a built-in **dashboard** with a real-time activity feed.
|
|
72
|
+
|
|
73
|
+
**Key insight**: Your AI tools (Claude, Cursor, Copilot) are stateless. StackMemory makes them stateful — and self-curating.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## The memory model
|
|
78
|
+
|
|
79
|
+
This is the core mechanic, not a footnote:
|
|
80
|
+
|
|
81
|
+
- **Every memory has its own half-life.** New memories start at a default (168h) — like short-term memory, they fade fast unless something happens.
|
|
82
|
+
- **Recalling a memory resets its clock and reinforces it.** Each time a memory is retrieved (or explicitly reinforced), its half-life grows — modeled on spaced repetition / the testing effect, the same mechanism flashcard apps like Anki use to build long-term retention.
|
|
83
|
+
- **Importance accelerates consolidation**, like emotional salience in human memory: a `0.9`-importance memory becomes durable much faster per recall than a `0.1` one.
|
|
84
|
+
- **Outcome feedback closes the loop.** `memory_feedback(helpful=false)` cuts a memory's stability so wrong or stale information fades out fast instead of resurfacing; `helpful=true` reinforces it. Your AI can call this whenever you correct it.
|
|
85
|
+
- **New information interferes with old.** Storing a memory near-identical to an existing one weakens the older version (retroactive interference) — "the deploy branch is prod" naturally supersedes "the deploy branch is main" without anyone deleting anything.
|
|
86
|
+
- **Pinning is permanent encoding** — for rules and facts that must never be forgotten, skip decay entirely. Pinned memories are also immune to interference and never auto-deduped.
|
|
87
|
+
- **Fading memories surface for review.** The dashboard (and the `list_fading_memories` tool) shows memories whose predicted retention has dropped below 35% — rescue what still matters with one click, let the rest go.
|
|
88
|
+
- Every memory's curve is visible in the dashboard: open any memory to see its predicted retention over the next 30 days, its current strength, and one-click **Reinforce** / **Stale** actions.
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
retention(t) = 0.5 ^ (hours_since_last_recall / stability_hours)
|
|
92
|
+
stability_hours(after recall) = min(stability × (1 + gain·(0.5+importance)), max_stability)
|
|
93
|
+
stability_hours(negative feedback) = max(stability × weaken_factor, 1h)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Features
|
|
99
|
+
|
|
100
|
+
- **Adaptive memory decay**: per-memory half-life, reinforced by recall, weakened by negative feedback and interference, visualized as a forgetting curve — see [The memory model](#the-memory-model)
|
|
101
|
+
- **3-Layer Memory**: ShortTerm (FIFO deque, max 50) → Episodic (SQLite) → Vector Store (NumPy cosine similarity)
|
|
102
|
+
- **H(x,ψ) Scoring**: Multi-factor ranking: `α·(1-similarity) + β·(1-decay) + γ·(1-importance) + δ·(1-frequency)` — every weight env-configurable, every score explainable in the UI
|
|
103
|
+
- **Ask your memory**: `ask_memory` / `POST /api/ask` / dashboard "Ask" panel — a natural-language question returns a synthesized answer that **cites the exact memories** it drew from (with dates). LLM-powered when `OPENAI_API_KEY` is set, deterministic ranked-evidence fallback offline. Read-only: asking never reinforces memories.
|
|
104
|
+
- **People graph**: everyone you interact with, extracted automatically from calendar attendees, email senders/recipients, and transcript speakers — `/api/people`, `list_people`/`about_person` MCP tools, and a dashboard **People** page ("what do I know about X?"). No manual tagging.
|
|
105
|
+
- **Timeline**: episodic memories grouped by the day they actually happened — "what happened this/last week" — `/api/timeline`, the `timeline` MCP tool, and a dashboard **Timeline** page.
|
|
106
|
+
- **Daily Briefing**: memory as an active assistant — today's events, open commitments detected from your own words ("I'll send…", "yapacağım…"), and what you may be forgetting. Fully offline/deterministic (no LLM key). `/api/briefing`, the `briefing` MCP tool, and a dashboard **Briefing** page.
|
|
107
|
+
- **Organizations**: the people graph rolled up by email domain — the companies you actually interact with, who from them, and how often. Personal email providers excluded. `/api/organizations`, `list_organizations`/`about_organization` MCP tools, and a dashboard **Organizations** page.
|
|
108
|
+
- **Decisions**: decision statements detected from memory content ("we decided", "agreed to", "karar verdik") — what was decided, and when/where. Deterministic, no LLM. `/api/decisions`, the `list_decisions` MCP tool, and a dashboard **Decisions** page.
|
|
109
|
+
- **Encrypted Backup & Restore**: full portable snapshot (every memory *with its decay state* + every session), optionally encrypted at rest with a passphrase (PBKDF2 + Fernet/AES). `/api/backup` + `/api/restore`, `create_backup`/`restore_backup` MCP tools, and a Settings → **Backup & Restore** panel with merge/replace.
|
|
110
|
+
- **Meeting Prep**: the proactive "before you walk in" brief — your next meeting, who's attending, what you last discussed with each of them, plus relevant open commitments and decisions. Deterministic, offline. `/api/meeting-prep`, the `meeting_prep` MCP tool, and a dashboard **Meeting Prep** page.
|
|
111
|
+
- **Memory Consolidation**: sleep-like compression — clusters of related, aged, unpinned memories collapse into one durable summary each (the raw episodes archived inside it, not lost). `/api/memories/consolidate-similar`, the `consolidate_similar` MCP tool, and Settings → Data Management buttons.
|
|
112
|
+
- **Spaced-Repetition Review**: the fading queue as an active review flow — keep / reinforce / weaken / pin / snooze / forget each memory losing strength, every decision recorded in its history. Closes the lifecycle loop. `/api/memories/review`, `list_review_memories`/`review_memory` MCP tools, `stackmemory review` CLI, and a dashboard **Review** page.
|
|
113
|
+
- **Memory Admission Gate**: decides what happens to an incoming memory *before* it's stored — admit / review / reject (duplicates) / redact (strips secrets like API keys & passwords; keeps emails). Deterministic, offline. `/api/memories/admit` + `/api/memories/evaluate-admission`, `admit_memory`/`evaluate_admission` MCP tools, `stackmemory admit` CLI, and a Settings preview card.
|
|
114
|
+
- **Connector Framework v2**: gate-integrated, incremental ingest — every fetched item is routed through the admission gate (dedupe + secret redaction) with per-item error isolation, and each run is recorded so re-syncing is incremental and reportable. `/api/connectors/sync` + `/api/connectors/sync-state`, `sync_connector`/`connector_sync_status` MCP tools, `stackmemory sync` CLI, and a Settings gate toggle + sync history.
|
|
115
|
+
- **Hard-delete Audit & Redaction**: deletes a memory from the tracked primary stores and reports any detected residue (`purge_memory`), and finds + strips secrets stored before the gate existed (`audit_secrets` / `redact_secrets`, logged to each memory's redaction history). Full derived-state cascade is verified by the 2.26.x privacy-hardening gates before public RC. `/api/memories/audit-secrets` + `/redact-all` + `/{id}/redact` + `/{id}/purge`, matching MCP tools, `stackmemory audit-secrets`/`redact-secrets`/`purge` CLI, and a Settings **Privacy & Redaction** card.
|
|
116
|
+
- **Entity Knowledge Graph**: memories indexed into persistent `entities` + `memory_entities` tables — person / organization / event / document / task — so "which memories mention X" and "which entities co-occur with X" are real joins. `/api/entities` (reindex / stats / list / detail), `reindex_entities`/`list_entities`/`about_entity` MCP tools, `stackmemory entities` CLI, and a dashboard **Graph** page.
|
|
117
|
+
- **Provenance / Trust Score**: a deterministic, explainable *reliability* signal per memory — source type + entity-graph corroboration (how many independent sources back it) + review lifecycle + recency − risk flags → a `confidence` with a label and a human-readable breakdown. Separate from the H-score; never changes recall ranking; not a "truth" claim. `/api/memories/{id}/trust` + `/trust/recompute` + `/low-trust`, `memory_trust`/`recompute_trust_scores`/`list_low_trust_memories` MCP tools, `stackmemory trust` CLI, and a Settings **Trust & provenance** card.
|
|
118
|
+
- **Conflict Candidates**: deterministic flagging of memories that *might* disagree (share an entity + an opposing surface pattern: antonym / negation / same-attribute-different-value) — a **review signal, never a verdict**, never auto-deletes; an open candidate adds a small risk to the trust score. Not LLM contradiction detection. `/api/conflicts` (detect / list / review), `detect_conflict_candidates`/`list_conflict_candidates`/`review_conflict_candidate` MCP tools, `stackmemory conflicts` CLI, and a dashboard **Conflicts** page.
|
|
119
|
+
- **59 MCP Tools**: Store, admit, evaluate-admission, recall, ask, forget, purge, audit-secrets, redact-secrets, search, update, list, stats, consolidate, consolidate-similar, sessions, export/import, backup/restore, connectors, connector-sync, pinning, reinforcement, feedback, fading review, spaced-repetition review, projects, people, organizations, decisions, timeline, briefing, meeting prep, context files, dedupe, related memories, session summarization
|
|
120
|
+
- **Auto-Capture Summaries**: `summarize_session` distills a session's memories into one durable memory — LLM-powered when `OPENAI_API_KEY` is set, deterministic offline fallback otherwise; can run automatically on `end_session` (`AUTO_SUMMARIZE_SESSIONS=true`)
|
|
121
|
+
- **Related Memories**: live nearest-neighbour "see also" for any memory, computed from embedding similarity — no manual linking, no extra schema
|
|
122
|
+
- **Recall Quality Benchmark**: `stackmemory benchmark` / Settings panel reports hit@1/hit@3/hit@5/MRR on a labelled query set, so recall quality is measurable, not just claimed
|
|
123
|
+
- **Project Memory**: Namespace memories per repo/workspace; filter recall by project
|
|
124
|
+
- **Source Tracking**: Know which AI client (claude-code, cursor, ...) stored each memory
|
|
125
|
+
- **Pinned Memories**: Rules and decisions that never decay and always surface
|
|
126
|
+
- **Context File Generation**: Compile memories into `CLAUDE.md` / `.cursorrules` so every session starts pre-loaded — from the UI, the CLI, or an MCP tool
|
|
127
|
+
- **Auto-Capture**: `stackmemory hook install` captures every git commit message as a memory; `stackmemory capture` for one-liners (auto-detects your repo as the project)
|
|
128
|
+
- **4 Embedding Modes**: OpenAI `text-embedding-3-small`, local `all-MiniLM-L6-v2`, **Ollama** (fully offline), or deterministic hash fallback — the system always works
|
|
129
|
+
- **App Connectors**: Import from Calendar (.ics), Email (.mbox/.eml), Meeting transcripts (.vtt/.srt), Notion, Obsidian, GitHub repos, local files
|
|
130
|
+
- **Live Dashboard**: Next.js dashboard served by the API itself (one process, one port) with a real-time WebSocket activity feed, semantic search, insights charts, and full memory management
|
|
131
|
+
- **Zero Infrastructure**: SQLite (no MongoDB, no Redis, no external services); old v1 databases migrate automatically
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Quick Start
|
|
136
|
+
|
|
137
|
+
### 1. Install
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
git clone https://github.com/ali-ulu/levh.git
|
|
141
|
+
cd levh
|
|
142
|
+
pip install -e ".[dev]"
|
|
143
|
+
# PyPI package coming soon — until published, install from source with: pip install -e .
|
|
144
|
+
pip install levh
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### 2. Configure
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
cp .env.example .env
|
|
151
|
+
# Defaults work out of the box; set EMBEDDER_MODE=local for semantic search
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### First run: choose demo or real data
|
|
155
|
+
|
|
156
|
+
**Try the demo**
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
# PyPI package coming soon — until published, install from source with: pip install -e .
|
|
160
|
+
pip install levh
|
|
161
|
+
stackmemory setup --demo --client claude --profile work
|
|
162
|
+
stackmemory serve
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
**Start with real data**
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
# PyPI package coming soon — until published, install from source with: pip install -e .
|
|
169
|
+
pip install levh
|
|
170
|
+
stackmemory setup --real --client claude --profile work
|
|
171
|
+
stackmemory capture "Atlas uses PostgreSQL in production."
|
|
172
|
+
stackmemory serve
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
The first-run dashboard offers the same two paths, shows real readiness state,
|
|
176
|
+
generates focused MCP configs, and explains the local/off-by-default dogfood
|
|
177
|
+
measurement. See [Getting Started](docs/getting-started.md) and the
|
|
178
|
+
[5-minute demo](docs/demo/5-minute-demo.md).
|
|
179
|
+
|
|
180
|
+
### 3. Run
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
stackmemory serve # or: uvicorn server.api:app --port 8000
|
|
184
|
+
# Dashboard + API on http://localhost:8000
|
|
185
|
+
# MCP SSE stream endpoint: http://localhost:8000/api/mcp/sse
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
The dashboard is served by the API. Source checkouts serve `frontend/out/`; built
|
|
189
|
+
wheels include a packaged static export under `server/dashboard/`. To rebuild the
|
|
190
|
+
dashboard after changes: `cd frontend && npm ci && npm run build`.
|
|
191
|
+
|
|
192
|
+
### Try it in 5 minutes
|
|
193
|
+
|
|
194
|
+
Empty store? Load a deterministic demo corpus — 4 people, 2 organizations, a few
|
|
195
|
+
decisions and tasks, meetings, and one real conflict candidate — so every view has
|
|
196
|
+
something to show:
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
stackmemory seed-demo # or click "Load demo data" on the empty dashboard
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Then open the dashboard and explore **Briefing** (daily digest), **Meeting Prep**
|
|
203
|
+
(who/what before a call), **Conflicts** (review the disputed Atlas deadline), and
|
|
204
|
+
**Insights** (watch low-importance memories fade while pinned ones persist). The
|
|
205
|
+
seed refuses to touch a non-empty store unless you pass `--force`.
|
|
206
|
+
|
|
207
|
+
### 4. Connect Your AI Client
|
|
208
|
+
|
|
209
|
+
Open **Settings** in the dashboard for copy-paste MCP configs, or see
|
|
210
|
+
[Platform Setup](#platform-setup) below.
|
|
211
|
+
|
|
212
|
+
### 5. (Optional) Auto-capture your work
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
stackmemory hook install # capture every git commit message
|
|
216
|
+
stackmemory capture "we use pnpm, not npm" --pin
|
|
217
|
+
stackmemory context -o CLAUDE.md # compile memory into a context file
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## Platform Setup
|
|
223
|
+
|
|
224
|
+
All clients use the same stdio server. Generate any config with
|
|
225
|
+
`stackmemory mcp config <claude|claude_code|cursor|windsurf|vscode|cline>`.
|
|
226
|
+
|
|
227
|
+
### Claude Desktop
|
|
228
|
+
|
|
229
|
+
Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
|
|
230
|
+
|
|
231
|
+
```json
|
|
232
|
+
{
|
|
233
|
+
"mcpServers": {
|
|
234
|
+
"stackmemory": {
|
|
235
|
+
"command": "python",
|
|
236
|
+
"args": ["-m", "server.mcp_stdio"],
|
|
237
|
+
"cwd": "/path/to/stackmemory-new",
|
|
238
|
+
"env": {
|
|
239
|
+
"EMBEDDER_MODE": "local"
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Cursor IDE
|
|
247
|
+
|
|
248
|
+
Same server block in `.cursor/mcp.json` in your project root.
|
|
249
|
+
|
|
250
|
+
### Claude Code (CLI)
|
|
251
|
+
|
|
252
|
+
Same server block in `~/.claude.json`.
|
|
253
|
+
|
|
254
|
+
### VS Code (Cline Extension)
|
|
255
|
+
|
|
256
|
+
Same server block (under a `servers` key) in `.vscode/mcp.json`.
|
|
257
|
+
|
|
258
|
+
### Windsurf
|
|
259
|
+
|
|
260
|
+
Same server block in `~/.codeium/windsurf/mcp_config.json`.
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
## Architecture
|
|
265
|
+
|
|
266
|
+
```
|
|
267
|
+
┌─────────────────────────────────────────────┐
|
|
268
|
+
│ StackMemory Server │
|
|
269
|
+
│ │
|
|
270
|
+
Claude Desktop ───┤ ┌─────────┐ ┌──────────┐ ┌──────┐ │
|
|
271
|
+
Cursor IDE ───┤ │ MCP │ │ Memory │ │Embed │ │
|
|
272
|
+
Claude Code ───┤ │ Server ├───▶│ Engine ├───▶│OpenAI│ │
|
|
273
|
+
VS Code/Cline ───┤ │(stdio + │ │ 3-Layer │ │Local │ │
|
|
274
|
+
Windsurf ───┤ │ SSE) │ │ H(x,ψ) │ │Ollama│ │
|
|
275
|
+
│ └─────────┘ └────┬─────┘ └──────┘ │
|
|
276
|
+
REST API ───┤ one shared │ │
|
|
277
|
+
WebSocket ───┤ engine ┌─────▼──────┐ │
|
|
278
|
+
Dashboard (/) ───┤ instance │ SQLite │ │
|
|
279
|
+
│ │ (aiosqlite)│ │
|
|
280
|
+
─────────────────┤ └────────────┘ │
|
|
281
|
+
App Connectors: │ │
|
|
282
|
+
Notion / Obsidian │ import_from_app() → store → recall │
|
|
283
|
+
GitHub / Files ───┤ │
|
|
284
|
+
└─────────────────────────────────────────────┘
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
All transports share **one engine instance** — a memory stored via MCP is
|
|
288
|
+
instantly visible in the dashboard's live feed, and vice versa.
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
## 59 MCP Tools
|
|
293
|
+
|
|
294
|
+
> **Tool profiles.** Advertising all 59 tools to a client hurts tool-selection
|
|
295
|
+
> accuracy, so StackMemory groups them into cumulative profiles —
|
|
296
|
+
> `minimal` (5) ⊂ `work` (15) ⊂ `admin` (54) ⊂ `full` (59). Generated configs
|
|
297
|
+
> default to **`work`**; run `stackmemory mcp profiles` to see the bands, or set
|
|
298
|
+
> `STACKMEMORY_MCP_PROFILE` / `mcp config --profile <name>` to change it. The
|
|
299
|
+
> full table below is the `full` surface. Profiles only filter which tools a
|
|
300
|
+
> client sees — they are **not** an authentication or authorization boundary;
|
|
301
|
+
> every profile talks to the same engine instance with the same access.
|
|
302
|
+
|
|
303
|
+
| # | Tool | Description |
|
|
304
|
+
|---|------|-------------|
|
|
305
|
+
| 1 | `store_memory` | Store a memory with importance, tags, project, source, pin |
|
|
306
|
+
| 2 | `recall_memory` | Recall memories ranked by H(x,ψ) score (filter by session/project) |
|
|
307
|
+
| 3 | `forget_memory` | Delete from all 3 layers |
|
|
308
|
+
| 4 | `search_memory` | Semantic search with detailed results |
|
|
309
|
+
| 5 | `update_memory` | Update content/importance/tags |
|
|
310
|
+
| 6 | `list_memories` | List with type/tag/session/project/source/pinned filters |
|
|
311
|
+
| 7 | `get_memory_stats` | System statistics and metrics |
|
|
312
|
+
| 8 | `consolidate_memories` | Promote short-term → episodic |
|
|
313
|
+
| 9 | `clear_short_term` | Clear the live FIFO deque |
|
|
314
|
+
| 10 | `set_importance` | Set importance (0.0-1.0) |
|
|
315
|
+
| 11 | `get_context` | Build context window (short-term + pinned + important) |
|
|
316
|
+
| 12 | `create_session` | Start a named session |
|
|
317
|
+
| 13 | `end_session` | End session + consolidate its memories |
|
|
318
|
+
| 14 | `export_memories` | Export all memories as JSON |
|
|
319
|
+
| 15 | `import_memories` | Import memories from JSON |
|
|
320
|
+
| 16 | `import_from_app` | Import from Calendar/Email/Transcripts/Notion/Obsidian/GitHub/local files |
|
|
321
|
+
| 17 | `list_connectors` | List available app connectors |
|
|
322
|
+
| 18 | `get_connector_help` | Get config help for a connector |
|
|
323
|
+
| 19 | `pin_memory` | Pin a memory — exempt from decay, always in context files |
|
|
324
|
+
| 20 | `unpin_memory` | Restore normal decay |
|
|
325
|
+
| 21 | `list_projects` | Workspaces with memory counts |
|
|
326
|
+
| 22 | `list_sources` | Which AI clients stored memories |
|
|
327
|
+
| 23 | `generate_context_file` | Compile memories into CLAUDE.md / .cursorrules |
|
|
328
|
+
| 24 | `dedupe_memories` | Find/remove near-duplicates (dry-run by default) |
|
|
329
|
+
| 25 | `reinforce_memory` | Manually strengthen a memory — resets decay clock, grows stability |
|
|
330
|
+
| 26 | `memory_feedback` | helpful=true reinforces; helpful=false makes wrong/stale info fade fast |
|
|
331
|
+
| 27 | `list_fading_memories` | Review queue of memories about to be forgotten |
|
|
332
|
+
| 28 | `related_memories` | Nearest-neighbour "see also" for a memory (live, embedding-based) |
|
|
333
|
+
| 29 | `summarize_session` | Distill a session's memories into one durable summary memory |
|
|
334
|
+
| 30 | `ask_memory` | Ask your memory a question → synthesized, cited answer (read-only) |
|
|
335
|
+
| 31 | `list_people` | People across your memories (calendar/email/transcript), by frequency |
|
|
336
|
+
| 32 | `about_person` | One person's profile + the memories mentioning them |
|
|
337
|
+
| 33 | `timeline` | Recent memories grouped by day (what happened this/last week) |
|
|
338
|
+
| 34 | `briefing` | Daily briefing — today's events, open commitments, and what you may be forgetting |
|
|
339
|
+
| 35 | `list_organizations` | Organizations across your memories (people grouped by email domain) |
|
|
340
|
+
| 36 | `about_organization` | One organization's profile + the memories mentioning it |
|
|
341
|
+
| 37 | `list_decisions` | Decisions detected in recent memories — what was decided, when/where |
|
|
342
|
+
| 38 | `create_backup` | Write a full backup (memories + sessions) to a file, optionally passphrase-encrypted |
|
|
343
|
+
| 39 | `restore_backup` | Restore memories + sessions from a backup file (merge or replace) |
|
|
344
|
+
| 40 | `meeting_prep` | Pre-meeting brief — next meeting, attendees, what you last discussed, open items |
|
|
345
|
+
| 41 | `consolidate_similar` | Compress clusters of related aged memories into durable summaries (sleep-like) |
|
|
346
|
+
| 42 | `list_review_memories` | Memories due for spaced-repetition review (fading, unpinned, un-snoozed) |
|
|
347
|
+
| 43 | `review_memory` | Apply a review decision — keep / reinforce / weaken / pin / forget / snooze |
|
|
348
|
+
| 44 | `evaluate_admission` | Preview the admission verdict for candidate text (admit/review/reject/redact) |
|
|
349
|
+
| 45 | `admit_memory` | Store through the admission gate — dedupe + secret redaction |
|
|
350
|
+
| 46 | `sync_connector` | Connector v2 — fetch + gate-filtered incremental ingest |
|
|
351
|
+
| 47 | `connector_sync_status` | Per-source sync bookkeeping (last synced, totals, run count) |
|
|
352
|
+
| 48 | `audit_secrets` | Scan stored memories for secrets (credentials, tokens) |
|
|
353
|
+
| 49 | `redact_secrets` | Strip secrets from stored memories (preview or apply) |
|
|
354
|
+
| 50 | `purge_memory` | Hard-delete a memory and report residue across tracked storage layers |
|
|
355
|
+
| 51 | `reindex_entities` | Rebuild the persistent entity graph from all memories |
|
|
356
|
+
| 52 | `list_entities` | List graph entities by type, most-mentioned first |
|
|
357
|
+
| 53 | `about_entity` | One entity's profile — its memories and co-occurring entities |
|
|
358
|
+
| 54 | `memory_trust` | A memory's provenance/trust breakdown (confidence + explainable evidence) |
|
|
359
|
+
| 55 | `recompute_trust_scores` | Recompute provenance/trust scores for all memories |
|
|
360
|
+
| 56 | `list_low_trust_memories` | Memories below a confidence threshold, least-trusted first |
|
|
361
|
+
| 57 | `detect_conflict_candidates` | Flag memory pairs that might disagree (shared entity + opposing pattern) |
|
|
362
|
+
| 58 | `list_conflict_candidates` | List conflict candidates by status (open/confirmed/…) |
|
|
363
|
+
| 59 | `review_conflict_candidate` | Human review — dismiss / confirm / keep-A / keep-B / both-valid |
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
## CLI
|
|
368
|
+
|
|
369
|
+
```bash
|
|
370
|
+
stackmemory serve # API + dashboard on :8000
|
|
371
|
+
stackmemory doctor # health checks
|
|
372
|
+
stackmemory setup --status # computed first-run readiness
|
|
373
|
+
stackmemory setup --demo --client claude --profile work
|
|
374
|
+
stackmemory setup --real --client cursor --profile minimal
|
|
375
|
+
stackmemory seed-demo # load a demo corpus into an empty store
|
|
376
|
+
stackmemory capture "note" --pin # store a memory (auto-detects git repo as project)
|
|
377
|
+
stackmemory context -o CLAUDE.md # generate a context file from memories
|
|
378
|
+
stackmemory hook install # git post-commit auto-capture
|
|
379
|
+
stackmemory summarize <session_id> # distill a session into one summary memory
|
|
380
|
+
stackmemory benchmark # recall-quality harness (hit@k / MRR)
|
|
381
|
+
stackmemory mcp config cursor # print MCP config for a client
|
|
382
|
+
stackmemory mcp stdio # run the MCP stdio server
|
|
383
|
+
stackmemory eval run # golden-fixture memory evaluation → eval_report.json
|
|
384
|
+
stackmemory eval report # print the last written evaluation report
|
|
385
|
+
stackmemory dogfood status # aggregate view of the local usage journal
|
|
386
|
+
stackmemory dogfood export -o out.json # write the aggregate dogfood report (explicit)
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
---
|
|
390
|
+
|
|
391
|
+
## H(x,ψ) Scoring Algorithm
|
|
392
|
+
|
|
393
|
+
Memories are ranked by a multi-factor score (lower = more relevant):
|
|
394
|
+
|
|
395
|
+
```
|
|
396
|
+
H(x,ψ) = α·(1-similarity) + β·(1-decay_factor) + γ·(1-importance) + δ·(1-frequency)
|
|
397
|
+
|
|
398
|
+
α = 0.4 (semantic relevance) — HSCORE_ALPHA
|
|
399
|
+
β = 0.2 (time decay) — HSCORE_BETA
|
|
400
|
+
γ = 0.3 (user-marked importance) — HSCORE_GAMMA
|
|
401
|
+
δ = 0.1 (access frequency) — HSCORE_DELTA
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
- **Similarity**: Cosine similarity between query and memory embeddings
|
|
405
|
+
- **Decay**: Exponential decay measured from **last access** (not creation) at the memory's own `stability_hours` half-life — default 168h, but it grows every time the memory is recalled or reinforced (see [The memory model](#the-memory-model)). **Pinned memories never decay.**
|
|
406
|
+
- **Importance**: User-assigned importance (0.0-1.0) — also accelerates stability growth on reinforcement
|
|
407
|
+
- **Frequency**: How often the memory has been accessed — only memories actually returned by a recall are counted
|
|
408
|
+
- **Explainability**: every score can be broken into its four components — in the dashboard's detail drawer or via `GET /api/memories/{id}/score-breakdown`; the forgetting curve itself is available via `GET /api/memories/{id}/forgetting-curve`
|
|
409
|
+
|
|
410
|
+
---
|
|
411
|
+
|
|
412
|
+
## REST API Endpoints
|
|
413
|
+
|
|
414
|
+
| Method | Endpoint | Description |
|
|
415
|
+
|--------|----------|-------------|
|
|
416
|
+
| POST | `/api/memories` | Store a memory |
|
|
417
|
+
| GET | `/api/memories` | List with filters (`q`, `project`, `source`, `tag`, `pinned`, ...) |
|
|
418
|
+
| GET | `/api/memories/{id}` | Get single memory |
|
|
419
|
+
| PUT | `/api/memories/{id}` | Update memory |
|
|
420
|
+
| PATCH | `/api/memories/{id}/pin` | Pin / unpin |
|
|
421
|
+
| POST | `/api/memories/{id}/reinforce` | Manually strengthen a memory |
|
|
422
|
+
| POST | `/api/memories/{id}/feedback` | helpful=true/false — learn from recall outcomes |
|
|
423
|
+
| GET | `/api/memories/fading` | Memories about to be forgotten (review queue) |
|
|
424
|
+
| DELETE | `/api/memories/{id}` | Delete memory |
|
|
425
|
+
| POST | `/api/memories/recall` | Recall by query (optional project filter) |
|
|
426
|
+
| POST | `/api/memories/consolidate` | Short-term → episodic |
|
|
427
|
+
| POST | `/api/memories/dedupe` | Find or remove near-duplicates |
|
|
428
|
+
| POST | `/api/memories/export` | Export all as JSON |
|
|
429
|
+
| POST | `/api/memories/import` | Import from JSON |
|
|
430
|
+
| GET | `/api/memories/{id}/score-breakdown` | Explain a memory's H(x,ψ) score |
|
|
431
|
+
| GET | `/api/memories/{id}/forgetting-curve` | Predicted retention curve over time |
|
|
432
|
+
| GET | `/api/memories/{id}/related` | Nearest-neighbour "see also" memories |
|
|
433
|
+
| POST | `/api/sessions` | Create session |
|
|
434
|
+
| GET | `/api/sessions` | List sessions |
|
|
435
|
+
| GET | `/api/sessions/{id}` | Get session |
|
|
436
|
+
| PATCH | `/api/sessions/{id}/end` | End session (consolidates) |
|
|
437
|
+
| POST | `/api/sessions/{id}/summarize` | Distill a session into one summary memory |
|
|
438
|
+
| GET | `/api/projects` | Projects with counts |
|
|
439
|
+
| GET | `/api/sources` | AI clients with counts |
|
|
440
|
+
| GET | `/api/tags` | Tags with counts |
|
|
441
|
+
| GET | `/api/people` | People across memories, by frequency |
|
|
442
|
+
| GET | `/api/people/{key}` | A person's profile + their memories |
|
|
443
|
+
| GET | `/api/timeline` | Memories grouped by day |
|
|
444
|
+
| GET | `/api/context` | Current context window |
|
|
445
|
+
| POST | `/api/context-file` | Generate CLAUDE.md / .cursorrules |
|
|
446
|
+
| GET | `/api/stats` | System statistics |
|
|
447
|
+
| GET | `/api/config` | Server configuration |
|
|
448
|
+
| GET | `/api/health` | Health check |
|
|
449
|
+
| POST | `/api/benchmark/recall` | Run the recall-quality benchmark (hit@k / MRR) |
|
|
450
|
+
| WS | `/ws/memory` | Real-time event stream + RPC actions |
|
|
451
|
+
| SSE | `/api/mcp/sse` | MCP SSE stream endpoint |
|
|
452
|
+
| POST | `/api/connectors/import` | Import from app |
|
|
453
|
+
| GET | `/api/connectors` | List connectors |
|
|
454
|
+
| GET | `/api/connectors/{name}/config` | Connector config help |
|
|
455
|
+
|
|
456
|
+
---
|
|
457
|
+
|
|
458
|
+
## App Connectors
|
|
459
|
+
|
|
460
|
+
Import data from your existing tools directly into StackMemory's memory layer.
|
|
461
|
+
Every import can be namespaced under a project.
|
|
462
|
+
|
|
463
|
+
```python
|
|
464
|
+
import_from_app("calendar", config={"ics_path": "/path/to/calendar.ics"}) # or ics_url
|
|
465
|
+
import_from_app("email", config={"mbox_path": "/path/to/mail.mbox"}) # or eml_path / eml_dir
|
|
466
|
+
import_from_app("transcript", config={"transcript_path": "/path/to/meeting.vtt"}) # or transcript_dir
|
|
467
|
+
import_from_app("notion", config={"api_key": "ntn_xxx", "database_ids": ["..."]})
|
|
468
|
+
import_from_app("obsidian", config={"vault_path": "/path/to/vault"})
|
|
469
|
+
import_from_app("github", config={"token": "ghp_xxx", "repos": ["owner/repo"]})
|
|
470
|
+
import_from_app("local_files", config={"directory": "/path/to/project"})
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
**Calendar, Email & Transcripts — the work-life capture trio** (roadmap Phase 1):
|
|
474
|
+
*when/who* + *correspondence* + *what was said*. All parse the universal *offline*
|
|
475
|
+
export formats with zero extra dependencies, so no OAuth, no API keys, nothing leaves
|
|
476
|
+
your machine:
|
|
477
|
+
|
|
478
|
+
- **Calendar** (`.ics`): the format Google Calendar, Outlook, and Apple Calendar all
|
|
479
|
+
export. Each event → a memory with title, time, attendees, and location — so you can
|
|
480
|
+
ask *"what did I discuss with X last week?"*. Optional `past_days`/`future_days` window.
|
|
481
|
+
- **Email** (`.mbox` / `.eml`): Gmail Takeout, Thunderbird, Apple Mail, Outlook export.
|
|
482
|
+
Each message → a memory with sender, recipients, subject, date, and a body excerpt —
|
|
483
|
+
ask *"what did Dana email me about pricing?"*. Options: `past_days`, `max_messages`,
|
|
484
|
+
`body_chars`, `exclude_senders` (skip no-reply/notification noise).
|
|
485
|
+
- **Transcripts** (`.vtt` / `.srt` / `.txt`): Zoom, Google Meet, Teams, Otter, Fireflies,
|
|
486
|
+
or Whisper output. Each meeting → one **summarized** memory (LLM if `OPENAI_API_KEY` is
|
|
487
|
+
set, offline extractive otherwise) with the speaker list and a transcript excerpt — ask
|
|
488
|
+
*"what did we decide in the roadmap call?"*. Options: `summarize`, `max_chars`.
|
|
489
|
+
|
|
490
|
+
Or use the **Import from Apps** panel in the dashboard's Settings page.
|
|
491
|
+
|
|
492
|
+
---
|
|
493
|
+
|
|
494
|
+
## Docker
|
|
495
|
+
|
|
496
|
+
```bash
|
|
497
|
+
docker compose up -d
|
|
498
|
+
# Dashboard + API: http://localhost:8000
|
|
499
|
+
# MCP SSE stream: http://localhost:8000/api/mcp/sse
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
One container, one port. The image builds the dashboard and serves it from the API.
|
|
503
|
+
|
|
504
|
+
---
|
|
505
|
+
|
|
506
|
+
## Configuration
|
|
507
|
+
|
|
508
|
+
Runtime settings use one precedence order across CLI, API, MCP and generated
|
|
509
|
+
client configs:
|
|
510
|
+
|
|
511
|
+
```text
|
|
512
|
+
explicit CLI/API override > environment > .stackmemory/config.json > defaults
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
`stackmemory init` and `stackmemory setup` create `.stackmemory/config.json`.
|
|
516
|
+
Relative database paths in that file are resolved from the working directory.
|
|
517
|
+
StackMemory does not load `.env` implicitly; export environment variables in
|
|
518
|
+
the process that launches it when environment overrides are required.
|
|
519
|
+
|
|
520
|
+
| Variable | Default | Description |
|
|
521
|
+
|----------|---------|-------------|
|
|
522
|
+
| `SQLITE_DB_PATH` | `./stackmemory.db` | SQLite database path |
|
|
523
|
+
| `EMBEDDER_MODE` | `auto` | `auto`, `local`, `openai`, `ollama`, `hash`; `auto` is local-first and never selects OpenAI just because a key exists |
|
|
524
|
+
| `OPENAI_API_KEY` | — | Used only when `EMBEDDER_MODE=openai` (and separately by optional LLM summaries/Ask features) |
|
|
525
|
+
| `LOCAL_MODEL` | `all-MiniLM-L6-v2` | Local embedding model |
|
|
526
|
+
| `OLLAMA_URL` | `http://localhost:11434` | Ollama server (mode `ollama`) |
|
|
527
|
+
| `OLLAMA_MODEL` | `nomic-embed-text` | Ollama embedding model |
|
|
528
|
+
| `SHORT_TERM_MAX` | `50` | Max short-term memories |
|
|
529
|
+
| `DECAY_HALF_LIFE_HOURS` | `168` | Starting half-life for new memories |
|
|
530
|
+
| `HSCORE_ALPHA` | `0.4` | Similarity weight |
|
|
531
|
+
| `HSCORE_BETA` | `0.2` | Decay weight |
|
|
532
|
+
| `HSCORE_GAMMA` | `0.3` | Importance weight |
|
|
533
|
+
| `HSCORE_DELTA` | `0.1` | Frequency weight |
|
|
534
|
+
| `REINFORCEMENT_GAIN` | `0.5` | Stability growth per recall (higher = faster consolidation) |
|
|
535
|
+
| `MAX_STABILITY_HOURS` | `8760` | Cap on how durable a memory can become (1 year) |
|
|
536
|
+
| `FEEDBACK_WEAKEN_FACTOR` | `0.5` | Stability multiplier on negative feedback |
|
|
537
|
+
| `INTERFERENCE_THRESHOLD` | `0.97` | Similarity above which new memories weaken old ones (1.0 = off) |
|
|
538
|
+
| `INTERFERENCE_FACTOR` | `0.6` | Stability multiplier applied to superseded memories |
|
|
539
|
+
| `AUTO_SUMMARIZE_SESSIONS` | `false` | Auto-summarize a session's memories on `end_session` |
|
|
540
|
+
| `SUMMARY_MODEL` | `gpt-4o-mini` | OpenAI chat model used for session summaries |
|
|
541
|
+
| `STACKMEMORY_TOKEN` | — | Optional shared-secret gate on `/api/*` (except `/api/health`) and the WebSocket |
|
|
542
|
+
| `STACKMEMORY_CORS_ORIGINS` | localhost only | Comma-separated allowed browser origins (`*` for wildcard) |
|
|
543
|
+
| `STACKMEMORY_AUTH_RATE_LIMIT` | `10` | Failed token attempts allowed per rate-limit window, per client/process |
|
|
544
|
+
| `STACKMEMORY_API_RATE_LIMIT` | `120` | Authenticated API requests allowed per window, per client/process |
|
|
545
|
+
| `STACKMEMORY_RATE_LIMIT_WINDOW_SECONDS` | `60` | In-process rate-limit window; not a distributed quota system |
|
|
546
|
+
| `STACKMEMORY_SQLITE_BUSY_TIMEOUT_MS` | `5000` | SQLite lock wait before failing; file databases use WAL mode |
|
|
547
|
+
| `STACKMEMORY_SAFETY_BACKUP_DIR` | DB sibling `safety-backups/` | Location for automatic pre-replace SQLite safety backups |
|
|
548
|
+
|
|
549
|
+
---
|
|
550
|
+
|
|
551
|
+
## Security
|
|
552
|
+
|
|
553
|
+
StackMemory binds to loopback by default. `stackmemory serve --host 0.0.0.0`
|
|
554
|
+
(or any non-loopback host) is refused unless `STACKMEMORY_TOKEN` is set. The
|
|
555
|
+
Docker Compose default publishes only `127.0.0.1:8000`; deployments that widen
|
|
556
|
+
the bind must set a strong token. CORS is not an authorization boundary.
|
|
557
|
+
|
|
558
|
+
The default REST, WebSocket, MCP `store_memory`, CLI `capture`, and connector
|
|
559
|
+
import paths pass through the deterministic admission gate before persistence.
|
|
560
|
+
Rejected/review candidates are not stored; secrets are redacted. An explicit
|
|
561
|
+
`admit_memory(force=true)` operation is the audited administrative override.
|
|
562
|
+
|
|
563
|
+
|
|
564
|
+
StackMemory is designed as a **local, single-user tool** — no accounts, no
|
|
565
|
+
multi-tenancy. Two lightweight controls harden the default local deployment:
|
|
566
|
+
|
|
567
|
+
- **CORS defaults to localhost origins**, not `*` — without this, any website
|
|
568
|
+
open in your browser could `fetch()` your entire memory store from a
|
|
569
|
+
service running on `localhost:8000`. Widen it with `STACKMEMORY_CORS_ORIGINS`
|
|
570
|
+
only if you know what you're exposing.
|
|
571
|
+
- **Optional shared-secret token** (`STACKMEMORY_TOKEN`) gates every `/api/*`
|
|
572
|
+
route and the WebSocket behind an `X-StackMemory-Token` header (or `?token=`
|
|
573
|
+
for the socket). When enabled, failed token attempts and authenticated API
|
|
574
|
+
traffic are limited in-process. Unset by default so local use stays zero-config.
|
|
575
|
+
|
|
576
|
+
This is not per-user auth or a substitute for running behind your own
|
|
577
|
+
reverse proxy if you expose the service beyond localhost.
|
|
578
|
+
|
|
579
|
+
SQLite file databases use WAL mode, a 5-second busy timeout, numbered
|
|
580
|
+
`PRAGMA user_version` migrations, and an FTS5 text index when the local SQLite
|
|
581
|
+
build supports it. Full-text search falls back to `LIKE` if FTS5 is unavailable.
|
|
582
|
+
Before `restore --replace` changes an existing file database, StackMemory creates
|
|
583
|
+
a consistent online SQLite safety backup in a local `safety-backups/` directory.
|
|
584
|
+
|
|
585
|
+
---
|
|
586
|
+
|
|
587
|
+
## Evaluation & Dogfood (2.25)
|
|
588
|
+
|
|
589
|
+
Two offline tools for judging whether the memory system is actually working,
|
|
590
|
+
distinct from the H(x,ψ) recall benchmark above.
|
|
591
|
+
|
|
592
|
+
- **`stackmemory eval run [--fixtures DIR] [--embedder-mode hash|local|...] [--output FILE]`**
|
|
593
|
+
runs the golden-fixture evaluation (`tests/fixtures/evaluation/*.json`)
|
|
594
|
+
through the real admission → store → trust → conflict → recall → review
|
|
595
|
+
pipeline and writes a JSON report (default `eval_report.json`). Deterministic
|
|
596
|
+
for a fixed fixture set + embedder mode.
|
|
597
|
+
- **`stackmemory eval report [--output FILE]`** prints the last written report.
|
|
598
|
+
- **`stackmemory dogfood status`** prints the aggregate view of the local
|
|
599
|
+
usage journal (event counts, time-to-first-value, recall-feedback rate,
|
|
600
|
+
review distribution).
|
|
601
|
+
- **`stackmemory dogfood export --output report.json`** is an explicit user
|
|
602
|
+
action that writes the *aggregate* journal report to a file.
|
|
603
|
+
|
|
604
|
+
Live instrumentation (2.25.1) is **opt-in**: set
|
|
605
|
+
`STACKMEMORY_DOGFOOD_ENABLED=true` and every transport that uses the shared
|
|
606
|
+
engine (REST API / `serve`, MCP stdio, MCP SSE) journals coarse usage events
|
|
607
|
+
automatically — store, recall, briefing opened, meeting prep opened, trust
|
|
608
|
+
viewed, review keep/reinforce/weaken/forget, conflict confirm/dismiss, seed
|
|
609
|
+
demo completed. The journal is a plain JSONL file next to the SQLite database
|
|
610
|
+
(override with `DOGFOOD_JOURNAL_PATH`). With the flag unset (the default)
|
|
611
|
+
nothing is journaled at all.
|
|
612
|
+
|
|
613
|
+
Privacy rules, both tools:
|
|
614
|
+
|
|
615
|
+
- **Local-only, no network.** Neither module performs any network I/O; the
|
|
616
|
+
evaluation report and the dogfood journal are plain local files.
|
|
617
|
+
- **No default telemetry.** Nothing is collected or sent anywhere unless the
|
|
618
|
+
user explicitly sets `STACKMEMORY_DOGFOOD_ENABLED=true`; there is no
|
|
619
|
+
opt-out because there's no opt-in by default.
|
|
620
|
+
- **No raw memory content.** The evaluation report contains fixture keys,
|
|
621
|
+
scenario names, labels, and numbers only. The dogfood journal accepts only
|
|
622
|
+
a whitelisted set of event types and scalar attributes (ids, counts,
|
|
623
|
+
labels) — content and query text are rejected at the API boundary, not
|
|
624
|
+
filtered after the fact.
|
|
625
|
+
- **Export is explicit.** `dogfood export` writes aggregates, never raw event
|
|
626
|
+
lines; you decide if and when a report leaves the machine.
|
|
627
|
+
|
|
628
|
+
Do not quote evaluation numbers (hit@1, hit@3, MRR, precision/recall, etc.)
|
|
629
|
+
from anything other than a real `stackmemory eval run` against a known
|
|
630
|
+
fixture set — every report is tagged with its `evaluation_version`
|
|
631
|
+
(currently `memory-eval-v1`) so a number is only meaningful alongside the
|
|
632
|
+
fixture set that produced it.
|
|
633
|
+
|
|
634
|
+
---
|
|
635
|
+
|
|
636
|
+
## Testing
|
|
637
|
+
|
|
638
|
+
```bash
|
|
639
|
+
pip install -e ".[dev]"
|
|
640
|
+
EMBEDDER_MODE=hash python -m pytest -q
|
|
641
|
+
```
|
|
642
|
+
|
|
643
|
+
**125 tests** covering memory lifecycle, H(x,ψ) scoring, adaptive decay/reinforcement,
|
|
644
|
+
outcome feedback, retroactive interference, fading review queue, forgetting curves,
|
|
645
|
+
sessions, consolidation, export/import, concurrent operations, edge cases, session
|
|
646
|
+
isolation, project namespacing, source tracking, pinning,
|
|
647
|
+
recall correctness (no side effects on
|
|
648
|
+
non-returned candidates), env-configurable weights, mixed embedding dimensions,
|
|
649
|
+
v1 → v2 schema migration, dedupe, context file generation, related memories,
|
|
650
|
+
session summarization, the recall-quality benchmark harness, and the REST API.
|
|
651
|
+
|
|
652
|
+
Benchmark recall quality directly with `stackmemory benchmark`. Source-tree users
|
|
653
|
+
can also run `python scripts/benchmark_recall.py`; the runtime implementation is
|
|
654
|
+
packaged under `server.core.benchmark` so wheel installs do not depend on the
|
|
655
|
+
non-package `scripts/` directory. Run with `EMBEDDER_MODE=local`, `ollama`, or
|
|
656
|
+
`openai` for a meaningful semantic signal; the default `hash` embedder is
|
|
657
|
+
non-semantic and intended for deterministic smoke checks.
|
|
658
|
+
|
|
659
|
+
---
|
|
660
|
+
|
|
661
|
+
## Tech Stack
|
|
662
|
+
|
|
663
|
+
| Component | Technology |
|
|
664
|
+
|-----------|-----------|
|
|
665
|
+
| MCP Server | Python `mcp` SDK + `FastMCP` |
|
|
666
|
+
| API | FastAPI + Uvicorn |
|
|
667
|
+
| Database | SQLite via `aiosqlite` (auto-migrating schema) |
|
|
668
|
+
| Embeddings | OpenAI / sentence-transformers / Ollama / hash |
|
|
669
|
+
| Vector Search | NumPy cosine similarity |
|
|
670
|
+
| Frontend | Next.js 14 (static export) + shadcn/ui + Recharts |
|
|
671
|
+
| Container | Docker (single image: API + dashboard) |
|
|
672
|
+
|
|
673
|
+
---
|
|
674
|
+
|
|
675
|
+
## License
|
|
676
|
+
|
|
677
|
+
MIT
|