+#!/usr/bin/env python3
+"""Verify a clean Retinue install through Hermes' real plugin loader.
+
+Run with the Python and environment produced by:
+ eval "$(hermes --run-module pm.environments --format sh)"
+No model provider or API credential is needed.
+"""
+
+from __future__ import annotations
+
+import json
+import os
+import subprocess
+from pathlib import Path
+from typing import Any, cast
+
+EXPECTED_TOOLS = {
+ "retinue_memory_add",
+ "retinue_memory_search",
+ "retinue_memory_delete",
+ "retinue_memory_stats",
+}
+SOURCE_DIR = Path(__file__).resolve().parents[2]
+HERMES_HOME = Path(
+ os.environ.get("HERMES_HOME", str(Path.home() / ".hermes"))
+).resolve()
+
+
+def run(command: list[str]) -> str:
+ result = subprocess.run(
+ command,
+ check=False,
+ text=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ )
+ output = result.stdout
+ if result.returncode != 0:
+ raise AssertionError(
+ f"command exited {result.returncode}: {' '.join(command)}\n{output}"
+ )
+ return output
+
+
+def require(condition: bool, message: str) -> None:
+ if not condition:
+ raise AssertionError(message)
+
+
+def main() -> None:
+ status = run(["hermes", "memory", "status"])
+ require("Provider:" in status and "retinue" in status,
+ f"Retinue is not the selected provider:\n{status}")
+ require("available" in status and "✓" in status,
+ f"Retinue is not available through Hermes:\n{status}")
+
+ selected = run(["hermes", "config", "get", "memory.provider"])
+ require("retinue" in selected,
+ f"memory.provider was not activated automatically:\n{selected}")
+
+ tools = run(["hermes", "tools", "list", "--platform", "cli"])
+ memory_lines = [line for line in tools.splitlines()
+ if " memory " in line and "Memory" in line]
+ require(len(memory_lines) == 1 and "✓ enabled" in memory_lines[0],
+ f"the CLI memory toolset is not enabled:\n{tools}")
+
+ # This is Hermes' own discovery and construction path, not a direct import
+ # that could hide a broken plugin registration.
+ from plugins.memory import load_memory_provider
+
+ provider = cast(Any, load_memory_provider("retinue"))
+ require(provider is not None, "Hermes could not load the Retinue provider")
+ require(provider.is_available(), "Retinue reports unavailable after install")
+ require({schema["name"] for schema in provider.get_tool_schemas()} == EXPECTED_TOOLS,
+ "Retinue's four tools were not registered correctly")
+
+ provider.initialize("clean-install-verification", hermes_home=str(HERMES_HOME))
+ try:
+ stats = json.loads(provider.handle_tool_call("retinue_memory_stats", {}))
+ require(stats.get("success") is True, f"stats tool failed: {stats}")
+ result = stats["result"]
+ require(result["total"] == 2,
+ f"fresh install must contain exactly two seed memories; got {result}")
+ require(Path(result["db_path"]).resolve()
+ == HERMES_HOME / "retinue_memory.db",
+ f"Retinue opened the wrong database: {result}")
+
+ rows = provider._store.list() # noqa: SLF001 - inspect real persisted rows
+ contents = [row[1] for row in rows]
+ require(any(
+ "Retinue" in text
+ and "minishlab/potion-multilingual-128M" in text
+ and "sqlite-vec" in text
+ and "prefetch" in text
+ for text in contents
+ ),
+ f"the Retinue explanation seed is missing or incomplete: {contents}")
+ require(any(
+ "Retinue installation source" in text
+ and f'"{SOURCE_DIR}"' in text
+ and f'"{SOURCE_DIR}/Install Retinue"' in text
+ for text in contents
+ ),
+ f"the quoted installation-source seed is missing: {contents}")
+
+ found = json.loads(provider.handle_tool_call(
+ "retinue_memory_search",
+ {
+ "query": "How does Retinue store and automatically recall memories?",
+ "limit": 5,
+ "include_seen": True,
+ },
+ ))
+ require(found.get("success") is True and found["result"],
+ f"semantic search over the seed memories failed: {found}")
+ require(any("sqlite-vec" in row["content"] for row in found["result"]),
+ f"the Retinue explanation was not semantically retrievable: {found}")
+ finally:
+ provider.shutdown()
+
+ print("PASS: Hermes loads Retinue and selects it automatically")
+ print("PASS: the CLI memory toolset and all four Retinue tools are available")
+ print("PASS: exactly two useful seed memories persist and remain idempotent")
+ print("PASS: semantic search works with the preloaded model in offline mode")
+
+
+if __name__ == "__main__":
+ main()