# NousResearch/hermes-agent · BOOT.md startup hook lifecycle in gateway

## Open now

- Nothing open on GitHub.

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.

## TL;DR

- 4 member(s): 0 open issue(s), 1 closed issue(s), 0 open PR(s), 1 merged PR(s), 2 PR(s) closed without merging.
- A fix was merged to main in PR #17093. Verify it addresses your case.
- **Recommended:** read PR #17093 (and any competing PRs below) before filing. Confirm the merged change covers your symptom.

## Maintainer resolution verdict

- Internal-tracker verdict over this cluster's issue members: `resolved` · deciding PR(s): `pr-17093`. This is distinct from the fix status above. Weigh it yourself.

## How this cluster was grouped

- Link evidence (`STRUCTURAL_SPANNING`): every member is connected by structural evidence: shared changed files, or a closing/superseded reference.
- Pairwise link density `0.50`: the share of member pairs that carry a link, counting a structural link in full and a relevance-only link at 0.36. `1.00` means every pair is linked.

## Closed / duplicate issues

- #5239: BOOT.md startup hook bypasses gateway runtime auth

## Prior & competing PRs

- **#17093: remove: BOOT.md built-in hook**. merged to main · fix tier `verified`
  - maintainer direction: category `merged`
  - files: `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:
  - `AGENTS.md`

    ```diff
    @@ -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
    ```
  - `/dev/null`

    ```diff
    @@ -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()
    ```
  - `gateway/hooks.py`

    ```diff
    @@ -52,19 +52,13 @@ def loaded_hooks(self) -> List[dict]:
             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
    -
    -            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)
    +        """Register built-in hooks that are always active.
    +
    +        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:
             """
    ```
  - `hermes_cli/tips.py`

    ```diff
    @@ -263,7 +263,6 @@
         "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.",
    ```
  - `website/docs/developer-guide/architecture.md`

    ```diff
    @@ -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,
    ```
  - `website/docs/developer-guide/gateway-internals.md`

    ```diff
    @@ -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
    ```
  - `website/docs/user-guide/features/hooks.md`

    ```diff
    @@ -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:
    ```
- **#5240: fix(gateway): use resolved runtime for BOOT.md**. closed without merge
  - maintainer direction: category `superseded_by_pr`; implication `superseded`; refs `#17093`, `#3733`
- **#6441: refactor: extract turn assembly; fix gateway BOOT.md startup guard**. closed without merge
  - maintainer direction: category `implemented_elsewhere`; implication `superseded`; refs `#5239`, `#17093`

## Fix status

- Merged to main in PR #17093 (cited above). No release data is tracked. Verify downstream.
- Fix last verified (merged) `2026-04-28`.
- Subsystem: `gateway`
