Discord Thread Dashboard — Implementation Plan

Status: Planned (not implemented)
Last updated: 2026-05-22
Audience: Funday devs and agents maintaining Hermes on Discord
Hermes tree: ~/.hermes/hermes-agent/ (upstream: NousResearch/hermes-agent)

This document captures the design for a hook-driven embed dashboard in Discord: when Hermes auto-creates a thread and adds 👀 on the user’s message, a separate embed message in the thread acts as a live status panel (edited on each agent step, finalized on completion).

Related context: slash-command visibility fix (allowed_contexts / allowed_installs on discord.py 2.7+) is documented here for Funday’s install only — see § Background.


Table of Contents


1. Goals

GoalDetail
VisibilityOne embed in the thread shows the user’s request and live agent status (tools, step count).
Non-noisyAvoid spamming the thread with many tool-progress text bubbles when the embed is enough.
ExtensibleLayout and copy live in ~/.hermes/hooks/, not hard-coded in Funday-only patches.
Aligned with todayKeep 👀 on the parent-channel trigger message; dashboard lives in the thread where replies go.

Non-goals (v1): Buttons on the dashboard, cross-platform parity (Telegram/Matrix), replacing the final agent reply.


2. Background

2.1 Slash commands and discord.py 2.7+

Hermes pins discord.py[voice]==2.7.1. In 2.7+, allowed_contexts and allowed_installs default to None. When synced to Discord API v10, null values make slash commands invisible in the / picker.

Mitigation (local patch today): After registering all slash commands, set on every command without explicit values:

  • allowed_contexts: guild + DM + private channel
  • allowed_installs: guild + user

Location: gateway/platforms/discord.py_register_slash_commands() (end of registration, before optional DISCORD_HIDE_SLASH_COMMANDS).

Other installs may not have noticed this if they were on older discord.py, had fewer global commands, or never relied on the slash picker.

2.2 Auto-thread + reactions (already shipped)

SettingFunday defaultEffect
DISCORD_AUTO_THREADtrueNew thread per @mention in channels
DISCORD_REACTIONStrue👀 on processing start, ✅/❌ on complete

3. Current behavior

User @mentions Hermes in #channel


DISCORD_AUTO_THREAD → create thread; session routes to thread id


MessageEvent:
  source.chat_id  = thread id
  raw_message     = original message in #channel


on_processing_start → 👀 on raw_message (parent channel)
Agent reply         → sent to thread
Tool progress       → optional editable TEXT bubble in thread
                      (display.platforms.discord.tool_progress)

Implication: The dashboard embed should be posted in the thread (source.chat_id), while 👀 stays on the user’s message in the parent channel.


4. Proposed UX

  1. User mentions bot in a text channel.
  2. Hermes creates a thread (existing behavior).
  3. 👀 appears on the user’s original message (existing behavior).
  4. New: Bot posts a single embed in the thread:
    • Title: e.g. Hermes or session label
    • Description: excerpt of the user’s message (from trigger text)
    • Fields: Status (Processing…), step, last tools
  5. On each tool-calling iteration, the embed is edited in place.
  6. On success/failure, embed color/footer updates (e.g. green / red); optional cleanup of tool-progress text messages.

5. Architecture

LayerResponsibility
hermes-agentDetect auto-thread; send/edit/finish embed via DiscordAdapter; emit hook events; apply hook-returned embed dicts
~/.hermes/hooks/Return embed structure (title, description, color, fields) per event — survives hermes update
┌─────────────────────┐     emit_collect      ┌──────────────────────────┐
│  Gateway / run.py   │ ────────────────────► │ ~/.hermes/hooks/         │
│  agent:step, etc.   │                         │ discord-thread-dashboard │
└─────────┬───────────┘                         └────────────┬─────────────┘
          │                                                  │
          │ apply embed dict                                 │ return layout
          ▼                                                  │
┌─────────────────────┐◄─────────────────────────────────────┘
│ DiscordAdapter      │
│ send / edit embed   │
└─────────────────────┘

5.2 Alternatives considered

OptionProsCons
A. Hook-only (REST)No upstream diffNo chat_id/thread_id in hook context today; fragile state
B. Core + hooksCorrect routing; Funday customizes layout in HERMES_HOMESmall patch in hermes-agent
C. Built-in onlyFastestHard to customize

6. Hook contract

New gateway events (exact names TBD; prefer discord:dashboard:* prefix):

EventWhenContext keys (minimum)
discord:dashboard:createAuto-thread + processing startsession_id, session_key, chat_id, thread_id, message_id, user_id, user_name, user_message, discord_auto_thread
discord:dashboard:updateEach agent:step while dashboard activeAbove + iteration, tool_names, tools
discord:dashboard:finishProcessing completeAbove + outcome (success / failure / cancelled), response_preview

Handler return shape (first non-None result wins via emit_collect):

{
    "title": "Hermes",
    "description": "…",           # optional; max ~4096 for Discord
    "color": 0x5865F2,              # int, Discord embed color
    "fields": [
        {"name": "Status", "value": "👀 Processing…", "inline": False},
        {"name": "Tools", "value": "read_file, …", "inline": False},
    ],
    "footer": {"text": "Step 3"},   # optional
}

Errors in hooks are logged; they never block the agent pipeline (same as existing Event Hooks).

6.1 Enrich existing agent:* hooks (optional)

Extend agent:start / agent:step / agent:end context with chat_id, thread_id, message_id for hooks that do not need Discord-specific events. Dashboard plumbing should still use discord:dashboard:* so layouts stay platform-scoped.


7. Core changes (hermes-agent)

Planned touch points (upstream PR or Funday fork branch):

FileChange
gateway/platforms/base.pyOptional discord_auto_thread: bool on MessageEvent (or tag in source)
gateway/platforms/discord.pySet flag when _auto_create_thread succeeds; _thread_dashboards map session_key → message_id; send/edit embed helpers; call hooks via gateway_runner.hooks
gateway/run.pyOn agent:step for Discord, call adapter dashboard update; enrich agent:start hook context
gateway/hooks.pyDocument new events in module docstring
website/docs/.../hooks.mdDocument discord:dashboard:* and return shape

Adapter methods (sketch):

async def _start_thread_dashboard(self, event: MessageEvent) -> None: ...
async def _update_thread_dashboard(self, session_key: str, step_ctx: dict) -> None: ...
async def _finish_thread_dashboard(self, event: MessageEvent, outcome: ProcessingOutcome) -> None: ...

Integration point: on_processing_start → create; bridge from existing agent:step emission in _run_agent; on_processing_complete → finish.


8. Funday hook (~/.hermes/hooks/)

Planned layout (not created until core emits events):

~/.hermes/hooks/discord-thread-dashboard/
├── HOOK.yaml
└── handler.py

HOOK.yaml (draft):

name: discord-thread-dashboard
description: Embed layout for auto-thread processing dashboard on Discord
events:
  - discord:dashboard:create
  - discord:dashboard:update
  - discord:dashboard:finish

handler.py (draft): Return embed dicts; quote user message on create; show tool list on update; set green/red on finish.

This directory is not overwritten by hermes update (lives under HERMES_HOME, not the git repo).


9. Configuration

Variable / configDefaultPurpose
DISCORD_THREAD_DASHBOARDfalseEnable embed dashboard for auto-thread sessions
discord.thread_dashboard in config.yamlYAML equivalent (if wired in gateway/config.py)
display.platforms.discord.tool_progressallSet to off in threads if embed replaces text progress

Funday rollout suggestion: enable dashboard in ~/.hermes/.env after core lands; tune tool progress per channel noise preference.


10. hermes update and persistence

ArtifactAfter hermes update
~/.hermes/hooks/discord-thread-dashboard/Kept
~/.hermes/.env, config.yaml, SOUL.mdKept
gateway/platforms/discord.py in repoReplaced by git pull unless changes are committed upstream or stashed locally
Local-only patches (e.g. allowed_contexts block)Lost if uncommitted when pull/reset runs

Practice: Put agent changes in upstream Hermes or a tracked fork branch; keep Funday-specific behavior in ~/.hermes/hooks/ and config.


11. Implementation phases

PhaseScopeOwner
P0Document plan (this page)Funday docs ✅
P1allowed_contexts fix upstream or committed on deploy branchHermes
P2MessageEvent auto-thread flag + adapter embed send/editHermes
P3discord:dashboard:* events + emit_collect wiringHermes
P4Funday hook under ~/.hermes/hooks/ + DISCORD_THREAD_DASHBOARD=trueFunday
P5Docs in upstream Hermes hooks guide; runbook entry in Funday runbooksBoth

12. Testing

Manual checklist (Discord test server):

  1. @mention bot in a channel with DISCORD_AUTO_THREAD=true and dashboard enabled.
  2. Confirm thread created, 👀 on parent message, embed appears in thread with user text.
  3. Trigger a multi-tool turn; confirm embed fields update without new spam messages.
  4. Confirm ✅ on parent message and embed shows success state on completion.
  5. Failure path: tool error → embed shows failure color; ❌ on parent message.
  6. hermes update → hook still loaded; dashboard still works if core events present.

13. Open decisions

#QuestionRecommendation
1Dashboard alongside or instead of tool-progress text?Alongside initially; Funday can set tool_progress: off for Discord if noisy
2Delete dashboard embed after final reply?No (v1) — leave as breadcrumb; optional cleanup_progress-style flag later
3Only auto-thread, or all thread sessions?Auto-thread only (v1) — avoids duplicate dashboards in long-lived threads
4Slash-command threads (/thread)?Out of scope (v1) — mention/auto-thread path only

References

  • Hermes Discord messaging: hermes-agent/website/docs/user-guide/messaging/discord.md
  • Gateway event hooks: hermes-agent/website/docs/user-guide/features/hooks.md
  • Funday Hermes setup: Hermes Setup
  • Code: gateway/platforms/discord.py (_auto_create_thread, on_processing_start, _register_slash_commands)