memento-mcp 0.1.0
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.
- package/.env.example +3 -0
- package/LICENSE +21 -0
- package/README.md +206 -0
- package/docs/self-hosting.md +86 -0
- package/package.json +45 -0
- package/scripts/memento-memory-recall.sh +101 -0
- package/scripts/memento-precompact-distill.sh +82 -0
- package/src/index.js +713 -0
- package/src/storage/hosted.js +207 -0
- package/src/storage/interface.js +151 -0
package/.env.example
ADDED
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Myra Krusemark
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
# The Memento Protocol
|
|
2
|
+
|
|
3
|
+
Persistent memory for AI agents.
|
|
4
|
+
|
|
5
|
+
AI agents have anterograde amnesia — every session starts blank. The Memento Protocol gives agents a structured way to remember, not by recording everything, but by writing **instructions to their future selves**. Memories decay, consolidate, and evolve — like biological memory, not a log file.
|
|
6
|
+
|
|
7
|
+
## Get Started
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
git clone https://github.com/myrakrusemark/memento-protocol.git
|
|
11
|
+
cd memento-protocol && npm install
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Verify the install:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm run test:smoke
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
You should see all tools listed and "All smoke tests passed."
|
|
21
|
+
|
|
22
|
+
### Step 1: Sign up
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
curl -X POST https://memento-api.myrakrusemark.workers.dev/v1/auth/signup \
|
|
26
|
+
-H "Content-Type: application/json" \
|
|
27
|
+
-d '{"workspace": "my-project"}'
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
No email, no password, no OAuth. One curl, one key. Optionally include `"email"` for account recovery later.
|
|
31
|
+
|
|
32
|
+
Save the `api_key` from the response — you'll need it next.
|
|
33
|
+
|
|
34
|
+
### Step 2: Configure your MCP client
|
|
35
|
+
|
|
36
|
+
**Claude Code (project-level):** Create `.mcp.json` in your project root.
|
|
37
|
+
|
|
38
|
+
**Claude Code (global):** Add to `~/.claude.json` under `"mcpServers"`.
|
|
39
|
+
|
|
40
|
+
**Claude Desktop:** Add to your `claude_desktop_config.json`.
|
|
41
|
+
|
|
42
|
+
```json
|
|
43
|
+
{
|
|
44
|
+
"mcpServers": {
|
|
45
|
+
"memento": {
|
|
46
|
+
"command": "node",
|
|
47
|
+
"args": ["/home/you/memento-protocol/src/index.js"],
|
|
48
|
+
"env": {
|
|
49
|
+
"MEMENTO_API_KEY": "mp_live_your_key_here",
|
|
50
|
+
"MEMENTO_API_URL": "https://memento-api.myrakrusemark.workers.dev",
|
|
51
|
+
"MEMENTO_WORKSPACE": "my-project"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
> **Tip:** Replace the path with the actual absolute path to `src/index.js` in your clone. Run `echo "$(pwd)/src/index.js"` from inside the repo to get it.
|
|
59
|
+
|
|
60
|
+
### Step 3: Restart your client
|
|
61
|
+
|
|
62
|
+
The MCP server connects at startup. Restart so it picks up the new config.
|
|
63
|
+
|
|
64
|
+
### Step 4: First session
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
> memento_health() # verify connection
|
|
68
|
+
> memento_store( # store your first memory
|
|
69
|
+
content: "API uses /v2 endpoints. Auth is Bearer token in header.",
|
|
70
|
+
type: "instruction",
|
|
71
|
+
tags: ["api", "auth"]
|
|
72
|
+
)
|
|
73
|
+
> memento_recall(query: "api auth") # find it again
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
That's it. The agent reads memory at session start, updates it as it works, and writes instructions for next time.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Add to Your CLAUDE.md
|
|
81
|
+
|
|
82
|
+
Paste this block into your project's `CLAUDE.md` to teach your agent memory discipline:
|
|
83
|
+
|
|
84
|
+
```markdown
|
|
85
|
+
## Memory (Memento Protocol)
|
|
86
|
+
|
|
87
|
+
On session start:
|
|
88
|
+
1. `memento_health` — verify connection
|
|
89
|
+
2. `memento_item_list` — check active work items and their next actions
|
|
90
|
+
3. `memento_recall` with current task context — find relevant past memories
|
|
91
|
+
|
|
92
|
+
Writing memories:
|
|
93
|
+
- Instructions, not logs: "API moved to /v2 — update all calls" not "checked API, got 404"
|
|
94
|
+
- Tag generously — tags power recall and consolidation
|
|
95
|
+
- Set expiration on time-sensitive facts
|
|
96
|
+
- Use `memento_skip_add` for things to actively avoid (with expiry)
|
|
97
|
+
- Use `memento_item_create` for structured work tracking with next actions
|
|
98
|
+
|
|
99
|
+
Before session ends:
|
|
100
|
+
- `memento_item_update` with progress on active work (include what was done AND what comes next)
|
|
101
|
+
- `memento_store` for new decisions and discoveries
|
|
102
|
+
- `memento_skip_add` for things to skip next time
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Hooks
|
|
108
|
+
|
|
109
|
+
Hooks automate memory at session boundaries — the agent doesn't need to remember to recall or save. Two production-ready scripts are included in `scripts/`.
|
|
110
|
+
|
|
111
|
+
### Setup
|
|
112
|
+
|
|
113
|
+
1. **Create a `.env` file** in the repo root (copy from the example):
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
cp .env.example .env
|
|
117
|
+
# Then edit .env with your actual API key and workspace name
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
The `.env` file is gitignored. It needs three variables:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
MEMENTO_API_KEY=mp_live_your_key_here
|
|
124
|
+
MEMENTO_API_URL=https://memento-api.myrakrusemark.workers.dev
|
|
125
|
+
MEMENTO_WORKSPACE=my-project
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
2. **Make scripts executable** (they should already be, but just in case):
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
chmod +x scripts/*.sh
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
3. **Register in Claude Code settings** — add to `.claude/settings.json` (project-level) or `~/.claude/settings.json` (global):
|
|
135
|
+
|
|
136
|
+
```json
|
|
137
|
+
{
|
|
138
|
+
"hooks": {
|
|
139
|
+
"UserPromptSubmit": [
|
|
140
|
+
{
|
|
141
|
+
"command": "/path/to/memento-protocol/scripts/memento-memory-recall.sh",
|
|
142
|
+
"timeout": 5000
|
|
143
|
+
}
|
|
144
|
+
],
|
|
145
|
+
"PreCompact": [
|
|
146
|
+
{
|
|
147
|
+
"command": "/path/to/memento-protocol/scripts/memento-precompact-distill.sh",
|
|
148
|
+
"timeout": 30000
|
|
149
|
+
}
|
|
150
|
+
]
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Replace `/path/to/memento-protocol` with the actual absolute path to your clone.
|
|
156
|
+
|
|
157
|
+
### `memento-memory-recall.sh` (UserPromptSubmit)
|
|
158
|
+
|
|
159
|
+
Fires before every agent response. Sends the user's message to the `/v1/context` endpoint, which returns relevant memories and skip list warnings.
|
|
160
|
+
|
|
161
|
+
- **Timeout:** 5 seconds (3s API call + overhead)
|
|
162
|
+
- **User sees:** "Memento Recall: N memories" in their terminal
|
|
163
|
+
- **Model sees:** Full memory details and skip list warnings as injected context (via `additionalContext`)
|
|
164
|
+
- **Short messages:** Messages under 10 characters are skipped (greetings, "yes", etc.)
|
|
165
|
+
|
|
166
|
+
### `memento-precompact-distill.sh` (PreCompact)
|
|
167
|
+
|
|
168
|
+
Fires before Claude Code compresses the conversation. Parses the full JSONL transcript into readable text, then sends it to `/v1/distill` which extracts key memories, decisions, and observations — so nothing important is lost to compaction.
|
|
169
|
+
|
|
170
|
+
- **Timeout:** 30 seconds (transcript processing is heavier)
|
|
171
|
+
- **User sees:** "Memento Distill: extracted N memories" in their terminal
|
|
172
|
+
- **Transcript parsing:** Uses a dedicated parser script if available at `/data/Dropbox/Work/fathom/infrastructure/fathom-mcp/scripts/parse-transcript.sh`. Falls back to direct JSONL extraction (works everywhere, just less polished formatting).
|
|
173
|
+
- **Minimum threshold:** Transcripts under 200 characters are skipped.
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Dashboard
|
|
178
|
+
|
|
179
|
+
Browse and manage memories visually at [hifathom.com/dashboard](https://hifathom.com/dashboard). Paste your API key and workspace name to connect.
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Documentation
|
|
184
|
+
|
|
185
|
+
Full reference docs at [hifathom.com/projects/memento](https://hifathom.com/projects/memento):
|
|
186
|
+
|
|
187
|
+
- **[Quick Start](https://hifathom.com/projects/memento/quick-start)** — 5-minute setup guide
|
|
188
|
+
- **[Core Concepts](https://hifathom.com/projects/memento/concepts)** — memories, working memory, skip lists, identity crystals
|
|
189
|
+
- **[MCP Tools](https://hifathom.com/projects/memento/mcp-tools)** — full tool reference with parameters and examples
|
|
190
|
+
- **[API Reference](https://hifathom.com/projects/memento/api)** — REST endpoints, request/response schemas, authentication
|
|
191
|
+
- **[Self-Hosting](docs/self-hosting.md)** — deploy your own instance with Cloudflare Workers + Turso
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## Development
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
npm test # Run unit + integration tests
|
|
199
|
+
npm run lint # Lint with ESLint
|
|
200
|
+
npm run format:check # Check formatting with Prettier
|
|
201
|
+
npm run test:smoke # Quick smoke test of all tools
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## License
|
|
205
|
+
|
|
206
|
+
MIT
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Self-Hosting
|
|
2
|
+
|
|
3
|
+
The Memento Protocol API runs on Cloudflare Workers with Turso edge databases. The full source is in `saas/`.
|
|
4
|
+
|
|
5
|
+
For most users, the [hosted service](https://memento-api.myrakrusemark.workers.dev) is the fastest path — free tier, no infrastructure to manage. Self-hosting makes sense if you need data sovereignty or want to modify the API.
|
|
6
|
+
|
|
7
|
+
## Prerequisites
|
|
8
|
+
|
|
9
|
+
- [Cloudflare account](https://dash.cloudflare.com/sign-up) (Workers free tier works)
|
|
10
|
+
- [Turso account](https://turso.tech) (free tier: 500 databases, 9GB storage)
|
|
11
|
+
- Node.js 18+
|
|
12
|
+
- [Wrangler CLI](https://developers.cloudflare.com/workers/wrangler/install-and-update/): `npm i -g wrangler`
|
|
13
|
+
|
|
14
|
+
## Setup
|
|
15
|
+
|
|
16
|
+
### 1. Create the control plane database
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
turso db create memento-control
|
|
20
|
+
turso db tokens create memento-control
|
|
21
|
+
turso db show memento-control --url
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Save the URL and token — you'll need them as secrets.
|
|
25
|
+
|
|
26
|
+
### 2. Create the Vectorize index
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
wrangler vectorize create memento-memories --dimensions=384 --metric=cosine
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
This powers semantic search. The API degrades gracefully without it (keyword-only recall), but you'll want it.
|
|
33
|
+
|
|
34
|
+
### 3. Set secrets
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
cd saas
|
|
38
|
+
wrangler secret put MEMENTO_DB_URL # Turso control plane URL
|
|
39
|
+
wrangler secret put MEMENTO_DB_TOKEN # Turso control plane token
|
|
40
|
+
wrangler secret put TURSO_API_TOKEN # Turso Platform API token (for creating workspace DBs)
|
|
41
|
+
wrangler secret put TURSO_ORG # Your Turso organization slug
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The Turso Platform API token is needed because the API auto-creates a separate database per workspace. Get it from [Turso dashboard > Settings > Platform API Tokens](https://turso.tech/app).
|
|
45
|
+
|
|
46
|
+
### 4. Deploy
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
cd saas
|
|
50
|
+
npm install
|
|
51
|
+
wrangler deploy
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Your API is now live at `https://memento-api.<your-subdomain>.workers.dev`.
|
|
55
|
+
|
|
56
|
+
### 5. Point the MCP server at your instance
|
|
57
|
+
|
|
58
|
+
In your MCP client config, set the environment variables to your instance:
|
|
59
|
+
|
|
60
|
+
```json
|
|
61
|
+
{
|
|
62
|
+
"env": {
|
|
63
|
+
"MEMENTO_API_KEY": "mp_live_your_key",
|
|
64
|
+
"MEMENTO_API_URL": "https://memento-api.your-subdomain.workers.dev",
|
|
65
|
+
"MEMENTO_WORKSPACE": "my-project"
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## What you get
|
|
71
|
+
|
|
72
|
+
| Feature | Requires |
|
|
73
|
+
|---------|----------|
|
|
74
|
+
| Core memory (store, recall, working memory, skip list) | Workers + Turso |
|
|
75
|
+
| Semantic search (vector embeddings) | + Vectorize + Workers AI |
|
|
76
|
+
| AI consolidation summaries | + Workers AI |
|
|
77
|
+
| Scheduled decay + consolidation | Cron triggers (auto-configured in `wrangler.toml`) |
|
|
78
|
+
|
|
79
|
+
Workers AI and Vectorize are included in the Cloudflare Workers free tier.
|
|
80
|
+
|
|
81
|
+
## What's different from hosted
|
|
82
|
+
|
|
83
|
+
- You manage your own Turso databases and Cloudflare account
|
|
84
|
+
- You handle upgrades by pulling from the repo and redeploying
|
|
85
|
+
- No usage dashboard at hifathom.com (you'd use Cloudflare's dashboard)
|
|
86
|
+
- Signup endpoint creates keys in your control plane database
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "memento-mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "The Memento Protocol — persistent memory for AI agents",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "src/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"memento-server": "src/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"start": "node src/index.js",
|
|
12
|
+
"test": "node --test test/*.test.js",
|
|
13
|
+
"test:smoke": "node test-smoke.js",
|
|
14
|
+
"lint": "eslint .",
|
|
15
|
+
"lint:fix": "eslint --fix .",
|
|
16
|
+
"format": "prettier --write .",
|
|
17
|
+
"format:check": "prettier --check ."
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
21
|
+
"zod": "^3.24.2"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"src/",
|
|
25
|
+
"scripts/",
|
|
26
|
+
"docs/",
|
|
27
|
+
"LICENSE",
|
|
28
|
+
"README.md",
|
|
29
|
+
".env.example"
|
|
30
|
+
],
|
|
31
|
+
"keywords": [
|
|
32
|
+
"mcp",
|
|
33
|
+
"memory",
|
|
34
|
+
"ai-agent",
|
|
35
|
+
"persistent",
|
|
36
|
+
"memento"
|
|
37
|
+
],
|
|
38
|
+
"license": "MIT",
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@eslint/js": "^10.0.1",
|
|
41
|
+
"eslint": "^10.0.0",
|
|
42
|
+
"globals": "^17.3.0",
|
|
43
|
+
"prettier": "^3.8.1"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Memento SaaS recall — context retrieval from Memento Protocol on every user message.
|
|
3
|
+
# JSON output: systemMessage (user sees count) + additionalContext (model sees details).
|
|
4
|
+
#
|
|
5
|
+
# Calls /v1/context endpoint for memories + skip list matches.
|
|
6
|
+
|
|
7
|
+
set -o pipefail
|
|
8
|
+
|
|
9
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
10
|
+
|
|
11
|
+
# Source credentials from .env (gitignored)
|
|
12
|
+
if [ -f "$SCRIPT_DIR/../.env" ]; then
|
|
13
|
+
set -a
|
|
14
|
+
source "$SCRIPT_DIR/../.env"
|
|
15
|
+
set +a
|
|
16
|
+
fi
|
|
17
|
+
|
|
18
|
+
MEMENTO_API="${MEMENTO_API_URL:-https://memento-api.myrakrusemark.workers.dev}"
|
|
19
|
+
MEMENTO_KEY="${MEMENTO_API_KEY:?MEMENTO_API_KEY not set — check memento-protocol/.env}"
|
|
20
|
+
MEMENTO_WS="${MEMENTO_WORKSPACE:-fathom}"
|
|
21
|
+
|
|
22
|
+
INPUT=$(cat)
|
|
23
|
+
USER_MESSAGE=$(echo "$INPUT" | jq -r '.prompt // empty' 2>/dev/null)
|
|
24
|
+
|
|
25
|
+
if [ -z "$USER_MESSAGE" ] || [ ${#USER_MESSAGE} -lt 10 ]; then
|
|
26
|
+
exit 0
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
QUERY="${USER_MESSAGE:0:500}"
|
|
30
|
+
|
|
31
|
+
# Call Memento SaaS /v1/context
|
|
32
|
+
SAAS_OUTPUT=$(curl -s --max-time 3 \
|
|
33
|
+
-X POST \
|
|
34
|
+
-H "Authorization: Bearer $MEMENTO_KEY" \
|
|
35
|
+
-H "X-Memento-Workspace: $MEMENTO_WS" \
|
|
36
|
+
-H "Content-Type: application/json" \
|
|
37
|
+
-d "{\"message\": $(echo "$QUERY" | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))'), \"include\": [\"memories\", \"skip_list\"]}" \
|
|
38
|
+
"$MEMENTO_API/v1/context" 2>/dev/null \
|
|
39
|
+
| python3 -c "
|
|
40
|
+
import json, sys
|
|
41
|
+
try:
|
|
42
|
+
data = json.load(sys.stdin)
|
|
43
|
+
lines = []
|
|
44
|
+
count = 0
|
|
45
|
+
|
|
46
|
+
# Memory matches
|
|
47
|
+
memories = data.get('memories', {}).get('matches', [])
|
|
48
|
+
if memories:
|
|
49
|
+
for m in memories[:5]:
|
|
50
|
+
tags = m.get('tags', [])
|
|
51
|
+
tag_str = f' [{\", \".join(tags)}]' if tags else ''
|
|
52
|
+
content = m['content'][:120]
|
|
53
|
+
score = m.get('score', '?')
|
|
54
|
+
lines.append(f' {m[\"id\"]} ({m[\"type\"]}, {score}){tag_str} — {content}')
|
|
55
|
+
count += 1
|
|
56
|
+
|
|
57
|
+
# Skip matches (WARNING format)
|
|
58
|
+
skip_matches = data.get('skip_matches', [])
|
|
59
|
+
if skip_matches:
|
|
60
|
+
lines.append('')
|
|
61
|
+
lines.append('SKIP LIST WARNINGS:')
|
|
62
|
+
for s in skip_matches:
|
|
63
|
+
lines.append(f' ⚠ SKIP: {s[\"item\"]} — {s[\"reason\"]} (expires: {s[\"expires\"]})')
|
|
64
|
+
|
|
65
|
+
# Output count and detail as tab-separated on first line, rest follows
|
|
66
|
+
detail = '\n'.join(lines)
|
|
67
|
+
print(f'{count}\t{detail}')
|
|
68
|
+
except Exception:
|
|
69
|
+
print('0\t')
|
|
70
|
+
" 2>/dev/null)
|
|
71
|
+
|
|
72
|
+
# Parse count and detail
|
|
73
|
+
SAAS_COUNT=$(echo "$SAAS_OUTPUT" | head -1 | cut -f1)
|
|
74
|
+
SAAS_DETAIL=$(echo "$SAAS_OUTPUT" | head -1 | cut -f2-)
|
|
75
|
+
# Append any remaining lines (skip warnings etc.)
|
|
76
|
+
REMAINING=$(echo "$SAAS_OUTPUT" | tail -n +2)
|
|
77
|
+
if [ -n "$REMAINING" ]; then
|
|
78
|
+
SAAS_DETAIL="$SAAS_DETAIL"$'\n'"$REMAINING"
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
if [ -z "$SAAS_COUNT" ] || [ "$SAAS_COUNT" = "0" ]; then
|
|
82
|
+
exit 0
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
DETAIL_TEXT="Memento Recall: ${SAAS_COUNT} memories"
|
|
86
|
+
DETAIL_TEXT="$DETAIL_TEXT"$'\n'"$SAAS_DETAIL"
|
|
87
|
+
DETAIL_TEXT="$DETAIL_TEXT"$'\n'$'\n'"REMINDER: If Memento MCP tools are not loaded, run: ToolSearch query=\"+memento\" max_results=20"
|
|
88
|
+
|
|
89
|
+
SUMMARY="Memento Recall: ${SAAS_COUNT} memories"
|
|
90
|
+
python3 -c "
|
|
91
|
+
import json, sys
|
|
92
|
+
summary = sys.argv[1]
|
|
93
|
+
detail = sys.argv[2]
|
|
94
|
+
print(json.dumps({
|
|
95
|
+
'systemMessage': summary,
|
|
96
|
+
'hookSpecificOutput': {
|
|
97
|
+
'hookEventName': 'UserPromptSubmit',
|
|
98
|
+
'additionalContext': detail
|
|
99
|
+
}
|
|
100
|
+
}))
|
|
101
|
+
" "$SUMMARY" "$DETAIL_TEXT"
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# PreCompact hook (Memento) — Distill memories from conversation transcript before context compression.
|
|
3
|
+
# Parses JSONL transcript into readable text, then sends it to Memento SaaS /v1/distill endpoint,
|
|
4
|
+
# which extracts key memories, decisions, and observations.
|
|
5
|
+
#
|
|
6
|
+
# Independent of other PreCompact hooks — reads the raw JSONL transcript directly.
|
|
7
|
+
|
|
8
|
+
set -o pipefail
|
|
9
|
+
|
|
10
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
11
|
+
INPUT=$(cat)
|
|
12
|
+
|
|
13
|
+
TRANSCRIPT_PATH=$(echo "$INPUT" | jq -r '.transcript_path' | sed "s|~|$HOME|")
|
|
14
|
+
|
|
15
|
+
# Only distill if transcript exists and has content
|
|
16
|
+
if [ ! -f "$TRANSCRIPT_PATH" ]; then
|
|
17
|
+
exit 0
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
LINE_COUNT=$(wc -l < "$TRANSCRIPT_PATH")
|
|
21
|
+
if [ "$LINE_COUNT" -lt 2 ]; then
|
|
22
|
+
exit 0
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
# Source credentials from .env (gitignored)
|
|
26
|
+
if [ -f "$SCRIPT_DIR/../.env" ]; then
|
|
27
|
+
set -a
|
|
28
|
+
source "$SCRIPT_DIR/../.env"
|
|
29
|
+
set +a
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
MEMENTO_API="${MEMENTO_API_URL:-https://memento-api.myrakrusemark.workers.dev}"
|
|
33
|
+
MEMENTO_KEY="${MEMENTO_API_KEY:?MEMENTO_API_KEY not set — check memento-protocol/.env}"
|
|
34
|
+
MEMENTO_WS="${MEMENTO_WORKSPACE:-fathom}"
|
|
35
|
+
|
|
36
|
+
# Parse transcript to readable text (use fathom's parser if available, else raw)
|
|
37
|
+
FATHOM_PARSER="/data/Dropbox/Work/fathom/infrastructure/fathom-mcp/scripts/parse-transcript.sh"
|
|
38
|
+
if [ -x "$FATHOM_PARSER" ]; then
|
|
39
|
+
TRANSCRIPT_TEXT=$("$FATHOM_PARSER" "$TRANSCRIPT_PATH")
|
|
40
|
+
else
|
|
41
|
+
# Fallback: extract text content directly from JSONL
|
|
42
|
+
TRANSCRIPT_TEXT=$(jq -r 'select(.type == "user" or .type == "assistant") | .message.content | if type == "string" then . elif type == "array" then [.[] | select(.type == "text") | .text] | join("\n") else empty end' "$TRANSCRIPT_PATH" 2>/dev/null)
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
if [ ${#TRANSCRIPT_TEXT} -lt 200 ]; then
|
|
46
|
+
exit 0 # Too short to distill anything useful
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
# Send to Memento SaaS /v1/distill
|
|
50
|
+
RESPONSE=$(curl -s --max-time 30 \
|
|
51
|
+
-X POST \
|
|
52
|
+
-H "Authorization: Bearer $MEMENTO_KEY" \
|
|
53
|
+
-H "X-Memento-Workspace: $MEMENTO_WS" \
|
|
54
|
+
-H "Content-Type: application/json" \
|
|
55
|
+
-d "{\"transcript\": $(echo "$TRANSCRIPT_TEXT" | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))')}" \
|
|
56
|
+
"$MEMENTO_API/v1/distill" 2>/dev/null)
|
|
57
|
+
|
|
58
|
+
# Report results
|
|
59
|
+
MEMORY_COUNT=$(echo "$RESPONSE" | python3 -c "
|
|
60
|
+
import json, sys
|
|
61
|
+
try:
|
|
62
|
+
data = json.load(sys.stdin)
|
|
63
|
+
print(len(data.get('memories', [])))
|
|
64
|
+
except Exception:
|
|
65
|
+
print('0')
|
|
66
|
+
" 2>/dev/null)
|
|
67
|
+
|
|
68
|
+
if [ "$MEMORY_COUNT" -gt 0 ] 2>/dev/null; then
|
|
69
|
+
python3 -c "
|
|
70
|
+
import json, sys
|
|
71
|
+
msg = sys.argv[1]
|
|
72
|
+
print(json.dumps({'systemMessage': msg}))
|
|
73
|
+
" "Memento Distill: extracted ${MEMORY_COUNT} memories"
|
|
74
|
+
else
|
|
75
|
+
python3 -c "
|
|
76
|
+
import json, sys
|
|
77
|
+
msg = sys.argv[1]
|
|
78
|
+
print(json.dumps({'systemMessage': msg}))
|
|
79
|
+
" "Memento Distill: no memories extracted"
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
exit 0
|