am-memory 0.1.0__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.
- am_memory-0.1.0/PKG-INFO +573 -0
- am_memory-0.1.0/README.md +551 -0
- am_memory-0.1.0/agent_memory/__init__.py +4 -0
- am_memory-0.1.0/agent_memory/cli.py +425 -0
- am_memory-0.1.0/agent_memory/dashboard.py +488 -0
- am_memory-0.1.0/agent_memory/db.py +264 -0
- am_memory-0.1.0/agent_memory/dream.py +1057 -0
- am_memory-0.1.0/agent_memory/embedding.py +278 -0
- am_memory-0.1.0/agent_memory/extract.py +120 -0
- am_memory-0.1.0/agent_memory/init_cmd.py +181 -0
- am_memory-0.1.0/agent_memory/llm.py +43 -0
- am_memory-0.1.0/agent_memory/llm_extract.py +186 -0
- am_memory-0.1.0/agent_memory/mcp_server.py +278 -0
- am_memory-0.1.0/agent_memory/models.py +21 -0
- am_memory-0.1.0/agent_memory/search.py +380 -0
- am_memory-0.1.0/agent_memory/session.py +567 -0
- am_memory-0.1.0/agent_memory/state.py +51 -0
- am_memory-0.1.0/agent_memory/store.py +717 -0
- am_memory-0.1.0/agent_memory/vector.py +115 -0
- am_memory-0.1.0/agent_memory/watch.py +81 -0
- am_memory-0.1.0/agent_memory/write_queue.py +186 -0
- am_memory-0.1.0/am_memory.egg-info/PKG-INFO +573 -0
- am_memory-0.1.0/am_memory.egg-info/SOURCES.txt +41 -0
- am_memory-0.1.0/am_memory.egg-info/dependency_links.txt +1 -0
- am_memory-0.1.0/am_memory.egg-info/entry_points.txt +2 -0
- am_memory-0.1.0/am_memory.egg-info/requires.txt +8 -0
- am_memory-0.1.0/am_memory.egg-info/top_level.txt +1 -0
- am_memory-0.1.0/pyproject.toml +38 -0
- am_memory-0.1.0/setup.cfg +4 -0
- am_memory-0.1.0/tests/test_cli.py +117 -0
- am_memory-0.1.0/tests/test_dashboard.py +102 -0
- am_memory-0.1.0/tests/test_db.py +58 -0
- am_memory-0.1.0/tests/test_dream.py +560 -0
- am_memory-0.1.0/tests/test_dream_e2e.py +290 -0
- am_memory-0.1.0/tests/test_embedding.py +81 -0
- am_memory-0.1.0/tests/test_extract.py +80 -0
- am_memory-0.1.0/tests/test_integration.py +71 -0
- am_memory-0.1.0/tests/test_search.py +148 -0
- am_memory-0.1.0/tests/test_session.py +252 -0
- am_memory-0.1.0/tests/test_state.py +25 -0
- am_memory-0.1.0/tests/test_store.py +433 -0
- am_memory-0.1.0/tests/test_watch.py +43 -0
- am_memory-0.1.0/tests/test_write_queue.py +203 -0
am_memory-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,573 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: am-memory
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Persistent memory for AI coding agents — SQLite-backed knowledge store with BM25+Vector search and MCP integration
|
|
5
|
+
License: MIT
|
|
6
|
+
Keywords: claude,mcp,memory,rag,claude-code
|
|
7
|
+
Classifier: Development Status :: 4 - Beta
|
|
8
|
+
Classifier: Intended Audience :: Developers
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Requires-Python: >=3.10
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
Requires-Dist: mcp>=1.0
|
|
17
|
+
Provides-Extra: vector
|
|
18
|
+
Requires-Dist: sqlite-vec; extra == "vector"
|
|
19
|
+
Provides-Extra: dev
|
|
20
|
+
Requires-Dist: pytest; extra == "dev"
|
|
21
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
22
|
+
|
|
23
|
+
# am-memory
|
|
24
|
+
|
|
25
|
+
Persistent memory for [Claude Code](https://claude.ai/code) — a self-evolving knowledge layer that survives across sessions, grows from every conversation, and surfaces relevant context automatically.
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
pip install am-memory
|
|
29
|
+
am init
|
|
30
|
+
# Restart Claude Code → done
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
No external database. No cloud service. A single SQLite file at `~/.am-memory/memory.db`.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## What problem does this solve?
|
|
38
|
+
|
|
39
|
+
Every Claude Code session starts from zero. Context window fills up. You re-explain the same architecture, re-debug the same gotchas, re-type the same config values — session after session.
|
|
40
|
+
|
|
41
|
+
`am-memory` gives Claude a memory that persists across sessions. Knowledge is captured automatically from your conversations and file edits. A debugging insight from six months ago surfaces when it's relevant today.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Quick Start
|
|
46
|
+
|
|
47
|
+
**Requirements:** Python 3.10+, Claude Code
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pip install am-memory
|
|
51
|
+
am init
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`am init` does everything in one shot:
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
✓ Created ~/.am-memory/memory.db
|
|
58
|
+
✓ Registered MCP server in ~/.claude/mcp.json
|
|
59
|
+
✓ Installed hook: ~/.claude/hooks/SessionStart/am-memory.sh
|
|
60
|
+
✓ Installed hook: ~/.claude/hooks/Stop/am-memory.sh
|
|
61
|
+
✓ Appended memory instructions to ~/.claude/CLAUDE.md
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Restart Claude Code. Done. Claude can now search and save memory across sessions.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## How it works
|
|
69
|
+
|
|
70
|
+
### The big picture
|
|
71
|
+
|
|
72
|
+

|
|
73
|
+
|
|
74
|
+
### Session lifecycle
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
Claude Code opens
|
|
78
|
+
│
|
|
79
|
+
▼
|
|
80
|
+
SessionStart hook
|
|
81
|
+
→ am session start --project myproject
|
|
82
|
+
→ writes session_id to state table
|
|
83
|
+
│
|
|
84
|
+
▼
|
|
85
|
+
Claude works (multiple turns)
|
|
86
|
+
→ calls am_search before answering
|
|
87
|
+
→ calls am_save when it learns something
|
|
88
|
+
│
|
|
89
|
+
▼
|
|
90
|
+
Claude Code closes (Stop hook)
|
|
91
|
+
→ am session end
|
|
92
|
+
→ quality-gate promote:
|
|
93
|
+
decisions non-empty → P0 (never expires)
|
|
94
|
+
key_facts ≥ 3 → P1 (90 days)
|
|
95
|
+
else → P2 (30 days)
|
|
96
|
+
→ session promoted to documents table
|
|
97
|
+
→ raw session + messages deleted
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Architecture: memory.db
|
|
103
|
+
|
|
104
|
+
One SQLite file. Four semantic layers.
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
~/.am-memory/memory.db
|
|
108
|
+
│
|
|
109
|
+
│ ── SEARCH LAYER (virtual) ──────────────────────────────────────
|
|
110
|
+
│
|
|
111
|
+
├── documents_fts FTS5 virtual table
|
|
112
|
+
│ trigram tokenizer (Chinese + English)
|
|
113
|
+
│ indexes: title, summary, key_facts, decisions
|
|
114
|
+
│ auto-synced via INSERT/UPDATE/DELETE triggers
|
|
115
|
+
│ BM25 ranking
|
|
116
|
+
│
|
|
117
|
+
├── vec_documents sqlite-vec virtual table (optional)
|
|
118
|
+
│ float32[4096] HNSW index
|
|
119
|
+
│ cosine similarity
|
|
120
|
+
│ joined to documents via document_id FK
|
|
121
|
+
│
|
|
122
|
+
│ ── KNOWLEDGE LAYER ─────────────────────────────────────────────
|
|
123
|
+
│
|
|
124
|
+
├── documents long-term knowledge store
|
|
125
|
+
│ ├── doc_id INTEGER PK
|
|
126
|
+
│ ├── title TEXT — primary search signal, BM25 weight ×3
|
|
127
|
+
│ ├── summary TEXT — 2-3 sentence distillation
|
|
128
|
+
│ ├── key_facts TEXT — JSON array of extracted facts
|
|
129
|
+
│ ├── decisions TEXT — JSON array of architectural decisions
|
|
130
|
+
│ ├── code_sigs TEXT — function/class names mentioned
|
|
131
|
+
│ ├── embedding BLOB — float32[4096], populated async
|
|
132
|
+
│ ├── priority P0 | P1 | P2
|
|
133
|
+
│ ├── source explicit | session_extract | hook | file
|
|
134
|
+
│ ├── file_path TEXT UNIQUE — upsert key for file-sourced docs
|
|
135
|
+
│ ├── expires_at REAL — NULL = never expires (P0)
|
|
136
|
+
│ └── last_accessed_at REAL — updated on every search hit (LRU)
|
|
137
|
+
│
|
|
138
|
+
│ ── CONVERSATION LAYER ──────────────────────────────────────────
|
|
139
|
+
│
|
|
140
|
+
├── sessions session lifecycle records
|
|
141
|
+
│ ├── session_id TEXT PK
|
|
142
|
+
│ ├── project, topic metadata
|
|
143
|
+
│ ├── source "cli:myproject"
|
|
144
|
+
│ ├── summary extracted at session end
|
|
145
|
+
│ ├── key_facts JSON array
|
|
146
|
+
│ └── decisions JSON array
|
|
147
|
+
│
|
|
148
|
+
├── messages raw message storage (30-day TTL, auto-pruned)
|
|
149
|
+
│
|
|
150
|
+
│ ── WORKING MEMORY ──────────────────────────────────────────────
|
|
151
|
+
│
|
|
152
|
+
└── state K/V working memory
|
|
153
|
+
├── current_session_id
|
|
154
|
+
├── active_work JSON: { ticket, topic, ... }
|
|
155
|
+
└── scratchpad freeform per-session notes
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Architecture: search
|
|
161
|
+
|
|
162
|
+
Every `am_search` call flows through a 3.5-layer cascade. It stops at the first layer that returns results. The cheapest path is always tried first.
|
|
163
|
+
|
|
164
|
+

|
|
165
|
+
|
|
166
|
+
> **Score ranges are not comparable across layers.**
|
|
167
|
+
> Sub-L1: 0.008–0.066 · Sub-L2: 1e-6–0.2 · Sub-L3: 4–500+
|
|
168
|
+
> Detect origin by magnitude.
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## Architecture: memory lifecycle
|
|
173
|
+
|
|
174
|
+
Memory is not static. Three automated paths write to it continuously.
|
|
175
|
+
|
|
176
|
+

|
|
177
|
+
|
|
178
|
+
### TTL + LRU
|
|
179
|
+
|
|
180
|
+
TTL is derived automatically from `source`. Accessed documents have their TTL reset on every search hit — frequently used knowledge never expires.
|
|
181
|
+
|
|
182
|
+

|
|
183
|
+
|
|
184
|
+
> **TTL only affects the search index.** Physical files in your knowledge base are never deleted. An expired document is unsearchable, but the file remains. Re-editing it via PostToolUse rebuilds the index entry automatically.
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Architecture: dream consolidation
|
|
189
|
+
|
|
190
|
+
`am dream` runs background memory consolidation in 5 phases:
|
|
191
|
+
|
|
192
|
+
```
|
|
193
|
+
Phase 1: Orient — read existing documents (top 100 recent)
|
|
194
|
+
Phase 2: Gather — collect ended sessions since last dream
|
|
195
|
+
Phase 3: Consolidate — cross-session pattern detection + contradiction resolution
|
|
196
|
+
Phase 3.5: Health Check — proactive knowledge base quality maintenance
|
|
197
|
+
Phase 4: Prune — remove expired documents
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Phase 3.5: Health Check
|
|
201
|
+
|
|
202
|
+
The health check operates on the **entire knowledge base**, not just new sessions. It runs three sub-checks:
|
|
203
|
+
|
|
204
|
+
**1. Staleness Detection**
|
|
205
|
+
|
|
206
|
+
Scans non-P0 documents for `code_sigs` (function/class references) that no longer exist in the project directory. Documents with >50% dead references get downgraded:
|
|
207
|
+
|
|
208
|
+
- P1 → `expires_at` set to 7 days (grace period)
|
|
209
|
+
- P2 → `expires_at` set to now (pruned immediately in Phase 4)
|
|
210
|
+
|
|
211
|
+
**2. Cross-Document Contradiction Scan**
|
|
212
|
+
|
|
213
|
+
Extends contradiction detection across ALL documents (not just within a single consolidation batch). When two documents in the same project have conflicting facts (e.g., `timeout: 30s` vs `timeout: 600s`), the older fact is removed.
|
|
214
|
+
|
|
215
|
+
**3. Redundancy Merge**
|
|
216
|
+
|
|
217
|
+
Finds document pairs with >70% key_facts overlap (fuzzy Jaccard similarity) and merges the smaller into the larger. Unique facts and decisions from the source document transfer to the target before deletion.
|
|
218
|
+
|
|
219
|
+
When 3+ documents cluster around the same topic, a **concept index** document is generated — a lightweight map linking related documents with shared themes.
|
|
220
|
+
|
|
221
|
+
### Gating
|
|
222
|
+
|
|
223
|
+
Dream only runs when:
|
|
224
|
+
- `min_hours` (default 24) have passed since last dream
|
|
225
|
+
- `min_sessions` (default 5) ended sessions exist since last dream
|
|
226
|
+
- Use `--force` to bypass gating
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
am dream --force # run now
|
|
230
|
+
am dream --force --dry-run # preview planned actions without writing
|
|
231
|
+
am dream --status # check gate state
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
## MCP tools reference
|
|
237
|
+
|
|
238
|
+
Claude calls these tools autonomously based on instructions injected by `am init` into `~/.claude/CLAUDE.md`.
|
|
239
|
+
|
|
240
|
+
### `am_search`
|
|
241
|
+
|
|
242
|
+
Search persistent memory for relevant documents.
|
|
243
|
+
|
|
244
|
+
```
|
|
245
|
+
Parameters:
|
|
246
|
+
query string required Keywords, technical terms, or concepts
|
|
247
|
+
limit integer default 5 Max results to return
|
|
248
|
+
|
|
249
|
+
Returns: structured context injection (~200 tokens)
|
|
250
|
+
Latency: ~50ms (BM25 only) · ~500ms (with Ollama vector)
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
**When Claude calls it:** Before answering questions about past work, architecture decisions, debugging solutions, technical constraints.
|
|
254
|
+
|
|
255
|
+
### `am_save`
|
|
256
|
+
|
|
257
|
+
Save a piece of knowledge to persistent memory.
|
|
258
|
+
|
|
259
|
+
```
|
|
260
|
+
Parameters:
|
|
261
|
+
title string required One-line title — primary search signal
|
|
262
|
+
content string required Full context: facts, decisions, rationale
|
|
263
|
+
source enum required architectural_decision | debug_solution | technical_insight
|
|
264
|
+
| session_note | routine
|
|
265
|
+
Determines TTL automatically — no priority field needed.
|
|
266
|
+
|
|
267
|
+
Returns: doc_id of saved document
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
**When Claude calls it:** After discovering a non-obvious config constraint, an architectural decision, a bug gotcha worth remembering.
|
|
271
|
+
|
|
272
|
+
### `am_state_get` / `am_state_set`
|
|
273
|
+
|
|
274
|
+
Read/write K/V working memory (active task, scratchpad notes).
|
|
275
|
+
|
|
276
|
+
```
|
|
277
|
+
am_state_get key: string
|
|
278
|
+
am_state_set key: string, value: any JSON-serializable
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
## CLI reference
|
|
284
|
+
|
|
285
|
+
```bash
|
|
286
|
+
am init # one-time setup (run once after install)
|
|
287
|
+
am update # upgrade to latest version
|
|
288
|
+
|
|
289
|
+
am search --query "kafka rebalance" # search documents (returns injection text)
|
|
290
|
+
am search --query "..." --format json # return raw JSON
|
|
291
|
+
|
|
292
|
+
am doc save \ # save a document
|
|
293
|
+
--title "bug title" \
|
|
294
|
+
--content "description" \
|
|
295
|
+
--source architectural_decision
|
|
296
|
+
|
|
297
|
+
am state get --key active_work # read working memory
|
|
298
|
+
am state set --key scratchpad \
|
|
299
|
+
--value "current task" # write working memory
|
|
300
|
+
|
|
301
|
+
am session start --project myproj # create session (prints session_id)
|
|
302
|
+
am session end --session-id S # end session + promote to documents
|
|
303
|
+
am session list # list recent sessions (JSON)
|
|
304
|
+
|
|
305
|
+
am mcp # start MCP server (stdio) — called by Claude Code
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
## Optional: vector search with Ollama
|
|
311
|
+
|
|
312
|
+
By default, am-memory uses BM25 full-text search (Sub-Layer 2). This handles ~80% of queries well — technical terms, config keys, function names, error codes.
|
|
313
|
+
|
|
314
|
+
For fuzzy / semantic queries ("that kafka thing we fixed"), install Ollama and pull an embedding model:
|
|
315
|
+
|
|
316
|
+
```bash
|
|
317
|
+
# Install Ollama: https://ollama.com
|
|
318
|
+
ollama pull qwen3-embedding:8b # 4096-dim, ~5GB
|
|
319
|
+
|
|
320
|
+
pip install 'am-memory[vector]'
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
When Ollama is running, searches automatically upgrade to hybrid BM25 + vector (Sub-Layer 1). When Ollama is offline, they fall back to BM25 silently. No configuration required.
|
|
324
|
+
|
|
325
|
+
---
|
|
326
|
+
|
|
327
|
+
## Real-world scenario: 8-hour session expiry
|
|
328
|
+
|
|
329
|
+
Claude Code sessions expire after ~8 hours. Here is what that means in practice, using a real data pipeline debugging workflow.
|
|
330
|
+
|
|
331
|
+
**Setup:** You are a engineer working on a Python ETL pipeline built on Airflow + Spark/YARN. The pipeline uses a CPL(YAML-driven config system) that generates DAGs at runtime. You are debugging a flaky Spark job submission.
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
### Day 1 — 09:00, session starts
|
|
336
|
+
|
|
337
|
+
**Without am-memory:**
|
|
338
|
+
```
|
|
339
|
+
You: The dan-sync Spark job keeps failing on YARN with a timeout.
|
|
340
|
+
Help me debug it.
|
|
341
|
+
Claude: Sure — what does the error look like? What's your submission
|
|
342
|
+
config? What version of the orchestration layer are you on?
|
|
343
|
+
(you spend 15 minutes re-explaining the stack)
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
**With am-memory:**
|
|
347
|
+
```
|
|
348
|
+
[SessionStart hook creates session silently]
|
|
349
|
+
|
|
350
|
+
You: The dan-sync Spark job keeps failing on YARN with a timeout.
|
|
351
|
+
|
|
352
|
+
[Claude calls am_search("dan-sync Spark YARN timeout")]
|
|
353
|
+
→ hits:
|
|
354
|
+
[P0] "Spark/YARN restart API — polling and timeout config"
|
|
355
|
+
key_facts: ["15s polling interval", "800s timeout default",
|
|
356
|
+
"HTTP API at /restart endpoint"]
|
|
357
|
+
[P1] "cpl-modules pipeline config — dan-sync"
|
|
358
|
+
key_facts: ["YAML → dtechclipy → cplapi → cplorchestration → Airflow",
|
|
359
|
+
"Spark executor config in pipeline YAML"]
|
|
360
|
+
|
|
361
|
+
Claude: The orchestration layer uses an HTTP restart API with 800s timeout
|
|
362
|
+
and 15s polling. Is the job hitting the 800s wall, or failing
|
|
363
|
+
before that? Check /restart endpoint response — it will tell you
|
|
364
|
+
whether YARN accepted the submission or rejected it upstream.
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
Zero re-explanation. Claude already knows your stack.
|
|
368
|
+
|
|
369
|
+
---
|
|
370
|
+
|
|
371
|
+
### Day 1 — 14:00, root cause found
|
|
372
|
+
|
|
373
|
+
After 3 hours of debugging you find the issue: the Spark executor memory config in the pipeline YAML was using a soft limit that YARN silently ignores, causing the container to get killed without a clear error.
|
|
374
|
+
|
|
375
|
+
**Without am-memory:**
|
|
376
|
+
```
|
|
377
|
+
Claude explains the fix. You apply it. The insight lives only in this session.
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
**With am-memory:**
|
|
381
|
+
```
|
|
382
|
+
Claude explains the fix, then calls am_save automatically:
|
|
383
|
+
|
|
384
|
+
title: "YARN silently ignores Spark soft memory limit in pipeline YAML"
|
|
385
|
+
content: "executor_memory soft limit is not enforced by YARN —
|
|
386
|
+
container gets OOM-killed with no error message.
|
|
387
|
+
Fix: use hard limit field executor_memory_hard.
|
|
388
|
+
Affected: all cpl-modules Spark pipelines on YARN."
|
|
389
|
+
priority: P0 ← architectural constraint, never expires
|
|
390
|
+
|
|
391
|
+
→ written to documents table permanently
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
---
|
|
395
|
+
|
|
396
|
+
### Day 1 — 17:00, session expires (8-hour limit)
|
|
397
|
+
|
|
398
|
+
**Without am-memory:**
|
|
399
|
+
```
|
|
400
|
+
[Session context window compresses / expires]
|
|
401
|
+
|
|
402
|
+
Day 2, 09:00:
|
|
403
|
+
You: Continue where we left off on dan-sync.
|
|
404
|
+
Claude: I don't have context from a previous session.
|
|
405
|
+
Could you describe the issue again?
|
|
406
|
+
|
|
407
|
+
(15 minutes re-explaining, then another 30 minutes to re-derive
|
|
408
|
+
what you already found yesterday)
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
**With am-memory:**
|
|
412
|
+
```
|
|
413
|
+
[Stop hook fires silently]
|
|
414
|
+
→ reads session messages
|
|
415
|
+
→ extracts summary + key_facts + decisions
|
|
416
|
+
→ quality gate: decisions non-empty → P0
|
|
417
|
+
→ promotes to documents:
|
|
418
|
+
title: "dan-sync YARN OOM debugging — Day 1"
|
|
419
|
+
summary: "Spark executor soft memory limit silently ignored by YARN.
|
|
420
|
+
Container OOM-killed. Fix: use executor_memory_hard in YAML."
|
|
421
|
+
decisions: ["executor_memory_hard replaces executor_memory_soft",
|
|
422
|
+
"applies to all cpl-modules YARN pipelines"]
|
|
423
|
+
→ raw session + messages deleted
|
|
424
|
+
|
|
425
|
+
Day 2, 09:00 — new session starts:
|
|
426
|
+
You: Continue where we left off on dan-sync.
|
|
427
|
+
|
|
428
|
+
[Claude calls am_search("dan-sync YARN memory")]
|
|
429
|
+
→ hits yesterday's promoted P0 doc + the fix from 14:00
|
|
430
|
+
|
|
431
|
+
Claude: Yesterday's finding: YARN silently ignores the soft memory limit.
|
|
432
|
+
The fix is executor_memory_hard in the pipeline YAML.
|
|
433
|
+
Did you get to deploy it, or do you need to pick up from there?
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
Exact continuation. No re-explanation. No re-derivation.
|
|
437
|
+
|
|
438
|
+
---
|
|
439
|
+
|
|
440
|
+
### 3 weeks later — different pipeline, same platform
|
|
441
|
+
|
|
442
|
+
**Without am-memory:**
|
|
443
|
+
```
|
|
444
|
+
A different Spark job starts failing with the same silent OOM pattern.
|
|
445
|
+
→ 45 minutes debugging
|
|
446
|
+
→ re-discover the same YAML config issue
|
|
447
|
+
→ apply the same fix
|
|
448
|
+
(every engineer re-learns the same lesson)
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
**With am-memory:**
|
|
452
|
+
```
|
|
453
|
+
You: This Airflow-triggered Spark job on YARN keeps dying silently.
|
|
454
|
+
No error in the logs.
|
|
455
|
+
|
|
456
|
+
[Claude calls am_search("YARN silent failure Spark")]
|
|
457
|
+
→ hits the P0 doc from 3 weeks ago
|
|
458
|
+
|
|
459
|
+
Claude: Seen this before — YARN silently kills the container when
|
|
460
|
+
executor_memory soft limit is exceeded. No error message.
|
|
461
|
+
Check executor_memory_hard in your pipeline YAML.
|
|
462
|
+
|
|
463
|
+
2 minutes to resolution instead of 45.
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
---
|
|
467
|
+
|
|
468
|
+
### What actually accumulates over time
|
|
469
|
+
|
|
470
|
+
```
|
|
471
|
+
Week 1: am init · 0 documents
|
|
472
|
+
First session — Claude saves 2 pipeline config decisions
|
|
473
|
+
→ 2 documents
|
|
474
|
+
|
|
475
|
+
Week 2: You debug YARN, edit 8 pipeline YAML files
|
|
476
|
+
PostToolUse captures each edit → upsert by file_path
|
|
477
|
+
→ 10 documents
|
|
478
|
+
|
|
479
|
+
Week 3: You delete 4 old sessions from dashboard
|
|
480
|
+
Each promoted with quality gate (P0/P1/P2)
|
|
481
|
+
→ 14 documents
|
|
482
|
+
|
|
483
|
+
Month 2: Routine work — edits, sessions, decisions
|
|
484
|
+
→ ~60 documents · growing
|
|
485
|
+
|
|
486
|
+
Month 6: ~200 documents · all searchable in <50ms
|
|
487
|
+
Claude answers "why did we move away from soft memory limits?"
|
|
488
|
+
with the exact rationale from a session that no longer exists
|
|
489
|
+
as a raw conversation — only the distilled decision survives.
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
## How knowledge grows over time
|
|
494
|
+
|
|
495
|
+
```
|
|
496
|
+
Day 1: am init · 0 documents
|
|
497
|
+
↓
|
|
498
|
+
Day 1: First session · Claude saves 2 decisions via <memory>
|
|
499
|
+
→ 2 documents
|
|
500
|
+
↓
|
|
501
|
+
Day 3: You edit 5 .py files · PostToolUse captures each
|
|
502
|
+
→ 7 documents
|
|
503
|
+
↓
|
|
504
|
+
Day 7: You delete a 30-message session from the dashboard
|
|
505
|
+
→ session distilled → 1 session_extract P1 doc promoted
|
|
506
|
+
→ 8 documents
|
|
507
|
+
↓
|
|
508
|
+
Day 30: Routine file edits, session work
|
|
509
|
+
→ ~50 documents · ~40% vectorized (if Ollama installed)
|
|
510
|
+
↓
|
|
511
|
+
Day 90: 301 documents · 98% vectorized · <50ms search
|
|
512
|
+
Claude answers "why did we choose X?" with full rationale
|
|
513
|
+
from sessions that no longer exist as raw conversations.
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
---
|
|
517
|
+
|
|
518
|
+
## How `am init` configures Claude Code
|
|
519
|
+
|
|
520
|
+
After `am init`, three things change in your `~/.claude/` directory:
|
|
521
|
+
|
|
522
|
+
**`mcp.json`** — registers the MCP server:
|
|
523
|
+
```json
|
|
524
|
+
{
|
|
525
|
+
"mcpServers": {
|
|
526
|
+
"am-memory": { "command": "am", "args": ["mcp"] }
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
**`hooks/SessionStart/am-memory.sh`** — creates a session on startup:
|
|
532
|
+
```bash
|
|
533
|
+
SESSION_ID=$(am session start --project "$PROJECT" --source "cli:$PROJECT")
|
|
534
|
+
am state set --key current_session_id --value "\"$SESSION_ID\""
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
**`hooks/Stop/am-memory.sh`** — ends and promotes session on exit:
|
|
538
|
+
```bash
|
|
539
|
+
SESSION_ID=$(am state get --key current_session_id | tr -d '"')
|
|
540
|
+
am session end --session-id "$SESSION_ID"
|
|
541
|
+
am state set --key current_session_id --value "null"
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
**`CLAUDE.md`** — tells Claude when to use the MCP tools:
|
|
545
|
+
```markdown
|
|
546
|
+
## Persistent Memory (am-memory)
|
|
547
|
+
You have am_search and am_save MCP tools.
|
|
548
|
+
• Before answering questions about past work → call am_search
|
|
549
|
+
• After learning non-obvious facts → call am_save with P0/P1/P2
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
---
|
|
553
|
+
|
|
554
|
+
## Updates
|
|
555
|
+
|
|
556
|
+
```bash
|
|
557
|
+
# Check current version
|
|
558
|
+
am --version
|
|
559
|
+
|
|
560
|
+
# Upgrade (pipx recommended)
|
|
561
|
+
pipx upgrade am-memory
|
|
562
|
+
|
|
563
|
+
# Or via am
|
|
564
|
+
am update
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
am-memory checks PyPI once every 24 hours and prints a notice when a newer version is available.
|
|
568
|
+
|
|
569
|
+
---
|
|
570
|
+
|
|
571
|
+
## License
|
|
572
|
+
|
|
573
|
+
MIT
|