diff --git a/AGENTS.md b/AGENTS.md index 05a6742d41..df14c68df2 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -38,7 +38,7 @@ hermes-agent/ │ │ # homeassistant, signal, matrix, mattermost, email, sms, │ │ # dingtalk, wecom, weixin, feishu, qqbot, bluebubbles, │ │ # webhook, api_server, ...). See ADDING_A_PLATFORM.md. -│ └── builtin_hooks/ # Always-registered gateway hooks (boot-md, ...) +│ └── builtin_hooks/ # Extension point for always-registered gateway hooks (none shipped) ├── plugins/ # Plugin system (see "Plugins" section below) │ ├── memory/ # Memory-provider plugins (honcho, mem0, supermemory, ...) │ ├── context_engine/ # Context-engine plugins diff --git a/gateway/builtin_hooks/boot_md.py b/gateway/builtin_hooks/boot_md.py deleted file mode 100644 index c2868a1e63..0000000000 --- a/gateway/builtin_hooks/boot_md.py +++ /dev/null @@ -1,85 +0,0 @@ -"""Built-in boot-md hook — run ~/.hermes/BOOT.md on gateway startup. - -This hook is always registered. It silently skips if no BOOT.md exists. -To activate, create ``~/.hermes/BOOT.md`` with instructions for the -agent to execute on every gateway restart. - -Example BOOT.md:: - - # Startup Checklist - - 1. Check if any cron jobs failed overnight - 2. Send a status update to Discord #general - 3. If there are errors in /opt/app/deploy.log, summarize them - -The agent runs in a background thread so it doesn't block gateway -startup. If nothing needs attention, it replies with [SILENT] to -suppress delivery. -""" - -import logging -import threading - -logger = logging.getLogger("hooks.boot-md") - -from hermes_constants import get_hermes_home -HERMES_HOME = get_hermes_home() -BOOT_FILE = HERMES_HOME / "BOOT.md" - - -def _build_boot_prompt(content: str) -> str: - """Wrap BOOT.md content in a system-level instruction.""" - return ( - "You are running a startup boot checklist. Follow the BOOT.md " - "instructions below exactly.\n\n" - "---\n" - f"{content}\n" - "---\n\n" - "Execute each instruction. If you need to send a message to a " - "platform, use the send_message tool.\n" - "If nothing needs attention and there is nothing to report, " - "reply with ONLY: [SILENT]" - ) - - -def _run_boot_agent(content: str) -> None: - """Spawn a one-shot agent session to execute the boot instructions.""" - try: - from run_agent import AIAgent - - prompt = _build_boot_prompt(content) - agent = AIAgent( - quiet_mode=True, - skip_context_files=True, - skip_memory=True, - max_iterations=20, - ) - result = agent.run_conversation(prompt) - response = result.get("final_response", "") - if response and "[SILENT]" not in response: - logger.info("boot-md completed: %s", response[:200]) - else: - logger.info("boot-md completed (nothing to report)") - except Exception as e: - logger.error("boot-md agent failed: %s", e) - - -async def handle(event_type: str, context: dict) -> None: - """Gateway startup handler — run BOOT.md if it exists.""" - if not BOOT_FILE.exists(): - return - - content = BOOT_FILE.read_text(encoding="utf-8").strip() - if not content: - return - - logger.info("Running BOOT.md (%d chars)", len(content)) - - # Run in a background thread so we don't block gateway startup. - thread = threading.Thread( - target=_run_boot_agent, - args=(content,), - name="boot-md", - daemon=True, - ) - thread.start() diff --git a/gateway/hooks.py b/gateway/hooks.py index 374e5b25fc..f887cf5df0 100644 --- a/gateway/hooks.py +++ b/gateway/hooks.py @@ -52,19 +52,13 @@ class HookRegistry: return list(self._loaded_hooks) def _register_builtin_hooks(self) -> None: - """Register built-in hooks that are always active.""" - try: - from gateway.builtin_hooks.boot_md import handle as boot_md_handle + """Register built-in hooks that are always active. - self._handlers.setdefault("gateway:startup", []).append(boot_md_handle) - self._loaded_hooks.append({ - "name": "boot-md", - "description": "Run ~/.hermes/BOOT.md on gateway startup", - "events": ["gateway:startup"], - "path": "(builtin)", - }) - except Exception as e: - print(f"[hooks] Could not load built-in boot-md hook: {e}", flush=True) + Currently empty — no shipped built-in hooks. Kept as the extension + point for future always-on gateway hooks so they drop in without + re-plumbing discover_and_load(). + """ + return def discover_and_load(self) -> None: """ diff --git a/hermes_cli/tips.py b/hermes_cli/tips.py index b22f457134..8e07323b62 100644 --- a/hermes_cli/tips.py +++ b/hermes_cli/tips.py @@ -263,7 +263,6 @@ TIPS = [ "hermes status --deep runs deeper diagnostic checks across all components.", # --- Hidden Gems & Power-User Tricks --- - "BOOT.md at ~/.hermes/BOOT.md runs automatically on every gateway start — use it for startup checks.", "Cron jobs can attach a Python script (--script) whose stdout is injected into the prompt as context.", "Cron scripts live in ~/.hermes/scripts/ and run before the agent — perfect for data collection pipelines.", "prefill_messages_file in config.yaml injects few-shot examples into every API call, never saved to history.", diff --git a/website/docs/developer-guide/architecture.md b/website/docs/developer-guide/architecture.md index 17e883081b..f153e47cbb 100644 --- a/website/docs/developer-guide/architecture.md +++ b/website/docs/developer-guide/architecture.md @@ -116,7 +116,7 @@ hermes-agent/ │ ├── hooks.py # Hook discovery and lifecycle events │ ├── mirror.py # Cross-session message mirroring │ ├── status.py # Token locks, profile-scoped process tracking -│ ├── builtin_hooks/ # Always-registered hooks +│ ├── builtin_hooks/ # Extension point for always-registered hooks (none shipped) │ └── platforms/ # 18 adapters: telegram, discord, slack, whatsapp, │ # signal, matrix, mattermost, email, sms, │ # dingtalk, feishu, wecom, wecom_callback, weixin, diff --git a/website/docs/developer-guide/gateway-internals.md b/website/docs/developer-guide/gateway-internals.md index b3c4324cca..4ed68082b6 100644 --- a/website/docs/developer-guide/gateway-internals.md +++ b/website/docs/developer-guide/gateway-internals.md @@ -20,7 +20,7 @@ The messaging gateway is the long-running process that connects Hermes to 14+ ex | `gateway/hooks.py` | Hook discovery, loading, and lifecycle event dispatch | | `gateway/mirror.py` | Cross-session message mirroring for `send_message` | | `gateway/status.py` | Token lock management for profile-scoped gateway instances | -| `gateway/builtin_hooks/` | Always-registered hooks (e.g., BOOT.md system prompt hook) | +| `gateway/builtin_hooks/` | Extension point for always-registered hooks (none shipped) | | `gateway/platforms/` | Platform adapters (one per messaging platform) | ## Architecture Overview diff --git a/website/docs/user-guide/features/hooks.md b/website/docs/user-guide/features/hooks.md index 3d81027ed6..f3cbeb79f3 100644 --- a/website/docs/user-guide/features/hooks.md +++ b/website/docs/user-guide/features/hooks.md @@ -89,26 +89,6 @@ Handlers registered for `command:*` fire for any `command:` event (`command:mode ### Examples -#### Boot Checklist (BOOT.md) — Built-in - -The gateway ships with a built-in `boot-md` hook that looks for `~/.hermes/BOOT.md` on every startup. If the file exists, the agent runs its instructions in a background session. No installation needed — just create the file. - -**Create `~/.hermes/BOOT.md`:** - -```markdown -# Startup Checklist - -1. Check if any cron jobs failed overnight — run `hermes cron list` -2. Send a message to Discord #general saying "Gateway restarted, all systems go" -3. Check if /opt/app/deploy.log has any errors from the last 24 hours -``` - -The agent runs these instructions in a background thread so it doesn't block gateway startup. If nothing needs attention, the agent replies with `[SILENT]` and no message is delivered. - -:::tip -No BOOT.md? The hook silently skips — zero overhead. Create the file whenever you need startup automation, delete it when you don't. -::: - #### Telegram Alert on Long Tasks Send yourself a message when the agent takes more than 10 steps: