- Plugin manifest (plugin.yaml) with pre_gateway_dispatch + on_session_start hooks - /identity slash command for config management - Honcho injector patch docs (6 lines in plugins/memory/honcho/__init__.py) - Config file at /opt/data/identity-config.json for persistence - Kanban task body convention: context_peer: <name> - Sample config with thierry/catherine mappings Architecture: user-installed plugin (hooks + CLI) + 6-line Honcho bundled plugin change
3.7 KiB
Honcho Injector Patch
The identity plugin cannot directly inject runtime_user_peer_name into
Honcho from a user-installed hook (the hook system only allows message
rewrite/skip, not user_id modification). Instead, we add ~6 lines in the
bundled Honcho plugin's session initialization.
File
plugins/memory/honcho/__init__.py — line ~362
The change
Before
runtime_user_peer_name=kwargs.get("user_id") or None,
After
runtime_user_peer_name=kwargs.get("user_id") or _resolve_identity_peer(),
Add this function in the same file (or import from the identity plugin)
def _resolve_identity_peer() -> str | None:
"""Resolve peer name from env vars and identity config.
Priority: HERMES_HONCHO_PEER_NAME → kanban task body context_peer
→ kanban board config → None (falls through to Honcho default).
"""
import json, os, sqlite3, re
from pathlib import Path
# 1. Explicit env override
explicit = os.environ.get("HERMES_HONCHO_PEER_NAME")
if explicit:
return explicit
# 2. Kanban worker: read task body for context_peer
task_id = os.environ.get("HERMES_KANBAN_TASK")
db_path = os.environ.get("HERMES_KANBAN_DB")
if task_id and db_path:
db = Path(db_path)
if db.exists():
try:
conn = sqlite3.connect(str(db))
conn.row_factory = sqlite3.Row
try:
row = conn.execute(
"SELECT body FROM tasks WHERE id = ?", (task_id,)
).fetchone()
if row and row["body"]:
m = re.search(r"context_peer:\s*(\S+)", row["body"])
if m:
return m.group(1)
finally:
conn.close()
except Exception:
pass
# 3. Identity config file
cfg_path = Path("/opt/data/identity-config.json")
if cfg_path.exists():
try:
cfg = json.loads(cfg_path.read_text())
# Check kanban board config
board = os.environ.get("HERMES_KANBAN_BOARD")
if board and board in cfg.get("boards", {}):
return cfg["boards"][board]
# Use fallback
return cfg.get("fallback_peer")
except Exception:
pass
return None
How it works
-
When a gateway session starts,
kwargs["user_id"]carries the platform ID (Discord snowflake, Telegram UID). The identity config file maps these to canonical peer names. The injector is bypassed — normal flow. -
When a kanban worker starts,
kwargs["user_id"]is None (no gateway). The injector kicks in:a. Checks
HERMES_HONCHO_PEER_NAMEenv var (set by a future dispatcher enhancement or manually).b. Reads the kanban task body from the SQLite database, extracts
context_peer: <name>from the body.c. Falls back to the board-level config from identity-config.json.
d. If nothing resolves → returns None → Honcho creates
user-default-*as today (safe fallback).
Why not modify the kanban dispatcher?
The kanban dispatcher (hermes_cli/kanban_db.py:_default_spawn) is core
Hermes code. We avoid touching it. Instead, the Honcho injector reads the
task directly from the kanban DB using env vars that are already set
(HERMES_KANBAN_TASK, HERMES_KANBAN_DB, HERMES_KANBAN_BOARD).
This adds ~10 microseconds to worker startup — negligible.
Compatibility
- If the identity plugin is removed, the injector function returns None and Honcho behaves exactly as before.
- If the config file is missing, same safe fallback.
- No data loss risk.