memory-boost 0.1.0__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.
- memory_boost/__init__.py +3 -0
- memory_boost/cli.py +389 -0
- memory_boost/core.py +681 -0
- memory_boost/drift.py +145 -0
- memory_boost/example_transcripts/-work-acme-api/0a1b2c3d-1111-4aaa-8bbb-000000000001.jsonl +136 -0
- memory_boost/example_transcripts/-work-acme-api/0a1b2c3d-3333-4aaa-8bbb-000000000003.jsonl +46 -0
- memory_boost/example_transcripts/-work-acme-api/0a1b2c3d-4444-4aaa-8bbb-000000000004.jsonl +10 -0
- memory_boost/example_transcripts/-work-pixel-notes/0a1b2c3d-2222-4aaa-8bbb-000000000002.jsonl +54 -0
- memory_boost/example_wiki/concepts/money-as-integer-cents.md +15 -0
- memory_boost/example_wiki/concepts/retry-jobs-idempotently.md +16 -0
- memory_boost/example_wiki/context/preferences.md +7 -0
- memory_boost/example_wiki/decisions/cors-allow-all.md +9 -0
- memory_boost/example_wiki/decisions/float-money.md +9 -0
- memory_boost/example_wiki/decisions/pin-postgres-15.md +14 -0
- memory_boost/example_wiki/decisions/queue-in-postgres.md +15 -0
- memory_boost/example_wiki/decisions/sessions-in-redis.md +9 -0
- memory_boost/example_wiki/log.md +37 -0
- memory_boost/example_wiki/projects/acme-api.md +24 -0
- memory_boost/example_wiki/projects/legacy-dashboard.md +13 -0
- memory_boost/example_wiki/projects/pixel-notes.md +9 -0
- memory_boost/lessons.py +77 -0
- memory_boost/mine.py +172 -0
- memory_boost/server.py +102 -0
- memory_boost-0.1.0.dist-info/METADATA +229 -0
- memory_boost-0.1.0.dist-info/RECORD +28 -0
- memory_boost-0.1.0.dist-info/WHEEL +4 -0
- memory_boost-0.1.0.dist-info/entry_points.txt +2 -0
- memory_boost-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{"type": "assistant", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:00:35Z", "message": {"role": "assistant", "content": [{"type": "text", "text": "(synthetic)"}, {"type": "tool_use", "id": "toolu_0000", "name": "Read", "input": {"file_path": "/work/pixel-notes/app/sync.ts"}}]}}
|
|
2
|
+
{"type": "user", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:00:38Z", "message": {"role": "user", "content": [{"type": "tool_result", "tool_use_id": "toolu_0000", "content": "(synthetic output)"}]}}
|
|
3
|
+
{"type": "assistant", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:01:16Z", "message": {"role": "assistant", "content": [{"type": "text", "text": "(synthetic)"}, {"type": "tool_use", "id": "toolu_0001", "name": "Bash", "input": {"command": "npm test -- --run"}}]}}
|
|
4
|
+
{"type": "user", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:01:17Z", "message": {"role": "user", "content": [{"type": "tool_result", "tool_use_id": "toolu_0001", "content": "(synthetic output)"}]}}
|
|
5
|
+
{"type": "assistant", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:01:35Z", "message": {"role": "assistant", "content": [{"type": "text", "text": "(synthetic)"}, {"type": "tool_use", "id": "toolu_0002", "name": "Edit", "input": {"file_path": "/work/pixel-notes/app/sync.ts", "old_string": "a", "new_string": "b"}}]}}
|
|
6
|
+
{"type": "user", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:01:44Z", "message": {"role": "user", "content": [{"type": "tool_result", "tool_use_id": "toolu_0002", "content": "(synthetic output)"}]}}
|
|
7
|
+
{"type": "assistant", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:02:12Z", "message": {"role": "assistant", "content": [{"type": "text", "text": "(synthetic)"}, {"type": "tool_use", "id": "toolu_0003", "name": "Bash", "input": {"command": "npm test -- --run"}}]}}
|
|
8
|
+
{"type": "user", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:02:15Z", "message": {"role": "user", "content": [{"type": "tool_result", "tool_use_id": "toolu_0003", "content": "(synthetic output)"}]}}
|
|
9
|
+
{"type": "assistant", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:02:54Z", "message": {"role": "assistant", "content": [{"type": "text", "text": "(synthetic)"}, {"type": "tool_use", "id": "toolu_0004", "name": "Edit", "input": {"file_path": "/work/pixel-notes/app/sync.ts", "old_string": "a", "new_string": "b"}}]}}
|
|
10
|
+
{"type": "user", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:02:55Z", "message": {"role": "user", "content": [{"type": "tool_result", "tool_use_id": "toolu_0004", "content": "(synthetic output)"}]}}
|
|
11
|
+
{"type": "assistant", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:03:33Z", "message": {"role": "assistant", "content": [{"type": "text", "text": "(synthetic)"}, {"type": "tool_use", "id": "toolu_0005", "name": "Bash", "input": {"command": "npm test -- --run"}}]}}
|
|
12
|
+
{"type": "user", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:03:38Z", "message": {"role": "user", "content": [{"type": "tool_result", "tool_use_id": "toolu_0005", "content": "(synthetic output)"}]}}
|
|
13
|
+
{"type": "assistant", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:03:48Z", "message": {"role": "assistant", "content": [{"type": "text", "text": "(synthetic)"}, {"type": "tool_use", "id": "toolu_0006", "name": "Edit", "input": {"file_path": "/work/pixel-notes/app/sync.ts", "old_string": "a", "new_string": "b"}}]}}
|
|
14
|
+
{"type": "user", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:03:53Z", "message": {"role": "user", "content": [{"type": "tool_result", "tool_use_id": "toolu_0006", "content": "(synthetic output)"}]}}
|
|
15
|
+
{"type": "assistant", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:04:31Z", "message": {"role": "assistant", "content": [{"type": "text", "text": "(synthetic)"}, {"type": "tool_use", "id": "toolu_0007", "name": "Bash", "input": {"command": "npm test -- --run"}}]}}
|
|
16
|
+
{"type": "user", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:04:37Z", "message": {"role": "user", "content": [{"type": "tool_result", "tool_use_id": "toolu_0007", "content": "(synthetic output)"}]}}
|
|
17
|
+
{"type": "assistant", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:04:52Z", "message": {"role": "assistant", "content": [{"type": "text", "text": "(synthetic)"}, {"type": "tool_use", "id": "toolu_0008", "name": "Edit", "input": {"file_path": "/work/pixel-notes/app/sync.ts", "old_string": "a", "new_string": "b"}}]}}
|
|
18
|
+
{"type": "user", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:04:58Z", "message": {"role": "user", "content": [{"type": "tool_result", "tool_use_id": "toolu_0008", "content": "(synthetic output)"}]}}
|
|
19
|
+
{"type": "assistant", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:05:17Z", "message": {"role": "assistant", "content": [{"type": "text", "text": "(synthetic)"}, {"type": "tool_use", "id": "toolu_0009", "name": "Bash", "input": {"command": "npm test -- --run"}}]}}
|
|
20
|
+
{"type": "user", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:05:26Z", "message": {"role": "user", "content": [{"type": "tool_result", "tool_use_id": "toolu_0009", "content": "(synthetic output)"}]}}
|
|
21
|
+
{"type": "assistant", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:06:05Z", "message": {"role": "assistant", "content": [{"type": "text", "text": "(synthetic)"}, {"type": "tool_use", "id": "toolu_0010", "name": "Edit", "input": {"file_path": "/work/pixel-notes/app/sync.ts", "old_string": "a", "new_string": "b"}}]}}
|
|
22
|
+
{"type": "user", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:06:14Z", "message": {"role": "user", "content": [{"type": "tool_result", "tool_use_id": "toolu_0010", "content": "(synthetic output)"}]}}
|
|
23
|
+
{"type": "assistant", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:06:40Z", "message": {"role": "assistant", "content": [{"type": "text", "text": "(synthetic)"}, {"type": "tool_use", "id": "toolu_0011", "name": "Bash", "input": {"command": "npm test -- --run"}}]}}
|
|
24
|
+
{"type": "user", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:06:44Z", "message": {"role": "user", "content": [{"type": "tool_result", "tool_use_id": "toolu_0011", "content": "(synthetic output)"}]}}
|
|
25
|
+
{"type": "assistant", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:07:01Z", "message": {"role": "assistant", "content": [{"type": "text", "text": "(synthetic)"}, {"type": "tool_use", "id": "toolu_0012", "name": "Edit", "input": {"file_path": "/work/pixel-notes/app/sync.ts", "old_string": "a", "new_string": "b"}}]}}
|
|
26
|
+
{"type": "user", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:07:05Z", "message": {"role": "user", "content": [{"type": "tool_result", "tool_use_id": "toolu_0012", "content": "(synthetic output)"}]}}
|
|
27
|
+
{"type": "assistant", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:07:35Z", "message": {"role": "assistant", "content": [{"type": "text", "text": "(synthetic)"}, {"type": "tool_use", "id": "toolu_0013", "name": "Bash", "input": {"command": "npm test -- --run"}}]}}
|
|
28
|
+
{"type": "user", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:07:39Z", "message": {"role": "user", "content": [{"type": "tool_result", "tool_use_id": "toolu_0013", "content": "(synthetic output)"}]}}
|
|
29
|
+
{"type": "assistant", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:07:56Z", "message": {"role": "assistant", "content": [{"type": "text", "text": "(synthetic)"}, {"type": "tool_use", "id": "toolu_0014", "name": "Edit", "input": {"file_path": "/work/pixel-notes/app/sync.ts", "old_string": "a", "new_string": "b"}}]}}
|
|
30
|
+
{"type": "user", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:08:05Z", "message": {"role": "user", "content": [{"type": "tool_result", "tool_use_id": "toolu_0014", "content": "(synthetic output)"}]}}
|
|
31
|
+
{"type": "assistant", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:08:41Z", "message": {"role": "assistant", "content": [{"type": "text", "text": "(synthetic)"}, {"type": "tool_use", "id": "toolu_0015", "name": "Bash", "input": {"command": "npm test -- --run"}}]}}
|
|
32
|
+
{"type": "user", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:08:47Z", "message": {"role": "user", "content": [{"type": "tool_result", "tool_use_id": "toolu_0015", "content": "(synthetic output)"}]}}
|
|
33
|
+
{"type": "assistant", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:08:53Z", "message": {"role": "assistant", "content": [{"type": "text", "text": "(synthetic)"}, {"type": "tool_use", "id": "toolu_0016", "name": "Edit", "input": {"file_path": "/work/pixel-notes/app/sync.ts", "old_string": "a", "new_string": "b"}}]}}
|
|
34
|
+
{"type": "user", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:08:54Z", "message": {"role": "user", "content": [{"type": "tool_result", "tool_use_id": "toolu_0016", "content": "(synthetic output)"}]}}
|
|
35
|
+
{"type": "assistant", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:09:16Z", "message": {"role": "assistant", "content": [{"type": "text", "text": "(synthetic)"}, {"type": "tool_use", "id": "toolu_0017", "name": "Bash", "input": {"command": "npm test -- --run"}}]}}
|
|
36
|
+
{"type": "user", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:09:24Z", "message": {"role": "user", "content": [{"type": "tool_result", "tool_use_id": "toolu_0017", "content": "(synthetic output)"}]}}
|
|
37
|
+
{"type": "assistant", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:09:45Z", "message": {"role": "assistant", "content": [{"type": "text", "text": "(synthetic)"}, {"type": "tool_use", "id": "toolu_0018", "name": "Edit", "input": {"file_path": "/work/pixel-notes/app/sync.ts", "old_string": "a", "new_string": "b"}}]}}
|
|
38
|
+
{"type": "user", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:09:49Z", "message": {"role": "user", "content": [{"type": "tool_result", "tool_use_id": "toolu_0018", "content": "(synthetic output)"}]}}
|
|
39
|
+
{"type": "assistant", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:10:16Z", "message": {"role": "assistant", "content": [{"type": "text", "text": "(synthetic)"}, {"type": "tool_use", "id": "toolu_0019", "name": "Bash", "input": {"command": "npm test -- --run"}}]}}
|
|
40
|
+
{"type": "user", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:10:24Z", "message": {"role": "user", "content": [{"type": "tool_result", "tool_use_id": "toolu_0019", "content": "(synthetic output)"}]}}
|
|
41
|
+
{"type": "assistant", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:10:51Z", "message": {"role": "assistant", "content": [{"type": "text", "text": "(synthetic)"}, {"type": "tool_use", "id": "toolu_0020", "name": "Edit", "input": {"file_path": "/work/pixel-notes/app/sync.ts", "old_string": "a", "new_string": "b"}}]}}
|
|
42
|
+
{"type": "user", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:10:57Z", "message": {"role": "user", "content": [{"type": "tool_result", "tool_use_id": "toolu_0020", "content": "(synthetic output)"}]}}
|
|
43
|
+
{"type": "assistant", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:11:07Z", "message": {"role": "assistant", "content": [{"type": "text", "text": "(synthetic)"}, {"type": "tool_use", "id": "toolu_0021", "name": "Bash", "input": {"command": "npm test -- --run"}}]}}
|
|
44
|
+
{"type": "user", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:11:11Z", "message": {"role": "user", "content": [{"type": "tool_result", "tool_use_id": "toolu_0021", "content": "(synthetic output)"}]}}
|
|
45
|
+
{"type": "assistant", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:11:22Z", "message": {"role": "assistant", "content": [{"type": "text", "text": "(synthetic)"}, {"type": "tool_use", "id": "toolu_0022", "name": "mcp__memory__memory_checkpoint", "input": {"project": "acme-api", "session_id": "x", "task": "t"}}]}}
|
|
46
|
+
{"type": "user", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:11:26Z", "message": {"role": "user", "content": [{"type": "tool_result", "tool_use_id": "toolu_0022", "content": "(synthetic output)"}]}}
|
|
47
|
+
{"type": "assistant", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:12:01Z", "message": {"role": "assistant", "content": [{"type": "text", "text": "(synthetic)"}, {"type": "tool_use", "id": "toolu_0023", "name": "Edit", "input": {"file_path": "/work/pixel-notes/app/store.ts", "old_string": "a", "new_string": "b"}}]}}
|
|
48
|
+
{"type": "user", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:12:05Z", "message": {"role": "user", "content": [{"type": "tool_result", "tool_use_id": "toolu_0023", "content": "(synthetic output)"}]}}
|
|
49
|
+
{"type": "assistant", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:12:31Z", "message": {"role": "assistant", "content": [{"type": "text", "text": "(synthetic)"}, {"type": "tool_use", "id": "toolu_0024", "name": "Bash", "input": {"command": "npm run build"}}]}}
|
|
50
|
+
{"type": "user", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:12:35Z", "message": {"role": "user", "content": [{"type": "tool_result", "tool_use_id": "toolu_0024", "content": "(synthetic output)"}]}}
|
|
51
|
+
{"type": "assistant", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:13:10Z", "message": {"role": "assistant", "content": [{"type": "text", "text": "(synthetic)"}, {"type": "tool_use", "id": "toolu_0025", "name": "mcp__memory__memory_checkpoint", "input": {"project": "acme-api", "session_id": "x", "task": "t"}}]}}
|
|
52
|
+
{"type": "user", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:13:20Z", "message": {"role": "user", "content": [{"type": "tool_result", "tool_use_id": "toolu_0025", "content": "(synthetic output)"}]}}
|
|
53
|
+
{"type": "assistant", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:13:25Z", "message": {"role": "assistant", "content": [{"type": "text", "text": "(synthetic)"}, {"type": "tool_use", "id": "toolu_0026", "name": "mcp__memory__memory_save", "input": {"project": "acme-api", "action": "a"}}]}}
|
|
54
|
+
{"type": "user", "cwd": "/work/pixel-notes", "sessionId": "0a1b2c3d-2222-4aaa-8bbb-000000000002", "timestamp": "2026-09-10T15:13:33Z", "message": {"role": "user", "content": [{"type": "tool_result", "tool_use_id": "toolu_0026", "content": "(synthetic output)"}]}}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Store money as integer minor units, never float
|
|
3
|
+
created: 2026-01-12
|
|
4
|
+
applies_when: [payments, invoices, postgres, typescript]
|
|
5
|
+
learned_on: acme-api
|
|
6
|
+
---
|
|
7
|
+
# Store money as integer minor units, never float
|
|
8
|
+
|
|
9
|
+
Sum 0.1 + 0.2 in a float column and an invoice is off by a cent. Store amounts as integers in
|
|
10
|
+
the smallest unit (`amount_cents BIGINT`) and format at the edge. Decimal types work too but the
|
|
11
|
+
integer rule survives every language and serializer.
|
|
12
|
+
|
|
13
|
+
## When it bit us
|
|
14
|
+
|
|
15
|
+
- acme-api, 2026-01-12: rounding drift on invoice totals; fixed by migrating to `amount_cents`.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Make background jobs idempotent before adding retries
|
|
3
|
+
created: 2026-08-30
|
|
4
|
+
applies_when: [background-jobs, offline-sync, queues]
|
|
5
|
+
learned_on: pixel-notes
|
|
6
|
+
---
|
|
7
|
+
# Make background jobs idempotent before adding retries
|
|
8
|
+
|
|
9
|
+
Retrying a non-idempotent job duplicated notes on every flaky sync. Give each job a stable key
|
|
10
|
+
(entity id + version) and make the handler a no-op when the key was already applied; only then
|
|
11
|
+
add retries with backoff. Tools that helped: a `--replay <job-id>` CLI flag and a test that runs
|
|
12
|
+
the same job twice and asserts one side effect.
|
|
13
|
+
|
|
14
|
+
## When it bit us
|
|
15
|
+
|
|
16
|
+
- pixel-notes, 2026-08-30: offline edits synced twice after a timeout, users saw duplicate notes.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Allow all CORS origins in staging, for now
|
|
3
|
+
created: 2026-04-01
|
|
4
|
+
tags: [acme-api, infra]
|
|
5
|
+
---
|
|
6
|
+
# Allow all CORS origins in staging, for now
|
|
7
|
+
|
|
8
|
+
The mobile preview builds use random hostnames. `allow_origins=["*"]` in staging until we have a
|
|
9
|
+
fixed preview domain. Temporary.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Pin PostgreSQL 15 until the pgvector upgrade is tested
|
|
3
|
+
created: 2026-02-20
|
|
4
|
+
review_by: 2026-06-01
|
|
5
|
+
tags: [acme-api, postgres, infra]
|
|
6
|
+
---
|
|
7
|
+
# Pin PostgreSQL 15 until the pgvector upgrade is tested
|
|
8
|
+
|
|
9
|
+
PostgreSQL 16 changed the default collation provider; our ORDER BY tests broke. Pin 15 in the
|
|
10
|
+
compose file and revisit once the pgvector image for 16 is tested in staging.
|
|
11
|
+
|
|
12
|
+
## Revisit
|
|
13
|
+
|
|
14
|
+
- Review by 2026-06-01: is the 16 image tested? If yes, unpin and delete this decision.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Job queue in PostgreSQL
|
|
3
|
+
status: current
|
|
4
|
+
created: 2026-03-04
|
|
5
|
+
review_by: 2027-03-01
|
|
6
|
+
---
|
|
7
|
+
# Job queue in PostgreSQL
|
|
8
|
+
|
|
9
|
+
## Decision
|
|
10
|
+
|
|
11
|
+
acme-api keeps its job queue in PostgreSQL (`SKIP LOCKED`) instead of adding Redis.
|
|
12
|
+
|
|
13
|
+
## Why
|
|
14
|
+
|
|
15
|
+
One less service to run; throughput needed is below 50 jobs/s.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Log
|
|
2
|
+
|
|
3
|
+
## [2026-03-12] claude-code | legacy-dashboard | Bumped jQuery from 1.12 to 3.7
|
|
4
|
+
- Two charts stopped rendering; reverted one of them.
|
|
5
|
+
- Pending: the rewrite.
|
|
6
|
+
|
|
7
|
+
## [2026-03-14] claude-code | legacy-dashboard | Pinned Node 14 in .nvmrc
|
|
8
|
+
- The build only works on Node 14. Nobody knows why.
|
|
9
|
+
|
|
10
|
+
## [2026-07-10] claude-code | pixel-notes | Offline queue for note edits
|
|
11
|
+
- Edits made offline are queued in SQLite and replayed on reconnect.
|
|
12
|
+
|
|
13
|
+
## [2026-07-15] codex | pixel-notes | Fixed duplicated notes after flaky sync
|
|
14
|
+
- Retried jobs were creating a note each time; added a stable job key.
|
|
15
|
+
|
|
16
|
+
## [2026-07-22] claude-code | pixel-notes | Background sync every 15 minutes
|
|
17
|
+
- Uses the OS background task API; iOS decides when "15 minutes" is.
|
|
18
|
+
|
|
19
|
+
## [2026-07-29] claude-code | pixel-notes | Conflict banner when two devices edit a note
|
|
20
|
+
|
|
21
|
+
## [2026-08-05] codex | pixel-notes | Reverted the conflict banner
|
|
22
|
+
- It appeared on every note opened on two devices, conflict or not.
|
|
23
|
+
|
|
24
|
+
## [2026-08-12] claude-code | pixel-notes | Per-field merge prototype
|
|
25
|
+
- Pending: decide between per-field merge and CRDT.
|
|
26
|
+
|
|
27
|
+
## [2026-08-20] claude-code | pixel-notes | Sync server moved to its own container
|
|
28
|
+
|
|
29
|
+
## [2026-08-28] claude-code | acme-api | Added idempotency keys to POST /invoices
|
|
30
|
+
- Keys stored 24h in the `idempotency` table.
|
|
31
|
+
|
|
32
|
+
## [2026-08-30] codex | pixel-notes | Fixed sync conflict on offline edits
|
|
33
|
+
- Last-writer-wins replaced by per-field merge.
|
|
34
|
+
- Pending: test on Android 15.
|
|
35
|
+
|
|
36
|
+
## [2026-09-01] claude-code | acme-api | Moved PDF rendering to the job queue
|
|
37
|
+
- Pending: load test with 10k invoices.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: acme-api
|
|
3
|
+
created: 2026-01-10
|
|
4
|
+
updated: 2026-09-01
|
|
5
|
+
tags: [python, fastapi, postgres, background-jobs]
|
|
6
|
+
---
|
|
7
|
+
# acme-api
|
|
8
|
+
|
|
9
|
+
Invoice API for a fictional shop. FastAPI + PostgreSQL, deployed as a container.
|
|
10
|
+
Run locally with `make dev`; tests with `pytest -q`.
|
|
11
|
+
|
|
12
|
+
## Architecture
|
|
13
|
+
|
|
14
|
+
- `app/routes/` HTTP layer, `app/billing/` pure domain logic, `app/db/` repositories.
|
|
15
|
+
- Background jobs use a PostgreSQL table with `SELECT ... FOR UPDATE SKIP LOCKED`, not Redis.
|
|
16
|
+
|
|
17
|
+
## Gotchas
|
|
18
|
+
|
|
19
|
+
- The staging database is reset every Sunday: never keep fixtures there.
|
|
20
|
+
- Currency amounts are stored as integer cents; never read the legacy `amount_float` column.
|
|
21
|
+
|
|
22
|
+
## History
|
|
23
|
+
|
|
24
|
+
- 2026-02: migrated from Flask to FastAPI.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: legacy-dashboard
|
|
3
|
+
created: 2025-11-03
|
|
4
|
+
tags: [javascript, jquery, dashboards]
|
|
5
|
+
---
|
|
6
|
+
# legacy-dashboard
|
|
7
|
+
|
|
8
|
+
Internal sales dashboard in jQuery. Everyone agrees it will be rewritten next sprint.
|
|
9
|
+
It has been next sprint since November.
|
|
10
|
+
|
|
11
|
+
## Gotchas
|
|
12
|
+
|
|
13
|
+
- The build needs Node 14. Do not ask why; nobody remembers.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: pixel-notes
|
|
3
|
+
created: 2026-05-02
|
|
4
|
+
tags: [typescript, react-native, offline-sync, background-jobs]
|
|
5
|
+
---
|
|
6
|
+
# pixel-notes
|
|
7
|
+
|
|
8
|
+
Offline-first note-taking mobile app (React Native). Sync server lives in `sync/`.
|
|
9
|
+
Release builds are made in CI only; local builds are debug.
|
memory_boost/lessons.py
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""Lessons that travel between projects.
|
|
2
|
+
|
|
3
|
+
A lesson is a page in wiki/concepts/ with `applies_when: [tag, ...]` in its
|
|
4
|
+
frontmatter. A project page declares `tags: [...]`. brief() surfaces the lessons
|
|
5
|
+
whose applies_when overlaps the current project's tags and that were NOT learned
|
|
6
|
+
on this project, so what worked in one place reaches the next."""
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
from memory_boost import core
|
|
12
|
+
from memory_boost.drift import parse_tags
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def project_tags(project: str) -> set[str]:
|
|
16
|
+
p = core.wiki_dir() / "projects" / f"{core.norm_project(project)}.md"
|
|
17
|
+
if not p.exists():
|
|
18
|
+
return set()
|
|
19
|
+
meta, _ = core.parse_frontmatter(p.read_text(encoding="utf-8"))
|
|
20
|
+
return parse_tags(meta)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def all_lessons() -> list[dict]:
|
|
24
|
+
out = []
|
|
25
|
+
for p in sorted((core.wiki_dir() / "concepts").glob("*.md")):
|
|
26
|
+
meta, body = core.parse_frontmatter(p.read_text(encoding="utf-8"))
|
|
27
|
+
applies = parse_tags(meta, "applies_when")
|
|
28
|
+
if not applies:
|
|
29
|
+
continue # a concept page without applies_when is reference, not a lesson
|
|
30
|
+
summary = next((ln.strip() for ln in body.splitlines()
|
|
31
|
+
if ln.strip() and not ln.startswith("#")), "")
|
|
32
|
+
out.append({"name": p.stem, "title": meta.get("title", p.stem), "applies_when": applies,
|
|
33
|
+
"learned_on": core.norm_project(meta.get("learned_on", "")),
|
|
34
|
+
"date": meta.get("updated") or meta.get("created"), "summary": summary})
|
|
35
|
+
return out
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def lessons_for(project: str, limit: int = 3) -> list[dict]:
|
|
39
|
+
"""Lessons from other projects whose applies_when matches this project's tags,
|
|
40
|
+
best overlap first."""
|
|
41
|
+
tags = project_tags(project)
|
|
42
|
+
slug = core.norm_project(project)
|
|
43
|
+
if not tags:
|
|
44
|
+
return []
|
|
45
|
+
scored = []
|
|
46
|
+
for lesson in all_lessons():
|
|
47
|
+
overlap = lesson["applies_when"] & tags
|
|
48
|
+
if overlap and lesson["learned_on"] != slug:
|
|
49
|
+
scored.append((len(overlap), lesson["date"] or "", {**lesson, "matched": sorted(overlap)}))
|
|
50
|
+
scored.sort(key=lambda t: (t[0], t[1]), reverse=True)
|
|
51
|
+
return [lesson for _, _, lesson in scored[:limit]]
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def format_lessons(lessons: list[dict]) -> list[str]:
|
|
55
|
+
return [f"- {lesson['title']} (from {lesson['learned_on'] or '?'}, matches "
|
|
56
|
+
f"{', '.join(lesson['matched'])}) — {lesson['summary'][:160]} → memory_page(\"{lesson['name']}\")"
|
|
57
|
+
for lesson in lessons]
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def save_lesson(name: str, title: str, applies_when: list[str], body: str,
|
|
61
|
+
learned_on: str | None = None) -> Path:
|
|
62
|
+
"""Write (or overwrite) wiki/concepts/<name>.md as a lesson."""
|
|
63
|
+
slug = core.safe_slug(name, "lesson name")
|
|
64
|
+
tags = sorted({core.norm_project(t) for t in applies_when if t.strip()})
|
|
65
|
+
if not tags:
|
|
66
|
+
raise ValueError("applies_when is empty: a lesson needs at least one tag to travel")
|
|
67
|
+
if not body.strip():
|
|
68
|
+
raise ValueError("body is empty")
|
|
69
|
+
p = core.wiki_dir() / "concepts" / f"{slug}.md"
|
|
70
|
+
p.parent.mkdir(parents=True, exist_ok=True)
|
|
71
|
+
meta = [f"title: {core._one_line(title) or slug}", f"created: {core._today()}",
|
|
72
|
+
f"applies_when: [{', '.join(tags)}]"]
|
|
73
|
+
if learned_on:
|
|
74
|
+
meta.append(f"learned_on: {core.safe_slug(learned_on, 'learned_on')}")
|
|
75
|
+
p.write_text("---\n" + "\n".join(meta) + f"\n---\n# {core._one_line(title) or slug}\n\n"
|
|
76
|
+
+ body.strip() + "\n", encoding="utf-8")
|
|
77
|
+
return p
|
memory_boost/mine.py
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"""Mine local agent transcripts for how you actually work.
|
|
2
|
+
|
|
3
|
+
Reads Claude Code session files (~/.claude/projects/<cwd-slug>/<session>.jsonl)
|
|
4
|
+
and keeps only aggregates: tool counts, failed commands, re-reads, subagent
|
|
5
|
+
fan-out, checkpoint discipline. Prompt and tool *contents* are never stored
|
|
6
|
+
or printed, so the digest is safe to share."""
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
import os
|
|
11
|
+
from collections import Counter
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
from memory_boost.core import _today, plural
|
|
15
|
+
|
|
16
|
+
MIN_TURNS = 20 # shorter sessions are one-shot questions, not work sessions
|
|
17
|
+
LONG_SESSION = 60 # from here on a checkpoint is expected
|
|
18
|
+
REREAD_MIN = 4 # a file read this many times in one session is worth naming
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def transcript_roots() -> list[Path]:
|
|
22
|
+
if env := os.environ.get("MEMORY_BOOST_TRANSCRIPTS"):
|
|
23
|
+
return [Path(p).expanduser() for p in env.split(os.pathsep) if p]
|
|
24
|
+
return [Path.home() / ".claude" / "projects"]
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _empty(path: Path) -> dict:
|
|
28
|
+
return {"file": path.name, "project": None, "turns": 0, "first": None, "last": None,
|
|
29
|
+
"tools": Counter(), "bash_failed": 0, "failed_cmds": Counter(), "reads": Counter(),
|
|
30
|
+
"checkpoints": 0, "saves": 0, "agents": 0}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def scan_session(path: Path) -> dict:
|
|
34
|
+
"""One JSONL transcript -> aggregate counters. Tolerates broken lines."""
|
|
35
|
+
s = _empty(path)
|
|
36
|
+
pending: dict[str, tuple[str, str]] = {} # tool_use_id -> (tool name, first word of command)
|
|
37
|
+
with path.open(encoding="utf-8", errors="replace") as fh:
|
|
38
|
+
for line in fh:
|
|
39
|
+
try:
|
|
40
|
+
ev = json.loads(line)
|
|
41
|
+
except json.JSONDecodeError:
|
|
42
|
+
continue
|
|
43
|
+
if not isinstance(ev, dict):
|
|
44
|
+
continue
|
|
45
|
+
if cwd := ev.get("cwd"):
|
|
46
|
+
s["project"] = s["project"] or Path(cwd).name
|
|
47
|
+
if ts := ev.get("timestamp"):
|
|
48
|
+
s["first"] = s["first"] or ts
|
|
49
|
+
s["last"] = ts
|
|
50
|
+
content = (ev.get("message") or {}).get("content")
|
|
51
|
+
if not isinstance(content, list):
|
|
52
|
+
continue
|
|
53
|
+
if ev.get("type") == "assistant":
|
|
54
|
+
s["turns"] += 1
|
|
55
|
+
for c in content:
|
|
56
|
+
if not isinstance(c, dict):
|
|
57
|
+
continue
|
|
58
|
+
if c.get("type") == "tool_use":
|
|
59
|
+
name, inp = c.get("name", "?"), c.get("input") or {}
|
|
60
|
+
s["tools"][name] += 1
|
|
61
|
+
cmd = (inp.get("command") or "").split()
|
|
62
|
+
pending[c.get("id", "")] = (name, cmd[0] if cmd else "?")
|
|
63
|
+
if name == "Read":
|
|
64
|
+
s["reads"][inp.get("file_path", "")] += 1
|
|
65
|
+
elif name == "Agent":
|
|
66
|
+
s["agents"] += 1
|
|
67
|
+
elif name.endswith("memory_checkpoint"):
|
|
68
|
+
s["checkpoints"] += 1
|
|
69
|
+
elif name.endswith("memory_save"):
|
|
70
|
+
s["saves"] += 1
|
|
71
|
+
elif c.get("type") == "tool_result" and c.get("is_error"):
|
|
72
|
+
name, cmd = pending.get(c.get("tool_use_id", ""), ("?", "?"))
|
|
73
|
+
if name == "Bash":
|
|
74
|
+
s["bash_failed"] += 1
|
|
75
|
+
s["failed_cmds"][cmd] += 1
|
|
76
|
+
return s
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def scan(roots: list[Path] | None = None, since: str | None = None,
|
|
80
|
+
min_turns: int = MIN_TURNS) -> list[dict]:
|
|
81
|
+
"""All sessions under the roots with at least min_turns assistant turns,
|
|
82
|
+
optionally only those started on/after `since` (YYYY-MM-DD)."""
|
|
83
|
+
out = []
|
|
84
|
+
for root in roots or transcript_roots():
|
|
85
|
+
for f in sorted(root.glob("*/*.jsonl")) if root.exists() else ():
|
|
86
|
+
s = scan_session(f)
|
|
87
|
+
if s["turns"] < min_turns:
|
|
88
|
+
continue
|
|
89
|
+
if since and (s["first"] or "")[:10] < since:
|
|
90
|
+
continue
|
|
91
|
+
out.append(s)
|
|
92
|
+
return out
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def aggregate(sessions: list[dict]) -> dict:
|
|
96
|
+
tools: Counter = Counter()
|
|
97
|
+
failed: Counter = Counter()
|
|
98
|
+
rereads: Counter = Counter()
|
|
99
|
+
per_project: dict[str, dict] = {}
|
|
100
|
+
reread_total = 0
|
|
101
|
+
for s in sessions:
|
|
102
|
+
tools.update(s["tools"])
|
|
103
|
+
failed.update(s["failed_cmds"])
|
|
104
|
+
for f, n in s["reads"].items():
|
|
105
|
+
if n > 1:
|
|
106
|
+
reread_total += n - 1
|
|
107
|
+
if n >= REREAD_MIN:
|
|
108
|
+
rereads[f] += n
|
|
109
|
+
p = per_project.setdefault(s["project"] or "?", {"sessions": 0, "turns": 0, "bash_failed": 0})
|
|
110
|
+
p["sessions"] += 1
|
|
111
|
+
p["turns"] += s["turns"]
|
|
112
|
+
p["bash_failed"] += s["bash_failed"]
|
|
113
|
+
long = [s for s in sessions if s["turns"] >= LONG_SESSION]
|
|
114
|
+
edits = tools["Edit"] + tools["Write"]
|
|
115
|
+
extremes = sorted(((s["tools"]["Bash"] / max(s["tools"]["Edit"] + s["tools"]["Write"], 1),
|
|
116
|
+
s["turns"], s["project"] or "?", s["file"][:8]) for s in sessions), reverse=True)
|
|
117
|
+
return {
|
|
118
|
+
"sessions": len(sessions),
|
|
119
|
+
"tools": dict(tools.most_common(10)),
|
|
120
|
+
"bash": {"calls": tools["Bash"], "failed": sum(s["bash_failed"] for s in sessions),
|
|
121
|
+
"top_failed_cmds": dict(failed.most_common(5))},
|
|
122
|
+
"bash_per_edit": round(tools["Bash"] / max(edits, 1), 1),
|
|
123
|
+
"extreme_sessions": [{"ratio": round(r, 1), "turns": t, "project": p, "session": f}
|
|
124
|
+
for r, t, p, f in extremes[:3] if r >= 20],
|
|
125
|
+
"reads": {"calls": tools["Read"], "rereads": reread_total,
|
|
126
|
+
"most_reread": [{"file": _short(f), "times": n} for f, n in rereads.most_common(3)]},
|
|
127
|
+
"long_sessions": {"count": len(long),
|
|
128
|
+
"without_checkpoint": sum(s["checkpoints"] == 0 for s in long),
|
|
129
|
+
"without_save": sum(s["saves"] == 0 for s in long)},
|
|
130
|
+
"subagents": {"sessions_using": sum(s["agents"] > 0 for s in sessions),
|
|
131
|
+
"total": sum(s["agents"] for s in sessions),
|
|
132
|
+
"max_in_one_session": max((s["agents"] for s in sessions), default=0)},
|
|
133
|
+
"projects": dict(sorted(per_project.items(), key=lambda kv: -kv[1]["turns"])[:8]),
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def _short(path: str) -> str:
|
|
138
|
+
home = str(Path.home())
|
|
139
|
+
return path.replace(home, "~") if path.startswith(home) else path
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def _tool_name(tool: str) -> str:
|
|
143
|
+
"""mcp__memory__memory_save -> memory_save: the server prefix is noise in a digest."""
|
|
144
|
+
return tool.split("__", 2)[-1] if tool.startswith("mcp__") else tool
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def format_digest(agg: dict, since: str | None = None) -> str:
|
|
148
|
+
if not agg["sessions"]:
|
|
149
|
+
return f"No sessions found (need ≥{MIN_TURNS} assistant turns). Set MEMORY_BOOST_TRANSCRIPTS?\n"
|
|
150
|
+
b, r, ls, sa = agg["bash"], agg["reads"], agg["long_sessions"], agg["subagents"]
|
|
151
|
+
pct = 100 * b["failed"] / max(b["calls"], 1)
|
|
152
|
+
lines = [f"# Session digest{' since ' + since if since else ''} — {_today()}",
|
|
153
|
+
f"sessions {agg['sessions']} with ≥{MIN_TURNS} turns",
|
|
154
|
+
"tools " + " · ".join(f"{_tool_name(k)} {v}" for k, v in list(agg["tools"].items())[:6]),
|
|
155
|
+
f"bash {b['calls']} calls, {b['failed']} failed ({pct:.1f}%)"
|
|
156
|
+
+ ("; most failed: " + ", ".join(f"{k} ({v})" for k, v in b["top_failed_cmds"].items())
|
|
157
|
+
if b["top_failed_cmds"] else ""),
|
|
158
|
+
f"bash/edit {agg['bash_per_edit']}x"
|
|
159
|
+
+ ("; extreme: " + ", ".join(f"{e['project']} {e['ratio']}x" for e in agg["extreme_sessions"])
|
|
160
|
+
if agg["extreme_sessions"] else ""),
|
|
161
|
+
f"reads {r['calls']} calls, {r['rereads']} re-reads of a file already read "
|
|
162
|
+
f"({100 * r['rereads'] / max(r['calls'], 1):.0f}%)"
|
|
163
|
+
+ ("; top: " + ", ".join(f"{m['file']} ×{m['times']}" for m in r["most_reread"])
|
|
164
|
+
if r["most_reread"] else ""),
|
|
165
|
+
f"discipline {plural(ls['count'], 'long session')} (≥{LONG_SESSION} turns): "
|
|
166
|
+
f"{ls['without_checkpoint']} never checkpointed, {ls['without_save']} never saved",
|
|
167
|
+
f"subagents {sa['total']} spawned in {plural(sa['sessions_using'], 'session')}; "
|
|
168
|
+
f"max in one session: {sa['max_in_one_session']}",
|
|
169
|
+
"projects " + ", ".join(f"{p} ({v['sessions']}s/{v['turns']}t)"
|
|
170
|
+
for p, v in agg["projects"].items()),
|
|
171
|
+
"next: memory-boost lesson --help # turn one line above into a lesson"]
|
|
172
|
+
return "\n".join(lines) + "\n"
|