-
Notifications
You must be signed in to change notification settings - Fork 7.5k
feat: silent stop hook — direct save instead of blocking MCP calls #556
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
473c59f
8bcae9c
70cf491
86eadc7
f0856ca
8aa33af
fccb705
5cd14bd
77ebae7
4406c58
d63ffd4
4a12748
83c50ac
8f565c7
8bd289a
d16ac4b
ad82c2d
d8c423b
6dc8891
2da4a65
0259154
1efa3ba
e9e06c8
5ebfcd4
930b6d8
995aed3
2209484
363ef37
094677b
362a8e1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,20 @@ | ||
| #!/bin/bash | ||
| # MemPalace PreCompact Hook — thin wrapper calling Python CLI | ||
| # All logic lives in mempalace.hooks_cli for cross-harness extensibility | ||
| # | ||
| # Python resolution order: | ||
| # 1. MEMPALACE_PYTHON env var (user override) | ||
| # 2. Plugin root's venv (development installs) | ||
| # 3. System python3 (pip install --user / pipx) | ||
| SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" | ||
| PLUGIN_ROOT="$(dirname "$SCRIPT_DIR")" | ||
|
|
||
| if [ -n "$MEMPALACE_PYTHON" ] && [ -x "$MEMPALACE_PYTHON" ]; then | ||
| PYTHON="$MEMPALACE_PYTHON" | ||
| elif [ -x "$PLUGIN_ROOT/venv/bin/python3" ]; then | ||
| PYTHON="$PLUGIN_ROOT/venv/bin/python3" | ||
| else | ||
| PYTHON="python3" | ||
| fi | ||
| INPUT=$(cat) | ||
| echo "$INPUT" | python3 -m mempalace hook run --hook precompact --harness claude-code | ||
| echo "$INPUT" | "$PYTHON" -m mempalace hook run --hook precompact --harness claude-code |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,20 @@ | ||
| #!/bin/bash | ||
| # MemPalace Stop Hook — thin wrapper calling Python CLI | ||
| # All logic lives in mempalace.hooks_cli for cross-harness extensibility | ||
| # | ||
| # Python resolution order: | ||
| # 1. MEMPALACE_PYTHON env var (user override) | ||
| # 2. Plugin root's venv (development installs) | ||
| # 3. System python3 (pip install --user / pipx) | ||
| SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" | ||
| PLUGIN_ROOT="$(dirname "$SCRIPT_DIR")" | ||
|
|
||
| if [ -n "$MEMPALACE_PYTHON" ] && [ -x "$MEMPALACE_PYTHON" ]; then | ||
| PYTHON="$MEMPALACE_PYTHON" | ||
| elif [ -x "$PLUGIN_ROOT/venv/bin/python3" ]; then | ||
| PYTHON="$PLUGIN_ROOT/venv/bin/python3" | ||
| else | ||
| PYTHON="python3" | ||
| fi | ||
| INPUT=$(cat) | ||
| echo "$INPUT" | python3 -m mempalace hook run --hook stop --harness claude-code | ||
| echo "$INPUT" | "$PYTHON" -m mempalace hook run --hook stop --harness claude-code |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| # CLAUDE.md — memorypalace | ||
|
|
||
| ## What This Is | ||
|
|
||
| JP's fork of [milla-jovovich/mempalace](https://github.com/milla-jovovich/mempalace) — a local AI memory system using ChromaDB for verbatim storage and semantic search. | ||
|
|
||
| - **Fork**: `jphein/mempalace` (origin) / `milla-jovovich/mempalace` (upstream) | ||
| - **Version**: 3.1.0 + local fixes | ||
| - **Python**: venv at `./venv/`, editable install with dev deps | ||
| - **Palace data**: `~/.mempalace/palace` (ChromaDB) + `~/.mempalace/config.json` | ||
|
|
||
| ## Key Files | ||
|
|
||
| - `~/Projects/mempalace.yaml` — **do not delete**. Mining config with wing/room definitions. Regenerate with `mempalace init ~/Projects --yes` if lost. | ||
| - `~/.mempalace/config.json` — topic wings and hall keywords, customized for JP's domains (infrastructure, development, tools, creative, projects, system). | ||
| - `~/.mempalace/palace/` — ChromaDB vector store. The actual data. | ||
| - `~/.mempalace/hook_state/` — stop hook session tracking. | ||
|
|
||
| ## Development | ||
|
|
||
| ```bash | ||
| source venv/bin/activate | ||
| python -m pytest tests/ -x -q # run tests (576 expected) | ||
| mempalace status # check palace state | ||
| mempalace search "query" # test search | ||
| python -m mempalace.mcp_server # run MCP server standalone | ||
| ``` | ||
|
|
||
| Ruff for linting (`ruff check`), line length 100, target Python 3.9. | ||
|
|
||
| ## Fork Changes (ahead of upstream) | ||
|
|
||
| 1. **fix: epsilon mtime comparison** — `palace.py` uses `abs() < 0.01` instead of `==` for float mtime dedup | ||
| 2. **feat: bulk_check_mined()** — paginated pre-fetch of all source_file/mtime pairs | ||
| 3. **fix: MCP server** — search limit capped [1,100], status/taxonomy tools paginated past 10K, duplicate cache decls removed | ||
| 4. **perf: batch ChromaDB writes** — one upsert per file instead of per chunk in both miners | ||
| 5. **fix: entity detector STOPWORDS** — 73 technical terms added (Handler, Node, Service, etc.) | ||
| 6. **feat: similarity threshold** — `min_similarity` parameter in search, default 1.5 L2 distance in MCP | ||
| 7. **feat: hooks_cli** — stop hook saves directly via Python API with systemMessage notification, precompact blocks for AI-driven save, auto-ingest transcripts | ||
|
|
||
| ## Upstream PRs | ||
|
|
||
| - milla-jovovich/mempalace#483 — mtime dedup fix | ||
| - milla-jovovich/mempalace#484 — search limit + pagination + cache fix | ||
|
|
||
| ## Integration | ||
|
|
||
| - **Claude Code plugin**: installed at user scope via marketplace | ||
| - **MCP server**: global user scope — available in all projects | ||
| - **Stop hook**: fires every 15 messages, saves directly via Python API + systemMessage notification + auto-ingests transcript | ||
| - **PreCompact hook**: emergency save before context compaction | ||
|
|
||
|
Comment on lines
+48
to
+52
|
||
| ## Testing | ||
|
|
||
| Always run `python -m pytest tests/ -x -q` after changes. 576 tests expected to pass. Benchmark and stress tests are excluded by default (use `-m benchmark` or `-m stress` to include). | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -95,6 +95,7 @@ def cmd_mine(args): | |
| dry_run=args.dry_run, | ||
| respect_gitignore=not args.no_gitignore, | ||
| include_ignored=include_ignored, | ||
| workers=args.workers, | ||
| ) | ||
|
|
||
|
|
||
|
|
@@ -150,6 +151,23 @@ def cmd_split(args): | |
| sys.argv = old_argv | ||
|
|
||
|
|
||
| def cmd_export(args): | ||
| from .exporter import export_palace | ||
|
|
||
| palace_path = os.path.expanduser(args.palace) if args.palace else MempalaceConfig().palace_path | ||
| output_dir = os.path.expanduser(args.output) | ||
|
|
||
| print(f"\n{'=' * 55}") | ||
| print(" MemPalace Export") | ||
| print(f"{'=' * 55}\n") | ||
| print(f" Palace: {palace_path}") | ||
| print(f" Output: {output_dir}\n") | ||
|
|
||
| export_palace(palace_path=palace_path, output_dir=output_dir) | ||
|
|
||
| print(f"\n{'=' * 55}\n") | ||
|
|
||
|
Comment on lines
+154
to
+169
|
||
|
|
||
| def cmd_status(args): | ||
| from .miner import status | ||
|
|
||
|
|
@@ -442,6 +460,12 @@ def main(): | |
| default="exchange", | ||
| help="Extraction strategy for convos mode: 'exchange' (default) or 'general' (5 memory types)", | ||
| ) | ||
| p_mine.add_argument( | ||
| "--workers", | ||
| type=int, | ||
| default=0, | ||
| help="Parallel workers for file processing (default: min(8, cpu_count); 1 = sequential)", | ||
| ) | ||
|
|
||
| # search | ||
| p_search = sub.add_parser("search", help="Find anything, exact words") | ||
|
|
@@ -462,6 +486,15 @@ def main(): | |
| "--config", default=None, help="Entity config JSON (e.g. entities.json)" | ||
| ) | ||
|
|
||
| # export | ||
| p_export = sub.add_parser("export", help="Export palace as browsable markdown files") | ||
| p_export.add_argument( | ||
| "--output", | ||
| "-o", | ||
| default="./palace-export", | ||
| help="Output directory (default: ./palace-export)", | ||
| ) | ||
|
|
||
| # wake-up | ||
| p_wakeup = sub.add_parser("wake-up", help="Show L0 + L1 wake-up context (~600-900 tokens)") | ||
| p_wakeup.add_argument("--wing", default=None, help="Wake-up for a specific project/wing") | ||
|
|
@@ -561,6 +594,7 @@ def main(): | |
| "mine": cmd_mine, | ||
| "split": cmd_split, | ||
| "search": cmd_search, | ||
| "export": cmd_export, | ||
| "mcp": cmd_mcp, | ||
| "compress": cmd_compress, | ||
| "wake-up": cmd_wakeup, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This testing note says “573 expected”, but the PR description/test plan indicates 576 tests passing and the suite has grown (new exporter/miner/MCP tests). Please update the expected test count here to match current reality so it remains useful during development.