Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5c8ba43dbf | ||
|
|
cf461ec99f |
@@ -64,11 +64,95 @@ people: []
|
||||
projects: []
|
||||
```
|
||||
|
||||
## Native MCP config snippet
|
||||
|
||||
```yaml
|
||||
mcp_servers:
|
||||
mempalace:
|
||||
command: python
|
||||
args:
|
||||
- -m
|
||||
- mempalace.mcp_server
|
||||
```
|
||||
|
||||
## Session start wake-up hook
|
||||
|
||||
Drop this into Ezra's session start wrapper (or source it before starting Hermes) so the wake-up context is refreshed automatically.
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
if command -v mempalace >/dev/null 2>&1; then
|
||||
mkdir -p "~/.hermes/wakeups"
|
||||
mempalace wake-up > "~/.hermes/wakeups/ezra_home.txt"
|
||||
export HERMES_MEMPALACE_WAKEUP_FILE="~/.hermes/wakeups/ezra_home.txt"
|
||||
printf '[MemPalace] wake-up context refreshed: %s\n' "$HERMES_MEMPALACE_WAKEUP_FILE"
|
||||
fi
|
||||
```
|
||||
|
||||
## Metrics reply for #568
|
||||
|
||||
Use this as the ready-to-fill comment body after the live Ezra run:
|
||||
|
||||
```md
|
||||
# Metrics reply for #568
|
||||
|
||||
Refs #570.
|
||||
|
||||
## Ezra live run
|
||||
- package: mempalace==3.0.0
|
||||
- hermes home: ~/.hermes/
|
||||
- sessions dir: ~/.hermes/sessions/
|
||||
- palace path: ~/.mempalace/palace
|
||||
- wake-up file: ~/.hermes/wakeups/ezra_home.txt
|
||||
|
||||
## Results to fill in
|
||||
- install result: [pass/fail + note]
|
||||
- init result: [pass/fail + note]
|
||||
- mine home duration: [seconds]
|
||||
- mine sessions duration: [seconds]
|
||||
- corpus size after mining: [drawers/rooms]
|
||||
- query 1: [query] -> [top result]
|
||||
- query 2: [query] -> [top result]
|
||||
- query 3: [query] -> [top result]
|
||||
- wake-up context token count: [tokens]
|
||||
- MCP wiring succeeded: [yes/no]
|
||||
- session-start hook enabled: [yes/no]
|
||||
|
||||
## Commands actually used
|
||||
```bash
|
||||
pip install mempalace==3.0.0
|
||||
mempalace init ~/.hermes/ --yes
|
||||
echo "" | mempalace mine ~/.hermes/
|
||||
echo "" | mempalace mine ~/.hermes/sessions/ --mode convos
|
||||
mempalace search "your common queries"
|
||||
mempalace wake-up
|
||||
hermes mcp add mempalace -- python -m mempalace.mcp_server
|
||||
```
|
||||
```
|
||||
|
||||
## Operator-ready support bundle
|
||||
|
||||
Generate copy-ready files for Ezra's host with:
|
||||
|
||||
```bash
|
||||
python3 scripts/mempalace_ezra_integration.py --bundle-dir /tmp/ezra-mempalace-bundle
|
||||
```
|
||||
|
||||
That bundle writes:
|
||||
- `mempalace.yaml`
|
||||
- `hermes-mcp-mempalace.yaml`
|
||||
- `session-start-mempalace.sh`
|
||||
- `issue-568-comment-template.md`
|
||||
|
||||
## Why this shape
|
||||
|
||||
- `wing: ezra_home` matches the issue's Ezra-specific integration target.
|
||||
- `rooms` split the mined material into sessions, config, and docs to keep retrieval interpretable.
|
||||
- Mining commands pipe empty stdin to avoid the interactive entity-detector hang noted in the evaluation.
|
||||
- `mcp_servers:` gives the native-MCP equivalent of `hermes mcp add ...`, so the operator can choose either path.
|
||||
- `HERMES_MEMPALACE_WAKEUP_FILE` makes the wake-up context explicit and reusable from the session-start boundary.
|
||||
|
||||
## Gotchas
|
||||
|
||||
@@ -86,6 +170,7 @@ After live execution on Ezra's actual environment, post back to #568 with:
|
||||
- 2-3 real search queries + retrieved results
|
||||
- wake-up context token count
|
||||
- whether MCP wiring succeeded
|
||||
- whether the session-start hook exported `HERMES_MEMPALACE_WAKEUP_FILE`
|
||||
|
||||
## Honest scope boundary
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Prepare a MemPalace v3.0.0 integration packet for Ezra's Hermes home."""
|
||||
"""Prepare an executable MemPalace v3.0.0 integration bundle for Ezra's Hermes home."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
@@ -38,6 +40,91 @@ def build_yaml_template(wing: str, palace_path: str) -> str:
|
||||
)
|
||||
|
||||
|
||||
def build_mcp_config_snippet() -> str:
|
||||
return (
|
||||
"mcp_servers:\n"
|
||||
" mempalace:\n"
|
||||
" command: python\n"
|
||||
" args:\n"
|
||||
" - -m\n"
|
||||
" - mempalace.mcp_server\n"
|
||||
)
|
||||
|
||||
|
||||
def build_session_start_hook(wakeup_file: str) -> str:
|
||||
wakeup_path = wakeup_file.rstrip()
|
||||
wakeup_dir = wakeup_path.rsplit("/", 1)[0]
|
||||
return (
|
||||
"#!/usr/bin/env bash\n"
|
||||
"set -euo pipefail\n\n"
|
||||
"if command -v mempalace >/dev/null 2>&1; then\n"
|
||||
f" mkdir -p \"{wakeup_dir}\"\n"
|
||||
f" mempalace wake-up > \"{wakeup_path}\"\n"
|
||||
f" export HERMES_MEMPALACE_WAKEUP_FILE=\"{wakeup_path}\"\n"
|
||||
" printf '[MemPalace] wake-up context refreshed: %s\\n' \"$HERMES_MEMPALACE_WAKEUP_FILE\"\n"
|
||||
"fi\n"
|
||||
)
|
||||
|
||||
|
||||
def build_report_back_template(plan: dict) -> str:
|
||||
return f"""# Metrics reply for #568
|
||||
|
||||
Refs #570.
|
||||
|
||||
## Ezra live run
|
||||
- package: {plan['package_spec']}
|
||||
- hermes home: {plan['hermes_home']}
|
||||
- sessions dir: {plan['sessions_dir']}
|
||||
- palace path: {plan['palace_path']}
|
||||
- wake-up file: {plan['wakeup_file']}
|
||||
|
||||
## Results to fill in
|
||||
- install result: [pass/fail + note]
|
||||
- init result: [pass/fail + note]
|
||||
- mine home duration: [seconds]
|
||||
- mine sessions duration: [seconds]
|
||||
- corpus size after mining: [drawers/rooms]
|
||||
- query 1: [query] -> [top result]
|
||||
- query 2: [query] -> [top result]
|
||||
- query 3: [query] -> [top result]
|
||||
- wake-up context token count: [tokens]
|
||||
- MCP wiring succeeded: [yes/no]
|
||||
- session-start hook enabled: [yes/no]
|
||||
|
||||
## Commands actually used
|
||||
```bash
|
||||
{plan['install_command']}
|
||||
{plan['init_command']}
|
||||
{plan['mine_home_command']}
|
||||
{plan['mine_sessions_command']}
|
||||
{plan['search_command']}
|
||||
{plan['wake_up_command']}
|
||||
{plan['mcp_command']}
|
||||
```
|
||||
"""
|
||||
|
||||
|
||||
def build_bundle_files(plan: dict) -> dict[str, str]:
|
||||
return {
|
||||
"mempalace.yaml": plan["yaml_template"],
|
||||
"hermes-mcp-mempalace.yaml": plan["mcp_config_snippet"],
|
||||
"session-start-mempalace.sh": plan["session_start_hook"],
|
||||
"issue-568-comment-template.md": plan["report_back_template"],
|
||||
}
|
||||
|
||||
|
||||
def write_bundle_files(bundle_dir: str | Path, plan: dict) -> list[Path]:
|
||||
output_dir = Path(bundle_dir).expanduser()
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
written: list[Path] = []
|
||||
for relative_path, content in build_bundle_files(plan).items():
|
||||
path = output_dir / relative_path
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(content, encoding="utf-8")
|
||||
written.append(path)
|
||||
return written
|
||||
|
||||
|
||||
def build_plan(overrides: dict | None = None) -> dict:
|
||||
overrides = overrides or {}
|
||||
hermes_home = overrides.get("hermes_home", DEFAULT_HERMES_HOME)
|
||||
@@ -47,6 +134,11 @@ def build_plan(overrides: dict | None = None) -> dict:
|
||||
yaml_template = build_yaml_template(wing=wing, palace_path=palace_path)
|
||||
|
||||
config_home = hermes_home[:-1] if hermes_home.endswith("/") else hermes_home
|
||||
wakeup_dir = overrides.get("wakeup_dir", f"{config_home}/wakeups")
|
||||
wakeup_file = f"{wakeup_dir.rstrip('/')}/{wing}.txt"
|
||||
mcp_config_snippet = build_mcp_config_snippet()
|
||||
session_start_hook = build_session_start_hook(wakeup_file)
|
||||
|
||||
plan = {
|
||||
"package_spec": PACKAGE_SPEC,
|
||||
"hermes_home": hermes_home,
|
||||
@@ -54,6 +146,8 @@ def build_plan(overrides: dict | None = None) -> dict:
|
||||
"palace_path": palace_path,
|
||||
"wing": wing,
|
||||
"config_path": f"{config_home}/mempalace.yaml",
|
||||
"wakeup_dir": wakeup_dir,
|
||||
"wakeup_file": wakeup_file,
|
||||
"install_command": f"pip install {PACKAGE_SPEC}",
|
||||
"init_command": f"mempalace init {hermes_home} --yes",
|
||||
"mine_home_command": f"echo \"\" | mempalace mine {hermes_home}",
|
||||
@@ -62,6 +156,8 @@ def build_plan(overrides: dict | None = None) -> dict:
|
||||
"wake_up_command": "mempalace wake-up",
|
||||
"mcp_command": "hermes mcp add mempalace -- python -m mempalace.mcp_server",
|
||||
"yaml_template": yaml_template,
|
||||
"mcp_config_snippet": mcp_config_snippet,
|
||||
"session_start_hook": session_start_hook,
|
||||
"gotchas": [
|
||||
"`mempalace init` is still interactive in room approval flow; write mempalace.yaml manually if the init output stalls.",
|
||||
"The yaml key is `wing:` not `wings:`. Using the wrong key causes mine/setup failures.",
|
||||
@@ -70,6 +166,7 @@ def build_plan(overrides: dict | None = None) -> dict:
|
||||
"Report Ezra's before/after metrics back to issue #568 after live installation and retrieval tests.",
|
||||
],
|
||||
}
|
||||
plan["report_back_template"] = build_report_back_template(plan)
|
||||
return plan
|
||||
|
||||
|
||||
@@ -101,11 +198,49 @@ YAML
|
||||
{plan['yaml_template'].rstrip()}
|
||||
```
|
||||
|
||||
## Native MCP config snippet
|
||||
|
||||
```yaml
|
||||
{plan['mcp_config_snippet'].rstrip()}
|
||||
```
|
||||
|
||||
## Session start wake-up hook
|
||||
|
||||
Drop this into Ezra's session start wrapper (or source it before starting Hermes) so the wake-up context is refreshed automatically.
|
||||
|
||||
```bash
|
||||
{plan['session_start_hook'].rstrip()}
|
||||
```
|
||||
|
||||
## Metrics reply for #568
|
||||
|
||||
Use this as the ready-to-fill comment body after the live Ezra run:
|
||||
|
||||
```md
|
||||
{plan['report_back_template'].rstrip()}
|
||||
```
|
||||
|
||||
## Operator-ready support bundle
|
||||
|
||||
Generate copy-ready files for Ezra's host with:
|
||||
|
||||
```bash
|
||||
python3 scripts/mempalace_ezra_integration.py --bundle-dir /tmp/ezra-mempalace-bundle
|
||||
```
|
||||
|
||||
That bundle writes:
|
||||
- `mempalace.yaml`
|
||||
- `hermes-mcp-mempalace.yaml`
|
||||
- `session-start-mempalace.sh`
|
||||
- `issue-568-comment-template.md`
|
||||
|
||||
## Why this shape
|
||||
|
||||
- `wing: {plan['wing']}` matches the issue's Ezra-specific integration target.
|
||||
- `rooms` split the mined material into sessions, config, and docs to keep retrieval interpretable.
|
||||
- Mining commands pipe empty stdin to avoid the interactive entity-detector hang noted in the evaluation.
|
||||
- `mcp_servers:` gives the native-MCP equivalent of `hermes mcp add ...`, so the operator can choose either path.
|
||||
- `HERMES_MEMPALACE_WAKEUP_FILE` makes the wake-up context explicit and reusable from the session-start boundary.
|
||||
|
||||
## Gotchas
|
||||
|
||||
@@ -119,6 +254,7 @@ After live execution on Ezra's actual environment, post back to #568 with:
|
||||
- 2-3 real search queries + retrieved results
|
||||
- wake-up context token count
|
||||
- whether MCP wiring succeeded
|
||||
- whether the session-start hook exported `HERMES_MEMPALACE_WAKEUP_FILE`
|
||||
|
||||
## Honest scope boundary
|
||||
|
||||
@@ -132,6 +268,7 @@ def main() -> None:
|
||||
parser.add_argument("--sessions-dir", default=DEFAULT_SESSIONS_DIR)
|
||||
parser.add_argument("--palace-path", default=DEFAULT_PALACE_PATH)
|
||||
parser.add_argument("--wing", default=DEFAULT_WING)
|
||||
parser.add_argument("--bundle-dir", default=None)
|
||||
parser.add_argument("--output", default=None)
|
||||
parser.add_argument("--json", action="store_true")
|
||||
args = parser.parse_args()
|
||||
@@ -146,12 +283,17 @@ def main() -> None:
|
||||
)
|
||||
rendered = json.dumps(plan, indent=2) if args.json else render_markdown(plan)
|
||||
|
||||
if args.bundle_dir:
|
||||
written = write_bundle_files(args.bundle_dir, plan)
|
||||
for path in written:
|
||||
print(f"Wrote bundle file: {path}")
|
||||
|
||||
if args.output:
|
||||
output_path = Path(args.output).expanduser()
|
||||
output_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
output_path.write_text(rendered, encoding="utf-8")
|
||||
print(f"MemPalace integration packet written to {output_path}")
|
||||
else:
|
||||
elif not args.bundle_dir:
|
||||
print(rendered)
|
||||
|
||||
|
||||
|
||||
@@ -32,6 +32,10 @@ class TestMempalaceEzraIntegration(unittest.TestCase):
|
||||
self.assertIn('wing:', plan["yaml_template"])
|
||||
self.assertTrue(any('stdin' in item.lower() for item in plan["gotchas"]))
|
||||
self.assertTrue(any('wing:' in item for item in plan["gotchas"]))
|
||||
self.assertIn('mcp_servers:', plan["mcp_config_snippet"])
|
||||
self.assertIn('export HERMES_MEMPALACE_WAKEUP_FILE=', plan["session_start_hook"])
|
||||
self.assertIn('#570', plan["report_back_template"])
|
||||
self.assertIn('#568', plan["report_back_template"])
|
||||
|
||||
def test_build_plan_accepts_path_and_wing_overrides(self):
|
||||
mod = load_module(SCRIPT_PATH, "mempalace_ezra_integration")
|
||||
@@ -47,6 +51,25 @@ class TestMempalaceEzraIntegration(unittest.TestCase):
|
||||
self.assertIn('/root/wizards/ezra/home', plan["mine_home_command"])
|
||||
self.assertIn('/root/wizards/ezra/home/sessions', plan["mine_sessions_command"])
|
||||
self.assertIn('wing: ezra_archive', plan["yaml_template"])
|
||||
self.assertIn('ezra_archive', plan["session_start_hook"])
|
||||
|
||||
def test_build_bundle_files_emits_operator_ready_support_files(self):
|
||||
mod = load_module(SCRIPT_PATH, "mempalace_ezra_integration")
|
||||
bundle = mod.build_bundle_files(mod.build_plan({}))
|
||||
|
||||
self.assertEqual(
|
||||
set(bundle),
|
||||
{
|
||||
"mempalace.yaml",
|
||||
"hermes-mcp-mempalace.yaml",
|
||||
"session-start-mempalace.sh",
|
||||
"issue-568-comment-template.md",
|
||||
},
|
||||
)
|
||||
self.assertIn('wing: ezra_home', bundle["mempalace.yaml"])
|
||||
self.assertIn('mcp_servers:', bundle["hermes-mcp-mempalace.yaml"])
|
||||
self.assertIn('HERMES_MEMPALACE_WAKEUP_FILE', bundle["session-start-mempalace.sh"])
|
||||
self.assertIn('Metrics reply for #568', bundle["issue-568-comment-template.md"])
|
||||
|
||||
def test_repo_contains_mem_palace_ezra_doc(self):
|
||||
self.assertTrue(DOC_PATH.exists(), "missing committed MemPalace Ezra integration doc")
|
||||
@@ -59,6 +82,9 @@ class TestMempalaceEzraIntegration(unittest.TestCase):
|
||||
"mempalace wake-up",
|
||||
"hermes mcp add mempalace -- python -m mempalace.mcp_server",
|
||||
"Report back to #568",
|
||||
"mcp_servers:",
|
||||
"HERMES_MEMPALACE_WAKEUP_FILE",
|
||||
"Metrics reply for #568",
|
||||
]
|
||||
for snippet in required:
|
||||
self.assertIn(snippet, text)
|
||||
|
||||
Reference in New Issue
Block a user