{"repo":"NousResearch/hermes-agent","public_id":"5239","display_label":"BOOT.md startup hook lifecycle in gateway","summary":"These items collectively trace the introduction, implementation, refinement, and removal of a BOOT.md startup hook feature in the gateway, including auth handling and runtime resolution concerns.","subsystem":"gateway","counts":{"members":4,"open_issues":0,"open_issues_distinct":0,"open_prs":0,"closed_issues":1,"merged_prs":1,"attempt_prs":2},"landed_fix":{"status":"merged_to_main","basis":"structural","pr":17093,"merged_at":"2026-04-28T16:50:27+00:00"},"resolution":{"state":"resolved","by":"pr-17093"},"freshness":{"state":"verified","last_verified_at":"2026-04-28T16:50:27+00:00","is_stale":false},"grouping":{"backbone":"STRUCTURAL_SPANNING","link_density":0.5},"fix_edges":[{"issue_number":5239,"pr_number":17093,"tier":"verified","basis":"closing_ref","confidence":0.95,"recoverable_from_timeline":true,"pr_merged_at":"2026-04-28T16:50:27+00:00"}],"members":[{"kind":"issue","number":5239,"title":"BOOT.md startup hook bypasses gateway runtime auth","url":null,"state":"closed"},{"kind":"pr","number":5240,"title":"fix(gateway): use resolved runtime for BOOT.md","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#17093","number":17093},{"kind":"pr","value":"#3733","number":3733}],"category":"superseded_by_pr","implication":"superseded"},"merged":false},{"kind":"pr","number":6441,"title":"refactor: extract turn assembly; fix gateway BOOT.md startup guard","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#5239","number":5239},{"kind":"pr","value":"#17093","number":17093}],"category":"implemented_elsewhere","implication":"superseded"},"merged":false},{"kind":"pr","number":17093,"title":"remove: BOOT.md built-in hook","url":null,"state":"merged","close_reason":{"category":"merged"},"merged":true,"is_fix_pr":true,"fix_tier":"verified","files_changed":["AGENTS.md","gateway/builtin_hooks/boot_md.py","gateway/hooks.py","hermes_cli/tips.py","website/docs/developer-guide/architecture.md","website/docs/developer-guide/gateway-internals.md","website/docs/user-guide/features/hooks.md"],"fix_hunks":[{"file":"AGENTS.md","hunks":["@@ -38,7 +38,7 @@ hermes-agent/\n │   │                     #   homeassistant, signal, matrix, mattermost, email, sms,\n │   │                     #   dingtalk, wecom, weixin, feishu, qqbot, bluebubbles,\n │   │                     #   webhook, api_server, ...). See ADDING_A_PLATFORM.md.\n-│   └── builtin_hooks/    # Always-registered gateway hooks (boot-md, ...)\n+│   └── builtin_hooks/    # Extension point for always-registered gateway hooks (none shipped)\n ├── plugins/              # Plugin system (see \"Plugins\" section below)\n │   ├── memory/           # Memory-provider plugins (honcho, mem0, supermemory, ...)\n │   ├── context_engine/   # Context-engine plugins"]},{"file":"/dev/null","hunks":["@@ -1,85 +0,0 @@\n-\"\"\"Built-in boot-md hook — run ~/.hermes/BOOT.md on gateway startup.\n-\n-This hook is always registered. It silently skips if no BOOT.md exists.\n-To activate, create ``~/.hermes/BOOT.md`` with instructions for the\n-agent to execute on every gateway restart.\n-\n-Example BOOT.md::\n-\n-    # Startup Checklist\n-\n-    1. Check if any cron jobs failed overnight\n-    2. Send a status update to Discord #general\n-    3. If there are errors in /opt/app/deploy.log, summarize them\n-\n-The agent runs in a background thread so it doesn't block gateway\n-startup. If nothing needs attention, it replies with [SILENT] to\n-suppress delivery.\n-\"\"\"\n-\n-import logging\n-import threading\n-\n-logger = logging.getLogger(\"hooks.boot-md\")\n-\n-from hermes_constants import get_hermes_home\n-HERMES_HOME = get_hermes_home()\n-BOOT_FILE = HERMES_HOME / \"BOOT.md\"\n-\n-\n-def _build_boot_prompt(content: str) -> str:\n-    \"\"\"Wrap BOOT.md content in a system-level instruction.\"\"\"\n-    return (\n-        \"You are running a startup boot checklist. Follow the BOOT.md \"\n-        \"instructions below exactly.\\n\\n\"\n-        \"---\\n\"\n-        f\"{content}\\n\"\n-        \"---\\n\\n\"\n-        \"Execute each instruction. If you need to send a message to a \"\n-        \"platform, use the send_message tool.\\n\"\n-        \"If nothing needs attention and there is nothing to report, \"\n-        \"reply with ONLY: [SILENT]\"\n-    )\n-\n-\n-def _run_boot_agent(content: str) -> None:\n-    \"\"\"Spawn a one-shot agent session to execute the boot instructions.\"\"\"\n-    try:\n-        from run_agent import AIAgent\n-\n-        prompt = _build_boot_prompt(content)\n-        agent = AIAgent(\n-            quiet_mode=True,\n-            skip_context_files=True,\n-            skip_memory=True,\n-            max_iterations=20,\n-        )\n-        result = agent.run_conversation(prompt)\n-        response = result.get(\"final_response\", \"\")\n-        if response and \"[SILENT]\" not in response:\n-            logger.info(\"boot-md completed: %s\", response[:200])\n-        else:\n-            logger.info(\"boot-md completed (nothing to report)\")\n-    except Exception as e:\n-        logger.error(\"boot-md agent failed: %s\", e)\n-\n-\n-async def handle(event_type: str, context: dict) -> None:\n-    \"\"\"Gateway startup handler — run BOOT.md if it exists.\"\"\"\n-    if not BOOT_FILE.exists():\n-        return\n-\n-    content = BOOT_FILE.read_text(encoding=\"utf-8\").strip()\n-    if not content:\n-        return\n-\n-    logger.info(\"Running BOOT.md (%d chars)\", len(content))\n-\n-    # Run in a background thread so we don't block gateway startup.\n-    thread = threading.Thread(\n-        target=_run_boot_agent,\n-        args=(content,),\n-        name=\"boot-md\",\n-        daemon=True,\n-    )\n-    thread.start()"]},{"file":"gateway/hooks.py","hunks":["@@ -52,19 +52,13 @@ def loaded_hooks(self) -> List[dict]:\n         return list(self._loaded_hooks)\n \n     def _register_builtin_hooks(self) -> None:\n-        \"\"\"Register built-in hooks that are always active.\"\"\"\n-        try:\n-            from gateway.builtin_hooks.boot_md import handle as boot_md_handle\n-\n-            self._handlers.setdefault(\"gateway:startup\", []).append(boot_md_handle)\n-            self._loaded_hooks.append({\n-                \"name\": \"boot-md\",\n-                \"description\": \"Run ~/.hermes/BOOT.md on gateway startup\",\n-                \"events\": [\"gateway:startup\"],\n-                \"path\": \"(builtin)\",\n-            })\n-        except Exception as e:\n-            print(f\"[hooks] Could not load built-in boot-md hook: {e}\", flush=True)\n+        \"\"\"Register built-in hooks that are always active.\n+\n+        Currently empty — no shipped built-in hooks. Kept as the extension\n+        point for future always-on gateway hooks so they drop in without\n+        re-plumbing discover_and_load().\n+        \"\"\"\n+        return\n \n     def discover_and_load(self) -> None:\n         \"\"\""]},{"file":"hermes_cli/tips.py","hunks":["@@ -263,7 +263,6 @@\n     \"hermes status --deep runs deeper diagnostic checks across all components.\",\n \n     # --- Hidden Gems & Power-User Tricks ---\n-    \"BOOT.md at ~/.hermes/BOOT.md runs automatically on every gateway start — use it for startup checks.\",\n     \"Cron jobs can attach a Python script (--script) whose stdout is injected into the prompt as context.\",\n     \"Cron scripts live in ~/.hermes/scripts/ and run before the agent — perfect for data collection pipelines.\",\n     \"prefill_messages_file in config.yaml injects few-shot examples into every API call, never saved to history.\","]},{"file":"website/docs/developer-guide/architecture.md","hunks":["@@ -116,7 +116,7 @@ hermes-agent/\n │   ├── hooks.py              # Hook discovery and lifecycle events\n │   ├── mirror.py             # Cross-session message mirroring\n │   ├── status.py             # Token locks, profile-scoped process tracking\n-│   ├── builtin_hooks/        # Always-registered hooks\n+│   ├── builtin_hooks/        # Extension point for always-registered hooks (none shipped)\n │   └── platforms/            # 18 adapters: telegram, discord, slack, whatsapp,\n │                             #   signal, matrix, mattermost, email, sms,\n │                             #   dingtalk, feishu, wecom, wecom_callback, weixin,"]},{"file":"website/docs/developer-guide/gateway-internals.md","hunks":["@@ -20,7 +20,7 @@ The messaging gateway is the long-running process that connects Hermes to 14+ ex\n | `gateway/hooks.py` | Hook discovery, loading, and lifecycle event dispatch |\n | `gateway/mirror.py` | Cross-session message mirroring for `send_message` |\n | `gateway/status.py` | Token lock management for profile-scoped gateway instances |\n-| `gateway/builtin_hooks/` | Always-registered hooks (e.g., BOOT.md system prompt hook) |\n+| `gateway/builtin_hooks/` | Extension point for always-registered hooks (none shipped) |\n | `gateway/platforms/` | Platform adapters (one per messaging platform) |\n \n ## Architecture Overview"]},{"file":"website/docs/user-guide/features/hooks.md","hunks":["@@ -89,26 +89,6 @@ Handlers registered for `command:*` fire for any `command:` event (`command:mode\n \n ### Examples\n \n-#### Boot Checklist (BOOT.md) — Built-in\n-\n-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.\n-\n-**Create `~/.hermes/BOOT.md`:**\n-\n-```markdown\n-# Startup Checklist\n-\n-1. Check if any cron jobs failed overnight — run `hermes cron list`\n-2. Send a message to Discord #general saying \"Gateway restarted, all systems go\"\n-3. Check if /opt/app/deploy.log has any errors from the last 24 hours\n-```\n-\n-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.\n-\n-:::tip\n-No BOOT.md? The hook silently skips — zero overhead. Create the file whenever you need startup automation, delete it when you don't.\n-:::\n-\n #### Telegram Alert on Long Tasks\n \n Send yourself a message when the agent takes more than 10 steps:\n"]}]}],"trust":{"default_tier":"verified","includes_suggested":false}}