@everme/claude-code 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/.claude-plugin/.mcp.json +9 -0
- package/.claude-plugin/marketplace.json +18 -0
- package/LICENSE +201 -0
- package/README.md +100 -0
- package/commands/everme-help.md +31 -0
- package/commands/recall.md +26 -0
- package/hooks/hooks.json +52 -0
- package/hooks/scripts/inject-memories.js +126 -0
- package/hooks/scripts/lib/api.js +54 -0
- package/hooks/scripts/lib/config.js +129 -0
- package/hooks/scripts/lib/profile.js +75 -0
- package/hooks/scripts/lib/redact.js +43 -0
- package/hooks/scripts/lib/source-key.js +54 -0
- package/hooks/scripts/lib/transcript.js +263 -0
- package/hooks/scripts/mcp-server.js +130 -0
- package/hooks/scripts/session-start.js +70 -0
- package/hooks/scripts/session-summary.js +24 -0
- package/hooks/scripts/store-memories.js +113 -0
- package/install.sh +112 -0
- package/package.json +40 -0
- package/plugin.json +12 -0
- package/skills/memory-tools.md +35 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* SessionStart hook — surface a recent-context block when a new
|
|
4
|
+
* Claude Code session begins. Helps the user (and Claude) pick up
|
|
5
|
+
* where the previous session left off without manually pasting
|
|
6
|
+
* context.
|
|
7
|
+
*
|
|
8
|
+
* Hook contract:
|
|
9
|
+
* stdin = JSON { cwd, session_id, ... }
|
|
10
|
+
* stdout = JSON { systemMessage, hookSpecificOutput: { ..., additionalContext } }
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
process.on("uncaughtException", () => process.exit(0));
|
|
14
|
+
process.on("unhandledRejection", () => process.exit(0));
|
|
15
|
+
|
|
16
|
+
import { isConfigured } from "./lib/config.js";
|
|
17
|
+
import { getContext } from "./lib/api.js";
|
|
18
|
+
import { redactError, debug } from "./lib/redact.js";
|
|
19
|
+
import { renderProfileBlock, profileItemCount } from "./lib/profile.js";
|
|
20
|
+
|
|
21
|
+
const TOP_K = 6;
|
|
22
|
+
|
|
23
|
+
async function main() {
|
|
24
|
+
if (!isConfigured()) {
|
|
25
|
+
debug("start", "skip: not configured");
|
|
26
|
+
return process.exit(0);
|
|
27
|
+
}
|
|
28
|
+
await readStdinJSON(); // drain stdin (may be empty)
|
|
29
|
+
|
|
30
|
+
let block = "";
|
|
31
|
+
let count = 0;
|
|
32
|
+
try {
|
|
33
|
+
// Empty query — the gateway returns the user's profile snapshot.
|
|
34
|
+
// Shape: { profile: {explicit_info, implicit_traits, ...} }
|
|
35
|
+
const ctx = await getContext("", { topK: TOP_K });
|
|
36
|
+
block = renderProfileBlock(ctx?.profile);
|
|
37
|
+
count = profileItemCount(ctx?.profile);
|
|
38
|
+
} catch (err) {
|
|
39
|
+
debug("start", "context failed:", redactError(err?.message));
|
|
40
|
+
return process.exit(0);
|
|
41
|
+
}
|
|
42
|
+
if (!block || count === 0) {
|
|
43
|
+
debug("start", "no context");
|
|
44
|
+
return process.exit(0);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const out = {
|
|
48
|
+
systemMessage: `🧠 EverMe loaded ${count} memory ${count === 1 ? "item" : "items"} from past sessions`,
|
|
49
|
+
hookSpecificOutput: {
|
|
50
|
+
hookEventName: "SessionStart",
|
|
51
|
+
additionalContext: block,
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
process.stdout.write(JSON.stringify(out));
|
|
55
|
+
process.exit(0);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async function readStdinJSON() {
|
|
59
|
+
const chunks = [];
|
|
60
|
+
for await (const c of process.stdin) chunks.push(c);
|
|
61
|
+
const raw = Buffer.concat(chunks).toString("utf8");
|
|
62
|
+
if (!raw) return {};
|
|
63
|
+
try {
|
|
64
|
+
return JSON.parse(raw);
|
|
65
|
+
} catch {
|
|
66
|
+
return {};
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
main();
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* SessionEnd hook — no runtime persistence here.
|
|
4
|
+
*
|
|
5
|
+
* Claude Code runtime memory is written turn-by-turn by the Stop hook through
|
|
6
|
+
* /mem/agent-memory. SessionEnd must not upload a markdown summary to
|
|
7
|
+
* /mem/sources, otherwise long-lived sessions create document sources.
|
|
8
|
+
*
|
|
9
|
+
* Hook contract:
|
|
10
|
+
* stdin = JSON { transcript_path, session_id, cwd, ... }
|
|
11
|
+
* stdout = empty (no UI surface needed)
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
process.on("uncaughtException", () => process.exit(0));
|
|
15
|
+
process.on("unhandledRejection", () => process.exit(0));
|
|
16
|
+
|
|
17
|
+
import { debug } from "./lib/redact.js";
|
|
18
|
+
|
|
19
|
+
async function main() {
|
|
20
|
+
debug("summary", "skip: runtime persistence is handled by Stop via /mem/agent-memory");
|
|
21
|
+
process.exit(0);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
main();
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Stop hook — fires after Claude finishes responding to a turn.
|
|
4
|
+
* We read the transcript JSONL Claude Code wrote, extract the
|
|
5
|
+
* just-completed raw turn, and POST it through the realtime gateway
|
|
6
|
+
* (/mem/agent-memory). Runtime turns must not create /mem/sources.
|
|
7
|
+
*
|
|
8
|
+
* Hook contract (from Claude Code):
|
|
9
|
+
* stdin = JSON { transcript_path, cwd, session_id, ... }
|
|
10
|
+
* stdout = empty (no need to surface anything to the user)
|
|
11
|
+
*
|
|
12
|
+
* Failure-mode: silent exit 0 — host must NEVER notice memory
|
|
13
|
+
* persistence is broken. The gateway has its own retry loop on the
|
|
14
|
+
* worker side, so a single dropped Stop event isn't catastrophic.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
process.on("uncaughtException", () => process.exit(0));
|
|
18
|
+
process.on("unhandledRejection", () => process.exit(0));
|
|
19
|
+
|
|
20
|
+
import { isConfigured, getConfig } from "./lib/config.js";
|
|
21
|
+
import {
|
|
22
|
+
saveAgentMemory,
|
|
23
|
+
EvermeError,
|
|
24
|
+
} from "./lib/api.js";
|
|
25
|
+
import { AGENT_MEMORY_ROLES } from "@everme/agent-sdk";
|
|
26
|
+
import { readTranscript, extractAgentMessages } from "./lib/transcript.js";
|
|
27
|
+
import { redactError, debug } from "./lib/redact.js";
|
|
28
|
+
|
|
29
|
+
const MIN_MESSAGES = 1;
|
|
30
|
+
|
|
31
|
+
async function main() {
|
|
32
|
+
if (!isConfigured()) {
|
|
33
|
+
debug("store", "skip: not configured");
|
|
34
|
+
return process.exit(0);
|
|
35
|
+
}
|
|
36
|
+
const cfg = getConfig();
|
|
37
|
+
if (cfg.authMode !== "evt" || !cfg.agentId) {
|
|
38
|
+
debug("store", "skip: realtime agent memory requires EVERME_AGENT_TOKEN + EVERME_AGENT_ID");
|
|
39
|
+
return process.exit(0);
|
|
40
|
+
}
|
|
41
|
+
const data = await readStdinJSON();
|
|
42
|
+
const transcriptPath = data?.transcript_path;
|
|
43
|
+
const sessionId = data?.session_id || "claude-code-session";
|
|
44
|
+
if (!transcriptPath) {
|
|
45
|
+
debug("store", "skip: no transcript_path");
|
|
46
|
+
return process.exit(0);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const lines = await readTranscript(transcriptPath);
|
|
50
|
+
const messages = extractAgentMessages(lines);
|
|
51
|
+
// Only persist the LAST user/assistant pair from this Stop event so
|
|
52
|
+
// we don't re-upload the entire history every turn — backend chains
|
|
53
|
+
// versions per documentKey, so each call appends.
|
|
54
|
+
const tail = lastTurn(messages);
|
|
55
|
+
if (tail.length < MIN_MESSAGES) {
|
|
56
|
+
debug("store", `skip: tail < ${MIN_MESSAGES} messages (got ${tail.length})`);
|
|
57
|
+
return process.exit(0);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
// Stop is the natural session-end signal for Claude Code; flush
|
|
62
|
+
// so EverOS extracts episodes/profiles instead of letting
|
|
63
|
+
// raw_messages accumulate indefinitely.
|
|
64
|
+
const res = await saveAgentMemory({
|
|
65
|
+
conversationId: sessionId,
|
|
66
|
+
messages: tail,
|
|
67
|
+
flush: true,
|
|
68
|
+
});
|
|
69
|
+
debug("store", `ok agent-memory status=${res?.status || "unknown"} flushed=${!!res?.flushed} messages=${res?.messageCount || tail.length}`);
|
|
70
|
+
} catch (err) {
|
|
71
|
+
if (err instanceof EvermeError) {
|
|
72
|
+
debug("store", `failed type=${err.type}:`, redactError(err.message));
|
|
73
|
+
} else {
|
|
74
|
+
debug("store", "unexpected:", redactError(err?.message || String(err)));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
process.exit(0);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Take the latest user prompt + assistant reply pair (plus any
|
|
82
|
+
* tool/tool_result events that fall between them). The gateway's
|
|
83
|
+
* realtime write API receives only this delta — uploading the whole
|
|
84
|
+
* history would duplicate memories on every turn.
|
|
85
|
+
*/
|
|
86
|
+
function lastTurn(messages) {
|
|
87
|
+
if (messages.length === 0) return [];
|
|
88
|
+
// Walk backwards: take everything from the last `user` event
|
|
89
|
+
// through the end. That captures user → tool... → assistant flow.
|
|
90
|
+
let startIdx = -1;
|
|
91
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
92
|
+
if (messages[i].role === AGENT_MEMORY_ROLES.USER) {
|
|
93
|
+
startIdx = i;
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (startIdx === -1) return messages;
|
|
98
|
+
return messages.slice(startIdx);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async function readStdinJSON() {
|
|
102
|
+
const chunks = [];
|
|
103
|
+
for await (const c of process.stdin) chunks.push(c);
|
|
104
|
+
const raw = Buffer.concat(chunks).toString("utf8");
|
|
105
|
+
if (!raw) return {};
|
|
106
|
+
try {
|
|
107
|
+
return JSON.parse(raw);
|
|
108
|
+
} catch {
|
|
109
|
+
return {};
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
main();
|
package/install.sh
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# EverMe plugin installer for Claude Code.
|
|
4
|
+
#
|
|
5
|
+
# What it does:
|
|
6
|
+
# 1. Verifies `claude` CLI exists and Node 18+.
|
|
7
|
+
# 2. Prompts for EVERME_API_KEY (an emk_*) if not already set, and
|
|
8
|
+
# writes it to ~/.claude/everme.env (mode 0600). The plugin's
|
|
9
|
+
# lib/config.js loads this file at hook startup.
|
|
10
|
+
# 3. Tells `claude` to install this plugin from the local directory.
|
|
11
|
+
#
|
|
12
|
+
# What it does NOT do:
|
|
13
|
+
# - Edit the user's shell profile. Earlier revisions appended an
|
|
14
|
+
# `export EVERME_API_KEY=…` line to ~/.zshrc / ~/.bashrc — that
|
|
15
|
+
# stored a secret in a typically world-readable file (mode 0644)
|
|
16
|
+
# and accumulated a duplicate line on every re-install. We now
|
|
17
|
+
# mirror the path `evercli plugin install claude-code` uses: a
|
|
18
|
+
# 0600 file at ~/.claude/everme.env, scoped to the plugin.
|
|
19
|
+
set -e
|
|
20
|
+
|
|
21
|
+
CYAN='\033[0;36m'
|
|
22
|
+
GREEN='\033[0;32m'
|
|
23
|
+
RED='\033[0;31m'
|
|
24
|
+
YELLOW='\033[1;33m'
|
|
25
|
+
NC='\033[0m'
|
|
26
|
+
|
|
27
|
+
PLUGIN_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
28
|
+
ENV_FILE="$HOME/.claude/everme.env"
|
|
29
|
+
|
|
30
|
+
echo
|
|
31
|
+
echo -e "${CYAN}EverMe — Claude Code plugin installer${NC}"
|
|
32
|
+
echo
|
|
33
|
+
|
|
34
|
+
if ! command -v claude >/dev/null 2>&1; then
|
|
35
|
+
echo -e "${RED}claude CLI not found.${NC}"
|
|
36
|
+
echo "Install Claude Code first: https://claude.ai/code"
|
|
37
|
+
exit 1
|
|
38
|
+
fi
|
|
39
|
+
echo -e "${GREEN}✓${NC} Claude Code CLI detected"
|
|
40
|
+
|
|
41
|
+
if ! command -v node >/dev/null 2>&1; then
|
|
42
|
+
echo -e "${RED}node not found.${NC} Plugin hooks need Node 18+."
|
|
43
|
+
exit 1
|
|
44
|
+
fi
|
|
45
|
+
NODE_MAJOR=$(node -p "process.versions.node.split('.')[0]" 2>/dev/null || echo 0)
|
|
46
|
+
if [ "$NODE_MAJOR" -lt 18 ]; then
|
|
47
|
+
echo -e "${RED}node $NODE_MAJOR is too old.${NC} Need Node 18+."
|
|
48
|
+
exit 1
|
|
49
|
+
fi
|
|
50
|
+
echo -e "${GREEN}✓${NC} Node $(node --version)"
|
|
51
|
+
|
|
52
|
+
# Persist credentials to ~/.claude/everme.env (mode 0600). atomic_write
|
|
53
|
+
# mirrors evercli's writeFileAtomic — body goes via .tmp then rename so
|
|
54
|
+
# the plugin never reads a half-written file.
|
|
55
|
+
atomic_write_env() {
|
|
56
|
+
local body=$1
|
|
57
|
+
mkdir -p "$(dirname "$ENV_FILE")"
|
|
58
|
+
chmod 0700 "$(dirname "$ENV_FILE")" 2>/dev/null || true
|
|
59
|
+
local tmp="${ENV_FILE}.tmp"
|
|
60
|
+
rm -f "$tmp"
|
|
61
|
+
# umask 0077 → 0600 file; -e/-c work with O_EXCL semantics on noclobber.
|
|
62
|
+
(umask 0077 && printf '%s' "$body" > "$tmp")
|
|
63
|
+
mv -f "$tmp" "$ENV_FILE"
|
|
64
|
+
chmod 0600 "$ENV_FILE"
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
# Configure auth.
|
|
68
|
+
if [ -z "${EVERME_API_KEY:-}" ] && [ -z "${EVERME_AGENT_TOKEN:-}" ] && [ ! -f "$ENV_FILE" ]; then
|
|
69
|
+
echo
|
|
70
|
+
echo -e "${YELLOW}EverMe credentials not found.${NC}"
|
|
71
|
+
echo -n "Paste your account API key (starts with emk_, from the EverMe Web UI; input is hidden): "
|
|
72
|
+
# -s suppresses echo so the token never lands in shell scrollback.
|
|
73
|
+
read -rs EMK_INPUT
|
|
74
|
+
echo
|
|
75
|
+
if [ -z "$EMK_INPUT" ]; then
|
|
76
|
+
echo -e "${RED}No key provided. Aborting.${NC}"
|
|
77
|
+
exit 1
|
|
78
|
+
fi
|
|
79
|
+
|
|
80
|
+
BODY="# Managed by ${PLUGIN_DIR##*/}/install.sh — do not edit by hand.
|
|
81
|
+
# Re-run install.sh to refresh, or remove this file to disable the plugin.
|
|
82
|
+
"
|
|
83
|
+
if [ -n "${EVERME_API_BASE:-}" ]; then
|
|
84
|
+
BODY="${BODY}EVERME_API_BASE=${EVERME_API_BASE}
|
|
85
|
+
"
|
|
86
|
+
fi
|
|
87
|
+
BODY="${BODY}EVERME_API_KEY=${EMK_INPUT}
|
|
88
|
+
"
|
|
89
|
+
atomic_write_env "$BODY"
|
|
90
|
+
unset EMK_INPUT BODY
|
|
91
|
+
echo -e "${GREEN}✓${NC} Wrote credentials to $ENV_FILE (mode 0600)"
|
|
92
|
+
elif [ -f "$ENV_FILE" ]; then
|
|
93
|
+
echo -e "${GREEN}✓${NC} Existing $ENV_FILE detected — leaving credentials as-is"
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
# Optional API base override (default https://everme.evermind.ai).
|
|
97
|
+
if [ -n "${EVERME_API_BASE:-}" ]; then
|
|
98
|
+
echo -e "${GREEN}✓${NC} Using EVERME_API_BASE=$EVERME_API_BASE"
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
# Install via Claude Code's plugin system.
|
|
102
|
+
echo
|
|
103
|
+
echo -e "${CYAN}Installing plugin via 'claude plugin install'…${NC}"
|
|
104
|
+
claude plugin install "$PLUGIN_DIR"
|
|
105
|
+
|
|
106
|
+
echo
|
|
107
|
+
echo -e "${GREEN}✓ EverMe plugin installed.${NC}"
|
|
108
|
+
echo
|
|
109
|
+
echo "Next steps:"
|
|
110
|
+
echo " 1. Start Claude Code: claude"
|
|
111
|
+
echo " 2. Try '/everme-help' or '/recall <something>' to verify."
|
|
112
|
+
echo " 3. Set EVERME_DEBUG=1 in your environment to see hook traces on stderr."
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@everme/claude-code",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "EverMe native plugin for Claude Code — automatic memory recall via SessionStart/UserPromptSubmit/Stop/SessionEnd hooks, plus /recall slash + bundled MCP server.",
|
|
6
|
+
"license": "Apache-2.0",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=18.0.0"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"test": "node --test tests/redact.test.js tests/config.test.js tests/transcript.test.js"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"plugin.json",
|
|
15
|
+
".claude-plugin/",
|
|
16
|
+
"hooks/",
|
|
17
|
+
"commands/",
|
|
18
|
+
"skills/",
|
|
19
|
+
"install.sh",
|
|
20
|
+
"LICENSE",
|
|
21
|
+
"README.md"
|
|
22
|
+
],
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@everme/agent-sdk": "^0.1.0"
|
|
25
|
+
},
|
|
26
|
+
"keywords": ["evermind", "everme", "claude-code", "claude", "anthropic", "memory", "ai", "agent", "mcp"],
|
|
27
|
+
"homepage": "https://everme.ai",
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "git+https://github.com/alwaysday1/everme.git",
|
|
31
|
+
"directory": "plugins/claude-code"
|
|
32
|
+
},
|
|
33
|
+
"bugs": {
|
|
34
|
+
"url": "https://github.com/alwaysday1/everme/issues"
|
|
35
|
+
},
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"access": "public",
|
|
38
|
+
"registry": "https://registry.npmjs.org"
|
|
39
|
+
}
|
|
40
|
+
}
|
package/plugin.json
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "everme",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "EverMe — automatic memory recall for Claude Code. Recalls relevant context from past sessions before each prompt and saves new turns through the EverMe gateway.",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "EverMind AI",
|
|
7
|
+
"url": "https://everme.evermind.ai"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://everme.evermind.ai",
|
|
10
|
+
"keywords": ["memory", "context", "recall", "persistence", "everme"],
|
|
11
|
+
"license": "Apache-2.0"
|
|
12
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: How and when to use EverMe memory tools to bring past-session context into the current Claude Code conversation.
|
|
3
|
+
alwaysInclude: true
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# EverMe Memory Tools
|
|
7
|
+
|
|
8
|
+
You have two MCP tools that surface memory persisted by EverMe across past Claude Code sessions:
|
|
9
|
+
|
|
10
|
+
- `everme_search` — semantic + keyword hybrid search over the user's memory store. Returns ranked items with subject, summary, score.
|
|
11
|
+
- `everme_context` — fetch a server-rendered context block (profile + recent episodes) ready to inject into the current turn.
|
|
12
|
+
|
|
13
|
+
The plugin's UserPromptSubmit hook already injects relevant memory automatically before each prompt. You usually do NOT need to call these tools manually — they're for cases the auto-recall missed.
|
|
14
|
+
|
|
15
|
+
## When to use these tools
|
|
16
|
+
|
|
17
|
+
**Do call** when:
|
|
18
|
+
- The user references something they discussed before ("last time", "remember when", "we decided to use X")
|
|
19
|
+
- The user asks about a project pattern, decision, or convention you have no inline context for
|
|
20
|
+
- You're debugging an error message that may have been seen + resolved before
|
|
21
|
+
- The auto-recall block (`<everme_recall>...</everme_recall>` in your context) is empty or clearly unrelated to the current task
|
|
22
|
+
- The user explicitly asks you to "search my memory" / "recall" / "look up"
|
|
23
|
+
|
|
24
|
+
**Do NOT call** when:
|
|
25
|
+
- The current message is self-contained and you can answer from inline context
|
|
26
|
+
- You already searched in the current turn (don't duplicate)
|
|
27
|
+
- It's a general-knowledge question with no project history component
|
|
28
|
+
|
|
29
|
+
## Best practices
|
|
30
|
+
|
|
31
|
+
1. Search with the user's specific terms first; only broaden if zero hits.
|
|
32
|
+
2. Cite memories by subject so the user can trace them.
|
|
33
|
+
3. Synthesize, don't copy-paste — quote the relevant lines, not whole memory bodies.
|
|
34
|
+
4. If recall returns conflicting info ("two prior sessions disagree"), say so and ask the user which is current.
|
|
35
|
+
5. The user's emk / evt is a credential — never echo it back, even when EverMe-related errors surface.
|