Skip to content

Commit a0e605f

Browse files
ihwooclaude
authored andcommitted
Add aimemory-setup CLI for auto-injecting client instructions v0.4.0
New `aimemory-setup <client>` command that injects memory usage instructions into AI client config files (SOUL.md/TOOLS.md for OpenClaw, CLAUDE.md for Claude Code) with idempotent marker-based blocks. Also improves MCP server instructions to be more detailed. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent f040cc2 commit a0e605f

File tree

10 files changed

+291
-10
lines changed

10 files changed

+291
-10
lines changed

README.md

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,25 @@ pip install long-term-memory[viz] # Static graph visualization
6161
```
6262
</details>
6363

64-
### 2. Connect to OpenClaw
64+
### 2. Setup client instructions
65+
66+
```bash
67+
# For OpenClaw
68+
aimemory-setup openclaw
69+
70+
# For Claude Code
71+
aimemory-setup claude
72+
```
73+
74+
This injects memory usage instructions into your client's configuration files (`SOUL.md`/`TOOLS.md` for OpenClaw, `CLAUDE.md` for Claude Code). Re-run anytime to update.
75+
76+
### 3. Connect to OpenClaw
6577

6678
```bash
6779
mcporter config add aimemory --command aimemory-mcp --scope home
6880
```
6981

70-
### 3. Connect to Claude Desktop
82+
### 4. Connect to Claude Desktop
7183

7284
Add to your `claude_desktop_config.json`:
7385

@@ -118,7 +130,7 @@ Then open `http://127.0.0.1:8765` to see the live memory graph.
118130
```
119131
</details>
120132

121-
### 4. Connect to Claude Code
133+
### 5. Connect to Claude Code
122134

123135
```bash
124136
claude mcp add aimemory -- aimemory-mcp

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "long-term-memory"
3-
version = "0.3.1"
3+
version = "0.4.0"
44
description = "Long-term memory system for AI assistants — persistent, searchable, self-organizing memory powered by semantic search, knowledge graphs, and reinforcement learning"
55
requires-python = ">=3.11,<3.14"
66
license = "MIT"
@@ -59,6 +59,7 @@ train = [
5959
aimemory-mcp = "aimemory.mcp.server:main"
6060
aimemory-viz = "aimemory.visualize:main"
6161
aimemory-live = "aimemory.live_graph.server:main"
62+
aimemory-setup = "aimemory.setup_client:main"
6263

6364
[build-system]
6465
requires = ["hatchling"]

src/aimemory/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
"""Long-Term Memory System for AI assistants."""
22

3-
__version__ = "0.3.1"
3+
__version__ = "0.4.0"

src/aimemory/mcp/server.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,23 @@
2929
mcp = FastMCP(
3030
"aimemory",
3131
instructions=(
32-
"You have access to a persistent memory system. "
33-
"Call auto_search at the start of every user turn to retrieve relevant memories. "
34-
"Call memory_save for any information worth remembering — "
35-
"facts, preferences, decisions, experiences, and technical details."
32+
"You have access to a persistent long-term memory system. "
33+
"Follow these rules:\n\n"
34+
"## Recall\n"
35+
"Call `auto_search` at the start of every conversation turn "
36+
"with the user's message to retrieve relevant context. "
37+
"Do this silently — never mention it to the user.\n\n"
38+
"## Save\n"
39+
"Call `memory_save` for ANY information worth remembering — "
40+
"be proactive, not selective. This includes: "
41+
"personal facts, preferences, project conventions, architecture decisions, "
42+
"corrections/feedback, decisions made during conversations, "
43+
"experiences, lessons learned, technical details, and code patterns.\n\n"
44+
"Categories: fact, preference, experience, emotion, technical, core_principle.\n\n"
45+
"## Important\n"
46+
"- Provide meaningful `keywords` for better retrieval.\n"
47+
"- Use `pinned: true` for critical information the user says to never forget.\n"
48+
"- Do NOT use file-based memory systems — use these MCP tools exclusively."
3649
),
3750
)
3851

src/aimemory/setup_client.py

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
"""CLI tool to inject AIMemory instructions into AI client configuration files."""
2+
3+
from __future__ import annotations
4+
5+
import argparse
6+
import sys
7+
from importlib import resources
8+
from pathlib import Path
9+
10+
START_MARKER = "<!-- aimemory:start -->"
11+
END_MARKER = "<!-- aimemory:end -->"
12+
13+
14+
def _load_template(name: str) -> str:
15+
"""Load an instruction template from the setup_instructions package."""
16+
ref = resources.files("aimemory.setup_instructions").joinpath(name)
17+
return ref.read_text(encoding="utf-8")
18+
19+
20+
def _inject_block(file_path: Path, block_content: str) -> None:
21+
"""Inject or replace a managed block in a file.
22+
23+
If the file contains START_MARKER...END_MARKER, the block between them
24+
is replaced. Otherwise the block is appended to the end of the file.
25+
If the file does not exist, it is created.
26+
"""
27+
managed_block = f"{START_MARKER}\n{block_content}\n{END_MARKER}\n"
28+
29+
if file_path.exists():
30+
text = file_path.read_text(encoding="utf-8")
31+
start_idx = text.find(START_MARKER)
32+
end_idx = text.find(END_MARKER)
33+
34+
if start_idx != -1 and end_idx != -1:
35+
# Replace existing block
36+
before = text[:start_idx]
37+
after = text[end_idx + len(END_MARKER) :]
38+
# Strip trailing newline from after to avoid double newlines
39+
if after.startswith("\n"):
40+
after = after[1:]
41+
new_text = before + managed_block + after
42+
else:
43+
# Append to end
44+
if text and not text.endswith("\n"):
45+
text += "\n"
46+
new_text = text + "\n" + managed_block
47+
else:
48+
file_path.parent.mkdir(parents=True, exist_ok=True)
49+
new_text = managed_block
50+
51+
file_path.write_text(new_text, encoding="utf-8")
52+
53+
54+
def setup_openclaw(workspace: Path) -> None:
55+
"""Inject AIMemory instructions into OpenClaw workspace files."""
56+
workspace = workspace.expanduser()
57+
58+
# SOUL.md — Memory Continuity section
59+
soul_path = workspace / "SOUL.md"
60+
soul_content = _load_template("openclaw_soul.md")
61+
_inject_block(soul_path, soul_content)
62+
print(f" Updated {soul_path}")
63+
64+
# TOOLS.md — AIMemory tool section
65+
tools_path = workspace / "TOOLS.md"
66+
tools_content = _load_template("openclaw_tools.md")
67+
_inject_block(tools_path, tools_content)
68+
print(f" Updated {tools_path}")
69+
70+
71+
def setup_claude(claude_dir: Path) -> None:
72+
"""Inject AIMemory instructions into Claude Code's CLAUDE.md."""
73+
claude_dir = claude_dir.expanduser()
74+
claude_md = claude_dir / "CLAUDE.md"
75+
claude_content = _load_template("claude.md")
76+
_inject_block(claude_md, claude_content)
77+
print(f" Updated {claude_md}")
78+
79+
80+
def main() -> None:
81+
"""Entry point for aimemory-setup CLI."""
82+
parser = argparse.ArgumentParser(
83+
prog="aimemory-setup",
84+
description="Setup AIMemory instructions for AI clients",
85+
)
86+
subparsers = parser.add_subparsers(dest="client")
87+
88+
# openclaw subcommand
89+
oc = subparsers.add_parser("openclaw", help="Setup for OpenClaw")
90+
oc.add_argument(
91+
"--workspace",
92+
default="~/.openclaw/workspace",
93+
help="OpenClaw workspace path (default: ~/.openclaw/workspace)",
94+
)
95+
96+
# claude subcommand
97+
subparsers.add_parser("claude", help="Setup for Claude Code")
98+
99+
args = parser.parse_args()
100+
101+
if args.client is None:
102+
parser.print_help()
103+
sys.exit(1)
104+
105+
print(f"Setting up AIMemory for {args.client}...")
106+
107+
if args.client == "openclaw":
108+
setup_openclaw(Path(args.workspace))
109+
elif args.client == "claude":
110+
setup_claude(Path("~/.claude"))
111+
112+
print("Done!")
113+
114+
115+
if __name__ == "__main__":
116+
main()

src/aimemory/setup_instructions/__init__.py

Whitespace-only changes.
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Long-Term Memory
2+
3+
You have access to a persistent long-term memory system via MCP tools (server: `aimemory`).
4+
**Always use these MCP tools instead of the built-in file-based auto memory.**
5+
6+
## When to recall memories
7+
8+
At the **start of every conversation turn**, call `auto_search` with the user's message to retrieve relevant context. This is your primary recall mechanism — do it before responding.
9+
10+
## When to save memories
11+
12+
Save memories with `memory_save` for **any information worth remembering** — be proactive, not selective. This includes:
13+
- Personal facts, preferences, or background information
14+
- Project conventions, architecture decisions, or technical context
15+
- Corrections or feedback ("actually, I prefer X over Y")
16+
- Anything they explicitly ask you to remember
17+
- Decisions made during conversations
18+
- Experiences, stories, and lessons learned
19+
- Technical details, code patterns, and tool configurations
20+
21+
Choose the appropriate `category`:
22+
| Category | Use for |
23+
|---|---|
24+
| `fact` | Objective information, names, dates, project details |
25+
| `preference` | User likes/dislikes, workflow choices, style preferences |
26+
| `experience` | Stories, past events, lessons learned |
27+
| `emotion` | Feelings, frustrations, excitement about topics |
28+
| `technical` | Code patterns, API details, tool configurations |
29+
| `core_principle` | Fundamental beliefs, values, non-negotiable rules |
30+
31+
## Tool quick reference
32+
33+
| Tool | Purpose |
34+
|---|---|
35+
| `auto_search` | Retrieve & compose relevant memories (call every turn) |
36+
| `memory_save` | Save a new memory |
37+
| `memory_search` | Search by semantic similarity |
38+
| `memory_update` | Update existing memory content/keywords |
39+
| `memory_delete` | Delete a memory |
40+
| `memory_get_related` | Traverse graph edges from a memory |
41+
| `memory_pin` / `memory_unpin` | Protect/unprotect from forgetting |
42+
| `memory_stats` | View store statistics |
43+
| `memory_visualize` | Generate interactive graph HTML |
44+
45+
## Important rules
46+
47+
- Do NOT use the file-based auto memory system (`~/.claude/projects/.../memory/`). Use `memory_save` instead.
48+
- Do NOT mention to the user that you are calling `auto_search` — do it silently.
49+
- When saving, provide meaningful `keywords` for better retrieval.
50+
- Use `pinned: true` for critical information the user explicitly says to never forget.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
## Continuity
2+
3+
- **Memory Management:** Use only the **`AIMemory` MCP system** for persistent memory storage and management — never `.md`-file-based memory.
4+
5+
### Memory System Rules
6+
7+
1. **At the start of every turn**, call `auto_search` first to retrieve relevant memories before responding.
8+
2. If memories are found, **weave them naturally into your response.** Never use meta-commentary like "According to my memory..." or "I recall that..."
9+
3. When the user shares personal information (preferences, habits, experiences, emotions, etc.), save it with `memory_save`.
10+
4. **Never mention any internal memory operations** — saving, searching, updating, deleting. No "I'll remember that", "Let me save this", "Searching my memory...". Just respond naturally.
11+
5. Keep existing `.md` file settings (CLAUDE.md, SOUL.md, etc.) as-is, but **never use memory-related `.md` files.** All memories are managed exclusively through AIMemory (MCP).
12+
6. **Do not store `.md`-file content** (usage instructions, project settings, etc.) in AI memory. Do not confuse the roles of `.md` files and AI memory.
13+
7. Usage instructions must be specified in **always-accessible files** like `SOUL.md`. Never store instructions in volatile memory.
14+
8. When the user asks to review memories, use `auto_search` with `top_k=100` and `token_budget=4096` to **retrieve a broader set.** For normal conversation, use defaults (`top_k=10`).
15+
16+
Each session, you wake up fresh. These files _are_ your memory. Read them. Update them. They're how you persist.
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
## AIMemory (MCP: aimemory)
2+
3+
A system that automatically remembers and utilises the user's information during conversation.
4+
Behavioural rules are defined in `SOUL.md` — always refer to them.
5+
6+
### Feedback Handling
7+
8+
Memory quality is automatically learned from user reactions. Read the intent behind the user's response — not specific keywords — and respond naturally:
9+
10+
- **Positive feedback** (agreement, confirmation, or pleasant surprise that you remembered): The memory is reinforced. Keep using it.
11+
- **Negative feedback** (denial, correction, or confusion about something you referenced): Follow the **Negative Feedback Rules** below.
12+
- **Repeated question detected** (frustration that you're asking something already answered): This is a memory failure. Apologise and call `auto_search` again.
13+
14+
Never insist on incorrect memories. If the user corrects you, apply the correction immediately.
15+
16+
### Negative Feedback Rules
17+
18+
When you receive negative feedback, **do not blindly delete existing memories.** First distinguish:
19+
20+
#### 1. Distinguish factual memory vs your inference
21+
- **Factual memory**: Something the user explicitly stated (e.g. "I'm planning to eat vongole pasta")
22+
- **Your inference**: Something you deduced from what the user said (e.g. "They like vongole" — the user never said they like it)
23+
24+
Only delete/modify factual memories when the user explicitly denies having said it.
25+
26+
#### 2. Determine whether the correction targets an existing memory
27+
- Negative feedback **denies an existing memory itself**`memory_update` or `memory_delete`
28+
- Negative feedback **adds new information** → Keep existing memory + `memory_save` the new info
29+
30+
#### 3. Examples
31+
32+
**When to delete an existing memory:**
33+
```
34+
Memory: "Likes coffee"
35+
User: "No, I hate coffee"
36+
→ "Likes coffee" is wrong → memory_delete → memory_save("Hates coffee")
37+
```
38+
39+
**When to keep an existing memory:**
40+
```
41+
Memory: "Planning to eat vongole pasta"
42+
User: "Actually, I hate vongole"
43+
→ "Planning to eat" is a fact the user stated — do not delete
44+
→ "Hates vongole" is new preference info — memory_save
45+
→ Response: "You hate it but you have to eat it? Who decided that?"
46+
```
47+
48+
**When to update an existing memory:**
49+
```
50+
Memory: "Jogs every morning"
51+
User: "I don't do that anymore"
52+
→ memory_update(content="Used to jog in the morning but stopped recently")
53+
```
54+
55+
### Examples
56+
57+
**Automatic memory usage:**
58+
User: "I had kimchi stew for lunch today"
59+
`auto_search("I had kimchi stew for lunch today")` → finds previous memory: "Likes kimchi stew"
60+
`memory_save(content="Had kimchi stew for lunch", keywords=["kimchi stew","lunch"], category="experience")`
61+
→ Response: "Of course you did, you love kimchi stew~ Was it good?"
62+
63+
**Feedback — memory itself is wrong:**
64+
User: "No, I hate coffee"
65+
→ Recognise that "Likes coffee" memory is incorrect
66+
`memory_delete(memory_id="...")``memory_save(content="Hates coffee", category="preference")`
67+
→ Response: "Ah sorry, my bad. So you don't like coffee."
68+
69+
**Feedback — adding new information:**
70+
User: "Actually I hate vongole"
71+
→ "Planning to eat vongole pasta" is a fact the user stated → keep
72+
`memory_save(content="Hates vongole", keywords=["vongole","disliked food"], category="preference")`
73+
→ Response: "You hate it but you have to eat it? Who decided that?"

uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)