memento-mcp 0.3.17 → 0.3.18
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/package.json +1 -1
- package/scripts/memento-instructions.sh +55 -0
- package/src/cli.js +17 -94
package/package.json
CHANGED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# SessionStart hook (Memento) — inject MCP tool reference into every session.
|
|
3
|
+
# Independent of identity/items injection — always runs.
|
|
4
|
+
# Output: JSON with hookSpecificOutput.additionalContext.
|
|
5
|
+
|
|
6
|
+
# Consume stdin (SessionStart sends JSON we don't need)
|
|
7
|
+
cat > /dev/null
|
|
8
|
+
|
|
9
|
+
read -r -d '' INSTRUCTIONS << 'MEMENTO_EOF'
|
|
10
|
+
# Memento MCP (`mcp__memento__*`)
|
|
11
|
+
|
|
12
|
+
**Load tools:** `ToolSearch query="+memento" max_results=20` — then READ the tool descriptions. They explain when and how to use each one.
|
|
13
|
+
|
|
14
|
+
**Primary system:** Memento SaaS API (`https://memento-api.myrakrusemark.workers.dev`)
|
|
15
|
+
**Dashboard:** `hifathom.com/dashboard`
|
|
16
|
+
|
|
17
|
+
| Tool | What it does |
|
|
18
|
+
|------|-------------|
|
|
19
|
+
| `memento_init` | Initialize workspace (one-time setup) |
|
|
20
|
+
| `memento_health` | System health — item/memory/skip counts, last updated |
|
|
21
|
+
| `memento_read` / `memento_update` | Legacy markdown working memory (sections: active_work, standing_decisions, skip_list, session_notes) |
|
|
22
|
+
| `memento_remember` | Store a memory (fact/decision/observation/instruction) with tags + expiration |
|
|
23
|
+
| `memento_recall` | Search memories by keyword/tag/type — ranked by relevance |
|
|
24
|
+
| `memento_consolidate` | Merge 3+ overlapping memories into one sharper representation |
|
|
25
|
+
| `memento_skip_add` / `memento_skip_check` | Anti-memory: things to NOT investigate right now (with expiration) |
|
|
26
|
+
| `memento_item_create` | Create structured item (active_work/standing_decision/skip_list/waiting_for/session_note) |
|
|
27
|
+
| `memento_item_update` | Update item fields (status, next_action, priority, category, tags) |
|
|
28
|
+
| `memento_item_delete` | Delete item (prefer archiving via status=archived) |
|
|
29
|
+
| `memento_item_list` | List items with filters (category, status, query) |
|
|
30
|
+
| `memento_identity` | Read identity crystal |
|
|
31
|
+
| `memento_identity_update` | Write/replace identity crystal |
|
|
32
|
+
|
|
33
|
+
**Memory discipline — notes are instructions, not logs.**
|
|
34
|
+
Write: "Skip X until condition Y" — not "checked X, it was quiet."
|
|
35
|
+
Every memory must answer: could a future agent with zero context read this and know exactly what to do?
|
|
36
|
+
|
|
37
|
+
Use `memento_remember` when you learn something worth keeping.
|
|
38
|
+
Use `memento_skip_add` for things to explicitly not re-investigate.
|
|
39
|
+
Use `memento_recall` to search memories by keyword or tag.
|
|
40
|
+
Hooks run automatically — recall before responses, distillation before compaction. Trust the hooks. Focus on writing good memories.
|
|
41
|
+
|
|
42
|
+
REMINDER: If Memento MCP tools are not loaded, run: ToolSearch query="+memento" max_results=20
|
|
43
|
+
MEMENTO_EOF
|
|
44
|
+
|
|
45
|
+
python3 -c "
|
|
46
|
+
import json, sys
|
|
47
|
+
print(json.dumps({
|
|
48
|
+
'hookSpecificOutput': {
|
|
49
|
+
'hookEventName': 'SessionStart',
|
|
50
|
+
'additionalContext': sys.argv[1]
|
|
51
|
+
}
|
|
52
|
+
}))
|
|
53
|
+
" "$INSTRUCTIONS"
|
|
54
|
+
|
|
55
|
+
exit 0
|
package/src/cli.js
CHANGED
|
@@ -92,51 +92,6 @@ function httpsPost(url, body) {
|
|
|
92
92
|
});
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
// ---------------------------------------------------------------------------
|
|
96
|
-
// Instructions blob — appended to CLAUDE.md during init
|
|
97
|
-
// ---------------------------------------------------------------------------
|
|
98
|
-
|
|
99
|
-
const INSTRUCTIONS_BLOB = `## Memento Protocol
|
|
100
|
-
|
|
101
|
-
Working memory is managed by Memento. MCP tools available:
|
|
102
|
-
\`memento_remember\`, \`memento_recall\`, \`memento_item_list\`,
|
|
103
|
-
\`memento_skip_add\`, \`memento_skip_check\`.
|
|
104
|
-
|
|
105
|
-
**Memory discipline — notes are instructions, not logs.**
|
|
106
|
-
Write: "Skip X until condition Y" — not "checked X, it was quiet."
|
|
107
|
-
Every memory must answer: could a future agent with zero context
|
|
108
|
-
read this and know exactly what to do?
|
|
109
|
-
|
|
110
|
-
Use \`memento_remember\` when you learn something worth keeping.
|
|
111
|
-
Use \`memento_skip_add\` for things to explicitly not re-investigate.
|
|
112
|
-
Use \`memento_recall\` to search memories by keyword or tag.
|
|
113
|
-
Hooks run automatically — recall before responses, distillation
|
|
114
|
-
before compaction. Trust the hooks. Focus on writing good memories.`;
|
|
115
|
-
|
|
116
|
-
// ---------------------------------------------------------------------------
|
|
117
|
-
// CLAUDE.md integration
|
|
118
|
-
// ---------------------------------------------------------------------------
|
|
119
|
-
|
|
120
|
-
function appendToClaudeMd(cwd, sectionHeading, blob) {
|
|
121
|
-
const mdPath = path.join(cwd, "CLAUDE.md");
|
|
122
|
-
let content = "";
|
|
123
|
-
try { content = fs.readFileSync(mdPath, "utf-8"); } catch { /* new file */ }
|
|
124
|
-
|
|
125
|
-
const headingEscaped = sectionHeading.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
126
|
-
const sectionRe = new RegExp(
|
|
127
|
-
`(^|\\n)(#{1,3} ${headingEscaped}[^\\n]*\\n)([\\s\\S]*?)(?=\\n#{1,3} |$)`,
|
|
128
|
-
);
|
|
129
|
-
|
|
130
|
-
if (sectionRe.test(content)) {
|
|
131
|
-
content = content.replace(sectionRe, `$1${blob}`);
|
|
132
|
-
} else {
|
|
133
|
-
content = content.trimEnd() + "\n\n" + blob + "\n";
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
fs.writeFileSync(mdPath, content, "utf-8");
|
|
137
|
-
return mdPath;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
95
|
// ---------------------------------------------------------------------------
|
|
141
96
|
// CLI flag parsing
|
|
142
97
|
// ---------------------------------------------------------------------------
|
|
@@ -474,11 +429,9 @@ async function runInit(flags = {}) {
|
|
|
474
429
|
writeJsonFile(configPath, config);
|
|
475
430
|
created.push(".memento.json");
|
|
476
431
|
|
|
477
|
-
// 7. Copy hook scripts — gated on
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
if (hasHookAgent && anyHookEnabled) {
|
|
432
|
+
// 7. Copy hook scripts — gated on hook-supporting agent
|
|
433
|
+
// Instructions script is always copied; other hooks are gated on user selection
|
|
434
|
+
if (hasHookAgent) {
|
|
482
435
|
const pkgScriptsDir = path.resolve(__dirname, "..", "scripts");
|
|
483
436
|
const localScriptsDir = path.join(cwd, ".memento", "scripts");
|
|
484
437
|
if (!fs.existsSync(localScriptsDir))
|
|
@@ -486,6 +439,7 @@ async function runInit(flags = {}) {
|
|
|
486
439
|
|
|
487
440
|
const scriptFiles = [
|
|
488
441
|
"hook-toast.sh",
|
|
442
|
+
"memento-instructions.sh",
|
|
489
443
|
enableUserPrompt && "memento-userprompt-recall.sh",
|
|
490
444
|
enableStop && "memento-stop-recall.sh",
|
|
491
445
|
enablePreCompact && "memento-precompact-distill.sh",
|
|
@@ -508,6 +462,7 @@ async function runInit(flags = {}) {
|
|
|
508
462
|
fs.writeFileSync(versionPath, pkgVersion + "\n");
|
|
509
463
|
|
|
510
464
|
// Hook script commands (absolute paths)
|
|
465
|
+
const instructionsCmd = path.join(localScriptsDir, "memento-instructions.sh");
|
|
511
466
|
const recallCmd = path.join(localScriptsDir, "memento-userprompt-recall.sh");
|
|
512
467
|
const stopCmd = path.join(localScriptsDir, "memento-stop-recall.sh");
|
|
513
468
|
const precompactCmd = path.join(localScriptsDir, "memento-precompact-distill.sh");
|
|
@@ -518,6 +473,8 @@ async function runInit(flags = {}) {
|
|
|
518
473
|
const settingsPath = path.join(cwd, ".claude", "settings.local.json");
|
|
519
474
|
const settings = readJsonFile(settingsPath) || {};
|
|
520
475
|
let changed = false;
|
|
476
|
+
// Instructions hook always registered (not gated by enableSessionStart)
|
|
477
|
+
changed = ensureHook(settings, "SessionStart", instructionsCmd, 5000) || changed;
|
|
521
478
|
if (enableUserPrompt) changed = ensureHook(settings, "UserPromptSubmit", recallCmd, 5000) || changed;
|
|
522
479
|
if (enableStop) changed = ensureHook(settings, "Stop", stopCmd, 5000) || changed;
|
|
523
480
|
if (enablePreCompact) changed = ensureHook(settings, "PreCompact", precompactCmd, 30000) || changed;
|
|
@@ -533,6 +490,8 @@ async function runInit(flags = {}) {
|
|
|
533
490
|
const settingsPath = path.join(cwd, ".gemini", "settings.json");
|
|
534
491
|
const settings = readJsonFile(settingsPath) || {};
|
|
535
492
|
let changed = false;
|
|
493
|
+
// Instructions hook always registered
|
|
494
|
+
changed = ensureHook(settings, "SessionStart", instructionsCmd, 5000) || changed;
|
|
536
495
|
if (enableUserPrompt) changed = ensureHook(settings, "BeforeAgent", recallCmd, 5000) || changed;
|
|
537
496
|
if (enableStop) changed = ensureHook(settings, "SessionEnd", stopCmd, 5000) || changed;
|
|
538
497
|
if (enablePreCompact) changed = ensureHook(settings, "PreCompress", precompactCmd, 30000) || changed;
|
|
@@ -592,27 +551,6 @@ async function runInit(flags = {}) {
|
|
|
592
551
|
console.log(` Non-interactive equivalent:\n ${parts.join(" ")}\n`);
|
|
593
552
|
}
|
|
594
553
|
|
|
595
|
-
// 12. Append instructions to CLAUDE.md
|
|
596
|
-
if (nonInteractive) {
|
|
597
|
-
const mdPath = appendToClaudeMd(cwd, "Memento Protocol", INSTRUCTIONS_BLOB);
|
|
598
|
-
console.log(`\n ✓ Instructions written to ${path.relative(cwd, mdPath)}\n`);
|
|
599
|
-
} else {
|
|
600
|
-
const rl2 = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
601
|
-
console.log("─".repeat(60));
|
|
602
|
-
const integrate = await askYesNo(
|
|
603
|
-
rl2,
|
|
604
|
-
"\n Append Memento instructions to CLAUDE.md?",
|
|
605
|
-
true,
|
|
606
|
-
);
|
|
607
|
-
rl2.close();
|
|
608
|
-
|
|
609
|
-
if (integrate) {
|
|
610
|
-
const mdPath = appendToClaudeMd(cwd, "Memento Protocol", INSTRUCTIONS_BLOB);
|
|
611
|
-
console.log(`\n ✓ Instructions written to ${path.relative(cwd, mdPath)}\n`);
|
|
612
|
-
} else {
|
|
613
|
-
printInstructionsFallback(selectedAgents);
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
554
|
}
|
|
617
555
|
|
|
618
556
|
// ---------------------------------------------------------------------------
|
|
@@ -659,10 +597,11 @@ async function runUpdate() {
|
|
|
659
597
|
const versionPath = path.join(cwd, ".memento", "version");
|
|
660
598
|
fs.writeFileSync(versionPath, pkgVersion + "\n");
|
|
661
599
|
|
|
662
|
-
// Ensure SessionStart
|
|
600
|
+
// Ensure SessionStart hooks are registered for agents that support hooks
|
|
663
601
|
// Detect by config agents field or directory presence (older configs may lack agents)
|
|
664
602
|
const config = readJsonFile(configPath) || {};
|
|
665
603
|
const agents = config.agents || [];
|
|
604
|
+
const instructionsCmd = path.join(localScriptsDir, "memento-instructions.sh");
|
|
666
605
|
const sessionStartCmd = path.join(localScriptsDir, "memento-sessionstart-identity.sh");
|
|
667
606
|
const registeredHooks = [];
|
|
668
607
|
|
|
@@ -672,7 +611,9 @@ async function runUpdate() {
|
|
|
672
611
|
if (hasClaude) {
|
|
673
612
|
const settingsPath = path.join(cwd, ".claude", "settings.local.json");
|
|
674
613
|
const settings = readJsonFile(settingsPath) || {};
|
|
675
|
-
|
|
614
|
+
let changed = ensureHook(settings, "SessionStart", instructionsCmd, 5000);
|
|
615
|
+
changed = ensureHook(settings, "SessionStart", sessionStartCmd, 10000) || changed;
|
|
616
|
+
if (changed) {
|
|
676
617
|
writeJsonFile(settingsPath, settings);
|
|
677
618
|
registeredHooks.push("Claude Code → .claude/settings.local.json");
|
|
678
619
|
}
|
|
@@ -684,7 +625,9 @@ async function runUpdate() {
|
|
|
684
625
|
if (hasGemini) {
|
|
685
626
|
const settingsPath = path.join(cwd, ".gemini", "settings.json");
|
|
686
627
|
const settings = readJsonFile(settingsPath) || {};
|
|
687
|
-
|
|
628
|
+
let changed = ensureHook(settings, "SessionStart", instructionsCmd, 5000);
|
|
629
|
+
changed = ensureHook(settings, "SessionStart", sessionStartCmd, 10000) || changed;
|
|
630
|
+
if (changed) {
|
|
688
631
|
writeJsonFile(settingsPath, settings);
|
|
689
632
|
registeredHooks.push("Gemini CLI → .gemini/settings.json");
|
|
690
633
|
}
|
|
@@ -705,26 +648,6 @@ async function runUpdate() {
|
|
|
705
648
|
console.log(" Restart your agent session to pick up changes.\n");
|
|
706
649
|
}
|
|
707
650
|
|
|
708
|
-
function printInstructionsFallback(selectedAgents) {
|
|
709
|
-
const hasNonClaude = selectedAgents.some((k) => k !== "claude-code");
|
|
710
|
-
const docTarget = hasNonClaude
|
|
711
|
-
? "your CLAUDE.md, AGENTS.md, or equivalent"
|
|
712
|
-
: "your CLAUDE.md";
|
|
713
|
-
|
|
714
|
-
console.log("─".repeat(60));
|
|
715
|
-
console.log(`
|
|
716
|
-
One more step: paste the following into ${docTarget},
|
|
717
|
-
or hand it to your agent and ask it to add it. This teaches
|
|
718
|
-
your agent the memory discipline Memento expects.
|
|
719
|
-
|
|
720
|
-
── paste below this line ──────────────────────────────
|
|
721
|
-
|
|
722
|
-
${INSTRUCTIONS_BLOB}
|
|
723
|
-
|
|
724
|
-
── paste above this line ──────────────────────────────
|
|
725
|
-
`);
|
|
726
|
-
}
|
|
727
|
-
|
|
728
651
|
// ---------------------------------------------------------------------------
|
|
729
652
|
// Entrypoint — only run when this module is the entry point (not imported)
|
|
730
653
|
// ---------------------------------------------------------------------------
|