feat(desktop): bundle Bot Mode as built-in default-on plugin + core teammate protocol - #87886
Merged
Conversation
Contributor
૮ >ﻌ< ა ci reviewran on 9687e5a — feat: sync bundled Bot Mode with multi-source roster (Hermes
|
…n plugin Adopts the Hermes-Bot-Mode desktop plugin (NousResearch/Hermes-Bot-Mode) into apps/desktop/src/plugins/hermes-bots/, registered by the bundled vite glob and ON by default. It stays a pure @hermes/plugin-sdk consumer in plain-ESM plugin.js form; users disable it live in Settings > Plugins. - contrib/plugins.ts: bundled glob accepts plugin.js entries - contrib/runtime-loader.ts: a disk/runtime copy of an id that ships bundled is skipped (standalone installs predating adoption cannot double-register) - package.json: check:test:plugins runs the plugin's node:test suite in CI (138 tests) - source: Hermes-Bot-Mode @ c19baba, incl. today's #107/#103/#99 merges
…tion Replaces the plugin-side SOUL.md protocol append: on Bot-Mode-managed installs (any profile carrying ui_meta['hermes-bots']) the prompt builder injects the "Messaging other agents" section into every session of every profile — including headless `hermes -p <bot> chat` sessions a teammate starts — so bot handoffs work without mutating user-authored SOUL files. - tools/bot_mode_probe.py: silent-when-unmanaged probe, cached per (process, home), keyed off the agent's OWN home (not ambient HERMES_HOME); silent when SOUL.md already carries the legacy section - agent/system_prompt.py + agent_init.py + config_defaults.py: wired as agent.bot_mode_protocol (default True), stable tier, byte-stable across rebuilds (E2E-verified against the real build_system_prompt) - tui_gateway profiles.list gains bot_mode_protocol capability flag; the bundled plugin gates ALL SOUL protocol writes on it (backfill, composeSoul, Edit save) — older gateways keep the SOUL-append path - overhead: ~916 bytes, only on Bot-Mode installs; zero elsewhere Supersedes the SOUL backfill half of Hermes-Bot-Mode#99 (credit @kaduxo — the handle fix, `hermes profile list` correction, and idempotent-append guards from that PR ship in the bundled plugin).
apps/desktop/src/**/*.js is gitignored (stale tsc output shadows .tsx), which silently dropped the hermes-bots plugin.js from the adoption commit — tests shipped, source didn't, CI ENOENT'd. Negate the pattern for src/plugins/*/plugin.js: adopted plain-ESM plugins have no .tsx sibling, so the shadow hazard cannot apply.
… sessions Per review: the protocol belongs only in official Bot Mode interactions, not every session on a managed install. The prompt builder now injects the section only when the agent's session row is titled "Bot Chat" (BOT_CHAT_TITLE, matching the desktop's createCanonicalChat pin and the `hermes -p <bot> chat -c "Bot Chat"` resume target). Regular sessions never carry it; the desktop composer middleware owns @mention sends. Title is read once at first prompt build and the rendered prompt is cached + DB-restored — cache-safe. E2E against the real AIAgent + SessionDB: absent in an untitled session, present in Bot Chat, byte-stable across rebuilds, absent after retitle, absent with the flag off. Overhead unchanged (~916B, Bot Chat sessions only).
Found in live desktop E2E: the generated-identity path of composeSoul still appended the protocol section even when the backend injects it into the system prompt. New agents now get a clean identity-only SOUL against capable backends; older gateways keep the append. Covered in the capability-suppression test.
Live desktop E2E caught a write-ordering bug the automated E2E missed: tui_gateway applies pending_title to state.db AFTER the first turn, but the system prompt builds at turn START — the DB-title gate saw nothing and the Bot Chat was cached protocol-less forever. The gateway now hands the agent its intended title at construction and the gate checks the hint first, DB second (CLI/messaging-gateway paths unchanged). Live-verified on the running desktop: fresh bot's Bot Chat persisted with the protocol section, handle, and roster in its system prompt; regular sessions and SOUL.md untouched.
…at sessions Bot Chats break the "new sessions come often" assumption behind build-once system prompts: capability edits used to sit invisible until /new or compression, and the frozen birth date became misinformation. - tools/bot_mode_probe.py: capability_fingerprint() hashes the profile's capability surface (disabled skills, toolset pins, MCP config, SOUL.md, installed skills, Bot-Mode roster); Bot Chat prompts embed the 12-hex epoch stamp - agent/conversation_loop.py restore path: stored Bot Chat prompt whose epoch mismatches disk → ONE rebuild (through a cleared skills-prompt cache so new installs appear), persisted so the next turn reuses the new bytes verbatim. Prompts without a stamp — every non-Bot-Chat session — never take the branch; probe failure fails closed to reuse - agent/system_prompt.py: Bot Chat prompts are timeless — the "Conversation started:" date is dropped (timezone kept); no ticking fields in an eternal session - tui_gateway: _sync_bot_capabilities at turn start rebuilds the live agent (tool definitions are construction-baked) when the fingerprint moves, same session id/history, with a user-visible notice Cache stance: this is the /model exception applied to capabilities — a loud, user-initiated, once-per-change prefix break. Unchanged state hashes identically and stored bytes are reused verbatim (E2E-proven). Validation: 9 probe unit tests incl. per-axis fingerprint changes; E2E v3 against the real restore path (fresh build → verbatim reuse → skill install → single refresh w/ new skill in index → verbatim reuse; regular sessions dated, unstamped, never refreshed); tests/agent/ 4647/4647.
Bot Chats created before the epoch mechanism persisted prompts with no protocol section and no stamp — the staleness check only fires on stamped prompts, so pre-existing bots would never learn to message teammates. stored_bot_chat_prompt_needs_upgrade() migrates them: one rebuild, title-gated to Bot Chat, only when the probe would actually emit a section (SOUL-append legacies and unmanaged installs are left alone — rebuilding those would loop). The rebuilt prompt carries the stamp, so the upgrade can never re-fire. E2E v3b through the real restore path: legacy Bot Chat upgraded once then verbatim-reused; legacy regular sessions byte-untouched. tests/agent/ 4648/4648.
The config-read guard (test_config_read_guard) correctly flagged the probe's raw yaml.safe_load of config.yaml — raw reads miss the managed overlay, env expansion, and normalization. Use load_config_readonly() under a scoped HERMES_HOME override instead. E2E v3/v3b and the guard both green.
…#68) Pulls the multi-source roster into the bundled plugin: profiles.list rows from the active gateway are merged with the host.agents() union roster (hermes-agent #86875), so the Bots panel shows agents from every registered Desktop connection with @name-device handles for duplicates. Feature-detected and best-effort — an older Desktop build or roster failure leaves the single-source list untouched. Adapted for the bundle: - useRoster queryFn combines the bot_mode_protocol capability read (which landed after #68 was cut) with the multi-source merge - multi-source-roster tests updated for the namespace SDK import harness - soul-protocol-backfill anchor widened for the new botHandle(name, bot) signature Plugin suite: 143/143.
teknium1
force-pushed
the
feat/bundle-bot-mode-desktop
branch
from
August 17, 2026 01:24
2085c7e to
9687e5a
Compare
This was referenced Aug 17, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Bot Mode is now part of the desktop app: the Hermes-Bot-Mode plugin ships bundled and ON by default, and the bot-to-bot messaging protocol moves out of user SOUL.md files into a core stable-tier system-prompt section that covers every session of every profile — including the headless
hermes -p <bot> chatsessions teammates start.Changes
apps/desktop/src/plugins/hermes-bots/— adopted from NousResearch/Hermes-Bot-Mode @ c19baba + the multi-source roster (Hermes-Bot-Mode#68): the Bots panel merges the active gateway's profiles.list with thehost.agents()union roster from feat(desktop): multi-source agents end-to-end — sockets, roster, SDK, fan-out updates #86875, showing bots from every registered Desktop connection (feature-detected; single-source behavior unchanged on older builds). Unchanged plugin.js form otherwise,descriptionadded for the Settings inventory; default-on, live-disable via Settings → Pluginsapps/desktop/src/contrib/plugins.ts— bundled glob acceptsplugin.jsapps/desktop/src/contrib/runtime-loader.ts— disk/runtime copy of a bundled plugin id is skipped (pre-adoption standalone installs can't double-register)apps/desktop/package.json—check:test:pluginsruns the plugin suite in js-tests CItools/bot_mode_probe.py(+ system_prompt/agent_init/config_defaults wiring) —agent.bot_mode_protocol(default on): silent unless a profile carriesui_meta['hermes-bots']; silent when SOUL.md has the legacy section; cached per (process, home), keyed off the agent's own home; byte-stable across rebuildstui_gateway/methods_profiles.py—profiles.listgains abot_mode_protocolcapability flag; the bundled plugin gates all SOUL protocol writes on it (backfill, composeSoul, Edit save). Older gateways keep the plugin-side SOUL-append fallbackwebsite/docs/user-guide/desktop.md— Bot Mode sectionValidation
build_system_promptSupersedes the SOUL-backfill half of Hermes-Bot-Mode#99 — credit @kaduxo, whose handle fix,
hermes profile listcorrection, and idempotent-append guards ship in the bundled plugin.Infographic