Uteke can be used as a complementary memory layer for Hermes Agent ecosystems.
Uteke integrates with Hermes in three modes. Pick the one that matches how you want memory to behave.
Hermes Agent
βββ Mode A: uteke-tool (recommended) β manual uteke(action=...) calls via uteke-serve
βββ Mode C: shell hook (recommended) β automatic recall on pre_llm_call, no daemon
βββ Mode B: memory-provider (deprecated β Hermes only, removed 2026-06-29)
| Mode A (uteke-tool) | Mode C (shell hook) | ||
|---|---|---|---|
| Install | uteke init --agent hermes |
Write handler script | uteke init --agent hermes --memory-provider |
| Invocation | Agent calls uteke(action="recall") |
Automatic (hook) | |
| Capture | Agent decides what to store | Manual (uteke remember) |
|
| Transport | HTTP to uteke-serve |
CLI subprocess | |
| Daemon | Requires uteke-serve |
No | |
| Rooms / multi-agent | Yes | Yes (via uteke-serve) | |
| Best for | Explicit, on-demand memory | Lightweight auto-recall |
Recommended: Mode A + Mode C side by side β automatic recall via hook, manual store via tool. Both read the same uteke store.
Mode B removed for Hermes. The memory-provider plugin was removed on 2026-06-29. Use Mode A + Mode C instead. The
--memory-providerpattern remains supported for pi, Claude Code, and Cursor β see Memory-Provider for Other Agents.
curl -fsSL https://raw.githubusercontent.com/codecoradev/uteke/main/install.sh | shuteke init --agent hermesThis generates the plugin directly to ~/.hermes/plugins/uteke-tool/ with:
plugin.yamlβ manifesttool.pyβ Python entry point (stdlib only, norequestsdependency)README.mdβ usage guide
uteke-serve --port 8767The plugin loads automatically.
# Store a memory
uteke(action="remember", content="User prefers dark mode", tags="preference,ui")
# Semantic recall
uteke(action="recall", content="user preferences")
# Keyword search
uteke(action="search", content="dark mode")
# List memories
uteke(action="list", limit=10)
# Delete a memory
uteke(action="forget", id="abc12345")
# Stats
uteke(action="stats")Rooms enable multi-agent collaborative memory β multiple agents share a room and contribute memories with author attribution.
# Create a shared room
uteke(action="room_remember", room_id="sprint-planning", content="Deploy scheduled for Friday", author="agent1")
uteke(action="room_create", room_id="sprint-planning", title="Sprint Planning")
# Add a memory to a room (use remember with room_id)
uteke(action="remember", content="Deploy at 3pm", room_id="sprint-planning", namespace="team")
# Recall from a room
uteke(action="room_recall", room_id="sprint-planning", content="deploy deadline")
# List all rooms (cross-namespace)
uteke(action="room_list")
# Room analytics
uteke(action="room_stats", room_id="sprint-planning")
uteke(action="room_summary", room_id="sprint-planning")
# Delete a room (memories preserved)
uteke(action="room_delete", room_id="sprint-planning")For MCP-compatible agents, use the uteke MCP server instead of the HTTP plugin:
# Register with Hermes
hermes mcp add uteke --command uteke-mcp
# Or use the HTTP transport
hermes mcp add uteke --url http://127.0.0.1:8767/mcpThe MCP server provides the same tools via JSON-RPC (protocol version 2025-06-18):
uteke_rememberβ store memory (supports type, room, author, tags)uteke_recallβ semantic search (supports tags filter, min_score)uteke_listβ list memories (supports pagination via offset)uteke_forgetβ delete memoryuteke_statsβ store statisticsuteke_room_memoriesβ list memories in a room (#569)
Create or edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS)
or %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"uteke": {
"command": "uteke-mcp"
}
}
}{
"mcpServers": {
"uteke": {
"url": "http://127.0.0.1:8767/mcp"
}
}
}Create or edit .cursor/mcp.json in your project root:
{
"mcpServers": {
"uteke": {
"command": "uteke-mcp"
}
}
}Or with HTTP transport:
{
"mcpServers": {
"uteke": {
"url": "http://127.0.0.1:8767/mcp"
}
}
}# Register with Hermes using HTTP transport (requires uteke-serve running)
hermes mcp add uteke --url http://127.0.0.1:8767/mcpOr with stdio transport:
# Register with Hermes using stdio transport
hermes mcp add uteke --command uteke-mcpTip: HTTP transport is recommended when
uteke-serveis already running β it avoids subprocess overhead and works across machines. Stdio transport is simpler for local, single-agent setups where no daemon is desired.
| Action | Description |
|---|---|
remember |
Store a new memory |
recall |
Semantic search |
search |
Keyword search |
list |
List memories |
forget |
Delete memory |
stats |
Store statistics |
room_remember |
Store memory in a room with author |
room_create |
Create a room |
room_recall |
Recall from a room |
room_list |
List all rooms |
room_summary |
Room topic summary |
room_stats |
Room statistics |
room_delete |
Delete a room |
The --memory-provider pattern also works for non-Hermes agents (#575, #577):
# pi (pi.dev)
uteke init --agent pi --memory-provider
# Claude Code
uteke init --agent claude --memory-provider
# Cursor
uteke init --agent cursor --memory-providerThis installs uteke as the agent's default memory provider β relevant memories are recalled and injected automatically every turn. No daemon needed; talks to the uteke binary directly via subprocess.
Note: For Hermes, use Mode A (uteke-tool) or Mode C (shell hook) instead β the Hermes memory-provider plugin has been removed (see Mode B).
DEPRECATED for Hermes (removed 2026-06-29). Use Mode A + Mode C instead.
The
--memory-providerpattern remains supported for pi, Claude Code, and Cursor. See Memory-Provider for Other Agents. The template source lives atextensions/hermes-memory-provider/.Historical reference: Mode B made uteke Hermes's long-term memory backend via
uteke init --agent hermes --memory-provider+memory.provider: utekeconfig. Automatic recall every turn, auto-extract facts on session end. No daemon needed.
| Environment Variable | Default | Description |
|---|---|---|
UTEKE_SERVER_URL |
http://127.0.0.1:8767 |
uteke server URL |
(For memory-provider configuration, see the reference table under Mode B.)
- Remember: POST to
/rememberβ content is embedded (EmbeddingGemma Q4, 768d) and stored in SQLite + HNSW vector index - Recall: POST to
/recallβ semantic search via hybrid RRF (vector + FTS5), returns ranked results - Rooms: Cross-namespace collaboration spaces β rooms span namespaces, enabling multi-agent coordination
- MCP: JSON-RPC over stdio or HTTP β standard MCP protocol for AI agent integration
The memory-provider plugin (Mode B) skips the HTTP layer entirely and shells
out to the uteke binary: recall --json for prefetch, import --extract for
session-end distillation.
Mode C is the lightest integration: a standalone Python script registered as a
Hermes pre_llm_call shell hook. It runs uteke recall on the user message
before every LLM call and injects the results into the prompt β no plugin, no
daemon, no memory-provider config.
| Aspect | Mode B (memory-provider) | Mode C (shell hook) |
|---|---|---|
| Recall | Automatic (via provider) | Automatic (via hook) |
| Extraction | Automatic (session end) | Not included (use uteke-tool or manual) |
| Plugin needed | Yes (plugins/uteke/) |
No |
memory.provider config |
Required | Not needed |
| Per-agent namespace | Single global | Per-agent via /proc/self/cmdline |
| Race-safe | Yes (process boundary) | Yes (process boundary) |
| Intervention level | Replaces Hermes memory | Complements Hermes memory |
Mode C is ideal when you want automatic recall without replacing Hermes's built-in memory system. It injects context at API-call time without touching the system prompt, preserving prompt caching.
curl -fsSL https://raw.githubusercontent.com/codecoradev/uteke/main/install.sh | shSave as ~/.hermes/hooks/uteke-recall/handler.py (or any path):
"""uteke-recall shell hook β recalls relevant memories on pre_llm_call."""
import json
import pathlib
import subprocess
import sys
def _resolve_agent_name(cwd: str = "") -> str:
"""Extract agent name from Hermes hook payload cwd.
The /proc/self/cmdline approach is unreliable β shell hooks run as
child subprocesses whose cmdline is the handler script, not the
gateway. Use the cwd payload field (always set by Hermes) instead.
Falls back to "default" if cwd is empty or resolution fails.
"""
if cwd:
p = pathlib.Path(cwd)
for parent in [p, *p.parents]:
if parent.name and parent.name != "profiles":
return parent.name
return "default"
def _recall_uteke(query: str, agent: str, limit: int = 5) -> list:
try:
proc = subprocess.run(
["uteke", "recall", "--namespace", agent,
"--limit", str(limit), "--json", query],
capture_output=True, text=True, timeout=15,
)
if proc.returncode != 0:
return []
data = json.loads(proc.stdout)
if not isinstance(data, list):
return []
return [{"content": m.get("memory", {}).get("content", ""),
"score": m.get("score", 0)} for m in data
if isinstance(m, dict) and "memory" in m]
except Exception:
return []
def main():
try:
raw = json.loads(sys.stdin.read())
except Exception:
sys.exit(0)
extra = raw.get("extra", raw)
message = extra.get("user_message") or raw.get("user_message", "")
if not isinstance(message, str) or not message.strip() or len(message) < 5:
sys.exit(0)
agent = _resolve_agent_name(raw.get("cwd", ""))
memories = _recall_uteke(message.strip()[:500], agent, limit=5)
if not memories:
sys.exit(0)
lines = []
for i, mem in enumerate(memories, 1):
content = mem["content"][:200] + ("..." if len(mem["content"]) > 200 else "")
lines.append(f"{i}. [{mem['score']:.2f}] {content}")
json.dump({"context": "Recalled memories (uteke):\n" + "\n".join(lines)},
sys.stdout, ensure_ascii=False)
if __name__ == "__main__":
main()In ~/.hermes/profiles/<profile>/config.yaml (or global config.yaml):
hooks:
pre_llm_call:
- command: "python3 /path/to/handler.py"
timeout: 20
hooks_auto_accept: trueecho '{"user_message": "test recall", "session_id": "verify"}' | \
python3 /path/to/handler.py
# Expected: {"context": "Recalled memories (uteke):\n1. [0.xx] ..."}Hermes sends JSON to stdin on every pre_llm_call:
{
"hook_event_name": "pre_llm_call",
"session_id": "...",
"extra": {
"user_message": "...",
"is_first_turn": true,
"model": "..."
}
}The handler returns JSON on stdout:
{"context": "Optional text to inject into the user message"}No stdout (exit 0) = observer mode, no injection.
| Mode A | Mode C | ||
|---|---|---|---|
| What | Manual tool | Shell hook (recall only) | |
| Recall | Agent calls uteke(action="recall") |
Automatic (via hook) | |
| Extraction | Manual uteke(action="remember") |
Manual (combine with Mode A) | |
| Daemon | uteke-serve required |
No | |
| Replaces Hermes memory | No | No | |
| Best for | On-demand memory, multi-agent rooms | Lightweight auto-recall |
Recommended: Mode A + Mode C β automatic recall via hook, manual store via tool. Keeps Hermes's built-in memory while adding uteke recall.
- uteke v0.3.0+ (includes
uteke-mcpbinary) - Mode A (
uteke-tool):uteke-serverunning (daemon mode) - Mode C (shell hook):
utekebinary onPATH, no daemon - Python 3.7+ (stdlib only β no pip install needed)