feat: add MemPalace Claude Code plugin with hooks and instructions

- Introduced README.md for plugin overview and installation instructions.
- Added hooks configuration in hooks.json for auto-save and pre-compact functionality.
- Implemented stop and pre-compact hooks in bash scripts for memory management.
- Created marketplace.json and plugin.json for plugin metadata and versioning.
- Developed skills and instructions for help, init, mine, search, and status functionalities.
- Added CLI commands for executing hooks and displaying skill instructions.
- Implemented hooks_cli.py for handling hook logic and JSON input/output.
- Enhanced instruction files for user guidance on setup and usage.
- Updated .gitignore to exclude additional files.
- Created GitHub Actions workflow for syncing plugin version on push.
This commit is contained in:
Tal Muskal
2026-04-08 14:55:46 +03:00
parent 71736a3f4f
commit 3d00a93655
21 changed files with 887 additions and 0 deletions
+60
View File
@@ -0,0 +1,60 @@
# MemPalace Claude Code Plugin
A Claude Code plugin that gives your AI a persistent memory system. Mine projects and conversations into a searchable palace backed by ChromaDB, with 19 MCP tools, auto-save hooks, and 5 guided skills.
## Prerequisites
- Python 3.9+
## Installation
### Claude Code Marketplace
```bash
claude plugin add mempalace
```
### Git
```bash
claude plugin add --git https://github.com/milla-jovovich/mempalace
```
### Local Clone
```bash
claude plugin add /path/to/mempalace
```
## Post-Install Setup
After installing the plugin, run the init command to complete setup (pip install, MCP configuration, etc.):
```
/mempalace:init
```
## Available Slash Commands
| Command | Description |
|---------|-------------|
| `/mempalace:help` | Show available tools, skills, and architecture |
| `/mempalace:init` | Set up MemPalace -- install, configure MCP, onboard |
| `/mempalace:search` | Search your memories across the palace |
| `/mempalace:mine` | Mine projects and conversations into the palace |
| `/mempalace:status` | Show palace overview -- wings, rooms, drawer counts |
## Hooks
MemPalace registers two hooks that run automatically:
- **Stop** -- Saves conversation context when a session ends.
- **PreCompact** -- Preserves important memories before context compaction.
## MCP Server
The plugin automatically configures a local MCP server with 19 tools for storing, searching, and managing memories. No manual MCP setup is required -- `/mempalace:init` handles everything.
## Full Documentation
See the main [README](../README.md) for complete documentation, architecture details, and advanced usage.
+25
View File
@@ -0,0 +1,25 @@
{
"description": "MemPalace auto-save and pre-compact hooks",
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "bash ${CLAUDE_PLUGIN_ROOT}/hooks/mempal-stop-hook.sh"
}
]
}
],
"PreCompact": [
{
"hooks": [
{
"type": "command",
"command": "bash ${CLAUDE_PLUGIN_ROOT}/hooks/mempal-precompact-hook.sh"
}
]
}
]
}
}
@@ -0,0 +1,5 @@
#!/bin/bash
# MemPalace PreCompact Hook — thin wrapper calling Python CLI
# All logic lives in mempalace.hooks_cli for cross-harness extensibility
INPUT=$(cat)
echo "$INPUT" | python3 -m mempalace hook run --hook precompact --harness claude-code
+5
View File
@@ -0,0 +1,5 @@
#!/bin/bash
# MemPalace Stop Hook — thin wrapper calling Python CLI
# All logic lives in mempalace.hooks_cli for cross-harness extensibility
INPUT=$(cat)
echo "$INPUT" | python3 -m mempalace hook run --hook stop --harness claude-code
+18
View File
@@ -0,0 +1,18 @@
{
"name": "mempalace",
"owner": {
"name": "milla-jovovich",
"url": "https://github.com/milla-jovovich"
},
"plugins": [
{
"name": "mempalace",
"source": ".",
"description": "AI memory system — mine projects and conversations into a searchable palace. 19 MCP tools, auto-save hooks, guided setup.",
"version": "3.0.0",
"author": {
"name": "milla-jovovich"
}
}
]
}
+33
View File
@@ -0,0 +1,33 @@
{
"name": "mempalace",
"version": "3.0.0",
"description": "Give your AI a memory — mine projects and conversations into a searchable palace. 19 MCP tools, auto-save hooks, and guided setup.",
"author": { "name": "milla-jovovich" },
"license": "MIT",
"hooks": {
"Stop": "hooks/mempal-stop-hook.sh",
"PreCompact": "hooks/mempal-precompact-hook.sh"
},
"skills": [
{ "name": "init", "file": "skills/init/SKILL.md" },
{ "name": "search", "file": "skills/search/SKILL.md" },
{ "name": "mine", "file": "skills/mine/SKILL.md" },
{ "name": "help", "file": "skills/help/SKILL.md" },
{ "name": "status", "file": "skills/status/SKILL.md" }
],
"commands": [
{ "name": "mempalace:help", "description": "Show MemPalace help — available tools, skills, architecture", "skill": "help" },
{ "name": "mempalace:init", "description": "Set up MemPalace — install, configure MCP, onboard", "skill": "init" },
{ "name": "mempalace:search", "description": "Search your memories across the palace", "skill": "search" },
{ "name": "mempalace:mine", "description": "Mine projects and conversations into the palace", "skill": "mine" },
{ "name": "mempalace:status", "description": "Show palace overview — wings, rooms, drawer counts", "skill": "status" }
],
"mcp": {
"mempalace": {
"command": "python3",
"args": ["-m", "mempalace.mcp_server"]
}
},
"keywords": ["memory", "ai", "rag", "mcp", "chromadb", "palace", "search"],
"repository": { "type": "git", "url": "https://github.com/milla-jovovich/mempalace" }
}
+12
View File
@@ -0,0 +1,12 @@
---
name: help
description: Show comprehensive MemPalace help — available skills, MCP tools, CLI commands, hooks, and architecture.
---
Run the following command and display its output to the user:
```bash
mempalace instructions help
```
Display the output as-is — it's pre-formatted markdown.
+18
View File
@@ -0,0 +1,18 @@
---
name: init
description: Set up MemPalace — install the package, initialize a palace, configure MCP server, and verify everything works.
---
Run the following command to get setup instructions, then follow them step by step:
```bash
mempalace instructions init
```
If the command fails (mempalace not installed yet), first install it:
```bash
pip install mempalace
```
Then run the instructions command again and follow the output.
+12
View File
@@ -0,0 +1,12 @@
---
name: mine
description: Mine projects and conversations into the MemPalace. Supports project files, conversation exports, and auto-classification.
---
Run the following command to get mining instructions, then follow them:
```bash
mempalace instructions mine
```
Follow the returned instructions to mine the user's data.
+12
View File
@@ -0,0 +1,12 @@
---
name: search
description: Search your memories across the MemPalace using semantic search with wing/room filtering.
---
Run the following command to get search instructions, then follow them:
```bash
mempalace instructions search
```
Follow the returned instructions to execute the user's search query.
+12
View File
@@ -0,0 +1,12 @@
---
name: status
description: Show the current state of your memory palace — wings, rooms, drawer counts, and suggestions.
---
Run the following command to get status instructions, then follow them:
```bash
mempalace instructions status
```
Follow the returned instructions to display the palace status.
+34
View File
@@ -0,0 +1,34 @@
name: Sync Plugin Version
on:
push:
branches: [main]
jobs:
sync-version:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v6
- name: Extract version from version.py
id: version
run: |
VERSION=$(python3 -c "exec(open('mempalace/version.py').read()); print(__version__)")
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
- name: Update plugin.json
run: |
jq --arg v "${{ steps.version.outputs.version }}" '.version = $v' .claude-plugin/plugin.json > tmp.json && mv tmp.json .claude-plugin/plugin.json
- name: Update marketplace.json
run: |
jq --arg v "${{ steps.version.outputs.version }}" '.plugins[0].version = $v' .claude-plugin/marketplace.json > tmp.json && mv tmp.json .claude-plugin/marketplace.json
- name: Commit if changed
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add .claude-plugin/plugin.json .claude-plugin/marketplace.json
git diff --staged --quiet || git commit -m "chore: sync plugin version to ${{ steps.version.outputs.version }}" && git push
+1
View File
@@ -5,3 +5,4 @@ __pycache__/
*.pyc
.pytest_cache/
mempal.yaml
.a5c/
+60
View File
@@ -226,6 +226,20 @@ def cmd_repair(args):
print(f"\n{'=' * 55}\n")
def cmd_hook(args):
"""Run hook logic: reads JSON from stdin, outputs JSON to stdout."""
from .hooks_cli import run_hook
run_hook(hook_name=args.hook, harness=args.harness)
def cmd_instructions(args):
"""Output skill instructions to stdout."""
from .instructions_cli import run_instructions
run_instructions(name=args.name)
def cmd_compress(args):
"""Compress drawers in a wing using AAAK Dialect."""
import chromadb
@@ -451,6 +465,35 @@ def main():
help="Only split files containing at least N sessions (default: 2)",
)
# hook
p_hook = sub.add_parser(
"hook",
help="Run hook logic (reads JSON from stdin, outputs JSON to stdout)",
)
hook_sub = p_hook.add_subparsers(dest="hook_action")
p_hook_run = hook_sub.add_parser("run", help="Execute a hook")
p_hook_run.add_argument(
"--hook",
required=True,
choices=["stop", "precompact"],
help="Hook name to run",
)
p_hook_run.add_argument(
"--harness",
required=True,
choices=["claude-code"],
help="Harness type (determines stdin JSON format)",
)
# instructions
p_instructions = sub.add_parser(
"instructions",
help="Output skill instructions to stdout",
)
instructions_sub = p_instructions.add_subparsers(dest="instructions_name")
for instr_name in ["init", "search", "mine", "help", "status"]:
instructions_sub.add_parser(instr_name, help=f"Output {instr_name} instructions")
# repair
sub.add_parser(
"repair",
@@ -466,6 +509,23 @@ def main():
parser.print_help()
return
# Handle two-level subcommands
if args.command == "hook":
if not getattr(args, "hook_action", None):
p_hook.print_help()
return
cmd_hook(args)
return
if args.command == "instructions":
name = getattr(args, "instructions_name", None)
if not name:
p_instructions.print_help()
return
args.name = name
cmd_instructions(args)
return
dispatch = {
"init": cmd_init,
"mine": cmd_mine,
+208
View File
@@ -0,0 +1,208 @@
"""
Hook logic for MemPalace — Python implementation of stop and precompact hooks.
Reads JSON from stdin, outputs JSON to stdout.
Supported hooks: stop, precompact
Supported harnesses: claude-code (extensible to cursor, gemini, etc.)
"""
import json
import os
import re
import subprocess
import sys
from datetime import datetime
from pathlib import Path
SAVE_INTERVAL = 15
STATE_DIR = Path.home() / ".mempalace" / "hook_state"
STOP_BLOCK_REASON = (
"AUTO-SAVE checkpoint. Save key topics, decisions, quotes, and code "
"from this session to your memory system. Organize into appropriate "
"categories. Use verbatim quotes where possible. Continue conversation "
"after saving."
)
PRECOMPACT_BLOCK_REASON = (
"COMPACTION IMMINENT. Save ALL topics, decisions, quotes, code, and "
"important context from this session to your memory system. Be thorough "
"\u2014 after compaction, detailed context will be lost. Organize into "
"appropriate categories. Use verbatim quotes where possible. Save "
"everything, then allow compaction to proceed."
)
def _sanitize_session_id(session_id: str) -> str:
"""Only allow alnum, dash, underscore to prevent path traversal."""
sanitized = re.sub(r"[^a-zA-Z0-9_-]", "", session_id)
return sanitized or "unknown"
def _count_human_messages(transcript_path: str) -> int:
"""Count human messages in a JSONL transcript, skipping command-messages."""
path = Path(transcript_path).expanduser()
if not path.is_file():
return 0
count = 0
try:
with open(path) as f:
for line in f:
try:
entry = json.loads(line)
msg = entry.get("message", {})
if isinstance(msg, dict) and msg.get("role") == "user":
content = msg.get("content", "")
if isinstance(content, str) and "<command-message>" in content:
continue
count += 1
except (json.JSONDecodeError, AttributeError):
pass
except OSError:
return 0
return count
def _log(message: str):
"""Append to hook state log file."""
try:
STATE_DIR.mkdir(parents=True, exist_ok=True)
log_path = STATE_DIR / "hook.log"
timestamp = datetime.now().strftime("%H:%M:%S")
with open(log_path, "a") as f:
f.write(f"[{timestamp}] {message}\n")
except OSError:
pass
def _output(data: dict):
"""Print JSON to stdout with consistent formatting (pretty-printed)."""
print(json.dumps(data, indent=2, ensure_ascii=False))
def _maybe_auto_ingest():
"""If MEMPAL_DIR is set and exists, run mempalace mine in background."""
mempal_dir = os.environ.get("MEMPAL_DIR", "")
if mempal_dir and os.path.isdir(mempal_dir):
try:
log_path = STATE_DIR / "hook.log"
with open(log_path, "a") as log_f:
subprocess.Popen(
[sys.executable, "-m", "mempalace", "mine", mempal_dir],
stdout=log_f,
stderr=log_f,
)
except OSError:
pass
def _parse_claude_code_input(data: dict) -> dict:
"""Parse stdin JSON for the claude-code harness."""
return {
"session_id": _sanitize_session_id(str(data.get("session_id", "unknown"))),
"stop_hook_active": data.get("stop_hook_active", False),
"transcript_path": str(data.get("transcript_path", "")),
}
def _parse_harness_input(data: dict, harness: str) -> dict:
"""Parse stdin JSON according to the harness type."""
parsers = {
"claude-code": _parse_claude_code_input,
}
parser = parsers.get(harness)
if parser is None:
print(f"Unknown harness: {harness}", file=sys.stderr)
sys.exit(1)
return parser(data)
def hook_stop(data: dict, harness: str):
"""Stop hook: block every N messages for auto-save."""
parsed = _parse_harness_input(data, harness)
session_id = parsed["session_id"]
stop_hook_active = parsed["stop_hook_active"]
transcript_path = parsed["transcript_path"]
# If already in a save cycle, let through (infinite-loop prevention)
if stop_hook_active in (True, "True", "true"):
_output({})
return
# Count human messages
exchange_count = _count_human_messages(transcript_path)
# Track last save point
STATE_DIR.mkdir(parents=True, exist_ok=True)
last_save_file = STATE_DIR / f"{session_id}_last_save"
last_save = 0
if last_save_file.is_file():
try:
last_save = int(last_save_file.read_text().strip())
except (ValueError, OSError):
last_save = 0
since_last = exchange_count - last_save
_log(f"Session {session_id}: {exchange_count} exchanges, {since_last} since last save")
if since_last >= SAVE_INTERVAL and exchange_count > 0:
# Update last save point
try:
last_save_file.write_text(str(exchange_count))
except OSError:
pass
_log(f"TRIGGERING SAVE at exchange {exchange_count}")
# Optional: auto-ingest if MEMPAL_DIR is set
_maybe_auto_ingest()
_output({"decision": "block", "reason": STOP_BLOCK_REASON})
else:
_output({})
def hook_precompact(data: dict, harness: str):
"""Precompact hook: always block with comprehensive save instruction."""
parsed = _parse_harness_input(data, harness)
session_id = parsed["session_id"]
_log(f"PRE-COMPACT triggered for session {session_id}")
# Optional: auto-ingest synchronously before compaction (so memories land first)
mempal_dir = os.environ.get("MEMPAL_DIR", "")
if mempal_dir and os.path.isdir(mempal_dir):
try:
log_path = STATE_DIR / "hook.log"
with open(log_path, "a") as log_f:
subprocess.run(
[sys.executable, "-m", "mempalace", "mine", mempal_dir],
stdout=log_f,
stderr=log_f,
)
except OSError:
pass
# Always block -- compaction = save everything
_output({"decision": "block", "reason": PRECOMPACT_BLOCK_REASON})
def run_hook(hook_name: str, harness: str):
"""Main entry point: read stdin JSON, dispatch to hook handler."""
try:
data = json.load(sys.stdin)
except (json.JSONDecodeError, EOFError):
data = {}
hooks = {
"stop": hook_stop,
"precompact": hook_precompact,
}
handler = hooks.get(hook_name)
if handler is None:
print(f"Unknown hook: {hook_name}", file=sys.stderr)
sys.exit(1)
handler(data, harness)
+105
View File
@@ -0,0 +1,105 @@
# MemPalace
AI memory system. Store everything, find anything. Local, free, no API key.
---
## Slash Commands
| Command | Description |
|----------------------|--------------------------------|
| /mempalace:init | Install and set up MemPalace |
| /mempalace:search | Search your memories |
| /mempalace:mine | Mine projects and conversations|
| /mempalace:status | Palace overview and stats |
| /mempalace:help | This help message |
---
## MCP Tools (19)
### Palace (read)
- mempalace_status -- Palace status and stats
- mempalace_list_wings -- List all wings
- mempalace_list_rooms -- List rooms in a wing
- mempalace_get_taxonomy -- Get the full taxonomy tree
- mempalace_search -- Search memories by query
- mempalace_check_duplicate -- Check if a memory already exists
- mempalace_get_aaak_spec -- Get the AAAK specification
### Palace (write)
- mempalace_add_drawer -- Add a new memory (drawer)
- mempalace_delete_drawer -- Delete a memory (drawer)
### Knowledge Graph
- mempalace_kg_query -- Query the knowledge graph
- mempalace_kg_add -- Add a knowledge graph entry
- mempalace_kg_invalidate -- Invalidate a knowledge graph entry
- mempalace_kg_timeline -- View knowledge graph timeline
- mempalace_kg_stats -- Knowledge graph statistics
### Navigation
- mempalace_traverse -- Traverse the palace structure
- mempalace_find_tunnels -- Find cross-wing connections
- mempalace_graph_stats -- Graph connectivity statistics
### Agent Diary
- mempalace_diary_write -- Write a diary entry
- mempalace_diary_read -- Read diary entries
---
## CLI Commands
mempalace init <dir> Initialize a new palace
mempalace mine <dir> Mine a project (default mode)
mempalace mine <dir> --mode convos Mine conversation exports
mempalace search "query" Search your memories
mempalace split <dir> Split large transcript files
mempalace wake-up Load palace into context
mempalace compress Compress palace storage
mempalace status Show palace status
mempalace repair Rebuild vector index
mempalace hook run Run hook logic (for harness integration)
mempalace instructions <name> Output skill instructions
---
## Auto-Save Hooks
- Stop hook -- Automatically saves memories every 15 messages. Counts human
messages in the session transcript (skipping command-messages). When the
threshold is reached, blocks the AI with a save instruction. Uses
~/.mempalace/hook_state/ to track save points per session. If
stop_hook_active is true, passes through to prevent infinite loops.
- PreCompact hook -- Emergency save before context compaction. Always blocks
with a comprehensive save instruction because compaction means the AI is
about to lose detailed context.
Hooks read JSON from stdin and output JSON to stdout. They can be invoked via:
echo '{"session_id":"abc","stop_hook_active":false,"transcript_path":"..."}' | mempalace hook run --hook stop --harness claude-code
---
## Architecture
Wings (projects/people)
+-- Rooms (topics)
+-- Closets (summaries)
+-- Drawers (verbatim memories)
Halls connect rooms within a wing.
Tunnels connect rooms across wings.
The palace is stored locally using ChromaDB for vector search and SQLite for
metadata. No cloud services or API keys required.
---
## Getting Started
1. /mempalace:init -- Set up your palace
2. /mempalace:mine -- Mine a project or conversation
3. /mempalace:search -- Find what you stored
+69
View File
@@ -0,0 +1,69 @@
# MemPalace Init
Guide the user through a complete MemPalace setup. Follow each step in order,
stopping to report errors and attempt remediation before proceeding.
## Step 1: Check Python version
Run `python3 --version` (or `python --version` on Windows) and confirm the
version is 3.9 or higher. If Python is not found or the version is too old,
tell the user they need Python 3.9+ installed and stop.
## Step 2: Check if mempalace is already installed
Run `pip show mempalace` to see if the package is already present. If it is,
report the installed version and skip to Step 4.
## Step 3: Install mempalace
Run `pip install mempalace`.
### Error handling -- pip failures
If `pip install mempalace` fails, try these fallbacks in order:
1. Try `pip3 install mempalace`
2. Try `python -m pip install mempalace` (or `python3 -m pip install mempalace`)
3. If the error mentions missing build tools or compilation failures (commonly
from chromadb or its native dependencies):
- On Linux/macOS: suggest `sudo apt-get install build-essential python3-dev`
(Debian/Ubuntu) or `xcode-select --install` (macOS)
- On Windows: suggest installing Microsoft C++ Build Tools from
https://visualstudio.microsoft.com/visual-cpp-build-tools/
- Then retry the install command
4. If all attempts fail, report the error clearly and stop.
## Step 4: Ask for project directory
Ask the user which project directory they want to initialize with MemPalace.
Offer the current working directory as the default. Wait for their response
before continuing.
## Step 5: Initialize the palace
Run `mempalace init <dir>` where `<dir>` is the directory from Step 4.
If this fails, report the error and stop.
## Step 6: Configure MCP server
Run the following command to register the MemPalace MCP server with Claude:
claude mcp add mempalace -- python -m mempalace.mcp_server
If this fails, report the error but continue to the next step (MCP
configuration can be done manually later).
## Step 7: Verify installation
Run `mempalace status` and confirm the output shows a healthy palace.
If the command fails or reports errors, walk the user through troubleshooting
based on the output.
## Step 8: Show next steps
Tell the user setup is complete and suggest these next actions:
- Use /mempalace:mine to start adding data to their palace
- Use /mempalace:search to query their palace and retrieve stored knowledge
+64
View File
@@ -0,0 +1,64 @@
# MemPalace Mine
When the user invokes this skill, follow these steps:
## 1. Ask what to mine
Ask the user what they want to mine and where the source data is located.
Clarify:
- Is it a project directory (code, docs, notes)?
- Is it conversation exports (Claude, ChatGPT, Slack)?
- Do they want auto-classification (decisions, milestones, problems)?
## 2. Choose the mining mode
There are three mining modes:
### Project mining
mempalace mine <dir>
Mines code files, documentation, and notes from a project directory.
### Conversation mining
mempalace mine <dir> --mode convos
Mines conversation exports from Claude, ChatGPT, or Slack into the palace.
### General extraction (auto-classify)
mempalace mine <dir> --mode convos --extract general
Auto-classifies mined content into decisions, milestones, and problems.
## 3. Optionally split mega-files first
If the source directory contains very large files, suggest splitting them
before mining:
mempalace split <dir> [--dry-run]
Use --dry-run first to preview what will be split without making changes.
## 4. Optionally tag with a wing
If the user wants to organize mined content under a specific wing, add the
--wing flag:
mempalace mine <dir> --wing <name>
## 5. Show progress and results
Run the selected mining command and display progress as it executes. After
completion, summarize the results including:
- Number of items mined
- Categories or classifications applied
- Any warnings or skipped files
## 6. Suggest next steps
After mining completes, suggest the user try:
- /mempalace:search -- search the newly mined content
- /mempalace:status -- check the current state of their palace
- Mine more data from additional sources
+57
View File
@@ -0,0 +1,57 @@
# MemPalace Search
When the user wants to search their MemPalace memories, follow these steps:
## 1. Parse the Search Query
Extract the core search intent from the user's message. Identify any explicit
or implicit filters:
- Wing -- a top-level category (e.g., "work", "personal", "research")
- Room -- a sub-category within a wing
- Keywords / semantic query -- the actual search terms
## 2. Determine Wing/Room Filters
If the user mentions a specific domain, topic area, or context, map it to the
appropriate wing and/or room. If unsure, omit filters to search globally. You
can discover the taxonomy first if needed.
## 3. Use MCP Tools (Preferred)
If MCP tools are available, use them in this priority order:
- mempalace_search(query, wing, room) -- Primary search tool. Pass the semantic
query and any wing/room filters.
- mempalace_list_wings -- Discover all available wings. Use when the user asks
what categories exist or you need to resolve a wing name.
- mempalace_list_rooms(wing) -- List rooms within a specific wing. Use to help
the user navigate or to resolve a room name.
- mempalace_get_taxonomy -- Retrieve the full wing/room/drawer tree. Use when
the user wants an overview of their entire memory structure.
- mempalace_traverse(room) -- Walk the knowledge graph starting from a room.
Use when the user wants to explore connections and related memories.
- mempalace_find_tunnels(wing1, wing2) -- Find cross-wing connections (tunnels)
between two wings. Use when the user asks about relationships between
different knowledge domains.
## 4. CLI Fallback
If MCP tools are not available, fall back to the CLI:
mempalace search "query" [--wing X] [--room Y]
## 5. Present Results
When presenting search results:
- Always include source attribution: wing, room, and drawer for each result
- Show relevance or similarity scores if available
- Group results by wing/room when returning multiple hits
- Quote or summarize the memory content clearly
## 6. Offer Next Steps
After presenting results, offer the user options to go deeper:
- Drill deeper -- search within a specific room or narrow the query
- Traverse -- explore the knowledge graph from a related room
- Check tunnels -- look for cross-wing connections if the topic spans domains
- Browse taxonomy -- show the full structure for manual exploration
+49
View File
@@ -0,0 +1,49 @@
# MemPalace Status
Display the current state of the user's memory palace.
## Step 1: Gather Palace Status
Check if MCP tools are available (look for mempalace_status in available tools).
- If MCP is available: Call the mempalace_status tool to retrieve palace state.
- If MCP is not available: Run the CLI command: mempalace status
## Step 2: Display Wing/Room/Drawer Counts
Present the palace structure counts clearly:
- Number of wings
- Number of rooms
- Number of drawers
- Total memories stored
Keep the output concise -- use a brief summary format, not verbose tables.
## Step 3: Knowledge Graph Stats (MCP only)
If MCP tools are available, also call:
- mempalace_kg_stats -- for a knowledge graph overview (triple count, entity
count, relationship types)
- mempalace_graph_stats -- for connectivity information (connected components,
average connections per entity)
Present these alongside the palace counts in a unified summary.
## Step 4: Suggest Next Actions
Based on the current state, suggest one relevant action:
- Empty palace (zero memories): Suggest "Try /mempalace:mine to add data from
files, URLs, or text."
- Has data but no knowledge graph (memories exist but KG stats show zero
triples): Suggest "Consider adding knowledge graph triples for richer
queries."
- Healthy palace (has memories and KG data): Suggest "Use /mempalace:search to
query your memories."
## Output Style
- Be concise and informative -- aim for a quick glance, not a report.
- Use short labels and numbers, not prose paragraphs.
- If any step fails or a tool is unavailable, note it briefly and continue
with what is available.
+28
View File
@@ -0,0 +1,28 @@
"""
Instruction text output for MemPalace CLI commands.
Each instruction lives as a .md file in the instructions/ directory
inside the package. The CLI reads and prints the file content.
"""
import sys
from pathlib import Path
INSTRUCTIONS_DIR = Path(__file__).parent / "instructions"
AVAILABLE = ["init", "search", "mine", "help", "status"]
def run_instructions(name: str):
"""Read and print the instruction .md file for the given name."""
if name not in AVAILABLE:
print(f"Unknown instructions: {name}", file=sys.stderr)
print(f"Available: {', '.join(sorted(AVAILABLE))}", file=sys.stderr)
sys.exit(1)
md_path = INSTRUCTIONS_DIR / f"{name}.md"
if not md_path.is_file():
print(f"Instructions file not found: {md_path}", file=sys.stderr)
sys.exit(1)
print(md_path.read_text())