134 lines
5.3 KiB
Markdown
134 lines
5.3 KiB
Markdown
# 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 loads** → `register()` 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
|
|
|
|
```bash
|
|
# 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`
|
|
|
|
```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:
|
|
|
|
```markdown
|
|
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.
|