Hermes c6b0e1c683 fix: read event.source.{platform,user_id} not event.{platform,user_id}
MessageEvent wraps source in nested SessionSource — fields at the
top level don't exist, causing resolve_peer() to always fall through
to the fallback_peer. This meant every Discord user got a raw
snowflake peer created instead of the mapped name.
2026-05-26 22:04:48 -04:00
2026-05-24 20:00:41 +00:00

Hermes Identity Plugin

Maps platform-specific user IDs (Discord snowflake, Telegram UID, terminal session) and kanban boards to stable Honcho peer names. Eliminates user-default-t_* peers from kanban workers and unifies a user's identity across platforms.

Zero modifications to the Hermes repo. No fork required. The plugin uses runtime monkey-patching at plugin load time to wrap Honcho's session initialization — no files are changed on disk.

Architecture

                    ┌──────────────────────────┐
                    │ identity-config.json      │
                    │ /opt/data/                │
                    └──────┬───────────────────┘
                           │ reads on every resolve
        ┌──────────────────┼───────────────────────┐
        │                  │                       │
        ▼                  ▼                       ▼
 ┌──────────────┐  ┌──────────────┐  ┌──────────────────────┐
 │ pre_gateway  │  │  /identity   │  │  Honcho monkey-patch  │
 │ dispatch     │  │  slash cmd   │  │  (runtime, no files)  │
 │ hook (log)   │  │  (manage)    │  └──────────┬───────────┘
 └──────────────┘  └──────────────┘             │
                                        injects peer_name
                                        into kwargs["user_id"]
                                        BEFORE Honcho session init

How it works

  1. Plugin loadsregister() is called → monkey-patches HonchoMemoryProvider._do_session_init with a wrapper.

  2. Kanban worker starts → Honcho tries to init → no user_id from gateway → the wrapper calls get_peer_name() → reads the task body from HERMES_KANBAN_DB → extracts context_peer: <name> → injects it as user_id → Honcho creates the session with the correct peer.

  3. Gateway session starts (Discord/Telegram) → normal flow with platform user ID → monkey-patch is bypassed (user_id already set).

  4. Missing config or env → returns None → Honcho behaves exactly as before (creates user-default-* peers — safe fallback).

Installation

# 1. Install the plugin from Gitea
hermes plugins install ssh://git@code.lazyworkhorse.net:2222/Hermes/hermes-identity-plugin.git

# 2. Create the config file (persistent volume)
cp config.sample.json /opt/data/identity-config.json

# 3. Edit /opt/data/identity-config.json with your mappings
# 4. Restart gateways to pick up the plugin

Config file: /opt/data/identity-config.json

{
  "mappings": [
    {"platform": "discord", "id": "479136126737711105", "peer": "thierry"},
    {"platform": "telegram", "id": "123456789", "peer": "thierry"},
    {"platform": "matrix", "id": "@thierry:example.org", "peer": "thierry"},
    {"platform": "terminal", "id": "default", "peer": "thierry"}
  ],
  "boards": {
    "default": "thierry",
    "catherine": "catherine"
  },
  "fallback_peer": "user",
  "enforce_context_peer": true
}

Task body convention

Every kanban task SHOULD include a context_peer in its body:

Do research on Postgres migration costs.

```metadata
context_peer: thierry

Profiles (Claire, Ashley, Finn, Matt) set this when calling `kanban_create`.

**If `context_peer` is missing**, the plugin falls back to the board
config (e.g., `boards.default` → `thierry`). If no board config either,
it uses `fallback_peer`. If that's also unset → `user-default-*` (safe).

## Commands

- `/identity status` — show current config and resolved peer
- `/identity list` — list all mappings
- `/identity add discord <id> <peer>` — add a new mapping
- `/identity rm <index>` — remove mapping by index
- `/identity board <slug> <peer>` — set board's default peer
- `/identity help` — full help

## Safety

- The monkey-patch is applied ONLY at plugin load time, before any session.
- If the plugin is uninstalled or fails to load, Honcho is untouched.
- If the config file is missing, all resolution returns None → Honcho
  creates `user-default-*` as today.
- No data loss risk. No changes to any file in the Hermes repo.

## SessionDB compatibility patch

The built-in `session_search` tool passes a `user_id` keyword argument to
`SessionDB.search_messages()` and `SessionDB.list_sessions_rich()`, but
the upstream backend methods do not accept it (they were removed in a
later release — the tool code wasn't updated to match). This causes:

SessionDB.search_messages() got an unexpected keyword argument 'user_id'


The plugin applies a monkey-patch at load time that wraps both methods
to accept (and silently drop) the `user_id` kwarg before calling the
original backend. Same zero-fork pattern as the Honcho patch.

The access-control filtering by user_id still happens in the tool code
after results are returned — this patch only removes the redundant
(and broke) passing of user_id to the DB layer.
Description
Hermes identity resolution plugin — maps platform IDs and kanban boards to stable Honcho peer names across Discord, Telegram, terminal, and kanban workers.
Readme 63 KiB
Languages
Python 100%