Skip to content

Instantly share code, notes, and snippets.

@limcheekin
Last active May 4, 2026 23:32
Show Gist options
  • Select an option

  • Save limcheekin/b22dc88a260c8e395b6d84d05bd62a04 to your computer and use it in GitHub Desktop.

Select an option

Save limcheekin/b22dc88a260c8e395b6d84d05bd62a04 to your computer and use it in GitHub Desktop.
Hermes Agent Repository Wiki — generated by GitNexus
This file has been truncated, but you can view the full file.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>hermes-agent — Wiki</title>
<script src="https://cdn.jsdelivr.net/npm/marked@11.0.0/marked.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js"></script>
<style>
*{margin:0;padding:0;box-sizing:border-box}
:root{
--bg:#ffffff;--sidebar-bg:#f8f9fb;--border:#e5e7eb;
--text:#1e293b;--text-muted:#64748b;--primary:#2563eb;
--primary-soft:#eff6ff;--hover:#f1f5f9;--code-bg:#f1f5f9;
--radius:8px;--shadow:0 1px 3px rgba(0,0,0,.08);
}
body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;
line-height:1.65;color:var(--text);background:var(--bg)}
.layout{display:flex;min-height:100vh}
.sidebar{width:280px;background:var(--sidebar-bg);border-right:1px solid var(--border);
position:fixed;top:0;left:0;bottom:0;overflow-y:auto;padding:24px 16px;
display:flex;flex-direction:column;z-index:10}
.content{margin-left:280px;flex:1;padding:48px 64px;max-width:960px}
.sidebar-header{margin-bottom:20px;padding-bottom:16px;border-bottom:1px solid var(--border)}
.sidebar-title{font-size:16px;font-weight:700;color:var(--text);display:flex;align-items:center;gap:8px}
.sidebar-title svg{flex-shrink:0}
.sidebar-meta{font-size:11px;color:var(--text-muted);margin-top:6px}
.nav-section{margin-bottom:2px}
.nav-item{display:block;padding:7px 12px;border-radius:var(--radius);cursor:pointer;
font-size:13px;color:var(--text);text-decoration:none;transition:all .15s;
white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.nav-item:hover{background:var(--hover)}
.nav-item.active{background:var(--primary-soft);color:var(--primary);font-weight:600}
.nav-item.overview{font-weight:600;margin-bottom:4px}
.nav-children{padding-left:14px;border-left:1px solid var(--border);margin-left:12px}
.nav-group-label{font-size:11px;font-weight:600;color:var(--text-muted);
text-transform:uppercase;letter-spacing:.5px;padding:12px 12px 4px;user-select:none}
.sidebar-footer{margin-top:auto;padding-top:16px;border-top:1px solid var(--border);
font-size:11px;color:var(--text-muted);text-align:center}
.content h1{font-size:28px;font-weight:700;margin-bottom:8px;line-height:1.3}
.content h2{font-size:22px;font-weight:600;margin:32px 0 12px;padding-bottom:6px;border-bottom:1px solid var(--border)}
.content h3{font-size:17px;font-weight:600;margin:24px 0 8px}
.content h4{font-size:15px;font-weight:600;margin:20px 0 6px}
.content p{margin:12px 0}
.content ul,.content ol{margin:12px 0 12px 24px}
.content li{margin:4px 0}
.content a{color:var(--primary);text-decoration:none}
.content a:hover{text-decoration:underline}
.content blockquote{border-left:3px solid var(--primary);padding:8px 16px;margin:16px 0;
background:var(--primary-soft);border-radius:0 var(--radius) var(--radius) 0;
color:var(--text-muted);font-size:14px}
.content code{font-family:'SF Mono',Consolas,'Courier New',monospace;font-size:13px;
background:var(--code-bg);padding:2px 6px;border-radius:4px}
.content pre{background:#1e293b;color:#e2e8f0;border-radius:var(--radius);padding:16px;
overflow-x:auto;margin:16px 0}
.content pre code{background:none;padding:0;font-size:13px;line-height:1.6;color:inherit}
.content table{border-collapse:collapse;width:100%;margin:16px 0}
.content th,.content td{border:1px solid var(--border);padding:8px 12px;text-align:left;font-size:14px}
.content th{background:var(--sidebar-bg);font-weight:600}
.content img{max-width:100%;border-radius:var(--radius)}
.content hr{border:none;border-top:1px solid var(--border);margin:32px 0}
.content .mermaid{margin:20px 0;text-align:center}
.menu-toggle{display:none;position:fixed;top:12px;left:12px;z-index:20;
background:var(--bg);border:1px solid var(--border);border-radius:var(--radius);
padding:8px 12px;cursor:pointer;font-size:18px;box-shadow:var(--shadow)}
@media(max-width:768px){
.sidebar{transform:translateX(-100%);transition:transform .2s}
.sidebar.open{transform:translateX(0);box-shadow:2px 0 12px rgba(0,0,0,.1)}
.content{margin-left:0;padding:24px 20px;padding-top:56px}
.menu-toggle{display:block}
}
.empty-state{text-align:center;padding:80px 20px;color:var(--text-muted)}
.empty-state h2{font-size:20px;margin-bottom:8px;border:none}
</style>
</head>
<body>
<button class="menu-toggle" id="menu-toggle" aria-label="Toggle menu">&#9776;</button>
<div class="layout">
<nav class="sidebar" id="sidebar">
<div class="sidebar-header">
<div class="sidebar-title">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M2 3h6a4 4 0 014 4v14a3 3 0 00-3-3H2z"/><path d="M22 3h-6a4 4 0 00-4 4v14a3 3 0 013-3h7z"/></svg>
hermes-agent
</div>
<div class="sidebar-meta" id="meta-info"></div>
</div>
<div id="nav-tree"></div>
<div class="sidebar-footer">Generated by GitNexus</div>
</nav>
<main class="content" id="content">
<div class="empty-state"><h2>Loading…</h2></div>
</main>
</div>
<script>
var PAGES = {"acp-adapter":"# acp_adapter\n\n# acp_adapter\n\nThe `acp_adapter` module implements the **Agent Communication Protocol (ACP)** for `hermes-agent`. It acts as a bridge between the Hermes AI agent and external editors (such as Zed) that support the ACP specification. The adapter handles JSON-RPC transport over `stdio`, manages persistent agent sessions, and translates Hermes-specific events into ACP-compliant notifications.\n\n## Architecture Overview\n\nThe adapter sits between the ACP client (the editor) and the core `AIAgent` logic. Because `AIAgent` is primarily synchronous and runs in worker threads, the adapter manages the transition to the asynchronous `asyncio` environment required by the ACP server.\n\n```mermaid\ngraph TD\n Editor[ACP Client / Editor] <-->|JSON-RPC over stdio| Server[HermesACPAgent]\n Server <--> SM[SessionManager]\n SM <--> DB[(SessionDB / state.db)]\n SM --> Agent[AIAgent Instance]\n Agent -->|Callbacks| Events[events.py]\n Events -->|Notifications| Server\n```\n\n## Key Components\n\n### HermesACPAgent (`server.py`)\nThe central class inheriting from `acp.Agent`. It implements the ACP lifecycle methods:\n- **`initialize`**: Advertises agent capabilities (multimodal support, session forking, etc.) and detects available auth providers.\n- **`new_session` / `load_session` / `resume_session`**: Orchestrates the creation or restoration of agent instances via the `SessionManager`.\n- **`prompt`**: The primary execution loop. It extracts text and images from ACP content blocks, handles slash commands, and runs the `AIAgent` inside a `ThreadPoolExecutor`.\n- **`set_session_model`**: Allows the editor to switch models/providers dynamically.\n\n### SessionManager (`session.py`)\nManages the lifecycle of `SessionState` objects. \n- **Persistence**: Sessions are backed by the shared Hermes `SessionDB` (`~/.hermes/state.db`). This allows sessions to survive process restarts and appear in global session searches.\n- **WSL Path Translation**: Includes logic (`_translate_acp_cwd`) to convert Windows drive paths (sent by Windows-based editors) into WSL mount paths when Hermes is running in a Linux environment.\n- **Agent Factory**: Creates `AIAgent` instances with specific configurations, including `hermes-acp` toolsets and redirected output (routing agent `stdout` to `stderr` to keep the ACP transport clean).\n\n### Event Bridging (`events.py`)\nSince `AIAgent` runs in a background thread, `events.py` provides factory functions to create thread-safe callbacks. These callbacks use `asyncio.run_coroutine_threadsafe` to push updates back to the main event loop:\n- **`make_tool_progress_cb`**: Emits `ToolCallStart` notifications.\n- **`make_step_cb`**: Emits `ToolCallProgress` (completion) notifications, including diff snapshots for file edits.\n- **`make_thinking_cb`**: Streams internal reasoning/thought text.\n- **`make_message_cb`**: Streams the final assistant response text.\n\n### Tool Mapping (`tools.py`)\nMaps Hermes tool definitions to ACP `ToolKind` (e.g., `read_file` -> `read`, `terminal` -> `execute`). It also contains logic for:\n- **Diff Generation**: Translates Hermes internal edit formats (V4A patches) into ACP-compliant diff blocks.\n- **Title Generation**: Creates human-readable labels for tool invocations (e.g., \"terminal: npm install\").\n\n### Permissions (`permissions.py`)\nBridges Hermes' internal `approval_callback` system to the ACP `request_permission` protocol. When a tool requires manual approval (like a terminal command), the adapter suspends the agent thread and sends a permission request to the editor, resuming only after the user provides an outcome.\n\n## Session Lifecycle and Persistence\n\nSessions are identified by a UUID. When a client calls `load_session` or `resume_session`, the `SessionManager`:\n1. Queries the SQLite database for existing history.\n2. Reconstructs the `AIAgent` with the previously used model and provider.\n3. Replays the conversation history to the client using `user_message_chunk` and `agent_message_chunk` notifications so the editor UI stays in sync with the server state.\n\n## Slash Commands\n\nThe adapter intercepts messages starting with `/` to provide \"headless\" control over the agent without invoking the LLM. Supported commands include:\n- `/model`: Switch the active model or provider.\n- `/context`: Show message counts and token pressure.\n- `/compact`: Manually trigger context compression.\n- `/steer`: Inject guidance into an active turn.\n- `/reset`: Clear the current session history.\n\n## Execution and Logging\n\nThe module is executed via `acp_adapter.entry`. \n\n- **Logging**: All logs are routed to `stderr`. This is critical because `stdout` is reserved for the JSON-RPC protocol.\n- **Environment**: Loads variables from `~/.hermes/.env` via `hermes_cli.env_loader`.\n- **Liveness Probes**: The `_BenignProbeMethodFilter` suppresses noisy tracebacks caused by common liveness checks (like `ping` or `health`) that are not part of the formal ACP schema but are frequently sent by bridge utilities.\n\nTo run the adapter manually:\n```bash\npython -m acp_adapter\n```\nOr via the Hermes CLI:\n```bash\nhermes acp\n```","acp-registry":"# acp_registry\n\n# ACP Registry\n\nThe `acp_registry` module serves as the discovery and configuration layer for the Hermes Agent within the Agent Control Protocol (ACP) ecosystem. It provides the static metadata required by host applications to identify the agent's capabilities and establish a communication channel via the command-line interface.\n\n## Module Overview\n\nThis module is primarily data-driven, centered around a standardized manifest file that defines the agent's identity and execution parameters. It acts as the entry point for any system attempting to orchestrate the Hermes Agent.\n\n### The Agent Manifest (`agent.json`)\n\nThe core of the registry is the `agent.json` file. This file follows the ACP schema version 1 and contains the following key sections:\n\n| Field | Value | Description |\n| :--- | :--- | :--- |\n| `name` | `hermes-agent` | The unique identifier for the agent within the registry. |\n| `display_name` | `Hermes Agent` | The human-readable name used in UIs. |\n| `description` | *Varies* | Highlights key features: 90+ tools, persistent memory, and multi-platform support. |\n| `distribution` | `object` | Defines how the host should launch the agent process. |\n\n## Distribution and Execution\n\nThe registry specifies a `command` distribution type. This indicates that the agent does not run as a persistent background service by default, but is instead invoked as a subprocess by the host application.\n\n### Execution Pattern\n\nTo initialize the Agent Control Protocol session, the host executes the following command pattern derived from the registry:\n\n```bash\nhermes acp\n```\n\nWhen invoked with the `acp` argument, the `hermes` binary enters a mode where it listens for JSON-RPC or similar protocol messages over standard input/output (STDIN/STDOUT), allowing the host to leverage the agent's toolset and memory.\n\n```mermaid\ngraph TD\n Host[Host Application] -->|Reads| Reg[acp_registry/agent.json]\n Reg -->|Provides Command| Host\n Host -->|Spawns Process| Sub[hermes acp]\n Sub <-->|ACP Protocol| Host\n```\n\n## Integration Details\n\n* **Tooling:** The registry signals that the agent provides a high-density tool environment (90+ tools). The specific schemas for these tools are typically negotiated over the protocol once the `hermes acp` process is active.\n* **Persistence:** The agent manages its own persistent memory; the registry ensures the host knows this capability is available, though the host does not need to manage the underlying database files directly.\n* **Iconography:** The `icon` field references `icon.svg`, which should be co-located with the manifest for use in graphical client interfaces.\n\n## Contributing\n\nWhen modifying the registry:\n1. Ensure the `schema_version` remains compatible with the target ACP host.\n2. If the CLI entry point changes, update the `distribution.args` array to reflect the new command structure.\n3. Keep the `description` concise as it is often rendered in constrained UI components (e.g., sidebars or marketplace cards).","agent-agent":"# agent — agent\n\n# Agent Internals Module\n\nThe `agent` module provides the core infrastructure for interacting with LLM providers, managing account usage, and routing auxiliary tasks. Originally extracted from the monolithic `run_agent.py`, these sub-modules isolate provider-specific logic, authentication flows, and fallback strategies.\n\n## Anthropic Adapter (`anthropic_adapter.py`)\n\nThis module acts as a comprehensive translation layer between Hermes's internal OpenAI-style message format and the Anthropic Messages API. It handles the nuances of Claude models, including \"thinking\" blocks, token limits, and complex authentication.\n\n### Model Normalization and Constraints\nThe adapter manages model-specific behaviors through several utility functions:\n- `normalize_model_name`: Converts dots to hyphens (e.g., `claude-3.5` to `claude-3-5`) while preserving AWS Bedrock namespace separators.\n- `_get_anthropic_max_output`: Maps model families to their specific output token ceilings (e.g., 128k for Opus 4.6/4.7).\n- `_resolve_anthropic_messages_max_tokens`: Ensures `max_tokens` is a positive finite integer, preventing API 400 errors.\n\n### Message Conversion Logic\nThe `convert_messages_to_anthropic` function transforms message arrays while enforcing Anthropic's strict protocol requirements:\n1. **Role Alternation**: Merges consecutive messages of the same role.\n2. **System Prompt Extraction**: Separates system messages into a standalone parameter.\n3. **Thinking Block Management**: \n - Strips Anthropic-proprietary signatures when routing to third-party endpoints (Azure, Bedrock, MiniMax) to avoid validation failures.\n - Preserves unsigned thinking blocks for Kimi and DeepSeek endpoints which require them for history validation.\n - Downgrades unsigned thinking to plain text for native Anthropic calls to prevent data loss.\n4. **Orphan Handling**: Removes `tool_use` blocks that lack corresponding `tool_result` blocks (and vice versa) to prevent 400 errors during context compression.\n\n### Authentication and OAuth\nThe module supports three primary authentication paths:\n- **Standard API Keys**: `sk-ant-api...` keys used with the `x-api-key` header.\n- **Claude Code Integration**: Detects and refreshes credentials from `~/.claude/.credentials.json` or the macOS Keychain.\n- **Hermes-Native OAuth**: Implements a PKCE flow (`run_hermes_oauth_login_pure`) for Claude Pro/Max subscriptions, storing tokens in `~/.hermes/.anthropic_oauth.json`.\n\n## Auxiliary Client (`auxiliary_client.py`)\n\nThe Auxiliary Client provides a unified interface for \"side tasks\" such as context compression, vision analysis, and session search. It implements a robust fallback chain to ensure these tasks succeed even if the primary provider is unavailable.\n\n### Resolution Strategy\nWhen a task is set to `auto`, the client follows a prioritized resolution order:\n1. **Main Provider**: The user's primary model.\n2. **OpenRouter**: Using `OPENROUTER_API_KEY`.\n3. **Nous Portal**: Using credentials from `auth.json`.\n4. **Custom/Native**: Fallbacks to direct Anthropic or OpenAI endpoints.\n\n### Codex Responses Shim\nSince auxiliary tasks expect an OpenAI-compatible `chat.completions` interface, the `_CodexCompletionsAdapter` class shims the OpenAI Codex Responses API. It translates multimodal content blocks (e.g., `image_url` to `input_image`) and handles the streaming event differences between the two protocols.\n\n### Key Functions\n- `resolve_provider_client`: Returns a configured OpenAI or Anthropic client based on the task type.\n- `call_llm` / `async_call_llm`: High-level wrappers that execute completions with automatic retry logic and jittered backoff.\n- `_fixed_temperature_for_model`: Enforces model-specific temperature constraints (e.g., omitting temperature for Kimi models that manage it server-side).\n\n## Account Usage (`account_usage.py`)\n\nThis module tracks and renders rate limits and credit balances across different providers.\n\n### Data Structures\n- `AccountUsageSnapshot`: A point-in-time record of a provider's status, including the plan type and fetched timestamp.\n- `AccountUsageWindow`: Represents a specific limit (e.g., \"Session\" or \"Weekly\") with usage percentages and reset times.\n\n### Provider Support\n- **OpenAI Codex**: Fetches from the `/wham/usage` or `/api/codex/usage` endpoints.\n- **Anthropic**: Requires OAuth-backed tokens to access the `/api/oauth/usage` endpoint.\n- **OpenRouter**: Queries both `/credits` and `/key` endpoints to provide a combined view of balance and key-specific quotas.\n\n## Execution Flow: Auxiliary Task Resolution\n\n```mermaid\ngraph TD\n A[Task Request] --> B{Provider Set?}\n B -- Explicit --> C[Resolve Specific Client]\n B -- \"auto\" --> D{Task Type?}\n D -- Text --> E[Main -> OpenRouter -> Nous -> Custom]\n D -- Vision --> F[Main -> OpenRouter -> Nous -> Anthropic]\n E --> G[Build Client]\n F --> G\n G --> H{Is Codex?}\n H -- Yes --> I[Apply _CodexCompletionsAdapter]\n H -- No --> J[Return Standard Client]\n```\n\n## Tool Guardrails (`tool_guardrails.py`)\n\nThis sub-module provides safety and idempotency checks for tool execution.\n- `before_call`: Checks if a tool call is idempotent or requires explicit user approval.\n- `after_call`: Uses `classify_tool_failure` to determine if a tool error is terminal or retryable based on the JSON response or exit code.\n- `canonical_tool_args`: Normalizes tool arguments to ensure consistent hashing for idempotency checks.\n\n## Subdirectory Hints (`subdirectory_hints.py`)\n\nOptimizes prompt context by scanning for relevant directories.\n- `_extract_directories`: Parses shell commands to find path references.\n- `_load_hints_for_directory`: Integrates with `prompt_builder.py` to inject directory-specific context into the system prompt, improving the agent's situational awareness of the project structure.","agent-transports":"# agent — transports\n\n# Agent Transports Module\n\nThe `agent.transports` module provides a unified interface for interacting with diverse LLM providers. It abstracts the complexities of message formatting, tool definition conversion, and response normalization into a consistent API, allowing the core agent logic to remain provider-agnostic.\n\n## Core Architecture\n\nThe module follows a registry pattern where transport implementations are mapped to specific `api_mode` strings.\n\n### The Transport Registry\nTransports are managed via `agent.transports.__init__.py`. The registry supports lazy discovery to ensure that all available transports are loaded regardless of import order.\n\n* `get_transport(api_mode: str)`: The primary entry point. It returns an instance of the requested transport or `None` if not found.\n* `register_transport(api_mode: str, transport_cls: type)`: Used by individual transport modules to register themselves (typically called at the bottom of the module).\n\n### ProviderTransport (ABC)\nAll transports must inherit from `ProviderTransport` in `agent.transports.base.py`. A transport is responsible for the data transformation path but does **not** manage client lifecycles, network calls, or retry logic.\n\n| Method | Purpose |\n| :--- | :--- |\n| `convert_messages` | Transforms OpenAI-format messages into provider-native structures. |\n| `convert_tools` | Transforms OpenAI tool schemas into provider-native tool definitions. |\n| `build_kwargs` | The main assembly point. Combines messages, tools, and model parameters into a dictionary ready for the provider's SDK. |\n| `normalize_response` | Converts a raw provider response into a `NormalizedResponse` object. |\n| `validate_response` | Performs structural checks to ensure the response is usable. |\n\n## Data Normalization\n\nThe module defines canonical types in `agent.transports.types.py` to ensure downstream consumers receive consistent data.\n\n### NormalizedResponse\nThis dataclass represents the final output of any transport.\n* `content`: The primary text response.\n* `tool_calls`: A list of `ToolCall` objects.\n* `finish_reason`: Normalized to one of: `\"stop\"`, `\"tool_calls\"`, `\"length\"`, or `\"content_filter\"`.\n* `reasoning`: Raw reasoning/thinking text (if supported).\n* `provider_data`: A dictionary for protocol-specific metadata that doesn't fit the global schema (e.g., Anthropic's `reasoning_details`).\n\n### ToolCall\nStandardizes tool invocations across providers.\n* `id`: The canonical identifier used for tool result mapping.\n* `name`: The function name.\n* `arguments`: A JSON-encoded string of arguments.\n* `provider_data`: Stores critical protocol-specific fields, such as Gemini's `thought_signature` or Codex's `call_id`, which must be replayed in subsequent turns.\n\n## Implementation Details\n\n### ChatCompletionsTransport\nLocated in `agent/transports/chat_completions.py`, this is the most complex transport. It serves as the default path for ~16 OpenAI-compatible providers (OpenRouter, DeepSeek, Ollama, etc.).\n\nKey responsibilities:\n* **Gemini Thinking:** Translates reasoning configurations into Gemini's specific `thinking_config` or `thinking_level` parameters.\n* **Moonshot/Kimi Sanitization:** Invokes `sanitize_moonshot_tools` to handle strict JSON schema requirements.\n* **Codex Leak Prevention:** Strips internal Codex fields (`codex_reasoning_items`) from messages before sending them to standard Chat Completion endpoints.\n* **Reasoning Extraction:** Handles various reasoning fields like `reasoning_content` (DeepSeek) and `reasoning_details` (OpenRouter).\n\n### AnthropicTransport\nWraps `agent/anthropic_adapter.py`. It handles the conversion between OpenAI's message list and Anthropic's `(system, messages)` tuple. It specifically manages the normalization of `thinking` blocks and `tool_use` blocks into the unified `NormalizedResponse`.\n\n### BedrockTransport\nInterfaces with the AWS Bedrock Converse API. It handles the specific dictionary structure required by `boto3` and maps Bedrock-specific stop reasons (like `guardrail_intervened`) to standard finish reasons.\n\n### ResponsesApiTransport (Codex)\nManages the OpenAI Responses API (Codex). Unlike standard chat completions, it handles `instructions` as a top-level parameter and manages complex `include` arrays for encrypted reasoning content. It also handles `prompt_cache_key` mapping for session persistence.\n\n## Execution Flow\n\nThe following diagram illustrates how the agent uses a transport to execute a request:\n\n```mermaid\ngraph TD\n A[AIAgent] -->|api_mode| B(get_transport)\n B --> C[Transport Instance]\n A -->|messages, tools, params| D[Transport.build_kwargs]\n D --> E{Provider Call}\n E -->|Raw Response| F[Transport.normalize_response]\n F --> G[NormalizedResponse]\n G -->|Consistent Schema| A\n```\n\n## Usage Example\n\n```python\nfrom agent.transports import get_transport\n\n# 1. Get the transport\ntransport = get_transport(\"anthropic_messages\")\n\n# 2. Prepare the request payload\napi_kwargs = transport.build_kwargs(\n model=\"claude-3-5-sonnet-latest\",\n messages=[{\"role\": \"user\", \"content\": \"Hello\"}],\n tools=my_tools,\n max_tokens=1024\n)\n\n# 3. Execute call (handled by agent/client, not transport)\nraw_response = client.messages.create(**api_kwargs)\n\n# 4. Normalize\nresult = transport.normalize_response(raw_response)\n\nprint(result.content)\nprint(result.finish_reason)\n```\n\n## Adding a New Transport\n\n1. Create a new file in `agent/transports/`.\n2. Define a class inheriting from `ProviderTransport`.\n3. Implement the abstract methods, delegating to provider-specific adapters where appropriate.\n4. Register the transport at the end of the file:\n ```python\n from agent.transports import register_transport\n register_transport(\"my_new_api\", MyNewTransport)\n ```\n5. Add the module to the `_discover_transports()` function in `agent/transports/__init__.py`.","agent":"# agent\n\n# Agent Module\n\nThe `agent` module serves as the central orchestration layer for Hermes. It abstracts the complexities of multi-provider LLM communication, enforces safety protocols through guardrails and redaction, and manages the lifecycle of \"skills\" (agent tools).\n\n## Core Architecture\n\nThe module is designed around a decoupled execution flow where the core agent logic remains provider-agnostic by relying on specialized sub-modules for transport, safety, and auxiliary processing.\n\n```mermaid\ngraph TD\n A[Agent Core] --> B[Transports]\n A --> C[Skill Management]\n A --> D[Safety & Governance]\n A --> E[Auxiliary Tasks]\n\n subgraph B [Communication]\n B1[anthropic_adapter]\n B2[transports registry]\n end\n\n subgraph C [Skills]\n C1[skill_preprocessing]\n C2[skill_commands]\n C3[skill_utils]\n end\n\n subgraph D [Safety]\n D1[tool_guardrails]\n D2[redact]\n D3[shell_hooks]\n end\n\n subgraph E [Auxiliary]\n E1[auxiliary_client]\n E2[title_generator]\n E3[usage_pricing]\n end\n```\n\n## Key Sub-Modules\n\n### Communication & Transports\nThe agent interacts with LLMs through a unified interface provided by the [Transports](agent-transports.md) module. This system uses a registry pattern to resolve specific provider implementations (like Bedrock or Anthropic) at runtime.\n* **[Agent Internals](agent-agent.md):** Manages the high-level interaction logic and model normalization.\n* **Anthropic Adapter:** A specialized layer within the agent internals that translates internal message formats to the Anthropic Messages API, handling \"thinking\" blocks and token constraints.\n\n### Skill & Context Management\nSkills are the functional tools available to the agent. The module handles their discovery, preprocessing, and injection into the model context.\n* **[Skill Utilities & Preprocessing](agent-skill-utils.md):** Manages directory discovery for skills and expands inline shell commands or dynamic content before they reach the LLM.\n* **[Subdirectory Hints](agent-subdirectory-hints.md):** Provides filesystem context to the agent, helping it navigate project structures more effectively.\n\n### Safety & Governance\nTo ensure secure execution, the module intercepts inputs and outputs to sanitize data and enforce permissions.\n* **[Tool Guardrails](agent-tool-guardrails.md):** Enforces constraints on tool execution, such as argument coercion and result hashing.\n* **[Redaction](agent-redact.md):** Automatically scrubs PII, query strings, and sensitive form data from logs and transmissions.\n* **[Shell Hooks](agent-shell-hooks.md):** Implements an approval workflow for shell command execution, utilizing allowlists to skip manual intervention for trusted commands.\n\n### Economics & Auxiliary Services\nThe module tracks the \"cost of intelligence\" and offloads non-critical tasks to secondary LLM instances.\n* **[Usage & Pricing](agent-usage-pricing.md):** Resolves billing routes and estimates costs by cross-referencing [Model Metadata](agent-model-metadata.md).\n* **[Auxiliary Client](agent-auxiliary-client.md):** Provides a dedicated client for background tasks like [Title Generation](agent-title-generator.md), ensuring that secondary processing does not interfere with the primary conversation state.\n\n### State Maintenance\n* **[Curator Backup](agent-curator-backup.md):** Provides snapshot and rollback capabilities for agent skills, ensuring that automated modifications to the agent's capabilities can be reverted if they lead to regressions.","cron":"# cron\n\n# Cron Module\n\nThe `cron` module provides a robust scheduling system for the Hermes Agent. It allows for automated task execution using cron expressions, fixed intervals, or one-shot timestamps. Jobs are executed in isolated sessions, ensuring that scheduled tasks do not pollute the primary user conversation history while still having access to the agent's full toolset and skills.\n\n## Architecture Overview\n\nThe module is split into two primary concerns:\n1. **Job Management (`jobs.py`)**: Handles the persistence, CRUD operations, and schedule parsing.\n2. **Execution Engine (`scheduler.py`)**: Manages the lifecycle of a \"tick,\" including job selection, parallel execution, and result delivery.\n\n```mermaid\ngraph TD\n G[Gateway/Daemon] -->|Every 60s| T[tick]\n T -->|File Lock| L[Lock Acquired]\n L --> GDJ[get_due_jobs]\n GDJ -->|Load| JF[(jobs.json)]\n T -->|Parallel/Sequential| RJ[run_job]\n RJ -->|Execute| S[Pre-run Script]\n RJ -->|Initialize| Agent[AIAgent Instance]\n RJ -->|Save| SO[save_job_output]\n RJ -->|Deliver| DR[_deliver_result]\n DR -->|Notify| Plat[External Platforms]\n```\n\n## Job Management\n\nJobs are stored as a JSON array in `~/.hermes/cron/jobs.json`. Each job definition includes the prompt, schedule, delivery configuration, and metadata.\n\n### Schedule Parsing\nThe `parse_schedule` function supports four formats:\n- **Duration**: `30m`, `2h` (One-shot execution after delay).\n- **Interval**: `every 30m`, `every 1d` (Recurring execution).\n- **Cron**: `0 9 * * *` (Standard 5 or 6 field cron expressions via `croniter`).\n- **Timestamp**: `2026-02-03T14:00:00` (One-shot execution at specific time).\n\n### Persistence and Safety\n- **Atomic Writes**: `save_jobs` uses `atomic_replace` to prevent database corruption during power failure or crashes.\n- **Concurrency**: An in-process `threading.Lock` (`_jobs_file_lock`) protects the load-modify-save cycle during parallel execution.\n- **At-Most-Once Semantics**: For recurring jobs, `advance_next_run` is called *before* execution. This ensures that if the agent crashes or the process is killed, the job does not enter an infinite loop on restart.\n\n## Execution Engine\n\nThe `tick()` function is the entry point for execution, typically invoked by the Hermes Gateway daemon.\n\n### The Tick Lifecycle\n1. **Locking**: Acquires a file-based lock (`.tick.lock`) using `fcntl` (Unix) or `msvcrt` (Windows) to prevent duplicate execution from overlapping processes.\n2. **Selection**: `get_due_jobs()` identifies jobs whose `next_run_at` is in the past. It includes a \"grace window\" logic to fast-forward stale recurring jobs rather than firing a burst of missed events.\n3. **Partitioning**: \n - **Parallel**: Standard jobs run in a `ThreadPoolExecutor`.\n - **Sequential**: Jobs with a defined `workdir` are run one-by-one because they mutate the process-global `TERMINAL_CWD` environment variable.\n4. **Cleanup**: Invokes `_kill_orphaned_mcp_children` to reap any leaked Model Context Protocol subprocesses.\n\n### Agent Execution (`run_job`)\nEach job spawns a fresh `AIAgent` instance. Key configurations include:\n- **Inactivity Timeout**: Controlled by `HERMES_CRON_TIMEOUT` (default 600s). If the agent stops producing tokens or calling tools, it is forcibly interrupted.\n- **Context Discovery**: If `workdir` is set, the agent discovers project-specific context (e.g., `CLAUDE.md`, `.cursorrules`) and sets the base directory for terminal/file tools.\n- **Session Isolation**: Uses a unique `session_id` (prefixed `cron_`) and its own SQLite session store.\n\n## Advanced Features\n\n### Pre-run Scripts and Wake Gates\nJobs can specify a `script` path. This Python script runs before the agent:\n- **Context Injection**: The script's `stdout` is prepended to the agent's prompt.\n- **Wake Gates**: If the script outputs JSON containing `{\"wakeAgent\": false}`, the execution is short-circuited. No LLM call is made, and no delivery occurs. This is ideal for \"poll and notify\" tasks where the agent only wakes if data has changed.\n\n### Context Chaining\nThe `context_from` field allows a job to ingest the most recent output of another job. This enables pipeline architectures (e.g., Job A scrapes data, Job B analyzes the output of Job A).\n\n### Delivery Routing\nThe `_deliver_result` function handles multi-target delivery:\n- **Origin**: Returns the result to the platform/chat where the job was created.\n- **Local**: Saves to `~/.hermes/cron/output/` only.\n- **Platform-Specific**: Supports `telegram`, `discord`, `slack`, etc.\n- **Silent Marker**: If the agent's response starts with `[SILENT]`, delivery is suppressed (though the output is still saved locally).\n\n### Curator Integration\n`rewrite_skill_refs` allows the `curator` module to update cron jobs when skills are renamed, consolidated, or deleted. This prevents scheduled tasks from failing when their underlying instructions are reorganized.\n\n## Configuration\n\n| Environment Variable | Description |\n| :--- | :--- |\n| `HERMES_CRON_TIMEOUT` | Seconds of inactivity before killing a job (default: 600). |\n| `HERMES_CRON_MAX_PARALLEL` | Max simultaneous jobs in the thread pool. |\n| `HERMES_CRON_SCRIPT_TIMEOUT` | Max execution time for pre-run scripts (default: 120). |\n| `HERMES_CRON_SESSION` | Set to `1` during execution to signal \"cron mode\" to internal systems. |\n\n## Key Functions\n\n- `create_job(...)`: Primary API for scheduling new tasks.\n- `tick(adapters, loop)`: The main loop; accepts live gateway adapters for E2EE-compatible delivery.\n- `parse_schedule(str)`: Converts human-readable strings into structured schedule dicts.\n- `run_job(job)`: Orchestrates the `AIAgent` lifecycle for a single execution.","datagen-config-examples":"# datagen-config-examples\n\n# datagen-config-examples\n\nThe `datagen-config-examples` module provides a suite of configuration templates, shell scripts, and sample datasets designed to orchestrate synthetic data generation via the `batch_runner.py` engine. These examples demonstrate how to configure agent environments, toolsets, and post-processing pipelines to create high-quality trajectories for model training.\n\n## Module Overview\n\nThis module acts as the configuration layer for the data generation pipeline. It defines how the agent should behave in specific environments (Browser, Web Research) and how the resulting data should be refined for training.\n\n```mermaid\ngraph TD\n A[JSONL Prompts] --> B[batch_runner.py]\n C[YAML/SH Configs] --> B\n B --> D[Raw Trajectories]\n D --> E[Trajectory Compression]\n E --> F[Training-Ready Data]\n```\n\n## Browser Automation Tasks\n\nThe browser automation examples focus on generating trajectories where an agent interacts with a live web environment using tools like `browser_snapshot`, `click`, and `type`.\n\n### `run_browser_tasks.sh`\nThis script wraps `batch_runner.py` with specific parameters optimized for browser-based agents. Key configurations include:\n* **Tool Distribution:** Heavily weighted toward `browser` (97%) and `web` (20%).\n* **System Prompt Logic:** Includes explicit instructions for handling common automation hurdles:\n * **Anti-Bot Mitigation:** Instructs the agent to use `web_search` for initial discovery rather than direct Google searches.\n * **State Management:** Mandates taking a `browser_snapshot` after dismissing cookie/privacy dialogs.\n * **Error Recovery:** Provides a fallback strategy for timeouts and blocked elements.\n\n### `example_browser_tasks.jsonl`\nContains seed prompts for the browser agent, ranging from data extraction (Hacker News, GitHub Trending) to form interaction (httpbin) and multi-step navigation (Books to Scrape).\n\n## Web Research Configuration\n\nThe `web_research.yaml` file provides a declarative configuration for the `WebResearchEnv`. This is used when the goal is to generate multi-step factual research trajectories.\n\n* **Environment:** Sets `environment: web-research`.\n* **Toolsets:** Restricts the agent to `web` and `file` tools, preventing unnecessary browser overhead while allowing for data persistence.\n* **Model Selection:** Defaults to high-reasoning models like `hermes-3-llama-3.1-405b` via OpenRouter to ensure research quality.\n* **Evaluation:** Configures `eval_every` and `eval_size` to perform periodic validation of the generated trajectories against a held-out set.\n\n## Trajectory Compression\n\nThe `trajectory_compression.yaml` file defines the post-processing logic required to fit long agent trajectories into the context windows of training LLMs. It uses a \"head-and-tail\" preservation strategy combined with LLM-based summarization.\n\n### Tokenization and Targets\n* **Tokenizer:** Uses `moonshotai/Kimi-K2-Thinking` for precise token counting.\n* **Budgeting:** Targets a `target_max_tokens` (e.g., 29,000) and a specific `summary_target_tokens` (750) for the middle sections of the conversation.\n\n### Protected Turns\nTo maintain the structural integrity of the trajectory, the configuration defines \"protected turns\" that the compression engine will never summarize:\n* `first_system`: Preserves the tool definitions and system instructions.\n* `first_human`: Preserves the original user intent.\n* `first_gpt` & `first_tool`: Preserves the initial action and its result to establish the starting state.\n* `last_n_turns`: Preserves the final 4 turns (typically the conclusion and final tool calls) to ensure the model learns how to successfully terminate a task.\n\n### Summarization Pipeline\nWhen a trajectory exceeds the budget, the module utilizes an external model (configured as `google/gemini-3-flash-preview`) to summarize the non-protected middle turns. \n* **Concurrency:** Supports `max_concurrent_requests: 50` for high-throughput post-processing.\n* **Notice Injection:** If `add_summary_notice` is true, it appends a disclaimer to the system message indicating that parts of the history have been summarized, preventing the training model from being confused by \"jumpy\" context.\n\n## Usage in Data Generation\n\nTo run a generation batch using these examples:\n\n1. **Browser Tasks:**\n ```bash\n bash datagen-config-examples/run_browser_tasks.sh\n ```\n\n2. **Web Research:**\n ```bash\n python batch_runner.py --config datagen-config-examples/web_research.yaml --run_name my_research_run\n ```\n\n3. **Compression:**\n The compression logic is typically invoked after a run completes, pointing to the `trajectories.jsonl` output of the `batch_runner.py`.","docker":"# docker\n\n# Docker Module\n\nThe `docker` module provides the containerization logic and runtime environment setup for the Hermes agent. It ensures that the application runs with correct permissions, initialized configuration files, and a consistent directory structure regardless of the host environment (Docker or Podman).\n\n## Entrypoint Lifecycle (`entrypoint.sh`)\n\nThe `entrypoint.sh` script is the primary bootstrap mechanism. It handles the transition from the container's initial root state to the unprivileged `hermes` user while maintaining host-volume compatibility.\n\n### 1. Privilege Management and UID/GID Remapping\nTo avoid permission mismatches when mounting host directories, the script dynamically adjusts the internal `hermes` user to match the host user's identity:\n\n* **Remapping:** If `HERMES_UID` or `HERMES_GID` environment variables are provided, the script uses `usermod` and `groupmod` to update the container's `hermes` user.\n* **Ownership Correction:** It performs a recursive `chown` on `$HERMES_HOME` if the UID has changed or if the top-level directory ownership is incorrect.\n* **Privilege Dropping:** Once permissions are aligned, it uses `gosu` to re-execute itself as the `hermes` user.\n\n### 2. Environment Initialization\nAfter dropping privileges, the script prepares the runtime environment:\n* **Virtual Environment:** Activates the Python environment located at `${INSTALL_DIR}/.venv`.\n* **Directory Structure:** Ensures essential subdirectories exist within `$HERMES_HOME`:\n * `cron/`, `sessions/`, `logs/`, `hooks/`, `memories/`, `skills/`, `skins/`, `plans/`, `workspace/`\n * `home/`: A dedicated home directory for subprocesses (git, ssh, npm) to prevent them from writing to the ephemeral `/root`.\n\n### 3. Configuration Bootstrapping\nThe script ensures the agent has a valid configuration by copying templates if files are missing:\n* `config.yaml`: Copied from `cli-config.yaml.example`.\n* `SOUL.md`: Copied from the module's persona template.\n\n### 4. Skill Synchronization\nIf bundled skills exist in the installation directory, the script executes `tools/skills_sync.py`. This utility synchronizes built-in skills into the user's data volume while preserving manual edits via manifest-based tracking.\n\n```mermaid\ngraph TD\n A[Start as Root] --> B{UID/GID Provided?}\n B -- Yes --> C[Remap hermes user]\n B -- No --> D[Check Ownership]\n C --> D\n D --> E[gosu hermes re-exec]\n E --> F[Activate Venv]\n F --> G[Init Directories]\n G --> H[Sync Skills]\n H --> I{Command Type}\n I -- Executable --> J[Exec Command Directly]\n I -- Subcommand --> K[Exec 'hermes <args>']\n```\n\n## Persona Configuration (`SOUL.md`)\n\nThe `SOUL.md` file defines the agent's personality, tone, and communication style. \n\n* **Dynamic Loading:** The application loads this file fresh for each message, allowing developers to modify the agent's persona without restarting the container.\n* **Customization:** It serves as a system prompt override. If the file is deleted or empty, the agent reverts to its default personality.\n\n## Execution Patterns\n\nThe entrypoint supports two primary invocation patterns to accommodate both standard usage and sandbox environments:\n\n1. **Wrapped Execution (Default):** If the arguments do not resolve to a known system executable, they are passed as subcommands to the `hermes` CLI.\n * *Example:* `docker run hermes chat -q \"hello\"` executes `hermes chat -q \"hello\"`.\n2. **Direct Execution:** If the first argument is an executable on the `PATH` (like `bash` or `sleep`), it is executed directly. This is used by the launcher to maintain long-lived sandbox containers.\n * *Example:* `docker run hermes sleep infinity` executes `sleep infinity` directly.\n\n## Environment Variables\n\n| Variable | Description | Default |\n| :--- | :--- | :--- |\n| `HERMES_HOME` | The data volume mount point. | `/opt/data` |\n| `HERMES_UID` | Host User ID to map to the `hermes` user. | `10000` |\n| `HERMES_GID` | Host Group ID to map to the `hermes` group. | `10000` |\n| `INSTALL_DIR` | Location of the application source and venv. | `/opt/hermes` |","environments-benchmarks":"# environments — benchmarks\n\n# Environments — Benchmarks\n\nThe `environments.benchmarks` module provides specialized evaluation environments for measuring the performance of agentic LLMs across diverse task types, ranging from short-horizon terminal coding tasks to long-horizon strategic simulations.\n\nThese environments are \"eval-only,\" meaning they are designed to be invoked via the `evaluate` subcommand rather than used for training. They inherit from `HermesAgentBaseEnv` and utilize the `HermesAgentLoop` to drive agent interactions.\n\n## Module Architecture\n\nThe module is structured into three primary benchmark suites:\n\n1. **Terminal-Bench 2.0 (TB2):** 89 complex terminal-based coding and system administration tasks.\n2. **OpenThoughts-TBLite:** A difficulty-calibrated, 100-task subset of TB2 designed for faster iteration and higher signal on smaller models.\n3. **YC-Bench:** A long-horizon simulation where the agent acts as a startup CEO, managing resources over hundreds of turns.\n\n```mermaid\ngraph TD\n Base[HermesAgentBaseEnv] --> TB2[TerminalBench2EvalEnv]\n TB2 --> TBLite[TBLiteEvalEnv]\n Base --> YC[YCBenchEvalEnv]\n \n TB2 -.-> Loop[HermesAgentLoop]\n YC -.-> Loop\n \n Loop --> Tools[Terminal / File Tools]\n Tools --> Sandbox[Modal / Docker Sandbox]\n```\n\n---\n\n## Terminal-Bench 2.0 & TBLite\n\nThese environments evaluate an agent's ability to solve real-world software engineering problems using a terminal.\n\n### Core Logic: `TerminalBench2EvalEnv`\nThe evaluation flow for a single task follows these steps:\n1. **Image Resolution:** `_resolve_task_image` determines if a pre-built Docker Hub image exists or if a local build from a `Dockerfile` (extracted via `_extract_base64_tar`) is required.\n2. **Sandbox Setup:** `register_task_env_overrides` configures the terminal backend (usually Modal) to use the specific task image.\n3. **Agent Execution:** `HermesAgentLoop` runs the agent until completion or the `max_agent_turns` limit is reached.\n4. **Verification:** `_run_tests` uploads a test suite, executes `test.sh`, and downloads the `/logs/verifier/reward.txt` file to determine success.\n\n### TBLite Specialization\n`TBLiteEvalEnv` is a thin subclass of `TerminalBench2EvalEnv`. It uses the same execution logic but points to the `NousResearch/openthoughts-tblite` dataset. It is calibrated across four difficulty tiers (Easy, Medium, Hard, Extreme) based on reference model pass rates.\n\n### Concurrency and Deadlock Prevention\nBecause TB2/TBLite tasks are resource-intensive, the environment uses an `asyncio.Semaphore` controlled by `max_concurrent_tasks`. This is critical when using the Modal backend to prevent deadlocks caused by simultaneous blocking calls to the Modal API within thread pool workers.\n\n---\n\n## YC-Bench\n\n`YCBenchEvalEnv` evaluates long-term strategic coherence. The agent manages a simulated AI startup over a 1-3 year horizon.\n\n### Simulation Mechanics\nUnlike the coding benchmarks, YC-Bench is a discrete-event simulation driven by a CLI tool (`yc-bench`).\n* **Initialization:** The environment calls `yc-bench sim init` to set up a deterministic SQLite-backed world based on a `preset` and `seed`.\n* **Interaction:** The agent uses the `terminal` tool to run subcommands like `market browse`, `task accept`, and `sim resume`.\n* **Persistence:** A \"scratchpad\" tool allows the agent to maintain state across context window truncations.\n\n### Scoring Logic\nThe environment calculates a composite score via `_compute_composite_score`:\n* **Survival (50%):** A binary metric indicating if the company avoided bankruptcy.\n* **Normalized Funds (50%):** A log-scale score based on final cash reserves relative to the initial $250,000 capital.\n\n---\n\n## Key Components\n\n### Configuration Classes\nEach environment uses a Pydantic-based configuration class extending `HermesAgentEnvConfig`:\n* `TerminalBench2EvalConfig`: Includes `task_filter`, `test_timeout`, and `max_concurrent_tasks`.\n* `TBLiteEvalConfig`: Inherits from TB2, defaulting to the TBLite dataset and a shorter `task_timeout` (1200s).\n* `YCBenchEvalConfig`: Includes `presets`, `seeds`, and weights for `survival` vs `funds`.\n\n### Execution Flow: `evaluate()`\nThe `evaluate()` method in these classes manages the high-level orchestration:\n1. **Logging Setup:** Redirects standard logging through `tqdm` to maintain a clean progress bar.\n2. **Parallel/Sequential Execution:** TB2 runs tasks in parallel (subject to the semaphore), while YC-Bench runs runs sequentially to avoid environment variable conflicts.\n3. **Result Streaming:** Results are written to a timestamped `.jsonl` file in real-time via `_save_result` to prevent data loss during crashes.\n4. **Cleanup:** Calls `cleanup_all_environments()` and shuts down the `_tool_executor` to ensure no orphaned sandboxes or threads remain.\n\n## Usage Examples\n\n### Running TB2 with Task Filtering\n```bash\npython environments/benchmarks/terminalbench_2/terminalbench2_env.py evaluate \\\n --env.task_filter \"fix-git,pandas-etl\" \\\n --openai.model_name \"anthropic/claude-3-5-sonnet\"\n```\n\n### Running YC-Bench with Specific Seeds\n```bash\npython environments/benchmarks/yc_bench/yc_bench_env.py evaluate \\\n --env.presets '[\"medium\"]' \\\n --env.seeds '[1, 2, 3, 4, 5]'\n```\n\n### Local Development (Docker Backend)\nFor local testing without cloud costs, use the `local.yaml` configurations which switch the `terminal_backend` from `modal` to `docker`.\n```bash\npython environments/benchmarks/tblite/tblite_env.py evaluate \\\n --config environments/benchmarks/tblite/local.yaml\n```","environments-environments":"# environments — environments\n\n# Hermes-Agent Atropos Environments\n\nThe `environments` module serves as the integration layer between the **hermes-agent** tool-calling framework and the **Atropos** Reinforcement Learning (RL) library. It enables agentic LLMs to perform multi-turn reasoning and tool execution within isolated sandboxes, while providing the infrastructure to score trajectories and feed data into RL training pipelines.\n\n## Architecture Overview\n\nThe module follows a hierarchical inheritance structure, starting from the Atropos `BaseEnv` and specializing into agent-specific logic.\n\n```mermaid\ngraph TD\n BaseEnv[Atropos BaseEnv] --> HermesBase[HermesAgentBaseEnv]\n HermesBase --> Concrete[Concrete Envs: SWE, TerminalBench, OPD]\n HermesBase --> Loop[HermesAgentLoop]\n HermesBase --> Context[ToolContext]\n Loop --> Dispatch[model_tools.handle_function_call]\n```\n\n### Core Components\n\n1. **`HermesAgentBaseEnv`**: An abstract base class that manages server communication, tool resolution via `registry.py`, and trajectory collection.\n2. **`HermesAgentLoop`**: The multi-turn engine that orchestrates the conversation. It handles API calls, extracts reasoning, and dispatches tool calls.\n3. **`ToolContext`**: A per-rollout handle provided to reward functions. it allows verifiers to execute commands and inspect files in the exact same sandbox used by the agent.\n4. **`ToolCallParsers`**: A suite of client-side parsers used in Phase 2 (VLLM ManagedServer) to extract structured tool calls from raw model output.\n\n---\n\n## The Agent Loop (`HermesAgentLoop`)\n\nThe `HermesAgentLoop` is the primary execution engine. It replicates the logic found in `run_agent.py` but is optimized for the Atropos rollout lifecycle.\n\n### Execution Flow\n1. **Prompt Construction**: Combines system prompts and user tasks.\n2. **API Interaction**: Calls `server.chat_completion()`.\n3. **Reasoning Extraction**: Uses `_extract_reasoning_from_message` to capture thinking blocks across various provider formats (OpenRouter, OpenAI, VLLM).\n4. **Tool Dispatch**: If `tool_calls` are present, it executes them via `model_tools.handle_function_call()`.\n5. **Thread Management**: Tool calls are executed in a global `ThreadPoolExecutor` (managed via `resize_tool_pool`). This prevents deadlocks when backends like Modal or Docker use `asyncio.run()` internally.\n6. **Persistence**: Large tool results are persisted to the sandbox via `maybe_persist_tool_result` to keep the context window manageable.\n\n---\n\n## Server Operation Phases\n\nThe module supports two distinct operational phases based on the training/evaluation stage:\n\n### Phase 1: OpenAI-Compatible API (Evaluation/SFT)\nUses standard `chat_completion` with the `tools=` parameter. The server (VLLM, SGLang, or OpenAI) handles tool call parsing natively.\n* **Use Case**: Evaluation, SFT data generation.\n* **Data**: Returns `ChatCompletion` objects; Atropos generates placeholder tokens.\n\n### Phase 2: ManagedServer (RL Training)\nUses the Atropos `ManagedServer` to interact with VLLM's `/generate` endpoint. This provides exact token IDs and logprobs required for RL algorithms like PPO or GRPO.\n* **Use Case**: Full RL training.\n* **Parsing**: Uses client-side parsers (e.g., `hermes_parser.py`, `deepseek_v3_parser.py`) to reconstruct tool calls from raw text.\n\n---\n\n## Reward Verification with `ToolContext`\n\n`ToolContext` provides an unrestricted interface for `compute_reward` functions to verify the agent's work. It uses the same `task_id` as the rollout, ensuring it connects to the same persistent sandbox (Modal container, Docker image, etc.).\n\n```python\nasync def compute_reward(self, item, result, ctx: ToolContext):\n # Run a command in the agent's sandbox\n test_run = ctx.terminal(\"python3 test_solution.py\")\n \n # Inspect files created by the agent\n if ctx.read_file(\"solution.py\").get(\"content\"):\n return 1.0 if test_run[\"exit_code\"] == 0 else 0.5\n \n return 0.0\n```\n\n**Key Methods:**\n* `terminal(command, timeout)`: Execute shell commands.\n* `read_file(path)` / `write_file(path, content)`: Direct filesystem access.\n* `download_file(remote, local)`: Pull artifacts for local validation.\n* `browser_snapshot()`: Capture state from the browser tool if active.\n\n---\n\n## On-Policy Distillation (`AgenticOPDEnv`)\n\nThe `AgenticOPDEnv` implements **On-Policy Distillation**, a technique where next-state signals (tool results or error traces) are used to generate \"hindsight hints.\"\n\n1. **Trajectory Collection**: Runs a standard agent rollout.\n2. **Hint Extraction**: An LLM judge (`_extract_hint`) analyzes (Assistant Response, Tool Result) pairs to determine if the response could have been improved with hindsight.\n3. **Teacher Scoring**: If a hint is found, the environment builds an \"enhanced prompt\" (Original + Hint) and uses `server.get_logprobs` to see how a teacher model would have distributed probability.\n4. **Distillation Fields**: Populates `distill_token_ids` and `distill_logprobs` in the `ScoredDataGroup`, allowing the trainer to optimize the student model against the teacher's hindsight-augmented distribution.\n\n---\n\n## Configuration (`HermesAgentEnvConfig`)\n\nEnvironments are configured via Pydantic models. Key fields include:\n\n| Field | Description |\n| :--- | :--- |\n| `enabled_toolsets` | List of tools (e.g., `['terminal', 'file']`) available to the agent. |\n| `distribution` | Name of a probabilistic toolset distribution from `toolset_distributions.py`. |\n| `terminal_backend` | The sandbox type: `local`, `docker`, `modal`, `daytona`, or `ssh`. |\n| `max_agent_turns` | Hard limit on the number of tool-calling iterations. |\n| `tool_call_parser` | The parser used for Phase 2 (e.g., `hermes`, `llama3_json`). |\n| `extra_body` | Dictionary passed to the OpenAI client for provider-specific features (e.g., OpenRouter transforms). |\n\n---\n\n## Creating a New Environment\n\nTo implement a new task, inherit from `HermesAgentBaseEnv` and define the following:\n\n1. **`setup()`**: Initialize your dataset (e.g., via HuggingFace `load_dataset`).\n2. **`get_next_item()`**: Logic to iterate through your task data.\n3. **`format_prompt(item)`**: Convert your data item into a string instruction for the agent.\n4. **`compute_reward(item, result, ctx)`**: Use the `ToolContext` to score the agent's performance.\n5. **`evaluate()`**: Define how to log periodic metrics to WandB or local JSONL files.","environments-hermes-swe-env":"# environments — hermes_swe_env\n\n# environments — hermes_swe_env\n\nThe `hermes_swe_env` module provides a concrete implementation of a Software Engineering (SWE) environment designed for agentic workflows. It facilitates tasks where an LLM must solve coding problems by interacting with a filesystem, executing terminal commands, and searching the web.\n\nThis environment is specifically built to use **Modal sandboxes** for cloud-isolated execution, ensuring that agent-generated code runs in a secure, reproducible environment that persists across the agent's reasoning steps and the final reward evaluation.\n\n## Core Architecture\n\n`HermesSweEnv` inherits from `HermesAgentBaseEnv`. It manages the lifecycle of a SWE task: loading the dataset, initializing the sandbox, executing the agent loop, and verifying the solution.\n\n```mermaid\ngraph TD\n A[Dataset Item] --> B[format_prompt]\n B --> C[Agent Loop]\n C <--> D[Modal Sandbox]\n D --> E[File/Terminal/Web Tools]\n C --> F[AgentResult]\n F --> G[compute_reward]\n G --> D\n G --> H[Final Score]\n```\n\n### Key Components\n\n#### 1. HermesSweEnv Class\nThe primary environment class. It orchestrates the interaction between the dataset, the agent, and the tool execution context.\n\n* **`setup()`**: Initializes the dataset (defaulting to `bigcode/humanevalpack`) and resets reward buffers.\n* **`get_next_item()`**: Iterates through the dataset to provide the next task.\n* **`format_prompt(item)`**: Prepares the input for the agent. It extracts the coding prompt and appends any available test information (from fields like `test`, `test_code`, or `tests`) to guide the agent.\n\n#### 2. Reward Mechanism (`compute_reward`)\nThe reward function is the critical component for Reinforcement Learning (RL) or evaluation. Unlike static environments, `HermesSweEnv` performs **dynamic verification**:\n\n1. **Test Execution**: It retrieves the test suite from the dataset item.\n2. **Sandbox Persistence**: It uses the `ToolContext` to access the *same* Modal sandbox the agent used. This ensures that any files created or modified by the agent are present during testing.\n3. **Scoring Logic**:\n * **1.0 (Success)**: The test code executes via `ctx.terminal` and returns an exit code of `0`.\n * **0.1 (Partial Credit)**: If the tests fail or are missing, the environment checks if the agent at least created new `.py` files in the `/workspace` directory (using a timestamp marker).\n * **0.0 (Failure)**: No files created and tests failed.\n\n#### 3. Configuration (`HermesSweEnvConfig`)\nConfiguration is handled via `HermesSweEnvConfig`, which defines:\n* **Toolsets**: Defaults to `[\"terminal\", \"file\", \"web\"]`.\n* **Backend**: Defaults to `modal` for terminal execution.\n* **Agent Constraints**: `max_agent_turns` (default 30) and `max_token_length` (default 4096) are tuned for complex SWE tasks.\n\n## Tooling and Sandbox Integration\n\nThe environment relies on `environments.tool_context.ToolContext` to bridge the gap between the model's tool calls and the remote execution environment.\n\n* **Terminal Backend**: When `terminal_backend` is set to `\"modal\"`, every rollout gets a dedicated, isolated container.\n* **File Tools**: The agent can read, write, and edit files within the `/workspace` directory of the sandbox.\n* **Web Tools**: Provides the agent with search capabilities to look up documentation or libraries.\n\n## Usage and Execution\n\nThe module is designed to be run as a standalone service or integrated into a training pipeline.\n\n### Phase 1: Evaluation/Inference\nTo run the environment with an OpenAI-compatible server (e.g., vLLM) for evaluation:\n\n```bash\npython environments/hermes_swe_env/hermes_swe_env.py serve \\\n --config environments/hermes_swe_env/default.yaml \\\n --openai.base_url http://localhost:8000/v1 \\\n --env.dataset_name \"bigcode/humanevalpack\"\n```\n\n### Phase 2: RL Training\nFor full RL training, the `server_type` is typically switched to `vllm` within the config or via CLI to allow for tighter integration with the training loop.\n\n## Metrics and Logging\n\nThe environment tracks performance via `wandb_log`:\n* **`train/avg_reward`**: The mean reward across the current buffer.\n* **`train/pass_rate`**: The percentage of tasks where the agent successfully passed the test suite (reward == 1.0).\n\nThese metrics are cleared after every logging interval to provide a rolling window of agent performance.","environments-terminal-test-env":"# environments — terminal_test_env\n\n# Terminal Test Environment\n\nThe `terminal_test_env` module provides a self-contained, end-to-end validation environment for the Atropos and Hermes Agent stack. It is designed to verify that the agent loop, tool execution (specifically terminal and file tools), and reward verification logic are functioning correctly without requiring external datasets.\n\n## Overview\n\n`TerminalTestEnv` implements a \"smoke test\" scenario where an agent is tasked with creating specific files in a terminal environment. The environment uses the **Modal** terminal backend for isolated sandboxing and **OpenRouter** (typically Claude) for inference.\n\n### Key Features\n- **Zero External Dependencies**: Tasks are defined inline within the module.\n- **Tool Integration**: Enables `terminal` and `file` toolsets.\n- **Automated Verification**: Uses the `ToolContext` to execute terminal commands (`cat`) to verify the agent's work.\n- **Scoring**: Provides granular rewards (1.0 for exact matches, 0.5 for partial matches).\n\n## Task Definitions\n\nThe environment cycles through a fixed set of tasks defined in `TRAIN_TASKS` and `EVAL_TASKS`.\n\n| Task Type | Objective | Verification Path | Expected Content |\n| :--- | :--- | :--- | :--- |\n| **Train** | Create greeting file | `~/greeting.txt` | \"Hello from Hermes Agent\" |\n| **Train** | List numbers 1-5 | `~/count.txt` | \"1\\n2\\n3\\n4\\n5\" |\n| **Train** | Simple addition | `~/answer.txt` | \"579\" |\n| **Eval** | Simple multiplication | `~/result.txt` | \"42\" |\n\n## Core Components\n\n### TerminalTestEnv Class\nInherits from `HermesAgentBaseEnv`. It manages the lifecycle of the test, from task distribution to reward calculation.\n\n- `get_next_item()`: Cycles through the `TRAIN_TASKS` list.\n- `format_prompt()`: Extracts the prompt string from the task dictionary.\n- `compute_reward()`: The primary validation logic. It uses the `ToolContext` to interact with the same terminal the agent used.\n\n### Reward Verification Flow\nThe reward logic is unique because it uses the agent's own tools to inspect the environment state.\n\n```mermaid\ngraph TD\n A[Agent Loop Ends] --> B[compute_reward]\n B --> C{ctx.terminal: cat path}\n C -->|Exit Code != 0| D[Score: 0.0]\n C -->|Exit Code 0| E{Compare Output}\n E -->|Exact Match| F[Score: 1.0]\n E -->|Contains Expected| G[Score: 0.5]\n E -->|No Match| D\n```\n\n### Configuration (`TerminalTestEnvConfig`)\nThe environment is configured via `default.yaml` or the `config_init` method. Key defaults include:\n- **Backend**: `modal` (provides a fresh containerized terminal for every rollout).\n- **Parser**: `hermes` (expects XML-style tool tags).\n- **Agent Constraints**: `max_agent_turns: 10`, `group_size: 3`.\n\n## Execution and Usage\n\nThe module supports two primary execution modes via the Atropos CLI.\n\n### 1. Server Mode (Serve)\nUsed for active training or interactive testing where the environment acts as a task provider for the Atropos API.\n```bash\n# Start the Atropos API first\nrun-api\n\n# Run the environment\npython environments/terminal_test_env/terminal_test_env.py serve \\\n --config environments/terminal_test_env/default.yaml\n```\n\n### 2. Process Mode\nUsed for generating offline datasets of rollouts and scores without a running API server.\n```bash\npython environments/terminal_test_env/terminal_test_env.py process \\\n --env.data_path_to_save_groups output.jsonl\n```\n\n## Metrics and Logging\nThe environment tracks performance via `reward_buffer` and logs to Weights & Biases (W&B) if enabled.\n- `train/avg_reward`: Mean score across rollouts.\n- `train/accuracy`: Percentage of tasks with a 1.0 score.\n- `train/partial_match_rate`: Percentage of tasks with a 0.5 score.","environments-tool-call-parsers":"# environments — tool_call_parsers\n\n# environments — tool_call_parsers\n\nThe `tool_call_parsers` module provides a client-side registry of parsers designed to extract structured tool calls from raw model output text. This is primarily used in environments where the model server (such as a VLLM instance using the `/generate` endpoint) returns raw text containing model-specific markup rather than pre-parsed tool call objects.\n\nEach parser is a standalone implementation of the extraction logic used by specific model families, producing OpenAI-compatible `ChatCompletionMessageToolCall` objects.\n\n## Core Architecture\n\nThe module uses a registry pattern to map model family names to specific parser implementations.\n\n### ToolCallParser Base Class\nAll parsers inherit from the `ToolCallParser` abstract base class and must implement the `parse` method.\n\n```python\nclass ToolCallParser(ABC):\n @abstractmethod\n def parse(self, text: str) -> ParseResult:\n \"\"\"\n Returns a tuple of (content, tool_calls).\n - content: The message text with tool markup stripped.\n - tool_calls: A list of ChatCompletionMessageToolCall objects or None.\n \"\"\"\n```\n\n### Parser Registry\nParsers are registered using the `@register_parser(name)` decorator. This allows the `get_parser(name)` factory function to instantiate the correct parser at runtime based on the model configuration.\n\n```mermaid\ngraph TD\n A[Raw Model Output] --> B[get_parser]\n B --> C{Registry}\n C --> D[HermesParser]\n C --> E[LlamaParser]\n C --> F[DeepSeekParser]\n D & E & F --> G[ParseResult]\n G --> H[Content String]\n G --> I[List of ToolCalls]\n```\n\n## Usage\n\nTo extract tool calls from a model response:\n\n```python\nfrom environments.tool_call_parsers import get_parser\n\n# 1. Get the appropriate parser\nparser = get_parser(\"hermes\")\n\n# 2. Parse the raw text\ncontent, tool_calls = parser.parse(raw_text)\n\nif tool_calls:\n for call in tool_calls:\n print(f\"Function: {call.function.name}\")\n print(f\"Args: {call.function.arguments}\")\n```\n\n## Supported Parser Implementations\n\nThe module includes specialized parsers for various model families, each handling unique delimiters and serialization formats:\n\n| Parser Name | Format Description |\n| :--- | :--- |\n| `hermes` / `qwen` | Wraps JSON in `<tool_call>...<\/tool_call>` tags. |\n| `llama3_json` | Extracts JSON objects containing `name` and `arguments`/`parameters` keys, often following a `<\\|python_tag\\|>`. |\n| `deepseek_v3` | Uses special unicode tokens (e.g., `<|tool▁calls▁begin|>`) and markdown JSON blocks. |\n| `deepseek_v3_1` | A variant of V3 using `<|tool▁call▁begin|>name<|tool▁sep|>args<|tool▁call▁end|>`. |\n| `mistral` | Supports both pre-v11 (JSON array) and v11+ (interleaved `[TOOL_CALLS]` tokens) formats. |\n| `glm45` / `glm47` | Uses XML-like tags: `<tool_call>`, `<arg_key>`, and `<arg_value>`. |\n| `qwen3_coder` | Uses nested XML tags: `<tool_call><function=name><parameter=key>val<\/parameter><\/function><\/tool_call>`. |\n| `kimi_k2` | Uses section tokens and a specific `function_name:index` ID format. |\n\n## Implementation Details\n\n### Robust JSON Extraction\nSeveral parsers (notably `LlamaToolCallParser` and `MistralToolCallParser`) utilize `json.JSONDecoder().raw_decode()` to find and extract JSON objects embedded within larger strings of text. This allows the parsers to handle cases where the model provides conversational thought before the actual tool call.\n\n### Value Deserialization\nFor models that do not output standard JSON (like GLM or Qwen3-Coder), the module provides internal utility functions:\n- `_deserialize_value` (GLM): Attempts `json.loads`, then `ast.literal_eval`, then falls back to a raw string.\n- `_try_convert_value` (Qwen3): Handles nulls, booleans, and numbers specifically before falling back to JSON/AST parsing.\n\n### ID Generation\nSince raw text outputs rarely include unique call IDs, the parsers generate them locally to satisfy the OpenAI type requirements:\n- Most parsers use `uuid.uuid4().hex[:8]`.\n- `MistralToolCallParser` uses a custom 9-character alphanumeric generator.\n- `KimiK2ToolCallParser` preserves the ID format provided in the model's text (e.g., `func:0`).\n\n## Adding a New Parser\n\n1. Create a new file in `environments/tool_call_parsers/`.\n2. Define a class inheriting from `ToolCallParser`.\n3. Decorate the class with `@register_parser(\"your_model_name\")`.\n4. Implement the `parse` logic.\n5. Import your new module in `environments/tool_call_parsers/__init__.py` to ensure it is registered when the package is loaded.","environments":"# environments\n\n# Environments\n\nThe `environments` module serves as the integration layer between the **hermes-agent** tool-calling framework and the **Atropos** Reinforcement Learning (RL) library. It provides the infrastructure necessary for agentic LLMs to interact with isolated sandboxes, execute tools, and generate trajectories that can be scored for evaluation or RL training.\n\n## Core Architecture\n\nThe module is built around a hierarchical structure that abstracts the complexities of multi-turn reasoning and tool execution.\n\n* **`HermesAgentBaseEnv`**: The foundational class that bridges Atropos `BaseEnv` with the Hermes agent logic. It handles tool resolution, trajectory collection, and integration with managed model servers.\n* **`HermesAgentLoop`**: The execution engine that drives the interaction between the LLM and the environment. It manages the state machine of \"Prompt -> Generate -> Parse -> Execute -> Observe.\"\n\n```mermaid\ngraph TD\n subgraph Execution Loop\n Loop[HermesAgentLoop]\n Parser[tool_call_parsers]\n Context[tool_context]\n end\n\n subgraph Environment Implementations\n Base[HermesAgentBaseEnv]\n SWE[hermes_swe_env]\n Bench[benchmarks]\n Test[terminal_test_env]\n end\n\n Loop -->|Extracts Calls| Parser\n Loop -->|Executes Tools| Context\n Base --> Loop\n SWE --> Base\n Bench --> Base\n Test --> Base\n```\n\n## Sub-modules\n\n### Execution & Sandboxing\nThese modules provide concrete implementations of environments where agents perform work.\n* **[hermes_swe_env](hermes_swe_env.md)**: A specialized environment for Software Engineering tasks. It utilizes **Modal sandboxes** to provide secure, isolated filesystems and terminal access for long-horizon coding tasks.\n* **[terminal_test_env](terminal_test_env.md)**: A zero-dependency \"smoke test\" environment used to validate the integrity of the tool-calling stack, terminal backends, and reward verification logic.\n\n### Evaluation & Benchmarking\n* **[benchmarks](benchmarks.md)**: A collection of \"eval-only\" suites, including Terminal-Bench 2.0 and OpenThoughts-TBLite. These environments are optimized for the `evaluate` subcommand to measure model performance across diverse system administration and coding scenarios.\n\n### Infrastructure & Parsing\n* **[tool_call_parsers](tool_call_parsers.md)**: A registry of model-specific parsers (e.g., for Qwen, Kimi, or GLM families). These parsers allow the `HermesAgentLoop` to extract structured tool calls from raw text generated by model servers that do not natively support OpenAI-style tool objects.\n\n## Key Workflows\n\n1. **Trajectory Collection**: The `HermesAgentBaseEnv` initiates a `HermesAgentLoop`. The loop requests completions from a model, uses a `tool_call_parser` to identify actions, and executes those actions within a `tool_context` (often a Modal container).\n2. **Tool Resolution**: Environments resolve tool definitions by mapping toolset aliases to the central tool registry. This ensures that the agent is presented with the correct schema for the tools available in its specific sandbox.\n3. **Reward Evaluation**: After a task reaches a terminal state (success, failure, or max turns), the environment invokes task-specific logic—such as running test suites in `hermes_swe_env` or LLM-based grading in `web_research_env`—to calculate a final reward.","gateway-builtin-hooks":"# gateway — builtin_hooks\n\n# Gateway Built-in Hooks\n\nThe `gateway.builtin_hooks` module serves as the central container for core interceptors and lifecycle events that are natively supported by the gateway. Unlike external plugins or optional middleware, hooks defined within this package are intended to be \"always-on\" or registered by default during the gateway's initialization sequence.\n\n## Overview\n\nIn a gateway architecture, hooks allow for the injection of logic at specific stages of a request's lifecycle (e.g., `pre_request`, `post_request`, `on_error`). The `builtin_hooks` package is reserved for logic that is fundamental to the gateway's operation, such as:\n\n* Core telemetry and logging.\n* Standardized header manipulation.\n* Internal routing logic.\n* Security defaults.\n\n## Architecture and Lifecycle\n\nBuilt-in hooks are integrated directly into the gateway's execution pipeline. Because they are registered at the package level, they typically execute before any user-defined or third-party plugins to ensure the environment is correctly bootstrapped.\n\n```mermaid\ngraph TD\n A[Incoming Request] --> B[Gateway Core]\n B --> C{Built-in Hooks}\n C --> D[External Plugins]\n D --> E[Upstream Service]\n E --> F[Response Processing]\n F --> C\n C --> G[Client Response]\n```\n\n## Registration Pattern\n\nWhile the `__init__.py` file currently acts as a namespace declaration, the module is designed to aggregate hooks from submodules. The gateway engine typically discovers these hooks through one of two patterns:\n\n1. **Explicit Import**: The gateway core imports `gateway.builtin_hooks` to trigger the registration of hooks defined in sub-packages.\n2. **Automated Discovery**: The gateway iterates through the members of this module to identify functions or classes decorated with hook markers.\n\n## Contributing New Hooks\n\nWhen adding functionality to this module, follow these guidelines:\n\n### 1. Submodule Organization\nDo not place complex logic directly in `__init__.py`. Create a new submodule for each logical hook group:\n- `gateway/builtin_hooks/telemetry.py`\n- `gateway/builtin_hooks/auth_defaults.py`\n\n### 2. Statelessness\nBuilt-in hooks should be stateless. They receive the current request context and should modify it or perform side effects (like logging) without maintaining internal state that could interfere with concurrent requests.\n\n### 3. Error Handling\nSince built-in hooks run for every request, they must be highly resilient. Ensure that any hook implementation includes robust try-except blocks to prevent a failure in a non-critical hook (e.g., a metrics counter) from dropping the entire request.","gateway-gateway":"# gateway — gateway\n\n# Hermes Gateway\n\nThe **Gateway** module is the multi-platform integration layer for the Hermes agent. It provides a unified interface for connecting the agent to messaging platforms (Telegram, Discord, Slack, WhatsApp, etc.) while managing persistent session contexts, message routing, and platform-specific capabilities.\n\n## Core Architecture\n\nThe gateway acts as a bridge between external messaging adapters and the internal agent logic. It ensures that regardless of the platform, the agent receives a consistent session context and can route responses or cron outputs to the correct destination.\n\n```mermaid\ngraph TD\n A[Platform Adapters] -->|Inbound Message| B[SessionStore]\n B -->|Context Injection| C[Agent Loop]\n C -->|Tool Call: send_message| D[DeliveryRouter]\n D -->|Outbound Message| A\n D -->|Mirror| B\n E[Cron Jobs] -->|Deliver| D\n```\n\n## Configuration Management\n\nConfiguration is handled by `gateway/config.py` and is aggregated from three sources (in priority order):\n1. **Environment Variables**: (e.g., `TELEGRAM_BOT_TOKEN`)\n2. **`~/.hermes/config.yaml`**: The primary user-facing configuration.\n3. **`~/.hermes/gateway.json`**: Legacy configuration support.\n\n### Platform Definition\nThe `Platform` enum defines supported services. It supports dynamic plugin discovery via `_missing_`, allowing new platform adapters to be registered at runtime without modifying the core enum.\n\n### Home Channels\nEach platform can define a `HomeChannel`. This is the default destination for automated outputs (like cron jobs) when a specific chat ID is not provided.\n\n## Session Management\n\nThe gateway maintains conversation state through `SessionStore` and `SessionContext`.\n\n### Session Reset Policies\n`SessionResetPolicy` determines when a conversation's context is cleared. This prevents the LLM context window from becoming cluttered with stale information.\n- **Modes**: `daily` (fixed hour), `idle` (inactivity timeout), `both`, or `none`.\n- **Isolation**: Controlled by `group_sessions_per_user` and `thread_sessions_per_user` settings in `GatewayConfig`.\n\n### Context Injection\nWhen an agent processes a message, `build_session_context_prompt` generates a system-level description of the current environment, including:\n- The platform and channel name.\n- The current user's identity.\n- Available platform-specific tools.\n\n## Delivery and Routing\n\nThe `DeliveryRouter` handles dispatching messages to one or more `DeliveryTarget` objects.\n\n### Target Resolution\nTargets are parsed from strings using `DeliveryTarget.parse()`:\n- `origin`: Routes back to the source of the current session.\n- `local`: Saves the output to `~/.hermes/cron/output/`.\n- `platform`: Routes to the platform's home channel (e.g., `telegram`).\n- `platform:id`: Routes to a specific chat or thread (e.g., `discord:123456789`).\n\n### Session Mirroring\n`gateway/mirror.py` provides `mirror_to_session()`. When the agent sends a message via a tool (like `send_message`) or a cron job fires, the content is \"mirrored\" back into the session's transcript. This ensures the agent \"remembers\" what it sent to the user, even if the message was generated outside the standard chat loop.\n\n## Channel Discovery\n\nThe `channel_directory.py` module maintains a cached map of reachable contacts and channels.\n- **Building**: `build_channel_directory()` queries active adapters (Discord guilds, Slack conversations) and scans `sessions.json` for historical contacts.\n- **Resolution**: `resolve_channel_name()` allows developers and users to use human-friendly names (e.g., `#general`) which are resolved to platform-specific numeric IDs.\n- **Persistence**: The directory is saved to `~/.hermes/channel_directory.json` and refreshed periodically.\n\n## Display and Verbosity\n\n`gateway/display_config.py` manages how information is presented across different platforms using a tiered capability system:\n- **Tier 1 (High)**: Supports message editing and streaming (Telegram, Discord).\n- **Tier 2 (Medium)**: Supports editing but is workspace-facing (Slack, Mattermost).\n- **Tier 3 (Low)**: No edit support; progress messages are permanent (Signal, WhatsApp).\n- **Tier 4 (Minimal)**: Non-interactive delivery (Email, SMS).\n\nThe `resolve_display_setting()` function determines settings like `tool_progress` and `show_reasoning` based on these tiers and user overrides.\n\n## Event Hooks\n\nThe `HookRegistry` in `gateway/hooks.py` implements an asynchronous event system. Hooks are discovered from `~/.hermes/hooks/`.\n\n### Lifecycle Events\n- `gateway:startup`: Fired when the gateway process begins.\n- `session:start` / `session:reset`: Fired during session lifecycle changes.\n- `agent:start` / `agent:step` / `agent:end`: Fired during the LLM reasoning loop.\n- `command:*`: Fired when a slash command is executed.\n\nHooks consist of a `HOOK.yaml` manifest and a `handler.py` containing an `async def handle(event_type, context)` function.\n\n## Security and Pairing\n\nFor platforms where the bot's identity is public (like Telegram or WhatsApp), `gateway/pairing.py` manages unauthorized access.\n- **PairingStore**: Tracks approved users and pending requests.\n- **Flow**: Unknown users receive a one-time 8-character pairing code. The owner must approve this code via the Hermes CLI to authorize the user.\n- **Rate Limiting**: Includes lockout mechanisms after failed attempts and expiration for pending codes.","gateway-platforms":"# gateway — platforms\n\n# Gateway Platforms\n\nThe **gateway platforms** module is the integration layer between the Hermes gateway and external messaging services. It provides a standardized interface for receiving messages, sending responses, and handling media across diverse protocols (HTTP, WebSockets, Protobuf, etc.).\n\n## Architecture Overview\n\nThe module follows a provider pattern where a central `BasePlatformAdapter` defines the contract, and specific implementations (e.g., `TelegramAdapter`, `DiscordAdapter`, `APIServerAdapter`) handle the platform-specific wire protocols.\n\n```mermaid\ngraph TD\n P[External Platform] <--> A[Platform Adapter]\n A -- MessageEvent --> G[Gateway Runner]\n G -- AIAgent --> AG[Agent Pipeline]\n AG -- SendMessageTool --> A\n A -- SendResult --> P\n```\n\n## Core Components\n\n### BasePlatformAdapter (`gateway/platforms/base.py`)\nAll platform integrations must inherit from this class. It provides the lifecycle methods and utility functions required for gateway integration.\n\n* **`connect()` / `disconnect()`**: Manage the lifecycle of the connection (e.g., starting a WebSocket or an HTTP server).\n* **`handle_message(event: MessageEvent)`**: The primary ingress point. Adapters convert platform-specific payloads into a `MessageEvent` and pass it to this method to trigger the agent pipeline.\n* **`send(...)`**: The primary egress point. Sends text and optional media to a specific `chat_id`.\n* **`build_source(...)`**: Constructs a `SessionSource` object to track user identity and platform context.\n\n### API Server Adapter (`gateway/platforms/api_server.py`)\nThe `APIServerAdapter` is a specialized built-in platform that exposes an OpenAI-compatible REST API. This allows external UIs (like Open WebUI or LibreChat) to use Hermes as a backend.\n\n#### Key Endpoints\n* `POST /v1/chat/completions`: Standard stateless chat endpoint. Supports streaming via SSE.\n* `POST /v1/responses`: A stateful \"Responses API\" that supports `previous_response_id` for conversation chaining.\n* `GET /v1/runs/{run_id}/events`: Provides a structured SSE stream of agent lifecycle events (tool starts, reasoning, completion).\n* `GET /health/detailed`: Returns rich status information, including PID and connected platform states.\n\n#### Session Continuity\nThe API server uses `_derive_chat_session_id` to generate stable session IDs based on the first user message and system prompt. Clients can also explicitly provide an `X-Hermes-Session-Id` header to persist state across turns in a specific sandbox.\n\n### Resource Management (`gateway/platforms/_http_client_limits.py`)\nTo prevent file-descriptor exhaustion (especially on macOS), the module uses `platform_httpx_limits()`. This helper configures `httpx.AsyncClient` with:\n* `max_keepalive_connections=10`: Limits per-adapter connection overhead.\n* `keepalive_expiry=2.0`: Aggressively recycles idle sockets to avoid `CLOSE_WAIT` accumulation.\n\n## Message Normalization\n\nThe module handles the complexity of multimodal inputs through normalization functions:\n\n* **`_normalize_chat_content`**: Flattens OpenAI-style content arrays (text parts) into plain strings for text-only pipelines.\n* **`_normalize_multimodal_content`**: Validates and converts various image/text formats into a canonical internal representation. It supports `data:image/` URIs and standard URLs while enforcing security checks via `is_safe_url`.\n\n## Integration Points\n\nAdding a new platform requires updates across several Hermes subsystems:\n\n1. **`gateway/config.py`**: Add the platform to the `Platform` enum and update environment variable loading.\n2. **`gateway/run.py`**: Register the adapter in `_create_adapter` and update authorization maps in `_is_user_authorized`.\n3. **`agent/prompt_builder.py`**: Add a `PLATFORM_HINTS` entry to inform the agent of platform-specific capabilities (e.g., Markdown support).\n4. **`tools/send_message_tool.py`**: Implement a standalone `_send_<platform>` function to allow the agent and cron jobs to send messages outside the main adapter loop.\n5. **`cron/scheduler.py`**: Map the platform name for scheduled delivery.\n\n## Security and Redaction\n\nAdapters are responsible for protecting user privacy:\n* **Redaction**: Sensitive identifiers (tokens, phone numbers) must be masked in logs. The `agent/redact.py` module provides regex patterns for this purpose.\n* **Authorization**: Adapters must check `_is_user_authorized` before processing messages, respecting the `ALLOWED_USERS` and `ALLOW_ALL_USERS` environment variables.\n* **URL Safety**: Media downloads must be validated against `tools/url_safety.py` to prevent SSRF attacks.","gateway":"# gateway\n\n# Gateway Module\n\nThe **Gateway** module serves as the unified integration and orchestration layer for the Hermes agent. It abstracts the complexities of various messaging protocols into a standardized interface, allowing the agent to communicate across multiple platforms while maintaining consistent session state and execution logic.\n\n## Module Hierarchy\n\nThe gateway is composed of three primary functional areas:\n\n* **[Gateway Core](gateway.md)**: The central orchestrator that manages the `Gateway Runner`, `SessionStore` for context persistence, and the `DeliveryRouter` for outbound message dispatching.\n* **[Platforms](platforms.md)**: The adapter layer containing specific implementations (e.g., `TelegramAdapter`, `DiscordAdapter`) that handle low-level wire protocols like WebSockets, Protobuf, and HTTP.\n* **[Built-in Hooks](builtin_hooks.md)**: A middleware system that injects \"always-on\" logic—such as telemetry, security defaults, and header manipulation—into the request lifecycle.\n\n## Integrated Workflow\n\nThe gateway facilitates a bidirectional flow between external users and the internal agent pipeline. When a message is received, the sub-modules interact as follows:\n\n1. **Ingress**: A platform-specific adapter in `platforms` receives raw data and transforms it into a standardized `MessageEvent`.\n2. **Interception**: The `builtin_hooks` execute lifecycle events (e.g., `pre_request`), performing core logging and security validation.\n3. **Contextualization**: The `gateway` core uses the `SessionStore` to inject historical context into the event before passing it to the Agent Loop.\n4. **Egress**: When the agent generates a response, the `DeliveryRouter` identifies the correct platform adapter to transmit the message back to the user.\n\n```mermaid\ngraph LR\n subgraph Platforms\n P[External Service] <--> PA[Platform Adapters]\n end\n\n subgraph Gateway Core\n PA <--> BH[Built-in Hooks]\n BH <--> GR[Gateway Runner]\n GR <--> SS[(Session Store)]\n end\n\n GR <--> A[Agent Pipeline]\n```\n\n## Runtime Management\n\nBeyond message routing, the module includes critical system utilities in `gateway/status.py`. These utilities manage runtime locks and PID tracking, which are utilized by external tools (such as the Hermes CLI) to monitor gateway health and prevent concurrent execution conflicts during uninstallation or profile switching.","graphify-out":"# graphify-out\n\n# graphify-out\n\nThe `graphify-out` module serves as the persistence and metadata layer for the Hermes Agent's workspace analysis. It stores structured data regarding file integrity, modification states, and resource consumption metrics. This module is critical for incremental processing, ensuring the agent only re-analyzes files that have changed and providing an audit trail for LLM token usage.\n\n## Core Components\n\nThe module consists of two primary JSON artifacts that represent the state of the project at a specific point in time.\n\n### 1. manifest.json\nThis file acts as the project's \"fingerprint.\" It contains a comprehensive mapping of every file within the agent's scope to its respective metadata.\n\n* **Key**: The absolute file path on the local system.\n* **mtime**: The Unix timestamp of the last modification.\n* **hash**: A unique identifier (typically MD5 or SHA-256) representing the file's content.\n\n**Developer Usage:**\nThe agent uses this manifest to perform change detection. Before a \"graphing\" or indexing operation, the system compares the current `mtime` and `hash` of local files against the values stored in `manifest.json`. If the values match, the agent skips the file to save compute resources.\n\n### 2. cost.json\nThis file tracks the operational overhead of the agent's runs. It provides a historical log of resource usage, which is essential for monitoring API costs and processing efficiency.\n\n* **date**: ISO 8601 timestamp of the execution run.\n* **input_tokens / output_tokens**: The volume of LLM traffic generated during the run.\n* **files**: The total number of files processed or indexed in that specific session.\n* **total_input_tokens / total_output_tokens**: Aggregated totals across all recorded runs.\n\n## Execution Flow\n\nThe `graphify-out` artifacts are updated at the end of a workspace analysis cycle. The following diagram illustrates how the data is generated and persisted:\n\n```mermaid\ngraph TD\n A[Workspace Scanner] -->|File Stream| B[Hash/Metadata Generator]\n B -->|Path, Hash, mtime| C[manifest.json]\n D[LLM Provider] -->|Token Usage| E[Cost Tracker]\n E -->|Usage Metrics| F[cost.json]\n C -.->|Change Detection| A\n```\n\n## Integration with Hermes Agent\n\nThe module is tightly coupled with the core agent logic in the following ways:\n\n1. **Incremental Indexing**: The `manifest.json` allows the agent to maintain a \"hot\" state of the codebase. Without this module, the agent would be forced to re-process the entire 2,600+ file repository on every launch.\n2. **Budgeting and Quotas**: The `cost.json` data is consumed by the CLI's status and quota commands (e.g., `gquota`) to inform the user of their current spending and remaining limits.\n3. **Integrity Verification**: During `doctor` or `setup` commands, the agent references the manifest to ensure that the local environment hasn't been corrupted or desynchronized from the expected state.\n\n## Maintenance\n\nThese files are automatically managed by the agent. However, if the workspace state becomes inconsistent, developers can safely delete the `graphify-out` directory. This will force the agent to perform a full, non-incremental re-indexing of the project on the next run, regenerating both the manifest and the cost baseline.","hermes-cli":"# hermes_cli\n\n# hermes_cli\n\nThe `hermes_cli` module serves as the unified entry point and command-line interface for the Hermes Agent. It handles command parsing, multi-provider authentication, configuration management, and service orchestration (gateway, web server, and cron).\n\n## Command Architecture\n\nThe CLI is built on `argparse`, but uses a decoupled structure to allow for dynamic command dispatch and \"relaunch\" capabilities.\n\n### Parser Construction (`_parser.py`)\nThe top-level parser is constructed in `build_top_level_parser()`. It distinguishes between standard arguments and **Inherited Flags**.\n\n* **Inherited Flags**: Marked via `_inherited_flag`, these arguments are tagged with `inherit_on_relaunch = True`. This allows the `hermes_cli.relaunch` module to introspect the parser and carry these flags over when the CLI re-executes itself (e.g., after a session picker or setup wizard completes).\n* **Pre-Argparse Flags**: Flags like `--profile` or `-p` are consumed by `main._apply_profile_override` before the main parser runs to set the `HERMES_HOME` environment variable.\n\n### Execution Flow\n```mermaid\ngraph TD\n A[sys.argv] --> B{Pre-Argparse Check}\n B -->|--profile| C[Set HERMES_HOME]\n B --> D[build_top_level_parser]\n D --> E[Dispatch to cmd_* functions]\n E --> F[Interactive Chat / TUI]\n E --> G[Gateway / Services]\n E --> H[Auth / Config Management]\n```\n\n## Authentication System (`auth.py`)\n\nThe authentication system is a multi-provider engine supporting OAuth 2.0 (Device Code and PKCE flows), API keys, and external credential pooling.\n\n### Provider Registry\nAll supported providers are defined in the `PROVIDER_REGISTRY` using the `ProviderConfig` dataclass. This registry maps provider IDs (e.g., `nous`, `anthropic`, `openai-codex`) to their specific authentication requirements and base URLs.\n\n### Credential Resolution Logic\nThe `resolve_provider()` function determines the active inference source based on a strict priority:\n1. **Active Provider**: The provider currently marked as active in `~/.hermes/auth.json`.\n2. **Explicit CLI Overrides**: `--api-key` or `--base-url` passed directly.\n3. **Environment Variables**: Presence of `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, etc.\n4. **Auto-Detection**: Probing for local servers (LM Studio) or specific key prefixes (e.g., `sk-kimi-` for Kimi Coding).\n\n### Persistence and Locking\nAuth state is stored in `~/.hermes/auth.json`. To prevent corruption during concurrent access (e.g., a background gateway and a foreground chat session both refreshing tokens), the module implements a cross-process advisory lock:\n* **Unix**: Uses `fcntl.flock`.\n* **Windows**: Uses `msvcrt.locking`.\n* **Reentrancy**: The `_auth_store_lock` context manager is thread-local aware and supports reentrant calls within the same process.\n\n### Specialized Auth Flows\n* **Nous Portal**: Implements OAuth Device Code flow and \"Agent Key\" minting (short-lived keys for inference).\n* **OpenAI Codex**: Manages a separate session from the official Codex CLI to avoid refresh token rotation conflicts.\n* **Spotify**: Implements a local loopback HTTP server (`_SpotifyCallbackHandler`) to handle OAuth PKCE redirects for tool authorization.\n\n## Configuration and Environment\n\nThe CLI manages several files within `HERMES_HOME` (defaulting to `~/.hermes`):\n* `config.yaml`: User preferences, model assignments, and toolset toggles.\n* `.env`: Local environment variables and API keys.\n* `auth.json`: Persisted OAuth tokens and active provider state.\n* `gateways.json`: Configuration for messaging platform integrations.\n\n## Internal Web Server (`web_server.py`)\n\nThe module includes a lightweight web server used primarily by the TUI and external integrations to:\n* **Status Monitoring**: Retrieve system health, running PIDs, and active sessions via `get_status()`.\n* **Session Management**: Search and retrieve message history using `hermes_state`.\n* **OAuth Orchestration**: Provides endpoints like `_start_anthropic_pkce` to facilitate browser-based logins that feed credentials back into the CLI's `credential_pool`.\n\n## Plugin and Hook System (`plugins.py`)\n\nThe CLI supports a hook system that allows external modules to intercept agent actions.\n* **`invoke_hook(hook_name, ...)`**: Triggers registered shell hooks or Python plugins.\n* **Tool Approval**: The `--yolo` flag and `hooks_auto_accept` config setting bypass interactive prompts for dangerous tool executions.\n\n## Key Functions for Contributors\n\n| Function | Purpose |\n| :--- | :--- |\n| `resolve_runtime_provider()` | The main entry point for the agent to get a valid API key and base URL. |\n| `build_top_level_parser()` | Where to add new global CLI flags or subcommands. |\n| `_load_auth_store()` | Safely reads the auth JSON; handles migrations and corruption recovery. |\n| `login_spotify_command()` | Reference implementation for adding new OAuth-based tool providers. |\n| `detect_zai_endpoint()` | Example of dynamic endpoint probing based on API key capabilities. |","nix":"# nix\n\n# Nix Infrastructure\n\nThe `nix` module provides the build, development, and deployment infrastructure for the Hermes Agent. It leverages `uv2nix` for reproducible Python environments, `buildNpmPackage` for frontend components, and provides a sophisticated NixOS module supporting both native systemd and OCI container execution modes.\n\n## Core Packaging Architecture\n\nThe primary package is defined in `hermes-agent.nix`. It acts as an aggregator that bundles the Python virtual environment, the TUI, the Web dashboard, and bundled assets (skills and plugins).\n\n### Python Environment (`python.nix`)\nThe Python environment is managed via `uv2nix`, which transforms `uv.lock` into a Nix-native dependency graph.\n- **Platform Overrides**: `python.nix` contains specific overrides for `aarch64-darwin` (macOS Silicon). Since some wheels (like `onnxruntime` or `faster-whisper`) are unavailable or incompatible, it maps these to Nixpkgs-provided versions using `hacks.nixpkgsPrebuilt`.\n- **Sealed Venv**: The environment is built as a sealed virtual environment, ensuring that the core agent dependencies are immutable and isolated.\n\n### The Wrapper (`hermes-agent.nix`)\nThe `hermes` binary is a shell wrapper created via `makeWrapper`. It injects critical environment variables that the Python source uses to locate assets:\n- `HERMES_BUNDLED_SKILLS`: Points to the immutable skills directory in the Nix store.\n- `HERMES_BUNDLED_PLUGINS`: Points to the immutable plugins directory.\n- `HERMES_TUI_DIR`: Points to the compiled Ink/React TUI.\n- `HERMES_PYTHON`: Points to the specific Python interpreter in the venv.\n- `PYTHONPATH`: Dynamically extended if `extraPythonPackages` are provided.\n\n### Collision Detection\nTo prevent runtime errors when users add `extraPythonPackages` (e.g., for plugins), the derivation includes a `checkPackageCollisions` script. This script runs during the install phase, scanning the metadata of extra packages to ensure they do not overlap with the core sealed virtual environment.\n\n## Frontend Builds\n\nThe agent includes two Node.js-based frontends, both managed via `lib.nix` helpers.\n\n- **TUI (`tui.nix`)**: A React/Ink-based terminal interface. It handles complex `node_modules` structures, including local file dependencies like `@hermes/ink`.\n- **Web (`web.nix`)**: A Vite/React dashboard.\n- **Lockfile Management**: `lib.nix` provides `mkNpmPassthru`, which normalizes trailing newlines in `package-lock.json` to prevent `npmConfigHook` mismatches. It also provides the `fix-lockfiles` utility to automatically update Nix hashes when NPM dependencies change.\n\n## NixOS Module (`nixosModules.nix`)\n\nThe NixOS module provides a declarative way to deploy the Hermes Agent. It supports two distinct execution modes:\n\n### 1. Native Mode\nRuns as a standard systemd service. The agent runs directly on the host, using tools provided in the service's `path` and `extraPackages`.\n\n### 2. Container Mode\nRuns the agent inside an OCI container (Docker or Podman).\n- **Persistent Writable Layer**: Unlike standard Nix containers, this mode bind-mounts the Nix store read-only but allows the container's root filesystem to be writable. This enables the agent to use `apt`, `pip`, and `uv` to modify its own environment at runtime.\n- **Provisioning**: The `containerEntrypoint` script handles first-boot setup, installing `nodejs`, `uv`, and creating a writable Python 3.12 venv at `~/.venv`.\n- **Host Integration**: If `container.hostUsers` is set, the module creates symlinks from the host user's `~/.hermes` to the service's state directory, allowing the host CLI to transparently `exec` into the running container.\n\n### Configuration Merging\nThe module uses `configMergeScript.nix` (a Python helper) during activation. This script performs a deep merge between the declarative Nix `settings` and the existing `config.yaml` on disk.\n- **Priority**: Nix-defined keys always override existing values.\n- **Preservation**: User-defined keys (like manually added skills or custom tool settings) are preserved.\n- **Managed Guard**: The module creates a `.managed` file in `HERMES_HOME`. When `HERMES_MANAGED=true` is set, the Hermes CLI blocks mutation commands (like `config set`) to prevent drift from the Nix configuration.\n\n## Development Environment (`devShell.nix`)\n\nThe development shell is designed to bridge the gap between Nix and imperative workflows:\n- **Automatic Setup**: It uses `passthru.devShellHook` to automatically run `uv pip install` or `npm install` when entering the shell.\n- **Stamp Checking**: Setup logic is wrapped in \"stamps\" (stored in `.nix-stamps/`). Dependencies are only re-installed if `pyproject.toml`, `uv.lock`, or `package-lock.json` have changed.\n\n## Build-time Verification (`checks.nix`)\n\nThe `checks` attribute provides automated testing of the Nix infrastructure:\n- **cross-eval**: Verifies that the package evaluates on Linux and Darwin without requiring a remote builder.\n- **config-roundtrip**: A comprehensive test suite that runs the `configMergeScript` against seven different scenarios (fresh install, overrides, additive MCP merges, etc.) and verifies the result using the actual `hermes_cli.config.load_config` Python logic.\n- **package-contents**: Ensures all entry points (`hermes`, `hermes-agent`, `hermes-acp`) are present and executable.\n\n```mermaid\ngraph TD\n subgraph NixStore [Nix Store]\n Venv[Python Venv]\n TUI[TUI Dist]\n Web[Web Dist]\n Skills[Bundled Skills]\n end\n\n Wrapper[hermes wrapper]\n Wrapper --> Venv\n Wrapper --> TUI\n Wrapper --> Skills\n\n subgraph Runtime [Runtime Environment]\n Config[config.yaml]\n Env[.env]\n State[(SQLite / Logs)]\n end\n\n Wrapper --> Config\n Wrapper --> Env\n Wrapper --> State\n\n NixOS[NixOS Module] -- \"configMergeScript\" --> Config\n NixOS -- \"Activation\" --> Env\n```\n\n## Key Environment Variables\n| Variable | Purpose |\n| :--- | :--- |\n| `HERMES_HOME` | Root directory for state, config, and logs. |\n| `HERMES_MANAGED` | Disables CLI configuration mutations. |\n| `HERMES_BUNDLED_SKILLS` | Path to read-only skills provided by the Nix package. |\n| `HERMES_TUI_DIR` | Path to the compiled TUI assets. |\n| `HERMES_NODE` | Path to the Node.js binary (required for TUI regex support). |","optional-skills-autonomous-ai-agents":"# optional-skills — autonomous-ai-agents\n\n# Autonomous AI Agents Module\n\nThe `autonomous-ai-agents` module provides optional integrations for delegating complex tasks to external coding agents and managing sophisticated, cross-session memory. It extends the Hermes agent's capabilities by allowing it to act as an orchestrator for other specialized AI systems.\n\n## Module Overview\n\nThis module consists of two primary integrations:\n1. **Blackbox CLI**: An external coding agent capable of multi-model reasoning and autonomous file manipulation.\n2. **Honcho**: An AI-native memory layer that provides cross-session user modeling, dialectic reasoning, and peer-based identity management.\n\n---\n\n## Blackbox CLI Integration\n\nThe Blackbox integration allows Hermes to delegate coding tasks to the [Blackbox AI CLI](https://github.com/blackboxaicode/cli). Blackbox is unique because it dispatches tasks to multiple LLMs (Claude, GPT-4, Gemini) and uses an internal \"judge\" to select the best implementation.\n\n### Execution Patterns\n\n#### 1. One-Shot Delegation\nFor simple tasks, use the `terminal` tool to invoke the CLI directly.\n```python\n# Example: Adding a feature to an existing codebase\nterminal(\n command=\"blackbox --prompt 'Add JWT authentication with refresh tokens to the Express API'\", \n workdir=\"/path/to/project\", \n pty=true\n)\n```\n\n#### 2. Background Execution (Long-Running Tasks)\nFor tasks that may take several minutes, use background mode to prevent blocking the main Hermes execution loop.\n```python\n# Start the task\nterminal(\n command=\"blackbox --prompt 'Refactor the auth module'\", \n background=true, \n pty=true\n)\n\n# Monitor via the process tool\nprocess(action=\"poll\", session_id=\"<id>\")\nprocess(action=\"log\", session_id=\"<id>\")\n```\n\n### Critical Requirements\n* **PTY Requirement**: The Blackbox CLI is an interactive terminal application. You **must** set `pty=true` in all `terminal` calls, or the process will hang indefinitely.\n* **Checkpoints**: Blackbox generates checkpoint tags (e.g., `task-abc123-2026-03-06`). These can be used with the `--resume-checkpoint` flag to continue a task in a later session.\n\n---\n\n## Honcho Memory System\n\nHoncho provides persistent, cross-session memory. It models conversations as interactions between **Peers** (the User and the AI) within a shared **Workspace**.\n\n### Architecture & Data Flow\n\n```mermaid\ngraph TD\n H[Hermes Agent] -->|Tool Call| HM[Honcho Module]\n HM -->|API| HC[Honcho Cloud/Local]\n HC -->|Context Injection| H\n subgraph \"Memory Components\"\n US[User Representation]\n AC[AI Peer Card]\n SS[Session Summary]\n end\n HC -.-> US\n HC -.-> AC\n HC -.-> SS\n```\n\n### Recall Modes\nThe integration supports three modes of memory access, configured via `recallMode`:\n* **`hybrid` (Default)**: Automatically injects context into the system prompt and provides tools for explicit memory access.\n* **`context`**: Only uses auto-injection. Tools are hidden to save tokens and reduce complexity.\n* **`tools`**: No auto-injection. The agent must explicitly call Honcho tools to retrieve information.\n\n### The Dialectic Engine\nHoncho uses a \"dialectic\" reasoning engine to synthesize answers about the user. This is controlled by three orthogonal settings:\n1. **Cadence**: How often the engine fires (e.g., `dialecticCadence: 2` fires every other turn).\n2. **Depth**: How many rounds of reasoning are performed (1-3). Higher depth runs an internal audit/reconcile cycle.\n3. **Level**: The intensity of the reasoning (`minimal` to `max`).\n\n### Toolset Reference\n\n| Tool | Purpose |\n| :--- | :--- |\n| `honcho_profile` | Read/Update the Peer Card (name, role, preferences). No LLM cost. |\n| `honcho_search` | Semantic search for raw excerpts from past conversations. |\n| `honcho_context` | Retrieve a full snapshot: summary, representation, and recent messages. |\n| `honcho_reasoning` | Ask a natural language question to be answered by the dialectic engine. |\n| `honcho_conclude` | Write a persistent fact (Conclusion) to the user or AI representation. |\n\n### Multi-Profile Peer Isolation\nEach Hermes profile (e.g., `default`, `coder`, `researcher`) is assigned a unique **AI Peer**. \n* **Shared Workspace**: All profiles see the same User Representation.\n* **Isolated Identity**: Each profile builds its own AI Peer Card and self-observations, allowing different agent personalities to maintain distinct self-knowledge while knowing the same user.\n\n---\n\n## Configuration & Setup\n\n### Blackbox Setup\nRequires the CLI and an API key:\n1. `npm install -g @blackboxai/cli`\n2. `blackbox configure`\n\n### Honcho Setup\nHoncho can be configured via the Hermes CLI:\n```bash\nhermes honcho setup # Interactive wizard\nhermes honcho status # Verify connection and peer info\n```\n\nSettings are stored in `honcho.json`. Key configuration keys include:\n* `sessionStrategy`: Determines session boundaries (`per-directory`, `per-repo`, `global`).\n* `contextTokens`: An optional cap on the size of the injected context block to prevent prompt blowup.\n* `observation`: Booleans (`observeMe`, `observeOthers`) controlling what the agent learns from.","optional-skills-blockchain":"# optional-skills — blockchain\n\n# Optional Skills — Blockchain Module\n\nThe `blockchain` module provides lightweight, zero-dependency CLI tools for querying on-chain data from the **Base (Ethereum L2)** and **Solana** networks. These tools are designed for the Hermes Agent to perform wallet audits, token lookups, and network health checks without requiring heavy libraries like `web3.py` or `solana-py`.\n\n## Architecture Overview\n\nBoth sub-modules (`base` and `solana`) follow a similar architectural pattern:\n1. **JSON-RPC Interface:** Communicates directly with blockchain nodes using `urllib`.\n2. **Pricing Integration:** Enriches on-chain data with USD values via the CoinGecko Public API.\n3. **Zero-Dependency Design:** Uses only the Python standard library for maximum portability.\n4. **Batching & Retries:** Implements custom RPC batching and exponential backoff for rate-limited endpoints.\n\n```mermaid\ngraph TD\n CLI[CLI Command] --> Dispatcher{Command Dispatcher}\n Dispatcher --> Wallet[cmd_wallet]\n Dispatcher --> Stats[cmd_stats]\n Dispatcher --> Token[cmd_token]\n \n Wallet --> RPC[JSON-RPC Provider]\n Wallet --> CG[CoinGecko API]\n \n RPC --> Chain((Blockchain))\n CG --> Price((Market Data))\n```\n\n---\n\n## Base (Ethereum L2) Module\n\nThe Base module interacts with the Ethereum L2 ecosystem. It handles EVM-specific logic such as ABI encoding for `eth_call` and EIP-1967 proxy resolution.\n\n### Key Components\n\n#### RPC & ABI Helpers\n- `_rpc_call(method, params)`: The core transport layer for JSON-RPC.\n- `rpc_batch(calls)`: Automatically chunks requests into groups of 10 to respect public RPC limits.\n- `_eth_call(to, selector, args)`: Low-level helper to execute contract reads.\n- `_decode_string(hex_data)` / `_decode_uint(hex_data)`: Manual ABI decoding for ERC-20 metadata (name, symbol, decimals).\n\n#### Core Logic\n- **`cmd_wallet`**: Queries ETH balance and iterates through `KNOWN_TOKENS` to call `balanceOf`. Note that unlike Solana, EVM chains require explicit contract addresses to find balances.\n- **`cmd_contract`**: Inspects an address to determine if it is an EOA or a contract. It checks for ERC-20, ERC-721, and ERC-1155 interfaces using `supportsInterface` (ERC-165) and resolves EIP-1967 proxy implementation slots.\n- **`cmd_gas`**: Provides L2 execution cost estimates. It calculates a 10-block trend for base fees and block utilization.\n\n### Configuration\n- **`BASE_RPC_URL`**: Environment variable to override the default `https://mainnet.base.org`.\n- **`KNOWN_TOKENS`**: A hardcoded dictionary of high-liquidity tokens (USDC, AERO, DEGEN) used for fast lookups and fallback metadata.\n\n---\n\n## Solana Module\n\nThe Solana module handles the unique account-based model of the Solana blockchain, including SPL tokens and NFTs.\n\n### Key Components\n\n#### RPC Helpers\n- `_rpc_call(method, params)`: Standard Solana JSON-RPC wrapper.\n- `rpc_batch(calls)`: Supports batching multiple requests into a single HTTP POST.\n- `lamports_to_sol(lamports)`: Utility to convert the native unit (10^9) to SOL.\n\n#### Core Logic\n- **`cmd_wallet`**: Uses `getTokenAccountsByOwner` to retrieve all SPL token holdings in a single call. This allows for comprehensive portfolio discovery, unlike the Base module which relies on a known-token list.\n- **`cmd_nft`**: Implements a heuristic to identify NFTs by filtering for SPL accounts where `amount == 1` and `decimals == 0`.\n- **`cmd_tx`**: Parses transaction signatures. It calculates balance changes by comparing `preBalances` and `postBalances` from the transaction metadata.\n- **`cmd_whales`**: Scans the latest block for transactions exceeding a specific SOL threshold (default 1000 SOL).\n\n### Configuration\n- **`SOLANA_RPC_URL`**: Environment variable to override the default public mainnet-beta endpoint.\n- **`KNOWN_TOKENS`**: Maps mint addresses to symbols (e.g., `So111...` to `SOL`).\n\n---\n\n## Common Implementation Patterns\n\n### Pricing Engine\nBoth modules share a similar pricing strategy in `fetch_prices()`:\n- It targets the CoinGecko `/simple/token_price` endpoint.\n- Because the CoinGecko free tier is rate-limited, the scripts implement a 1-second sleep between individual token lookups.\n- Users can pass `--no-prices` to skip these calls and return raw on-chain data immediately.\n\n### Error Handling & Rate Limiting\nThe modules implement a robust retry mechanism in `_http_get_json` and `_rpc_call`:\n- **HTTP 429 (Too Many Requests):** Triggers an exponential backoff (2.0s, 4.0s).\n- **RPC Errors:** The scripts catch JSON-RPC error objects and exit gracefully with a descriptive message rather than a stack trace.\n\n### Data Enrichment\nFunctions like `_token_label` and `resolve_token_name` provide a \"best-effort\" approach to human-readable data:\n1. Check `KNOWN_TOKENS` (Instant).\n2. Query on-chain metadata (RPC call).\n3. Query CoinGecko (API call).\n4. Fallback to abbreviated addresses (e.g., `0xabc...123`).\n\n## Usage for Developers\n\nWhen contributing to this module, ensure that any new commands follow the `cmd_<name>(args)` pattern and are registered in the `main()` dispatcher. \n\n### Adding a Known Token\nTo add a token to the fast-path lookup, update the `KNOWN_TOKENS` dictionary in the respective client script:\n- **Base:** Requires `(symbol, name, decimals)`.\n- **Solana:** Requires `(symbol, name)`.\n\n### Testing\nVerify connectivity and basic functionality using the `stats` command:\n```bash\npython3 base_client.py stats\npython3 solana_client.py stats\n```","optional-skills-communication":"# optional-skills — communication\n\n# Communication Module: 1-3-1 Rule\n\nThe `communication` module provides structured frameworks for decision-making and stakeholder reporting. Its primary component is the `one-three-one-rule`, a skill designed to transform complex technical trade-offs into actionable proposals.\n\n## Overview\n\nThe **1-3-1 Rule** is a communication pattern used when a task has multiple viable paths. It prevents \"analysis paralysis\" by forcing a specific structure:\n- **1** Clear Problem Statement\n- **3** Distinct Options\n- **1** Concrete Recommendation\n\nThis module is intended for use in architecture discussions, tool selection, refactoring strategies, and migration paths where stakeholders require a clear rationale for a chosen direction.\n\n## Module Structure\n\n### 1-3-1 Framework Components\n\n| Component | Requirement | Description |\n| :--- | :--- | :--- |\n| **Problem** | Single Sentence | A concise statement of the core issue. It must focus on the *what*, avoiding implementation details or technology names. |\n| **Options** | Exactly Three | Three distinct, viable strategies labeled A, B, and C. Each must include specific Pros and Cons. |\n| **Recommendation** | Single Choice | A direct selection of one option based on professional judgment and the specific project context. |\n| **Definition of Done** | Verifiable Criteria | A list of concrete outcomes that signal the recommended path is successfully completed. |\n| **Implementation Plan** | Actionable Steps | The sequence of commands, tools, or code changes required to execute the recommendation. |\n\n## Logic Flow\n\nThe module follows a linear progression from problem framing to execution planning. If the user rejects the initial recommendation in favor of one of the other two options, the `Definition of Done` and `Implementation Plan` must be dynamically updated to reflect the new choice.\n\n```mermaid\ngraph TD\n Start[User Request/Complex Task] --> Frame[1: Define Problem Statement]\n Frame --> Options[3: Generate Options A, B, C]\n Options --> Rec[1: Provide Recommendation]\n Rec --> DoD[Define Success Criteria]\n DoD --> Plan[Create Implementation Plan]\n Plan --> End[Stakeholder Review]\n```\n\n## Usage Guidelines\n\n### When to Trigger\nThe `one-three-one-rule` should be invoked when:\n- The user explicitly requests a \"1-3-1\".\n- The user asks for \"options\" or \"choices\" regarding a technical path.\n- A task involves significant trade-offs (e.g., choosing between a library vs. custom implementation).\n- The output needs to be forwarded to a team lead or stakeholder for approval.\n\n### Constraints\n- **No Hedging:** The recommendation must be decisive. Avoid \"it depends\" without picking a side.\n- **Distinct Options:** Options must represent different strategies (e.g., \"Buy vs. Build vs. Status Quo\"), not minor configuration tweaks.\n- **Atomicity:** The problem statement must address exactly one core issue. If \"and\" is required to describe the problem, the scope is likely too broad.\n\n## Metadata and Integration\n\nThe skill is registered under the `communication` category with the following metadata:\n\n- **Tags:** `communication`, `decision-making`, `proposals`, `trade-offs`\n- **Version:** 1.0.0\n- **License:** MIT\n\nAs an \"optional-skill,\" it is designed to be layered onto standard task execution when the complexity of a decision warrants a formal proposal structure. It does not have external dependencies or outgoing calls, making it a pure logic/formatting framework.","optional-skills-creative":"# optional-skills — creative\n\n# Optional Skills: Creative Module\n\nThe `optional-skills/creative` module provides a suite of tools for generating visual assets and controlling 3D environments. It is divided into three primary sub-modules: **Blender MCP**, **Concept Diagrams**, and **Meme Generation**.\n\n---\n\n## Blender MCP\n\nThe Blender MCP sub-module enables remote control of a running Blender instance (version 4.3+) via a TCP socket connection. This allows the agent to programmatically model, animate, and render 3D scenes.\n\n### Connection Protocol\nCommunication occurs over TCP port **9876** using plain UTF-8 JSON.\n- **Host:** `localhost`\n- **Port:** `9876`\n- **Format:** `{\"type\": \"<command>\", \"params\": {<kwargs>}}`\n\n### Core Commands\n| Command | Description |\n|:---|:---|\n| `execute_code` | Runs arbitrary Python code using the `bpy` (Blender Python) API. |\n| `get_scene_info` | Returns a list of all objects currently in the scene. |\n| `get_object_info` | Provides detailed metadata for a specific named object. |\n| `get_viewport_screenshot` | Captures the current Blender viewport as an image. |\n\n### Python Integration\nThe module includes a `blender_exec` helper function to manage the socket lifecycle, handling connection, payload serialization, and buffered response reading.\n\n```python\ndef blender_exec(code: str, host=\"localhost\", port=9876):\n # Connects to Blender, sends JSON payload, and returns parsed result\n # Handles JSONDecodeError for partial chunks and socket timeouts\n```\n\n---\n\n## Concept Diagrams\n\nThis sub-module generates minimal, educational-style SVG diagrams embedded in standalone HTML files. It uses a unified design system that automatically supports light and dark modes.\n\n### Design System & CSS Classes\nThe module relies on `templates/template.html`, which contains a comprehensive CSS framework for SVGs.\n\n- **Color Ramps:** 9 semantic ramps (`c-purple`, `c-teal`, `c-coral`, `c-pink`, `c-gray`, `c-blue`, `c-green`, `c-amber`, `c-red`). Each ramp automatically adjusts fill and stroke colors based on the user's system theme.\n- **Typography:**\n - `.th`: Header text (14px, Medium weight).\n - `.ts`: Subtitle/Small text (12px, Regular weight).\n - `.t`: Standard body text (14px, Regular weight).\n- **Shapes:** Standardized rounding (`rx=\"8\"` for nodes) and stroke widths (`0.5px`).\n\n### Workflow\n1. **Load Template:** Read `templates/template.html`.\n2. **Generate SVG:** Construct an SVG string using the provided boilerplate (including the `<marker id=\"arrow\">` definition).\n3. **Inject Content:** Replace placeholders `<!-- DIAGRAM TITLE HERE -->` and `<!-- PASTE SVG HERE -->`.\n4. **Export:** Save as a `.html` file for browser viewing.\n\n### Specialized Patterns\nThe module includes reference files for specific domains:\n- `infrastructure-patterns.md`: Hub-spoke layouts, solar panels, wind turbines, and semantic line styles (e.g., `.data-line`, `.power-line`).\n- `dashboard-patterns.md`: UI mockups with dark \"screens\" and status indicators.\n- `physical-shape-cookbook.md`: Guidance for using `<path>` and `<polygon>` for complex physical objects like aircraft or anatomy.\n\n---\n\n## Meme Generation\n\nThe Meme Generation sub-module produces `.png` files by overlaying text on image templates using the `Pillow` library.\n\n### Execution Flow\nThe primary entry point is `scripts/generate_meme.py`. It supports two distinct modes of operation:\n\n```mermaid\ngraph TD\n A[Start] --> B{Mode?}\n B -- Template --> C[resolve_template]\n C --> D[Fetch from Cache/Imgflip]\n D --> E[_overlay_on_image]\n B -- Custom Image --> F[generate_from_image]\n F --> G{Style?}\n G -- Overlay --> E\n G -- Bars --> H[_add_bars]\n E --> I[Save PNG]\n H --> I\n```\n\n### Template Resolution\nThe `resolve_template` function searches for templates in three stages:\n1. **Curated:** Matches against `scripts/templates.json` (10 templates with hand-tuned text coordinates like `drake` or `distracted-boyfriend`).\n2. **Slug Match:** Matches slugified names against curated IDs.\n3. **Imgflip API:** Fetches popular templates from the Imgflip API, caching the metadata in `.cache/imgflip_memes.json` for 24 hours.\n\n### Text Rendering Logic\n- **`draw_outlined_text`**: Renders white text with a black outline for legibility. It includes an auto-scaling loop that reduces font size until the text fits the designated `w_pct` (width percentage) of the template.\n- **`_wrap_text`**: Performs word-wrapping to ensure text does not overflow the horizontal bounds.\n- **`_add_bars`**: Used for custom images where text might obscure the subject. It adds black bars to the top and bottom of the image, resizing the canvas to accommodate the text.\n\n### CLI Usage\n```bash\n# Generate using a curated template\npython generate_meme.py drake /tmp/meme.png \"Option A\" \"Option B\"\n\n# Generate using a custom background image with bars\npython generate_meme.py --image background.png --bars /tmp/meme.png \"Top Caption\" \"Bottom Caption\"\n\n# Search for templates\npython generate_meme.py --search \"cat\"\n```\n\n### Dependencies\n- **Pillow:** Image processing and text rendering.\n- **Requests:** (Optional) For fetching remote templates; falls back to `urllib`.\n- **Fonts:** Searches for `Impact.ttf` or `LiberationSans-Bold.ttf` across standard Linux and macOS system paths.","optional-skills-devops":"# optional-skills — devops\n\n# DevOps Module\n\nThe `devops` module provides a suite of tools for managing cloud-based AI inference and local container infrastructure. It is divided into two primary functional areas: the **inference.sh CLI** for AI application execution and **Docker Management** for container orchestration.\n\n## Inference.sh CLI (`infsh`)\n\nThe `inference-sh-cli` sub-module enables the execution of over 150 AI applications (LLMs, image generation, video creation, 3D, and search) directly from the terminal. It abstracts complex provider APIs into a unified command-line interface.\n\n### Core Workflow\n\nThe module follows a strict \"Search-Run-Parse\" pattern to ensure accuracy and handle the dynamic nature of the app catalog.\n\n```mermaid\ngraph TD\n A[User Request] --> B[infsh app list --search]\n B --> C{App Found?}\n C -->|Yes| D[infsh app run --json]\n C -->|No| B\n D --> E[Parse JSON Output]\n E --> F[Display MEDIA:url]\n```\n\n### Key Commands\n\n* **Authentication**: Managed via `infsh login` or the `INFSH_API_KEY` environment variable. Use `infsh me` to verify the session.\n* **Discovery**: \n * `infsh app list --search <term>`: Always used before execution to find the correct `namespace/app-id`.\n * `infsh app get <app-id> --json`: Retrieves the input schema (JSON) required for the app.\n* **Execution**:\n * `infsh app run <app-id> --input '<json>' --json`: Executes the app. The `--json` flag is mandatory for machine-readable output.\n * **Local File Handling**: The CLI automatically handles uploads if a local path is provided in the input JSON (e.g., `{\"image\": \"./photo.jpg\"}`).\n* **Task Management**: For long-running tasks (like video generation), use `infsh task get <task-id>` to poll for completion.\n\n### Implementation Patterns\n\nWhen contributing to this module, follow these patterns:\n1. **Never Hardcode IDs**: App IDs can change. Always implement a search step.\n2. **Media Presentation**: Output URLs from the JSON response should be prefixed with `MEDIA:` to trigger inline rendering in supported interfaces.\n3. **Timeout Handling**: Video generation can take >60s. Ensure the terminal tool timeout is configured appropriately or use the `--no-wait` flag combined with task polling.\n\n---\n\n## Docker Management\n\nThe `docker-management` sub-module provides a standardized interface for managing the lifecycle of containers, images, volumes, and networks. It relies on the native Docker CLI and Docker Compose v2.\n\n### Functional Domains\n\nThe module categorizes operations into six domains:\n\n1. **Container Lifecycle**: `run`, `stop`, `start`, `restart`, `rm`.\n2. **Interaction**: `exec` (shell access), `logs` (debugging), `cp` (file transfer), `stats`.\n3. **Image Management**: `build` (using BuildKit), `pull`, `push`, `tag`, `prune`.\n4. **Docker Compose**: Managing multi-service stacks via `up`, `down`, and `ps`.\n5. **Infrastructure**: Managing `volumes` for persistence and `networks` for service discovery.\n6. **Maintenance**: System-wide cleanup using `docker system df` and `prune`.\n\n### Common Patterns\n\n#### Container Execution\nFor background services, use detached mode with explicit naming:\n```bash\ndocker run -d --name <name> -p <host>:<container> -e KEY=VAL <image>\n```\n\n#### Debugging\nTo analyze a crashing container, the module utilizes a combination of logs and inspection:\n```bash\ndocker logs --tail 100 <name>\ndocker inspect <name>\ndocker stats --no-stream\n```\n\n#### Dockerfile Optimization\nThe module promotes the following best practices for image creation:\n* **Multi-stage builds**: Separating build-time dependencies from the runtime environment.\n* **Layer Caching**: Ordering instructions from least-frequently changed (base image, OS deps) to most-frequently changed (source code).\n* **Base Image Selection**: Preferring `alpine` or `slim` variants to minimize attack surface and footprint.\n\n### Safety and Cleanup\nThe module includes safeguards for destructive operations. `docker system prune -a --volumes` should never be executed without explicit user confirmation, as it removes all unused images and named volumes.\n\n## Integration with Terminal Tools\n\nBoth sub-modules are designed to be invoked via a **terminal toolset**. They expect a shell environment where `infsh` and `docker` binaries are available in the `PATH`. \n\n* **Error Handling**: The module interprets exit codes (e.g., 127 for command not found, 137 for OOM kill) to provide actionable feedback.\n* **Output Parsing**: Prefers JSON output (`--json` for `infsh`, `docker inspect` for Docker) to avoid fragile regex-based parsing of stdout.","optional-skills-dogfood":"# optional-skills — dogfood\n\n# Dogfood — Advanced QA & Testing Skills\n\nThe **Dogfood** module provides specialized QA workflows designed to surface product-level friction that standard automated testing or traditional QA often misses. Unlike unit or integration tests that verify technical correctness, these skills focus on user experience (UX), accessibility, and \"cold-start\" viability.\n\n## Adversarial UX Test (`adversarial-ux-test`)\n\nThe `adversarial-ux-test` skill implements a structured methodology for identifying UX friction by roleplaying a \"tech-resistant\" persona. It simulates a worst-case user scenario to find where an application fails to provide value or clarity to non-experts.\n\n### Execution Workflow\n\nThe skill follows a linear 6-step pipeline to ensure that feedback is both visceral (from the user's perspective) and actionable (from a developer's perspective).\n\n```mermaid\ngraph TD\n A[Define Persona] --> B[Browse as Persona]\n B --> C[The Rant]\n C --> D[Pragmatism Filter]\n D --> E[Create Tickets]\n E --> F[Final Report]\n```\n\n### 1. Persona Engineering\nThe agent generates or accepts a specific persona characterized by low technical literacy and high skepticism. A valid persona must include:\n* **Tech Comfort Level:** Specific limitations (e.g., \"only uses WhatsApp,\" \"hates passwords\").\n* **Core Objective:** The single task they need to accomplish.\n* **Friction Threshold:** What specific triggers cause them to abandon the app.\n\n### 2. Adversarial Browsing\nThe agent navigates the application using browser tools while strictly adhering to the persona's constraints. Key focus areas include:\n* **Terminology:** Identifying developer jargon that confuses laypeople.\n* **Click Depth:** Counting steps to reach the \"Aha moment\" or core workflow.\n* **Error Recovery:** Testing how the app handles \"incorrect\" but human inputs.\n* **Visual Accessibility:** Evaluating font sizes, contrast, and click target density.\n\n### 3. The Pragmatism Filter\nThis is the critical logic layer that separates \"persona noise\" from actionable product improvements. Every complaint generated during the \"Rant\" phase is categorized:\n\n| Category | Criteria | Action |\n| :--- | :--- | :--- |\n| **RED** | Real UX Bug / Accessibility issue | Create high-priority ticket |\n| **YELLOW** | Valid but low priority / Edge case | Log in catch-all ticket |\n| **GREEN** | Feature Request hidden in complaint | Create feature ticket |\n| **WHITE** | Persona Noise (\"I hate computers\") | Ignore for ticketing; include in report |\n\n### 4. Integration & Output\nThe module interacts with the project's issue tracker and documentation:\n* **Screenshots:** Captured for every RED and YELLOW finding.\n* **Console Logs:** Checked for JS errors during the browsing phase.\n* **Tickets:** Generated with a mandatory `ux-review` tag. Tickets include the verbatim persona quote to provide context for developers.\n\n### Implementation Guidelines for Contributors\n\nWhen extending or using this module, adhere to the following patterns:\n\n* **Context Awareness:** The skill reads project documentation and `DESCRIPTION.md` files to understand the app's purpose before defining the persona.\n* **State Management:** Tests should ideally be run against a \"cold start\" environment (new user registration) rather than pre-seeded admin accounts to capture onboarding friction.\n* **Constraint Enforcement:** The \"Pragmatism Filter\" must never be skipped. Raw persona feedback is considered \"unprocessed data\" and should not be converted directly into tickets without the filtering step.\n\n### Related Skills\n* `dogfood`: The parent skill set for advanced QA workflows.\n* `browser-tools`: Utilized for navigation and DOM inspection during the test.","optional-skills-email":"# optional-skills — email\n\n# AgentMail Skill: Autonomous Email Communication\n\nThe `agentmail` module provides Hermes agents with dedicated, agent-owned email identities. Unlike traditional email integrations that access a user's existing inbox (like Gmail or IMAP), AgentMail allows the agent to create, manage, and operate its own email addresses (e.g., `agent-name@agentmail.to`) autonomously.\n\nThis skill is implemented as an **MCP (Model Context Protocol) server** integration, wrapping the AgentMail API into a set of tools the agent can invoke during execution.\n\n## Architecture\n\nThe module operates as a bridge between the Hermes core and the AgentMail cloud infrastructure.\n\n```mermaid\ngraph TD\n Hermes[Hermes Core] -->|MCP Protocol| MCPServer[agentmail-mcp Server]\n MCPServer -->|REST API| AgentMailAPI[AgentMail Cloud API]\n AgentMailAPI -->|SMTP/IMAP| Internet[External Email Servers]\n```\n\n## Configuration\n\nThe skill requires an API key from [AgentMail](https://console.agentmail.to). Configuration is handled via the Hermes global config file (`~/.hermes/config.yaml`).\n\n```yaml\nmcp_servers:\n agentmail:\n command: \"npx\"\n args: [\"-y\", \"agentmail-mcp\"]\n env:\n AGENTMAIL_API_KEY: \"am_your_key_here\"\n```\n\n### Requirements\n- **Node.js 18+**: Required to execute the `agentmail-mcp` package via `npx`.\n- **Python `mcp` package**: Required for Hermes to interface with MCP servers.\n\n## Tool Reference\n\nThe module exposes 11 tools for comprehensive inbox management.\n\n### Inbox Management\n- `create_inbox`: Generates a new email address. Requires a `username`.\n- `list_inboxes`: Returns all active inboxes associated with the API key.\n- `get_inbox`: Retrieves metadata for a specific inbox ID.\n- `delete_inbox`: Permanently removes an inbox.\n\n### Messaging & Threads\n- `send_message`: Dispatches a new email. Parameters: `inbox_id`, `to`, `subject`, `text`, and optional `html`.\n- `list_threads`: Fetches a list of conversations (threads) for an inbox. This is the primary method for checking for new mail.\n- `get_thread`: Retrieves the full history of messages within a specific conversation.\n- `reply_to_message`: Sends a reply within an existing thread context.\n- `forward_message`: Forwards an existing message to a new recipient.\n- `update_message`: Modifies message metadata, such as labels or read/unread status.\n\n### Attachments\n- `get_attachment`: Downloads binary data for email attachments.\n\n## Implementation Patterns\n\n### The Polling Pattern\nSince the MCP server does not currently support push-based webhooks for local Hermes instances, agents must implement a polling pattern to detect incoming mail:\n\n1. **Identify Inbox**: Use `list_inboxes` to find the target `inbox_id`.\n2. **Check Threads**: Periodically call `list_threads` to see if the `last_message_at` timestamp has updated.\n3. **Fetch Content**: Use `get_thread` to retrieve the latest message content.\n\n### Identity Management\nAgents should typically create a dedicated inbox for specific tasks to maintain context isolation. For example, an agent performing market research might create `research-bot@agentmail.to`, while a support agent uses `support-bot@agentmail.to`.\n\n## Technical Constraints\n\n- **Domain Restrictions**: On the free tier, all addresses use the `@agentmail.to` suffix. Custom domains require a paid AgentMail plan.\n- **Rate Limiting**: The free tier is limited to 3,000 emails per month and 3 active inboxes.\n- **Persistence**: Inboxes and threads are persisted on the AgentMail servers, allowing agents to maintain long-running conversations across different Hermes sessions.\n- **Environment Variables**: Note that `AGENTMAIL_API_KEY` must be hardcoded in the `config.yaml` or provided by the shell environment where Hermes is launched; the MCP configuration does not automatically expand `.env` files from the skill directory.\n\n## Error Handling\nThe MCP server returns standard JSON-RPC error codes. Common failures include:\n- `401 Unauthorized`: Invalid or missing `AGENTMAIL_API_KEY`.\n- `404 Not Found`: Attempting to access an `inbox_id` or `thread_id` that has been deleted.\n- `429 Too Many Requests`: Exceeding the AgentMail plan limits.","optional-skills-health":"# optional-skills — health\n\n# optional-skills — health\n\nThe **health** module provides a suite of tools for physical fitness, nutrition tracking, and real-time biometric monitoring via Brain-Computer Interface (BCI) wearables. It is divided into two primary sub-modules: `fitness-nutrition` and `neuroskill-bci`.\n\n## 1. Fitness & Nutrition\n\nThis sub-module provides exercise lookups, nutritional data retrieval, and scientific body composition calculators.\n\n### Data Sources\n- **wger API**: An open-source database for exercises.\n - *Usage Note*: Always include `language=2` (English) and `status=2` (verified) in queries.\n - *Endpoints*: `/api/v2/exercise/`, `/api/v2/exerciseinfo/{id}/`, `/api/v2/exercise/search/`.\n- **USDA FoodData Central**: Provides macro and micronutrient data for over 380,000 foods.\n - *Authentication*: Uses `USDA_API_KEY`. Defaults to `DEMO_KEY` (30 req/hr).\n - *Data Mapping*: Results are standardized to **per 100g** portions.\n\n### Core Scripts\n#### `body_calc.py`\nA standalone utility for physiological computations using validated formulas.\n- `bmi(weight_kg, height_cm)`: Standard Quetelet index.\n- `tdee(weight_kg, height_cm, age, sex, activity)`: Uses the **Mifflin-St Jeor** equation.\n- `one_rep_max(weight, reps)`: Returns an average of **Epley**, **Brzycki**, and **Lombardi** formulas.\n- `macros(tdee_kcal, goal)`: Calculates P/F/C splits based on `cut`, `maintain`, or `bulk` targets.\n- `bodyfat(sex, neck, waist, hip, height)`: Implements the **US Navy circumference method**.\n\n#### `nutrition_search.py`\nHandles asynchronous-style lookups to the USDA API.\n- `search(query, max_results)`: Queries the `Foundation` and `SR Legacy` data types.\n- `display(food)`: Parses the `foodNutrients` array to extract Energy, Protein, Fat, and Carbohydrates.\n\n---\n\n## 2. NeuroSkill BCI Integration\n\nThe `neuroskill-bci` sub-module integrates real-time EEG and PPG data from wearables (Muse 2/S, OpenBCI) into the agent's context. It relies on the **NeuroSkill** desktop application running a local server.\n\n### Architecture\nThe module communicates with the NeuroSkill server via a CLI wrapper (`npx neuroskill`) or direct HTTP/WebSocket requests to port **8375**.\n\n```mermaid\ngraph TD\n A[BCI Wearable] -- BLE --> B[NeuroSkill App]\n B -- Port 8375 --> C[NeuroSkill CLI]\n C -- --json --> D[Hermes Health Module]\n D -- Context --> E[Developer/User]\n```\n\n### Key Metrics & Interpretation\nData is retrieved primarily via `npx neuroskill status --json`. Key fields in the `scores` object include:\n\n| Metric | Logic | Threshold for Action |\n| :--- | :--- | :--- |\n| `focus` | $\\beta / (\\alpha + \\theta)$ | Suggest break if < 0.40 |\n| `relaxation` | $\\alpha / (\\beta + \\theta)$ | Suggest protocol if < 0.30 |\n| `cognitive_load` | Frontal $\\theta$ / Temporal $\\alpha$ | High load (> 0.70) suggests \"Mind Dump\" |\n| `tbr` | Theta/Beta Ratio | Elevated (> 1.5) indicates mental fatigue |\n| `faa` | Frontal Alpha Asymmetry | Negative values indicate withdrawal/low mood |\n\n### Guided Protocols\nThe module includes a library of ~70 protocols in `references/protocols.md`. These are interventions triggered by specific biometric states:\n- **Theta-Beta Anchor**: Triggered by high `tbr` to suppress theta and lift beta.\n- **Physiological Sigh**: Triggered by acute stress spikes (high `BAR` or `stress_index`).\n- **FAA Rebalancing**: Triggered by negative `faa` to shift toward positive affect.\n\n### Historical Analysis\n- **Similarity Search**: Uses `npx neuroskill search` to find neurally similar moments in history using 128-D ZUNA embeddings.\n- **Sleep Staging**: `npx neuroskill sleep` provides epoch-by-epoch staging (Wake, N1, N2, N3, REM) based on AASM heuristics.\n- **Comparison**: `npx neuroskill compare` calculates deltas between sessions for ~50 metrics.\n\n## Developer Integration Patterns\n\n### Biometric-Aware Responses\nWhen building features that react to user state, follow this execution flow:\n1. **Check Signal**: Verify `signal_quality` for all electrodes is $\\ge 0.7$.\n2. **Fetch Scores**: Execute `npx neuroskill status --json`.\n3. **Analyze Trends**: Use `npx neuroskill session 0` to determine if metrics (like focus) are trending \"up\" or \"down\".\n4. **Apply Protocol**: If a threshold is crossed, reference `protocols.md` to suggest a specific intervention.\n\n### Nutrition & Fitness Workflows\n1. **Search**: Use `nutrition_search.py` to find FDC IDs.\n2. **Calculate**: Pass TDEE results from `body_calc.py` into the `macros` function to generate a meal plan.\n3. **Exercise**: Query `wger` using specific `muscle` or `equipment` IDs (e.g., ID 1 for Barbell, ID 10 for Quads) to build routines.\n\n### Error Handling\n- **Port Discovery**: If the default port 8375 fails, the CLI attempts auto-discovery via mDNS.\n- **Rate Limiting**: `nutrition_search.py` implements a 1-second sleep between batch queries to respect USDA `DEMO_KEY` limits.\n- **Validation**: `body_calc.py` validates that `waist > neck` for male body fat calculations to prevent `math domain` errors.","optional-skills-mcp":"# optional-skills — mcp\n\n# MCP (Model Context Protocol) Module\n\nThe `mcp` module provides a comprehensive toolkit for building, testing, and managing Model Context Protocol (MCP) servers. It is divided into two primary sub-modules: **FastMCP** for Python-based server development and **mcporter** for CLI-based server interaction and management.\n\n## Module Architecture\n\nThe module facilitates the lifecycle of an MCP server from initial scaffolding to deployment and client integration.\n\n```mermaid\ngraph TD\n Developer -->|scaffold_fastmcp.py| Templates\n Templates -->|Implement| FastMCP_Server[FastMCP Server]\n FastMCP_Server -->|fastmcp inspect| Validation\n Validation -->|fastmcp install| MCP_Clients[Claude/Cursor/etc]\n MCP_Clients -->|stdio/HTTP| FastMCP_Server\n Developer -->|mcporter| FastMCP_Server\n```\n\n---\n\n## FastMCP: Server Development\n\nFastMCP is the primary framework for creating new MCP servers in Python. It simplifies the exposure of tools, resources, and prompts.\n\n### Scaffolding and Templates\nThe `scripts/scaffold_fastmcp.py` utility automates server creation by populating templates and replacing the `__SERVER_NAME__` placeholder.\n\n**Usage:**\n```bash\npython scripts/scaffold_fastmcp.py --template api_wrapper --name \"MyAPI\" --output ./my_server.py\n```\n\nAvailable templates include:\n- `api_wrapper.py`: A REST API integration using `httpx`. It centralizes logic in `_request` and `_headers` to handle authentication and timeouts.\n- `database_server.py`: A read-only SQLite interface. It uses `_reject_mutation` to enforce safety by blocking non-`SELECT` queries and `_validate_table_name` to prevent injection.\n- `file_processor.py`: A utility for inspecting local files. It uses a shared `_read_text` helper to handle encoding and file-not-found errors.\n\n### Core Decorators\nFastMCP servers are built using three primary decorators:\n1. **`@mcp.tool`**: Defines executable functions.\n - *Example:* `summarize_text_file(path: str)` in the file processor template.\n2. **`@mcp.resource`**: Exposes stable, read-only data via URIs.\n - *Example:* `read_file_resource` uses the URI pattern `file://{path}`.\n3. **`@mcp.prompt`**: Provides reusable LLM instruction templates.\n\n### Validation and Testing\nBefore deployment, servers should be validated using the FastMCP CLI:\n- **Inspection**: `fastmcp inspect server.py:mcp` verifies the server object and its capabilities.\n- **Local Execution**: `fastmcp run server.py:mcp` starts a stdio session.\n- **Direct Calling**: `fastmcp call server.py tool_name arg=value` tests specific tool logic without a full client.\n\n---\n\n## mcporter: Client and Management\n\n`mcporter` is a Node-based CLI tool used to interact with existing MCP servers, whether they are local stdio servers or remote HTTP endpoints.\n\n### Key Capabilities\n- **Discovery**: `mcporter list` identifies servers configured in Claude Desktop, Cursor, and other local clients.\n- **Ad-hoc Interaction**: Connect to servers without permanent configuration:\n - HTTP: `mcporter list --http-url <url>`\n - Stdio: `mcporter list --stdio \"npx @modelcontextprotocol/server-filesystem\"`\n- **Tool Execution**: Supports multiple argument formats:\n - Key=Value: `mcporter call server.tool key=value`\n - JSON: `mcporter call server.tool --args '{\"key\": \"value\"}'`\n- **Code Generation**: `mcporter generate-cli` creates standalone CLI wrappers for specific MCP servers, while `mcporter emit-ts` generates TypeScript clients and types.\n\n### Authentication and Persistence\nFor servers requiring OAuth, `mcporter auth <server>` initiates the browser-based flow. For persistent background connections, the `mcporter daemon` commands manage a long-running process that keeps server connections active.\n\n---\n\n## Deployment Patterns\n\n### HTTP Transport\nWhile MCP often defaults to stdio, FastMCP supports HTTP transport for remote deployment:\n```bash\nfastmcp run server.py:mcp --transport http --host 0.0.0.0 --port 8000\n```\n\n### Client Integration\nThe `fastmcp install` command automates the registration of servers into specific environments:\n- `claude-code`: Installs for the Claude CLI.\n- `claude-desktop`: Updates the `claude_desktop_config.json`.\n- `cursor`: Configures the server for the Cursor editor.\n\n### Quality Checklist\nA production-ready MCP server within this module must:\n1. Pass `fastmcp inspect`.\n2. Return structured, JSON-serializable data.\n3. Handle environment variables for sensitive data (e.g., `API_TOKEN` in `api_wrapper.py`).\n4. Implement input validation (e.g., `_validate_table_name` in `database_server.py`).","optional-skills-migration":"# optional-skills — migration\n\n# Optional Skills — Migration\n\nThe `optional-skills/migration` module provides workflows for importing user state, personas, and configurations from external agent systems into Hermes. The primary implementation is the **OpenClaw Migration** skill, which facilitates the transition from OpenClaw/ClawdBot environments to Hermes.\n\n## OpenClaw Migration Skill\n\nThis skill encapsulates the logic required to transform an OpenClaw footprint (typically located in `~/.openclaw`) into a Hermes-compatible structure. It handles file transformation, memory merging, and credential migration.\n\n### Core Components\n\n- **`SKILL.md`**: Defines the agentic interface, CLI commands, and user interaction protocols. It instructs the agent on how to use the `clarify` tool for interactive conflict resolution.\n- **`scripts/openclaw_to_hermes.py`**: The execution engine. It contains the `Migrator` class which performs the heavy lifting of file I/O, text transformation, and report generation.\n\n### The Migrator Engine\n\nThe `Migrator` class is the central coordinator for the migration process. It manages the source/target paths, execution state, and the collection of migration results.\n\n#### Key Data Structures\n\n- **`ItemResult`**: A dataclass that tracks the status of every individual item (file, setting, or memory entry) processed during the run.\n- **`MIGRATION_OPTION_METADATA`**: A registry of all migratable categories (e.g., `soul`, `memory`, `mcp-servers`).\n- **`MIGRATION_PRESETS`**: Predefined groups of options, such as `user-data` (safe) and `full` (includes secrets).\n\n#### Execution Flow\n\nThe migration follows a strict pipeline to ensure data integrity and prevent partial configuration corruption:\n\n```mermaid\ngraph TD\n A[Initialize Migrator] --> B[Discovery: source_candidate]\n B --> C[Selection Filter: run_if_selected]\n C --> D[Transformation: rebrand_text / merge_entries]\n D --> E[Conflict Resolution: skip/overwrite/rename]\n E --> F[Persistence: dump_yaml_file / save_env_file]\n F --> G[Reporting: write_report + Redaction]\n```\n\n### Data Transformation Logic\n\n#### 1. Brand Rewriting\nThe `rebrand_text` function uses case-preserving regex patterns to replace \"OpenClaw\", \"ClawdBot\", and \"MoltBot\" with \"Hermes\". This ensures that imported `SOUL.md` and memory files reflect the new agent identity while maintaining valid lowercase filesystem paths.\n\n#### 2. Memory Merging\nThe `merge_entries` function handles the transition of `MEMORY.md` and `USER.md`. \n- It parses existing Hermes memories and incoming OpenClaw entries.\n- It deduplicates entries based on normalized text.\n- It respects `memory_char_limit` and `user_char_limit` from the Hermes `config.yaml`.\n- Overflowing entries are diverted to an `overflow/` directory within the migration output for manual review.\n\n#### 3. Configuration Mutation\nThe script modifies `config.yaml` and `.env`. To prevent leaving the system in an inconsistent state, the `_config_apply_blocked` flag is triggered if any YAML write encounters a conflict or error. Subsequent config-mutating options are automatically skipped during that run.\n\n### Safety and Security\n\n#### Secret Redaction\nMigration reports often contain sensitive data. The `redact_migration_value` function recursively scans the migration report before it is written to disk. It:\n- Replaces values for keys matching `_SECRET_KEY_MARKERS` (e.g., `apikey`, `password`).\n- Uses regex (`_SECRET_VALUE_PATTERNS`) to find and redact strings matching common token formats (e.g., `sk-...`, `xoxb-...`, `Bearer ...`).\n\n#### Dry-Run Mode\nBy default, the `Migrator` runs in dry-run mode (`execute=False`). It populates the `ItemResult` list with `STATUS_PLANNED` or `STATUS_MIGRATED` (with a \"Would copy\" reason) to allow users to preview changes before any files are modified.\n\n### Skill Integration Patterns\n\nWhen the Hermes Agent invokes this skill, it follows a specific protocol:\n1. **Discovery**: Run a dry run to identify conflicts (e.g., existing `SOUL.md`).\n2. **Clarification**: Use the `clarify` tool to resolve specific blocking decisions (e.g., `skill-conflict` policy).\n3. **Execution**: Call the script with the `--execute` flag and the user-selected parameters.\n4. **Reporting**: Parse the `report.json` generated in the migration output directory to provide a final summary to the user.\n\n### CLI Usage\n\nThe script can be executed directly for manual migrations:\n\n```bash\n# Preview migration of user data\npython3 openclaw_to_hermes.py --preset user-data\n\n# Execute full migration including secrets, overwriting conflicts\npython3 openclaw_to_hermes.py --execute --preset full --migrate-secrets --overwrite\n```\n\n### Path Resolution Fallbacks\nThe `source_candidate` method implements a robust search strategy for OpenClaw data, checking:\n1. Standard `workspace/` paths.\n2. Legacy `workspace.default/` paths.\n3. Renamed `workspace-main/` or `workspace-assistant/` paths.\n4. Custom workspace paths defined in the source `openclaw.json` under `agents.defaults.workspace`.","optional-skills-mlops":"# optional-skills — mlops\n\n# MLOps Optional Skills Module\n\nThe **MLOps Optional Skills** module provides a curated set of high-performance tools for distributed training, vector search, multimodal intelligence, and constrained LLM generation. These modules are designed to be integrated into production machine learning pipelines to improve scalability, efficiency, and output reliability.\n\n## Module Overview\n\nThe toolkit is divided into four functional areas:\n1. **Distributed Training**: `accelerate`\n2. **Vector Databases & Search**: `chroma`, `faiss`\n3. **Multimodal Intelligence**: `clip`\n4. **Inference Optimization**: `flash-attention`, `guidance`\n\n```mermaid\ngraph TD\n A[Data Input] --> B[CLIP: Embeddings]\n B --> C{Storage}\n C --> D[Chroma: Metadata/RAG]\n C --> E[FAISS: Billion-scale Search]\n F[Training Script] --> G[Accelerate: Distributed]\n G --> H[Flash Attention: Memory Opt]\n I[LLM Inference] --> J[Guidance: Structured Output]\n```\n\n---\n\n## Distributed Training: HuggingFace Accelerate\n\nThe `accelerate` module provides a unified API for launching PyTorch scripts across any hardware configuration (Single GPU, Multi-GPU, TPU, or Multi-node) with minimal code changes.\n\n### Core API: The `Accelerator` Class\nThe primary entry point is the `Accelerator` object, which manages device placement and gradient scaling.\n\n```python\nfrom accelerate import Accelerator\n\naccelerator = Accelerator()\n\n# Automatic device placement and sharding\nmodel, optimizer, dataloader = accelerator.prepare(model, optimizer, dataloader)\n\n# Distributed backward pass\naccelerator.backward(loss)\n```\n\n### Key Features\n* **Mixed Precision**: Supports `fp16`, `bf16`, and `fp8` (H100+) via the `mixed_precision` argument.\n* **Gradient Accumulation**: Managed via `accelerator.accumulate(model)` context manager to handle synchronization across micro-batches.\n* **DeepSpeed/FSDP Integration**: Supports ZeRO-2/3 and Fully Sharded Data Parallelism through `DeepSpeedPlugin` and `FullyShardedDataParallelPlugin`.\n\n---\n\n## Vector Search: Chroma & FAISS\n\nThis module provides two distinct approaches to vector similarity search: **Chroma** for metadata-heavy RAG applications and **FAISS** for high-performance, large-scale retrieval.\n\n### Chroma (AI-Native Database)\nBest for local development and applications requiring complex metadata filtering.\n* **Persistence**: Use `chromadb.PersistentClient(path=\"./db\")` for on-disk storage.\n* **Filtering**: Supports MongoDB-style queries (e.g., `where={\"category\": {\"$eq\": \"tutorial\"}}`).\n* **Embedding Functions**: Built-in support for OpenAI, HuggingFace, and Sentence Transformers.\n\n### FAISS (Billion-Scale Search)\nBest for pure similarity search where speed and memory efficiency are the primary constraints.\n* **Index Types**:\n * `IndexFlatL2`: Exact search (baseline).\n * `IndexIVFFlat`: Inverted file index for fast approximate search (requires `train()`).\n * `IndexHNSWFlat`: Graph-based search for the best speed/accuracy trade-off.\n* **Quantization**: `IndexPQ` (Product Quantization) reduces memory usage by up to 32x.\n\n---\n\n## Multimodal Intelligence: CLIP\n\nThe `clip` module enables zero-shot image classification and cross-modal retrieval by connecting vision and language in a shared embedding space.\n\n### Key Functions\n* **`model.encode_image(image)`**: Generates a visual embedding from a preprocessed PIL image.\n* **`model.encode_text(text)`**: Generates a semantic embedding from tokenized text.\n* **Zero-Shot Classification**: By comparing image embeddings against a list of candidate text embeddings using cosine similarity.\n\n```python\n# Normalize for cosine similarity\nimage_features /= image_features.norm(dim=-1, keepdim=True)\ntext_features /= text_features.norm(dim=-1, keepdim=True)\nsimilarity = (image_features @ text_features.T)\n```\n\n---\n\n## Inference Optimization\n\n### Flash Attention\nOptimizes the transformer attention mechanism by reducing memory complexity from $O(N^2)$ to $O(N)$.\n\n* **Native Support**: PyTorch 2.2+ uses `F.scaled_dot_product_attention` (SDPA) to automatically trigger Flash Attention kernels.\n* **Advanced Features**: The `flash_attn_func` supports Multi-Query Attention (MQA), Sliding Window Attention, and FP8 precision on Hopper (H100) architectures.\n* **Performance**: Typically yields a 2-4x speedup for sequences longer than 512 tokens.\n\n### Guidance (Constrained Generation)\nEnsures LLM outputs adhere to specific formats (JSON, Regex, or Grammars) to prevent parsing errors in production.\n\n* **Token Healing**: Automatically fixes token boundary issues at the prompt/generation interface.\n* **Context Managers**: Uses `system()`, `user()`, and `assistant()` blocks to manage chat state.\n* **Constraints**:\n * `select([...])`: Forces the model to choose from a specific list.\n * `gen(regex=...)`: Enforces strict pattern matching (e.g., emails, dates).\n\n```python\nfrom guidance import models, gen, select\n\nlm = models.OpenAI(\"gpt-4\")\nlm += \"Sentiment: \" + select([\"positive\", \"negative\"], name=\"sentiment\")\nlm += \"\\nConfidence: \" + gen(regex=r\"[0-9]+\", name=\"score\") + \"%\"\n```\n\n---\n\n## Hardware & Performance Guidelines\n\n| Skill | Hardware Requirement | Primary Benefit |\n| :--- | :--- | :--- |\n| **Accelerate** | Multi-GPU / TPU | Distributed scaling with 4 lines of code. |\n| **FAISS** | CPU or GPU (CUDA) | Sub-millisecond search over millions of vectors. |\n| **Flash Attention** | Ampere+ (A100/A10/H100) | 10-20x memory reduction for long sequences. |\n| **Guidance** | API or Local (Llama.cpp) | 100% valid JSON/Structured output guarantee. |\n| **CLIP** | GPU Recommended | Zero-shot visual understanding without labels. |","optional-skills-optional-skills":"# optional-skills — optional-skills\n\n# Optional Skills Registry\n\nThe `optional-skills` module serves as a curated repository for official Hermes skills that are maintained by Nous Research but excluded from the default installation. This directory acts as a \"Skills Hub\" source, allowing the agent to remain lightweight while providing a path for users to opt-in to specialized functionality.\n\n## Purpose and Design Philosophy\n\nSkills in this module are categorized as \"Official\" but are kept optional for three primary reasons:\n\n1. **Dependency Management:** Skills requiring heavy third-party libraries or complex system-level setup.\n2. **Niche Utility:** Specialized tools (e.g., specific paid API integrations) that are not universally applicable.\n3. **Stability Tiers:** Experimental features that are functional but have not yet met the criteria for the core skill set.\n\n## Skill Lifecycle\n\nOptional skills reside within the `hermes-agent` source tree but are not active until explicitly moved to the user's local environment.\n\n```mermaid\ngraph LR\n A[optional-skills/ directory] -->|hermes skills install| B[~/.hermes/skills/]\n B --> C[Active Agent Runtime]\n subgraph \"Repository Source\"\n A\n end\n subgraph \"User Environment\"\n B\n C\n end\n```\n\n### Discovery\nThe Hermes CLI interacts with this module to facilitate discovery. When a user runs `hermes skills browse`, the CLI scans this directory and labels entries as `official`.\n\n* **Browse all:** `hermes skills browse`\n* **Filter by source:** `hermes skills browse --source official`\n* **Search:** `hermes skills search <query>`\n\n### Installation\nThe installation process is a filesystem operation managed by the CLI. Running `hermes skills install <identifier>` performs the following:\n1. Locates the skill directory within `optional-skills/`.\n2. Copies the skill assets to `~/.hermes/skills/`.\n3. Triggers the agent's skill discovery mechanism to load the new capabilities.\n\n## Directory Structure\n\nEach subdirectory within `optional-skills/` represents a standalone skill. To be compatible with the registry, a skill must follow the standard Hermes skill structure:\n\n```text\noptional-skills/\n└── <skill-identifier>/\n ├── skill.yaml # Metadata, permissions, and configuration\n ├── main.py # Entry point and logic\n └── requirements.txt # Dependencies (installed during 'hermes skills install')\n```\n\n## Contributing an Optional Skill\n\nWhen developing a new skill for the `hermes-agent` repository, place it in `optional-skills/` if it meets any of the \"optionality\" criteria mentioned above. \n\n### Requirements for Inclusion\n* **Metadata:** The `skill.yaml` must be fully populated with a clear description and versioning.\n* **Isolation:** The skill must not have hard dependencies on other optional skills.\n* **Documentation:** A `README.md` within the skill's subdirectory explaining any required API keys or environment variables.\n\nBy placing a skill here, you ensure it is discoverable via the `hermes skills` command suite while preventing \"dependency bloat\" for users who do not require the specific functionality.","optional-skills-productivity":"# optional-skills — productivity\n\n# Optional Skills — Productivity Module\n\nThe **productivity** module is a collection of specialized skills designed to extend the agent's capabilities into external platforms, learning systems, and communication infrastructure. These skills are primarily implemented as CLI wrappers (Python and Bash) that interface with REST and GraphQL APIs.\n\n## Module Overview\n\nThe module consists of six primary integrations:\n- **Canvas LMS**: Academic course and assignment management.\n- **here.now**: Static site deployment and private cloud storage (Drives).\n- **Memento Flashcards**: A local spaced-repetition system (SRS) with YouTube integration.\n- **Shopify**: E-commerce management via GraphQL Admin APIs.\n- **SiYuan**: Interaction with self-hosted knowledge bases.\n- **Telephony**: SMS, MMS, and AI-driven voice calling via Twilio, Bland.ai, and Vapi.\n\n## Architecture & Data Flow\n\nMost skills follow a \"Sidecar CLI\" pattern: the agent invokes a script located in the skill's `scripts/` directory, which handles authentication, network I/O, and data normalization.\n\n```mermaid\ngraph TD\n Agent[Hermes Agent] -->|CLI Call| Scripts[Skill Scripts]\n Scripts -->|JSON/Stdout| Agent\n Scripts -->|API Requests| External[External APIs: Shopify, Twilio, Canvas]\n Scripts -->|Local I/O| Storage[Local State: .env, cards.json, state.json]\n```\n\n---\n\n## Canvas LMS (`canvas`)\n\nThe Canvas skill provides read-only access to the Canvas Learning Management System.\n\n### Core Components\n- **`scripts/canvas_api.py`**: A Python CLI using `requests`.\n- **Pagination**: Implemented in `_paginated_get()`, which follows the `Link` headers provided by the Canvas API to aggregate results up to a `max_items` limit (default 200).\n\n### Key Functions\n- `list_courses(args)`: Fetches enrolled courses. Filters by `enrollment_state` (active, invited, etc.).\n- `list_assignments(args)`: Fetches assignments for a specific `course_id`. Truncates descriptions to 500 characters to manage context window size.\n\n---\n\n## here.now (`here-now`)\n\nA deployment and storage skill for publishing static content and managing private files.\n\n### Site Publishing (`publish.sh`)\nThe publishing flow is a three-step atomic operation:\n1. **Create/Update**: Initiates a session with the API.\n2. **Upload**: Iterates through local files, calculating SHA256 hashes to skip unchanged files.\n3. **Finalize**: Commits the version to make the site live.\n\n### Drive Storage (`drive.sh`)\nProvides a filesystem-like interface for private cloud storage.\n- **`resolve_drive()`**: Maps friendly names (e.g., \"default\") to internal `drv_` IDs.\n- **`put_file()`**: Handles multipart-like uploads with ETag validation (`If-Match` or `If-None-Match`) to prevent overwriting concurrent changes.\n\n---\n\n## Memento Flashcards (`memento-flashcards`)\n\nA local Spaced Repetition System (SRS) that uses an adaptive scheduling algorithm.\n\n### Storage Logic\nData is stored in `~/.hermes/skills/productivity/memento-flashcards/data/cards.json`. The `memento_cards.py` script uses `tempfile.mkstemp` and `os.replace` to ensure atomic writes, preventing JSON corruption during updates.\n\n### Spaced Repetition Algorithm (`cmd_rate`)\nThe system tracks an `ease_streak` and updates `next_review_at` based on user ratings:\n- **Hard**: +1 day, resets streak.\n- **Good**: +3 days, resets streak.\n- **Easy**: +7 days, increments streak.\n- **Retire**: If `ease_streak >= 3` or manually triggered, the card is moved to `retired` status.\n\n### YouTube Integration (`youtube_quiz.py`)\nUses `youtube-transcript-api` to fetch video text. The agent then processes this text to generate 5 discrete Q/A pairs, which are batch-added via `cmd_add_quiz`.\n\n---\n\n## Shopify (`shopify`)\n\nA pure `curl` and `jq` implementation for interacting with Shopify's GraphQL Admin API.\n\n### Implementation Pattern\nThe skill relies on a standard GraphQL POST pattern. Developers should use the `shop_gql` bash pattern for consistency:\n```bash\ncurl -sS -X POST \"https://${SHOPIFY_STORE_DOMAIN}/admin/api/${SHOPIFY_API_VERSION}/graphql.json\" \\\n -H \"X-Shopify-Access-Token: ${SHOPIFY_ACCESS_TOKEN}\" \\\n --data \"$(jq -nc --arg q \"$QUERY\" --argjson v \"$VARS\" '{query: $q, variables: $v}')\"\n```\n\n### Key Resources\n- **Products**: Managed via `productCreate` and `productVariantsBulkCreate`.\n- **Inventory**: Uses `inventoryAdjustQuantities` for deltas and `inventorySetQuantities` for absolute values.\n- **Bulk Operations**: Supports `bulkOperationRunQuery` for large datasets, returning a JSONL file.\n\n---\n\n## SiYuan Note (`siyuan`)\n\nInterfaces with the SiYuan kernel API for block-based note management.\n\n### Block Architecture\nSiYuan treats everything as a block. The skill interacts with these via:\n- **SQL Query**: `/api/query/sql` allows complex retrieval (e.g., `SELECT * FROM blocks WHERE content LIKE '%...'`).\n- **Kramdown**: `/api/block/getBlockKramdown` retrieves content in SiYuan's specific Markdown flavor.\n- **Attributes**: Custom metadata is managed via `/api/attr/setBlockAttrs`, requiring the `custom-` prefix for user-defined keys.\n\n---\n\n## Telephony (`telephony`)\n\nA comprehensive telephony wrapper for Twilio (infrastructure) and Bland.ai/Vapi (AI Voice).\n\n### State Management\nThe skill maintains `telephony_state.json` to track:\n- **Owned Numbers**: SIDs and E.164 formatted numbers.\n- **Inbox Checkpoints**: The `last_seen_message_sid` to allow `twilio-inbox --since-last` polling without a persistent webhook server.\n\n### Execution Logic (`telephony.py`)\n- **`twilio-call`**: Supports direct TwiML generation. It can wrap text in `<Say>` tags or point to an external MP3 via `<Play>`.\n- **`ai-call`**: Routes requests to either Bland.ai or Vapi.\n - **Bland.ai**: Uses a single POST to `/v1/calls`.\n - **Vapi**: Requires a `phone_number_id`. The script includes `vapi-import-twilio` to link Twilio SIDs to the Vapi platform.\n\n### Authentication Handling\nThe script implements `_json_request` using `urllib.request` (stdlib) to ensure zero-dependency execution. It handles Basic Auth for Twilio and Bearer tokens for AI providers.\n\n---\n\n## Configuration & Environment\n\nAll skills in this module look for credentials in `~/.hermes/.env`. Key variables include:\n\n| Skill | Required Variables |\n| :--- | :--- |\n| **Canvas** | `CANVAS_API_TOKEN`, `CANVAS_BASE_URL` |\n| **here.now** | `HERENOW_API_KEY` |\n| **Shopify** | `SHOPIFY_ACCESS_TOKEN`, `SHOPIFY_STORE_DOMAIN` |\n| **SiYuan** | `SIYUAN_TOKEN`, `SIYUAN_URL` |\n| **Telephony** | `TWILIO_ACCOUNT_SID`, `TWILIO_AUTH_TOKEN`, `BLAND_API_KEY`, `VAPI_API_KEY` |","optional-skills-research":"# optional-skills — research\n\n# Research Skills Module\n\nThe `optional-skills/research` module provides a suite of specialized tools for scientific discovery, infrastructure reconnaissance, advanced web scraping, and local knowledge retrieval. Unlike core tools, these skills are domain-specific and often interface with external biological databases, OSINT sources, or local RAG (Retrieval-Augmented Generation) engines.\n\n## Module Architecture\n\nThe module is organized into functional domains, each containing a `SKILL.md` definition and supporting scripts or reference materials.\n\n```mermaid\ngraph TD\n A[Research Module] --> B[Life Sciences]\n A --> C[Infrastructure & OSINT]\n A --> D[Web & Deep Research]\n A --> E[Local Knowledge]\n \n B --> B1[Bioinformatics Gateway]\n B --> B2[Drug Discovery]\n \n C --> C1[Domain Intel]\n \n D --> D1[DuckDuckGo]\n D --> D2[Parallel CLI]\n D --> D3[Scrapling]\n \n E --> E1[QMD Local Search]\n E --> E2[GitNexus Explorer]\n```\n\n---\n\n## Life Sciences & Chemistry\n\n### Bioinformatics Gateway\nThis skill acts as a dynamic index for two major open-source repositories. It does not bundle the data but provides a standardized way to fetch expert reference material on demand.\n\n* **Sources**: \n * `bioSkills`: 385+ reference skills (code patterns, tool flags).\n * `ClawBio`: 33+ runnable pipelines (Python/Conda).\n* **Workflow**: Identify the domain (e.g., `variant-calling`), perform a shallow clone of the target repo to `/tmp`, and read the specific `SKILL.md` or `README.md` as a domain guide.\n\n### Drug Discovery\nFocused on medicinal chemistry and pharmaceutical research, utilizing the ChEMBL, PubChem, OpenFDA, and OpenTargets APIs.\n\n* **Key Scripts**:\n * `ro5_screen.py`: Performs batch Lipinski Rule of Five and Veber screening. The `main()` function orchestrates `fetch()` (PubChem API), `check()` (logic validation), and `report()` (formatting).\n * `chembl_target.py`: Maps biological targets to active compounds. `main()` calls `get()` to query the ChEMBL API for bioactivity data (pChEMBL values).\n* **Capabilities**: Bioactivity lookups, ADMET profiling, drug-drug interaction analysis, and bioisosteric replacement suggestions.\n\n---\n\n## Infrastructure & OSINT\n\n### Domain Intelligence\nA zero-dependency passive reconnaissance tool implemented in `domain_intel.py`. It uses Python's standard library (`socket`, `ssl`, `urllib`) to gather data without active port scanning.\n\n* **Core Functions**:\n * `check_ssl()`: Inspects TLS certificates. Internally calls `flat()` for RDN parsing and `parse_date()` for expiry validation.\n * `whois_lookup()`: Queries authoritative WHOIS servers on TCP port 43.\n * `dns_records()`: Resolves A, AAAA, MX, NS, and TXT records via system DNS and Google DNS-over-HTTPS.\n * `bulk_check()`: Orchestrates parallel execution of checks across multiple domains using `ThreadPoolExecutor`.\n* **Data Sources**: crt.sh (Subdomains), Google DoH (DNS), and 100+ TLD-specific WHOIS servers.\n\n---\n\n## Web & Deep Research\n\n### Scrapling\nAn advanced scraping framework that provides three distinct fetching strategies:\n1. **`Fetcher`**: Standard HTTP requests for static content.\n2. **`DynamicFetcher`**: Playwright-based JS rendering for SPAs.\n3. **`StealthyFetcher`**: Specialized browser automation to bypass Cloudflare Turnstile and anti-bot fingerprints.\n\nIt includes a `Spider` class for multi-page crawling with link-following logic and session management.\n\n### Parallel CLI\nA vendor-specific tool for \"agentic\" research. It is preferred for:\n* **Enrichment**: Researching and filling missing columns in CSV/JSON datasets.\n* **FindAll**: Large-scale entity discovery (e.g., \"Find all AI startups in London\").\n* **Deep Research**: Long-running, multi-step research jobs with async polling (`status` and `poll` commands).\n\n### DuckDuckGo Search\nA fallback search utility that requires no API keys. It prioritizes the `ddgs` CLI for environment isolation but provides a Python API for integrated workflows.\n\n---\n\n## Local Knowledge & Code Exploration\n\n### QMD (Query Markup Documents)\nA local RAG engine designed for personal notes and documentation. It implements a hybrid search pipeline:\n1. **BM25**: Keyword matching via SQLite FTS5.\n2. **Vector Search**: Semantic retrieval using `embeddinggemma-300M`.\n3. **Reranking**: LLM-based scoring via `qwen3-reranker`.\n\nQMD can run as a persistent MCP (Model Context Protocol) daemon to keep models warm in memory, reducing query latency from ~19s (cold) to ~2s (warm).\n\n### GitNexus Explorer\nIndexes codebases into a visual knowledge graph.\n* **Indexing**: `npx gitnexus analyze` generates a symbol and call graph index in `.gitnexus/`.\n* **Serving**: Uses `proxy.mjs` to bridge the GitNexus backend API (port 4747) and the production Web UI.\n* **Proxy Logic**: `proxy.mjs` implements `proxyToApi()` for backend requests and `serveStatic()` for the Vite-built frontend, enabling access through Cloudflare tunnels without CORS issues.\n\n---\n\n## Implementation Patterns\n\n### CLI vs. Python Integration\nMost modules in this suite follow a \"CLI-First\" pattern to ensure compatibility across different runtimes (Terminal vs. Code Sandbox).\n\n| Skill | Primary Interface | Script/Entrypoint |\n| :--- | :--- | :--- |\n| **Domain Intel** | CLI | `scripts/domain_intel.py` |\n| **Drug Discovery** | CLI/Python | `scripts/ro5_screen.py` |\n| **GitNexus** | CLI/Web | `scripts/proxy.mjs` |\n| **QMD** | MCP/CLI | `qmd query` |\n| **Scrapling** | Python/CLI | `scrapling extract` |\n\n### Error Handling\n* **Network**: OSINT and Pharma tools use `urllib.request` with explicit timeouts (typically 10-15s) to prevent hanging on unresponsive APIs.\n* **Auth**: Parallel CLI and Scrapling check for environment variables (`PARALLEL_API_KEY`) or local browser binaries before execution.\n* **Platform**: `domain_intel.py` is cross-platform (pure Python), while `qmd` and `gitnexus` require Node.js environments.","optional-skills-security":"# optional-skills — security\n\n# Optional Skills: Security Module\n\nThe **Security** module provides a suite of tools for secrets management, open-source supply chain forensics, and OSINT reconnaissance. It is designed to integrate external security CLI tools into the Hermes environment while maintaining strict guardrails for data integrity and credential safety.\n\n## Module Overview\n\nThe module is divided into three primary functional areas:\n1. **Secrets Management (`1password`)**: Integration with the 1Password CLI (`op`) for secure credential retrieval.\n2. **OSS Forensics (`oss-forensics`)**: A multi-phase framework for investigating repository compromises and supply chain attacks.\n3. **OSINT (`sherlock`)**: Username reconnaissance across social networks.\n\n---\n\n## 1Password CLI Integration\n\nThis sub-module manages interactions with the `op` CLI. It supports multiple authentication flows, prioritizing non-interactive methods suitable for automated environments.\n\n### Authentication Patterns\n\n| Method | Configuration | Use Case |\n| :--- | :--- | :--- |\n| **Service Account** | `OP_SERVICE_ACCOUNT_TOKEN` | Recommended for headless/CI environments. Persists across terminal calls. |\n| **Desktop App** | Biometric/App Unlock | Interactive developer use. Requires `tmux` session management. |\n| **Connect Server** | `OP_CONNECT_HOST` & `OP_CONNECT_TOKEN` | Self-hosted enterprise environments. |\n\n### Non-Interactive Session Management\nBecause Hermes terminal calls are stateless, the module utilizes a `tmux` socket strategy to maintain authentication context for the Desktop App flow. This prevents repeated biometric prompts by wrapping `op signin` and subsequent commands in a persistent session.\n\n```bash\n# Pattern for maintaining auth context\nSOCKET=\"/tmp/hermes-tmux-sockets/hermes-op.sock\"\ntmux -S \"$SOCKET\" new -d -s \"op-session\"\ntmux -S \"$SOCKET\" send-keys -t \"op-session\" -- \"eval \\\"\\$(op signin)\\\"\" Enter\n```\n\n---\n\n## OSS Forensics Framework\n\nThe `oss-forensics` sub-module implements a 7-phase investigation framework inspired by the RAPTOR system. It is designed to detect force-pushes, recovered deleted commits, and identify Indicators of Compromise (IOCs).\n\n### Investigation Phases\n1. **Initialization**: Setup of the working directory and `evidence.json` store.\n2. **IOC Extraction**: Parsing handles, SHAs, and domains from the initial report.\n3. **Parallel Collection**: Spawning specialized investigators (Local Git, GitHub API, Wayback Machine, BigQuery).\n4. **Consolidation**: Aggregating findings into the evidence store.\n5. **Hypothesis Formation**: Creating evidence-backed claims (e.g., \"Maintainer Compromise\").\n6. **Validation**: Mechanical verification of evidence IDs and cross-source consistency.\n7. **Reporting**: Generating a structured `forensic-report.md`.\n\n### Evidence Management (`evidence-store.py`)\nThe `evidence-store.py` script acts as the source of truth for an investigation. It enforces data integrity using SHA-256 hashing of evidence content.\n\n**Key Data Structures:**\n* **Evidence Types**: `git`, `gh_api`, `gh_archive`, `web_archive`, `ioc`, `analysis`.\n* **Verification States**: `unverified`, `single_source`, `multi_source_verified`.\n\n```python\n# Example: Adding evidence via CLI\npython3 evidence-store.py --store evidence.json add \\\n --source \"git fsck\" \\\n --content \"dangling commit abc123...\" \\\n --type git \\\n --verification single_source\n```\n\n### Investigator Roles\nThe framework enforces **Role Boundaries** to prevent data contamination:\n* **Local Git**: Uses `git fsck --lost-found` and `reflog` to find orphaned objects.\n* **GitHub Archive**: Queries BigQuery `githubarchive.month.*` tables to find `PushEvents` where `distinct_size = 0` (indicating a force-push).\n* **Wayback Machine**: Uses the CDX API to recover deleted Issue or PR content.\n\n---\n\n## Sherlock OSINT\n\nThe `sherlock` sub-module provides a wrapper for the Sherlock Project CLI to perform username reconnaissance.\n\n### Execution Pattern\nThe module executes `sherlock` with specific flags to ensure output is machine-readable and performant:\n* `--print-found`: Filters output to only show successful matches.\n* `--no-color`: Removes ANSI escape codes for cleaner parsing.\n* `--timeout 90`: Prevents hanging on slow social network responses.\n\n### Result Handling\nFindings are parsed from the terminal output and saved to a local `<username>.txt` file. The module categorizes these links for the user, distinguishing between social media, professional networks, and forums.\n\n---\n\n## Security Guardrails\n\nDevelopers contributing to this module must adhere to the following safety rules:\n\n1. **Evidence-First Rule**: No claim may be made in a forensic report without a corresponding `EV-XXXX` ID in the evidence store.\n2. **Secret Redaction**: Any credentials discovered (API keys, tokens) must be redacted to `[REDACTED]` in final reports.\n3. **Static Analysis Only**: Never execute code found within an investigated repository. Use `execute_code` only in sandboxed environments for static analysis or regex extraction.\n4. **BigQuery Cost Control**: All BigQuery queries must include a `--dry_run` and use `_TABLE_SUFFIX` to limit scanned data.\n\n```mermaid\ngraph TD\n A[User Request] --> B{Module Router}\n B -->|Secrets| C[1Password CLI]\n B -->|Investigation| D[OSS Forensics]\n B -->|OSINT| E[Sherlock]\n D --> F[Evidence Store]\n F --> G[Forensic Report]\n C --> H[op run/inject]\n```\n\n## Component Reference\n\n| Component | Path | Description |\n| :--- | :--- | :--- |\n| **Evidence Store** | `oss-forensics/scripts/evidence-store.py` | Python CLI for managing investigation state. |\n| **Report Template** | `oss-forensics/templates/forensic-report.md` | Standardized markdown structure for findings. |\n| **Recovery Docs** | `oss-forensics/references/recovery-techniques.md` | Guide for fetching orphaned SHAs from GitHub. |\n| **1Password Skill** | `1password/SKILL.md` | Logic for `op` CLI authentication and usage. |","optional-skills-web-development":"# optional-skills — web-development\n\n# Web Development Skills: Page Agent\n\nThe `web-development` module provides tools for embedding AI-native UX patterns directly into client-side applications. Its primary focus is **page-agent**, an in-page GUI agent that allows end-users to interact with a website using natural language.\n\nUnlike server-side automation tools (e.g., Playwright or Browserbase) that operate on a site from the outside, `page-agent` lives within the Document Object Model (DOM) of the host application. It interprets the DOM as text and executes actions like clicking, typing, and navigating based on LLM instructions.\n\n## Architecture Overview\n\n`page-agent` operates as a bridge between a natural language interface and the browser's DOM API. It does not use screenshots or multi-modal vision; instead, it relies on a text-based representation of the accessibility tree and DOM structure.\n\n```mermaid\ngraph TD\n User[User Input] --> UI[page-agent UI Panel]\n UI --> Core[@page-agent/core]\n Core --> LLM[LLM Endpoint /v1/chat]\n LLM --> Core\n Core --> Controller[@page-agent/page-controller]\n Controller --> DOM[Browser DOM]\n DOM -.-> Core\n```\n\n## Integration Patterns\n\n### 1. Production Integration (npm)\nFor production SaaS or admin tools, install the package and initialize the agent with a custom LLM proxy.\n\n```bash\nnpm install page-agent\n```\n\n**Implementation:**\n```javascript\nimport { PageAgent } from 'page-agent';\n\nconst agent = new PageAgent({\n model: 'gpt-4o-mini',\n // Point to your backend proxy to protect API keys\n baseURL: 'https://api.your-domain.com/v1/ai-proxy', \n apiKey: 'SESSION_TOKEN', \n language: 'en-US',\n});\n\n// Programmatic execution\nawait agent.execute('Find the user named \"Alice\" and click Edit');\n\n// Or display the built-in GUI\nagent.panel.show();\n```\n\n### 2. Rapid Prototyping (CDN)\nFor evaluation or internal demos, the agent can be injected via a single script tag. This uses a pre-bundled IIFE (Immediately Invoked Function Expression).\n\n```html\n<script \n src=\"https://cdn.jsdelivr.net/npm/page-agent@1.8.0/dist/iife/page-agent.demo.js\" \n crossorigin=\"true\">\n<\/script>\n```\n\n## Core Configuration Reference\n\nThe `PageAgent` constructor accepts a configuration object with the following key fields:\n\n| Field | Type | Description |\n| :--- | :--- | :--- |\n| `model` | `string` | The LLM model name (e.g., `qwen3.5-plus`, `gpt-4o`). |\n| `baseURL` | `string` | OpenAI-compatible endpoint (Ollama, OpenRouter, DashScope). |\n| `apiKey` | `string` | Authentication token for the LLM provider. |\n| `language` | `string` | UI and interaction language (default: `en-US`). |\n| `allowList` | `string[]` | Optional list of allowed domains or selectors for security. |\n\n## Monorepo Structure\n\nWhen contributing to the module or building from source, the project is organized as an npm workspace monorepo:\n\n* **`packages/page-agent`**: The main entry point including the UI panel.\n* **`packages/core`**: The orchestration logic that handles the loop between LLM responses and action execution.\n* **`packages/page-controller`**: Low-level DOM operations, element highlighting, and visual feedback.\n* **`packages/llms`**: Standardized client for communicating with OpenAI-compatible APIs.\n* **`packages/ui`**: React-based components for the floating agent panel and i18n support.\n* **`packages/extension`**: A WXT-based browser extension implementation of the agent.\n\n## Security & Production Readiness\n\n### API Key Exposure\nThe `apiKey` passed to the `PageAgent` constructor is visible in the client-side JavaScript bundle. **Never hardcode production LLM keys.**\n* **Recommended:** Create a backend endpoint that forwards requests to the LLM provider and injects the real API key server-side. Point the `baseURL` to this endpoint.\n\n### Content Security Policy (CSP)\nStrict CSP headers may block the agent from:\n1. Loading from a CDN (requires `script-src`).\n2. Connecting to the LLM endpoint (requires `connect-src`).\n3. Executing inline scripts.\nIf your site has a strict CSP, self-host the `page-agent` assets and proxy the LLM traffic through your own domain.\n\n### Data Masking\nThe agent reads the DOM to understand the page state. Use the provided hooks in the `core` package to mask sensitive user data (PII) before the DOM tree is sent to the LLM.\n\n## Development Workflow\n\nTo modify the agent or test local changes:\n\n1. **Install Dependencies:** Requires Node 22.13+ or 24+.\n ```bash\n npm ci\n ```\n2. **Environment Setup:** Create a `.env` file in the root with `LLM_BASE_URL` and `LLM_API_KEY`.\n3. **Local Demo:**\n ```bash\n npm run dev:demo\n ```\n This serves the IIFE bundle at `http://localhost:5174/page-agent.demo.js`. You can inject this into any site via the browser console for testing.","optional-skills":"# optional-skills\n\n# Optional Skills Registry\n\nThe `optional-skills` module is a curated repository of official Hermes skills maintained by Nous Research. It functions as an opt-in \"Skills Hub,\" allowing the agent to remain lightweight by excluding specialized tools, experimental features, or modules with heavy third-party dependencies from the default installation.\n\n## Module Architecture\n\nThe registry organizes capabilities into functional domains that extend the agent's reach from local system management to specialized scientific research and autonomous external delegation.\n\n```mermaid\ngraph TD\n Hermes[Hermes Core] --> Registry[Optional Skills Registry]\n \n Registry --> Foundation[Foundation & Lifecycle]\n Registry --> Specialized[Domain Specific]\n Registry --> Interface[Interface & Automation]\n\n Foundation --> migration[Migration]\n Foundation --> security[Security]\n Foundation --> mcp[MCP]\n Foundation --> dogfood[Dogfood]\n\n Specialized --> health[Health]\n Specialized --> research[Research]\n Specialized --> blockchain[Blockchain]\n Specialized --> mlops[MLOps]\n\n Interface --> comms[Communication]\n Interface --> email[Email]\n Interface --> creative[Creative]\n Interface --> devops[DevOps]\n Interface --> agents[Autonomous Agents]\n```\n\n## Functional Groups\n\n### Foundation & Lifecycle\nThese modules manage the agent's environment, security, and evolution.\n* **[Migration](migration.md):** Facilitates the transition from external systems like OpenClaw into the Hermes ecosystem.\n* **[Security](security.md):** Provides secrets management via **1Password** and supply chain forensics to ensure the integrity of the agent's workspace.\n* **[MCP](mcp.md):** The backbone for extending agent capabilities using the Model Context Protocol, featuring **FastMCP** for server development.\n* **[Dogfood](dogfood.md):** Advanced QA workflows, such as **Adversarial UX Testing**, to identify friction in the agent's own implementations.\n\n### Infrastructure & Automation\nTools for managing code, deployments, and external AI orchestration.\n* **[DevOps](devops.md):** Orchestrates containers and AI inference via the **inference.sh CLI (`infsh`)**.\n* **[Autonomous AI Agents](autonomous-ai-agents.md):** Enables Hermes to act as an orchestrator, delegating complex coding tasks to the **Blackbox CLI** or managing long-term memory via **Honcho**.\n* **[MLOps](mlops.md):** High-performance tools for distributed training (**Accelerate**) and vector search (**Chroma**, **FAISS**).\n* **[Web Development](web-development.md):** Implements the **page-agent** for in-page GUI interaction and AI-native UX patterns.\n\n### Communication & Productivity\nExtends the agent's ability to interact with users and external platforms.\n* **[Communication](communication.md):** Implements structured frameworks like the **1-3-1 Rule** for technical decision-making.\n* **[Email](email.md):** Provides autonomous, agent-owned identities through the **AgentMail** MCP server.\n* **[Productivity](productivity.md):** A suite of integrations for **Shopify**, **Canvas LMS**, and **SiYuan** knowledge bases.\n\n### Domain-Specific Research\nSpecialized toolsets for technical and scientific fields.\n* **[Research](research.md):** Tools for bioinformatics, OSINT reconnaissance, and deep web scraping.\n* **[Blockchain](blockchain.md):** Zero-dependency CLI tools for auditing **Base** and **Solana** networks.\n* **[Health](health.md):** Integrates physical fitness tracking via **USDA/wger APIs** and real-time biometric monitoring through **NeuroSkill BCI**.\n* **[Creative](creative.md):** Programmatic control over **Blender** for 3D modeling and automated asset generation.\n\n## Cross-Module Workflows\n\nThe power of the `optional-skills` registry lies in the synergy between modules:\n* **Secure Automation:** Use **Security (1Password)** to retrieve credentials for **Productivity (Shopify)** or **DevOps (infsh)** tasks.\n* **Enhanced Memory:** Combine **Autonomous AI Agents (Honcho)** with **Research** modules to maintain persistent context across long-term scientific investigations.\n* **Full-Stack Development:** Utilize **Web Development (page-agent)** to test frontends while **DevOps** manages the backend containerization and **Creative (Blender)** generates visual assets.","overview":"# hermes-agent — Wiki\n\n# Hermes Agent ☤\n\nWelcome to the **Hermes Agent** repository. Built by [Nous Research](https://nousresearch.com), Hermes is a self-improving AI agent designed with a focus on advanced tool-calling and a unique learning loop that allows it to evolve its capabilities through experience.\n\nUnlike static agents, Hermes features a flexible toolset system and the ability to create new \"skills\" from its interactions, making it a powerful foundation for autonomous software engineering, research, and complex task orchestration.\n\n## System Architecture\n\nHermes is built on a modular architecture that decouples the \"brain\" (LLM orchestration) from the \"hands\" (tool execution) and the \"senses\" (platform interfaces).\n\n```mermaid\ngraph TD\n UI[User Interfaces: CLI / TUI / Web] --> CLI[hermes_cli]\n CLI --> Agent[Agent Core]\n Editors[External Editors: Zed] --> ACP[acp_adapter]\n ACP --> Agent\n Agent --> Tools[Tools Execution]\n Agent --> Skills[Skills Library]\n Agent --> Gateway[Gateway: Discord/Slack]\n Agent --> Cron[Cron Scheduler]\n Tools --> Env[Environments: RL/Sandboxes]\n```\n\n## Core Components\n\nThe ecosystem is organized into several functional layers:\n\n### 1. Orchestration & Logic\nThe [agent](agent.md) module serves as the central nervous system. It manages multi-provider LLM communication, enforces safety guardrails, and handles the lifecycle of agentic \"skills.\" It relies on the [Root](root.md) module for persistent state management and global configuration.\n\n### 2. Interfaces & Entry Points\nUsers primarily interact with the system through the [hermes_cli](hermes_cli.md), which handles command parsing and service orchestration. For a more immersive experience, the [ui-tui](ui-tui.md) provides a high-performance terminal interface, while the [web](web.md) module offers a React-based dashboard for monitoring sessions and configurations. Developers using editors like Zed can connect via the [acp_adapter](acp_adapter.md), which implements the Agent Communication Protocol.\n\n### 3. Execution & Capabilities\nThe [tools](tools.md) module is the execution engine that allows the agent to interact with the real world—performing web searches, executing terminal commands, or processing multimodal inputs. Higher-level logic is organized into the [skills](skills.md) module, which contains standardized methodologies for DevOps, task decomposition, and more. Specialized or heavy-dependency capabilities are maintained in the [optional-skills](optional-skills.md) registry to keep the core agent lightweight.\n\n### 4. Connectivity & Automation\nThe [gateway](gateway.md) module allows Hermes to live across different platforms (like Discord), maintaining consistent session state regardless of where the conversation happens. For recurring tasks, the [cron](cron.md) module provides a robust scheduling system to execute jobs in isolated sessions.\n\n### 5. Training & Evaluation\nHermes is designed for continuous improvement. The [environments](environments.md) module integrates the agent with reinforcement learning frameworks, allowing it to generate trajectories in isolated sandboxes. These trajectories can be processed using the [datagen-config-examples](datagen-config-examples.md) to create high-quality data for model fine-tuning.\n\n## Getting Started\n\nTo begin developing or running the agent locally:\n\n1. **Installation**: Clone the repository and run the setup scripts.\n ```bash\n npm install\n # The postinstall script will handle initial environment setup\n ```\n2. **Configuration**: Use the CLI to configure your preferred LLM providers.\n ```bash\n hermes configure\n ```\n3. **Testing**: Ensure your environment is correctly configured by running the [test suite](tests.md).\n ```bash\n pytest tests/\n ```\n\nFor detailed information on specific sub-systems, please navigate to the respective module pages linked above.","packaging":"# packaging\n\n# Packaging\n\nThe `packaging` module provides the configuration and scripts necessary to distribute Hermes Agent via system package managers. Currently, it focuses on **Homebrew** for macOS and Linux environments.\n\n## Homebrew Distribution\n\nThe Homebrew implementation is located in `packaging/homebrew/`. It utilizes a Ruby formula to automate the creation of a Python virtual environment, dependency resolution, and binary wrapping.\n\n### Formula Architecture (`hermes-agent.rb`)\n\nThe formula uses the `Language::Python::Virtualenv` mixin to ensure a clean, isolated installation that does not interfere with the system Python environment.\n\n```mermaid\ngraph TD\n A[brew install hermes-agent] --> B[Create Virtualenv in libexec]\n B --> C[Install PyPI Resources]\n C --> D[Install hermes-agent sdist]\n D --> E[Install Skills to pkgshare]\n E --> F[Generate Wrapper Scripts in bin]\n```\n\n### Key Components\n\n#### 1. Virtual Environment & Dependencies\nThe formula targets `python@3.14` and manages dependencies through two layers:\n- **System Dependencies:** `libyaml`, `certifi`, and `cryptography` are handled as Homebrew dependencies.\n- **Python Resources:** Transitive dependencies are defined via `resource` stanzas (generated by `brew update-python-resources`).\n- **Exclusions:** `certifi`, `cryptography`, and `pydantic` are explicitly ignored in the `pypi_packages` list to prevent conflicts with Homebrew-linked libraries or to handle specific versioning requirements.\n\n#### 2. Skill Management\nHermes Agent requires access to skill definitions at runtime. The formula relocates these from the source tree to the Homebrew `pkgshare` directory:\n- `skills/` -> `HOMEBREW_PREFIX/share/hermes-agent/skills`\n- `optional-skills/` -> `HOMEBREW_PREFIX/share/hermes-agent/optional-skills`\n\n#### 3. Binary Wrapping\nThe formula generates executable wrappers for `hermes`, `hermes-agent`, and `hermes-acp`. These wrappers inject environment variables that inform the application it is running in a managed context:\n\n| Variable | Purpose |\n| :--- | :--- |\n| `HERMES_BUNDLED_SKILLS` | Points the agent to the read-only skills in `pkgshare`. |\n| `HERMES_OPTIONAL_SKILLS` | Points the agent to the optional skills in `pkgshare`. |\n| `HERMES_MANAGED` | Set to `homebrew`. This disables internal self-update mechanisms. |\n\n### Runtime Behavior\nWhen `HERMES_MANAGED=homebrew` is set, the agent's internal update logic is modified. If a user attempts to run `hermes update`, the application detects the Homebrew environment and instructs the user to run `brew upgrade hermes-agent` instead.\n\n## Maintenance Workflow\n\nTo update the Homebrew package for a new release, follow these steps:\n\n1. **Identify the Asset:** Locate the semver-named source distribution (`.tar.gz`) attached to the GitHub release. Do not use the CalVer-named source code tarball automatically generated by GitHub.\n2. **Update Formula Metadata:**\n - Update the `url` to the new sdist link.\n - Update the `sha256` hash.\n - Update the `version` if necessary.\n3. **Refresh Resources:**\n Run the following command to update the Python dependency stanzas:\n ```bash\n brew update-python-resources --print-only hermes-agent\n ```\n4. **Validation:**\n - Run `brew audit --new --strict hermes-agent` to ensure compliance with Homebrew standards.\n - Run `brew test hermes-agent` to verify the version output and the \"managed\" update logic.\n\n## Design Considerations\n\n- **Voice Extra:** The `faster-whisper` dependency is excluded from the base Homebrew formula and moved to the `voice` extra. This avoids including heavy, wheel-only transitive dependencies that are difficult to build from source within the Homebrew environment.\n- **Stable vs. Bleeding Edge:** The formula is designed to track stable releases via `sdist` assets rather than tracking the `main` branch, ensuring reproducible builds for end-users.","plans":"# plans\n\n# Gemini OAuth Provider\n\nThe `plans/gemini-oauth-provider.md` defines the architecture and implementation strategy for integrating Google Gemini as a first-class provider within the Hermes ecosystem. Unlike standard API key configurations, this module implements a browser-based OAuth 2.0 flow to allow users to authenticate using their Google AI or Gemini API subscriptions.\n\n## Overview\n\nThe provider utilizes the standard Gemini API (`generativelanguage.googleapis.com/v1beta`) rather than the Cloud Code Assist API to avoid internal rate limits and account restrictions. It leverages the OpenAI SDK's `chat_completions` compatibility layer, ensuring that no new `api_mode` is required within the core agent logic.\n\n## OAuth Architecture\n\nThe implementation follows the **Authorization Code Flow with PKCE (S256)**, which is the security standard for desktop applications where client secrets cannot be fully protected.\n\n### Authentication Flow\n1. **Initiation**: The CLI triggers `start_oauth_flow()`, generating a 32-byte random verifier and a SHA-256 code challenge.\n2. **Authorization**: The system opens the user's default browser to `https://accounts.google.com/o/oauth2/v2/auth` with the required scopes:\n - `https://www.googleapis.com/auth/cloud-platform`\n - `https://www.googleapis.com/auth/userinfo.email`\n3. **Callback**: A temporary localhost server (listening on `http://localhost:8085/oauth2callback`) captures the authorization code.\n4. **Exchange**: The `exchange_code()` function sends the code and PKCE verifier to `https://oauth2.googleapis.com/token` to receive access and refresh tokens.\n\n```mermaid\nsequenceDiagram\n participant CLI as Hermes CLI\n participant OS as Browser\n participant G as Google OAuth\n participant S as Local Callback Server\n\n CLI->>CLI: Generate PKCE Verifier/Challenge\n CLI->>S: Start Listener (:8085)\n CLI->>OS: Open Auth URL\n OS->>G: User Approves Scopes\n G->>S: Redirect with Auth Code\n S->>CLI: Return Code\n CLI->>G: Exchange Code + Verifier\n G->>CLI: Access + Refresh Tokens\n CLI->>CLI: Save to ~/.hermes/gemini_oauth.json\n```\n\n## Token Lifecycle & Storage\n\nTokens are persisted locally to enable long-lived sessions without repeated browser interactions.\n\n- **Storage Path**: `~/.hermes/gemini_oauth.json`\n- **Permissions**: Restricted to `0o600` to prevent unauthorized local access.\n- **Concurrency**: Implements file locking to prevent corruption when multiple agent sessions attempt to refresh tokens simultaneously.\n- **Refresh Logic**: The `get_valid_access_token()` utility checks the `expires_at` field. If the token is within 5 minutes of expiration, it automatically triggers a `grant_type=refresh_token` POST request to the Google token endpoint.\n\n## Key Components\n\n### `agent/google_oauth.py`\nThe core logic for the OAuth lifecycle:\n- `start_oauth_flow()`: Orchestrates the browser opening and callback server.\n- `exchange_code()`: Handles the initial token swap.\n- `refresh_access_token()`: Uses the refresh token to obtain a new access token.\n- `load_credentials()` / `save_credentials()`: Manages secure I/O and file locking.\n\n### `hermes_cli/runtime_provider.py`\nThe bridge between the OAuth credentials and the API client. It retrieves a valid access token and injects it into the OpenAI SDK client configuration, targeting the Gemini base URL.\n\n## Integration Strategy\n\nThe provider is integrated across the following layers:\n\n1. **CLI Setup**: `hermes_cli/setup.py` includes a dedicated Gemini auth flow that triggers the browser-based login.\n2. **Model Catalog**: `hermes_cli/models.py` includes Gemini-specific models (e.g., `gemini-2.0-flash`, `gemini-1.5-pro`) and their respective context window limits.\n3. **Runtime Resolution**: `agent/auxiliary_client.py` and `hermes_cli/runtime_provider.py` handle the conditional logic to route requests to the Gemini endpoint when the `gemini` provider is selected.\n4. **Environment Overrides**: Supports `HERMES_GEMINI_CLIENT_ID` and `HERMES_GEMINI_CLIENT_SECRET` environment variables for developers using their own GCP projects.\n\n## Configuration\n\nThe provider configuration is stored in the standard Hermes config as `auth_type=\"oauth_google\"`. This distinguishes it from standard `api_key` providers, signaling the runtime to look for credentials in the `gemini_oauth.json` file rather than environment variables or the primary config file.","plugins-context-engine":"# plugins — context_engine\n\n# Plugins — Context Engine\n\nThe `plugins.context_engine` module provides a discovery and loading mechanism for context engine plugins. Unlike general plugins, context engines are built-in components located within the repository at `plugins/context_engine/`. They are responsible for managing, compressing, or transforming the agent's conversation context before it is sent to a Model Provider.\n\nOnly one context engine can be active at a time, determined by the `context.engine` setting in `config.yaml`. The default engine is `compressor`.\n\n## Plugin Structure\n\nEach context engine must reside in its own subdirectory within `plugins/context_engine/`.\n\n```text\nplugins/context_engine/\n├── my_engine/\n│ ├── __init__.py # Entry point\n│ ├── plugin.yaml # Metadata (optional)\n│ └── logic.py # Implementation details\n```\n\n### Metadata (`plugin.yaml`)\nThe discovery system reads `plugin.yaml` to extract descriptive information.\n```yaml\ndescription: \"A context engine that uses Long Context Memory (LCM) techniques.\"\n```\n\n## Discovery and Loading\n\nThe module provides two primary entry points for interacting with engines.\n\n### `discover_context_engines()`\nScans the filesystem for valid engine directories. For each directory, it:\n1. Checks for an `__init__.py`.\n2. Reads the `description` from `plugin.yaml`.\n3. Performs a lightweight availability check by attempting to load the engine and calling its `is_available()` method (if implemented).\n\n**Returns:** A list of tuples: `[(name, description, is_available), ...]`\n\n### `load_context_engine(name)`\nAttempts to instantiate a specific engine by name. It handles the complexities of dynamic Python imports, including:\n* Ensuring parent packages (`plugins` and `plugins.context_engine`) are registered in `sys.modules`.\n* Registering submodules within the engine's directory so that relative imports work correctly.\n* Executing the module and extracting the engine instance.\n\n## Implementation Patterns\n\nThe loader supports two patterns for defining a context engine. In both cases, the engine must eventually implement the `ContextEngine` abstract base class (ABC) defined in `agent.context_engine`.\n\n### 1. The Registration Pattern (Recommended)\nThis pattern mimics the general plugin system. The module defines a `register` function that receives a context object.\n\n```python\n# plugins/context_engine/my_engine/__init__.py\nfrom .logic import MyCustomEngine\n\ndef register(ctx):\n engine = MyCustomEngine()\n ctx.register_context_engine(engine)\n```\n\nThe loader uses an internal `_EngineCollector` to shim the `ctx` object and capture the registered engine.\n\n### 2. The Class Pattern (Fallback)\nIf no `register` function is found, the loader scans the module's top-level attributes for any class that is a subclass of `ContextEngine`. If found, it instantiates it without arguments.\n\n```python\n# plugins/context_engine/my_engine/__init__.py\nfrom agent.context_engine import ContextEngine\n\nclass MyCustomEngine(ContextEngine):\n def shrink_context(self, messages, limit):\n # Implementation\n pass\n```\n\n## Internal Execution Flow\n\nThe following diagram illustrates how `_load_engine_from_dir` processes a plugin directory to return an executable engine instance.\n\n```mermaid\ngraph TD\n A[Start Load] --> B{Module in sys.modules?}\n B -- No --> C[Setup Parent Packages]\n C --> D[Load Submodules]\n D --> E[Exec Main Module]\n E --> F{Has register?}\n B -- Yes --> F\n F -- Yes --> G[Call register with _EngineCollector]\n G --> H[Return collected engine]\n F -- No --> I{Find ContextEngine Subclass}\n I -- Found --> J[Instantiate Class]\n J --> K[Return Instance]\n I -- Not Found --> L[Return None]\n```\n\n## Error Handling\n* **Missing Engines:** If `load_context_engine` is called with a name that does not exist on disk, it logs a debug message and returns `None`.\n* **Import Failures:** If a plugin has syntax errors or missing dependencies, the loader catches the exception, logs a warning, and ensures the failed module is removed from `sys.modules` to prevent side effects.\n* **Availability:** Engines can define an `is_available()` method. If this returns `False` during discovery, the engine is marked as unavailable in the UI/CLI but can still be attempted to be loaded.","plugins-disk-cleanup":"# plugins — disk-cleanup\n\n# disk-cleanup\n\nThe `disk-cleanup` plugin provides automated lifecycle management for ephemeral files created during Hermes Agent sessions. It tracks files generated by tools like `write_file` and `terminal`, categorizes them, and applies deterministic cleanup rules to prevent disk bloat within `$HERMES_HOME`.\n\nThe module is designed to be \"zero-compliance,\" meaning the agent does not need to manually invoke cleanup tools; the behavior is wired directly into the agent's tool-call and session hooks.\n\n## Architecture and Lifecycle\n\nThe plugin integrates with the Hermes Agent via three primary entry points:\n\n1. **`post_tool_call` Hook**: Intercepts the results of `write_file`, `patch`, and `terminal`. It parses file paths and uses `guess_category()` to determine if a file should be tracked.\n2. **`on_session_end` Hook**: Triggered when a session finishes. If any files categorized as `test` were created during the session, it automatically invokes `disk_cleanup.quick()`.\n3. **Slash Command**: Provides a manual interface via `/disk-cleanup` for status reporting and deep cleaning.\n\n```mermaid\ngraph TD\n A[Tool Call: write_file/terminal] --> B[post_tool_call Hook]\n B --> C{guess_category}\n C -->|Match| D[track path in tracked.json]\n C -->|No Match| E[Ignore]\n F[Session End] --> G{New test files?}\n G -->|Yes| H[quick cleanup]\n G -->|No| I[End]\n```\n\n## File Tracking and Categorization\n\nTracking is handled by `disk_cleanup.track()`. Before a path is added to the tracking database, it must pass `is_safe_path()`.\n\n### Safety Constraints\n- **Allowed Scopes**: Strictly `$HERMES_HOME` or `/tmp/hermes-*`.\n- **Exclusions**: Rejects Windows mounts (e.g., `/mnt/c`), system directories, and internal Hermes state directories (e.g., `logs/`, `memories/`, `sessions/`, `plugins/`).\n- **Persistence**: Tracking data is stored in `$HERMES_HOME/disk-cleanup/tracked.json`.\n\n### Categories and Retention Rules\nThe `quick()` cleanup function processes files based on the following logic:\n\n| Category | Pattern / Source | Retention Policy | Cleanup Type |\n| :--- | :--- | :--- | :--- |\n| `test` | `test_*`, `*.test.py`, etc. | Delete at session end | Automatic |\n| `temp` | `tmp_*`, `cache/` | Delete after 7 days | Automatic |\n| `cron-output` | `cron/`, `cronjobs/` | Delete after 14 days | Automatic |\n| `empty-dirs` | Any empty dir in home | Delete immediately | Automatic |\n| `research` | Manual / Pattern | Keep 10 newest; prompt >30 days | Deep Only |\n| `chrome-profile`| Chrome automation | Prompt after 14 days | Deep Only |\n| `large-files` | Files > 500 MB | Always prompt | Deep Only |\n\n## Core Components\n\n### `disk_cleanup.py` (Logic Engine)\n- **`quick()`**: The primary automated cleanup function. It iterates through `tracked.json`, unlinks expired files, removes empty directories (excluding protected top-level dirs like `skills`), and updates the state file.\n- **`deep(confirm_callable)`**: An interactive cleanup mode. It performs a `quick()` pass and then identifies \"risky\" items (large files or old research) that require a confirmation callback to delete.\n- **`guess_category(path)`**: Heuristic engine that maps file names and locations to categories.\n- **`load_tracked()` / `save_tracked()`**: Handles atomic I/O for the tracking database. It uses a `.tmp` -> `.bak` -> rename pattern to prevent data loss during crashes.\n\n### `__init__.py` (Plugin Integration)\n- **`_on_post_tool_call`**: Extracts paths from tool arguments. For `terminal` calls, it tokenizes the command string and regex-scans the output to find created files.\n- **`_on_session_end`**: Manages a thread-safe set of `_recent_test_tracks`. This ensures that cleanup only triggers if the current session actually produced ephemeral test artifacts.\n\n## Manual Control (Slash Commands)\n\nDevelopers can interact with the plugin using the `/disk-cleanup` command:\n\n- `/disk-cleanup status`: Displays a breakdown of tracked files by category and lists the top 10 largest files.\n- `/disk-cleanup dry-run`: Previews which files would be deleted by `quick` vs. which would require prompts in `deep`.\n- `/disk-cleanup quick`: Manually triggers the deterministic cleanup.\n- `/disk-cleanup deep`: Runs `quick` and lists items requiring manual deletion.\n- `/disk-cleanup track <path> <category>`: Manually adds a file to the tracking system.\n- `/disk-cleanup forget <path>`: Removes a file from `tracked.json` without deleting the physical file.\n\n## Data Persistence and Logging\nAll actions are logged to `$HERMES_HOME/disk-cleanup/cleanup.log`. This log is independent of the standard agent logs to ensure auditability of filesystem changes even if session logs are rotated or cleared.","plugins-example-dashboard":"# plugins — example-dashboard\n\n# Example Dashboard Plugin\n\nThe `example-dashboard` module serves as the reference implementation for the dashboard's plugin architecture. It demonstrates how to extend the user interface via tabs and slots while providing a backend API integrated into the application's routing system.\n\n## Plugin Manifest (`manifest.json`)\n\nThe `manifest.json` file is the entry point for the plugin system. It defines how the plugin identifies itself and where it hooks into the main application.\n\n| Field | Description |\n| :--- | :--- |\n| `name` | Unique identifier for the plugin (`example`). |\n| `tab` | Defines a new top-level navigation item at `/example`, positioned after the `skills` tab. |\n| `slots` | Registers the plugin to render content in specific UI locations, such as `sessions:top`. |\n| `entry` | The compiled JavaScript bundle for the frontend (`dist/index.js`). |\n| `api` | The Python file containing the backend router (`plugin_api.py`). |\n\n## Backend API (`plugin_api.py`)\n\nThe plugin provides a backend extension using FastAPI. The dashboard plugin system automatically mounts the `router` defined in this file.\n\n### Routing and Namespacing\nAll plugin routes are namespaced to prevent collisions. The example plugin's routes are accessible under:\n`/api/plugins/example/`\n\n### Endpoints\n* **GET `/hello`**: A demonstration endpoint that returns a JSON object containing a greeting and version metadata.\n\n```python\n@router.get(\"/hello\")\nasync def hello():\n return {\"message\": \"Hello from the example plugin!\", \"plugin\": \"example\", \"version\": \"1.0.0\"}\n```\n\n## UI Integration Patterns\n\nThe plugin demonstrates two primary methods of frontend extension:\n\n1. **Full Page (Tabs)**: By defining a `tab` in the manifest, the plugin creates a dedicated route and navigation link. This is intended for standalone features.\n2. **Component Injection (Slots)**: By listing `sessions:top` in the `slots` array, the plugin signals that it provides a component to be rendered at the top of the Sessions view.\n\n```mermaid\ngraph TD\n Dashboard[Dashboard Core] -->|Loads| Manifest[manifest.json]\n Manifest -->|Registers Tab| UI[Navigation Bar]\n Manifest -->|Injects Slot| Sessions[Sessions View]\n Manifest -->|Mounts API| FastAPI[FastAPI Router]\n FastAPI -->|Serves| Hello[/api/plugins/example/hello]\n```\n\n## Development and Deployment\n\n### Frontend Entry Point\nThe `entry` field points to `dist/index.js`. This file should export the React components required for the tabs and slots defined in the manifest. The dashboard's plugin loader dynamically imports this script at runtime.\n\n### Backend Mounting\nThe dashboard's plugin manager looks for the `api` key in the manifest. It imports the `router` object from the specified file (`plugin_api.py`) and includes it in the main FastAPI application logic. Developers must ensure the `router` variable is an instance of `fastapi.APIRouter`.","plugins-google-meet":"# plugins — google_meet\n\n# google_meet Plugin\n\nThe `google_meet` plugin enables the Hermes agent to participate in Google Meet calls. It supports live transcription via caption scraping, real-time duplex audio for agent speech, and remote execution via node hosts.\n\n## Architecture\n\nThe module is designed to be \"explicit-by-design,\" meaning it only joins URLs provided by the user and does not perform automated calendar scanning or dialing.\n\n```mermaid\ngraph TD\n Agent[Hermes Agent] --> Tools[tools.py]\n Tools --> PM[process_manager.py]\n PM --> Bot[meet_bot.py Subprocess]\n Bot --> PW[Playwright/Chromium]\n PW --> Meet[meet.google.com]\n Bot --> Scraper[Caption Scraper JS]\n Scraper --> Trans[transcript.txt]\n Bot --> RT[RealtimeSpeaker Thread]\n RT --> OpenAI[OpenAI Realtime API]\n```\n\n## Core Components\n\n### 1. Bot Orchestration (`meet_bot.py`)\nThe `meet_bot.py` script runs as a standalone subprocess. It uses Playwright to automate a Chromium instance.\n- **Caption Scraping**: Instead of intercepting WebRTC audio, the bot enables Google Meet's built-in live captions and uses a `MutationObserver` (defined in `_CAPTION_OBSERVER_JS`) to scrape text from the DOM.\n- **Safety Gate**: The `_is_safe_meet_url` function enforces a regex check to ensure the bot only navigates to valid `meet.google.com` domains.\n- **State Management**: The `_BotState` class flushes internal state (e.g., `inCall`, `lobbyWaiting`, `transcriptLines`) to a `status.json` file every second.\n\n### 2. Process Lifecycle (`process_manager.py`)\nThis module manages the lifecycle of the bot subprocess.\n- **Single Instance**: It enforces a \"one active meeting\" rule. Calling `start()` while a bot is already running triggers `stop()` on the existing process.\n- **Active Tracking**: It maintains a `.active.json` file in `$HERMES_HOME/workspace/meetings/` containing the PID, meeting ID, and output directory.\n- **Cleanup**: The `stop()` function sends `SIGTERM` to the bot, waiting up to 10 seconds for a clean exit before falling back to `SIGKILL`.\n\n### 3. Audio Bridge (`audio_bridge.py`)\nFor `realtime` mode, the plugin provisions a virtual audio device to feed generated speech into Chromium's microphone input.\n- **Linux**: Uses `pactl` to create a `module-null-sink` and a `module-virtual-source`. The bot sets the `PULSE_SOURCE` environment variable so Chromium picks up the virtual mic.\n- **macOS**: Requires `BlackHole 2ch`. The module verifies installation but requires the user to manually set the system input to BlackHole to avoid unexpected system audio changes.\n\n### 4. Real-time Speech (`realtime/openai_client.py`)\nWhen `mode='realtime'` is enabled:\n- **RealtimeSession**: Establishes a WebSocket connection to OpenAI's Realtime API.\n- **PCM Pump**: The `RealtimeSpeaker` thread monitors `say_queue.jsonl`. When the agent calls `meet_say`, text is enqueued, sent to OpenAI, and the resulting PCM audio is streamed into the virtual audio device.\n- **Barge-in**: The bot monitors incoming captions. If a human speaker is detected while the bot is speaking, it calls `session.cancel_response()` to stop the agent's speech immediately.\n\n## Remote Node Execution (`node/`)\nThe plugin supports running the browser on a different machine (e.g., a user's Mac with a signed-in Google profile) while the gateway runs on a server.\n\n- **NodeServer**: A WebSocket server that wraps `process_manager.py` and executes commands locally on the node host.\n- **NodeClient**: A synchronous RPC client used by the gateway to send commands (`start_bot`, `say`, `status`) to the remote node.\n- **Protocol**: Uses a JSON-over-WebSocket envelope defined in `protocol.py`. All requests require a 32-character hex bearer token generated by the server and approved on the gateway via `hermes meet node approve`.\n\n## Data Layout\nAll meeting data is stored under `$HERMES_HOME/workspace/meetings/<meeting-id>/`:\n- `status.json`: Live telemetry (timestamps, error states, audio metrics).\n- `transcript.txt`: The accumulated meeting transcript.\n- `say_queue.jsonl`: A queue of text for the bot to speak (realtime mode only).\n- `speaker.pcm`: The raw PCM audio buffer being fed to the virtual mic.\n- `bot.log`: Combined stdout/stderr from the Playwright subprocess.\n\n## Tool Integration\nThe plugin registers five primary tools via `tools.py`:\n1. `meet_join`: Spawns the bot. Accepts `mode` (`transcribe` or `realtime`) and `node` (for remote execution).\n2. `meet_status`: Returns the current state of the bot and meeting admission status.\n3. `meet_transcript`: Reads the `transcript.txt` file, optionally returning only the `last` N lines.\n4. `meet_say`: Enqueues text for the bot to speak (requires `realtime` mode).\n5. `meet_leave`: Terminates the bot process and cleans up the active session pointer.","plugins-hermes-achievements":"# plugins — hermes-achievements\n\n# Hermes Achievements\n\nThe `hermes-achievements` module is a built-in dashboard plugin that implements a tiered achievement system. It analyzes local Hermes session history to unlock badges based on agent autonomy, debugging patterns, \"vibe coding\" behaviors, and model usage.\n\n## Architecture Overview\n\nThe plugin consists of a FastAPI backend (`plugin_api.py`) and a pre-bundled frontend. It integrates directly with the Hermes `SessionDB` to perform retrospective analysis of all user interactions.\n\n```mermaid\ngraph TD\n DB[(SessionDB)] --> API[plugin_api.py]\n API --> Engine[Achievement Engine]\n Engine --> State[(state.json)]\n Engine --> Cache[(scan_snapshot.json)]\n API --> Router[FastAPI Router]\n Router --> UI[Dashboard UI]\n```\n\n## The Achievement Engine\n\nThe engine operates by transforming raw session messages into a set of metrics, which are then evaluated against achievement definitions.\n\n### 1. Message Analysis\nThe `analyze_messages` function is the core parser. It iterates through session messages and uses regular expressions and tool-call inspection to extract:\n* **Tool Usage:** Counts for terminal, web, browser, and file tools.\n* **Error Patterns:** Detection of port conflicts (`PORT_RE`), permission denials, and stack traces.\n* **Context Signals:** Mentions of token limits, prompt caching, or rollbacks.\n* **Model Metadata:** Identification of providers (OpenRouter, Anthropic, etc.) and local vs. cloud models.\n\n### 2. Evaluation Logic\nAchievements are defined in the `ACHIEVEMENTS` list. Each definition uses one of three evaluation strategies via `evaluate_definition`:\n* **Tiered (`kind: \"best_session\"` or `\"lifetime\"`):** Uses `threshold_metric` to map progress to a ladder (Copper → Silver → Gold → Diamond → Olympian).\n* **Multi-condition (`kind: \"multi_condition\"`):** Requires multiple metrics to meet specific thresholds (e.g., \"Full Send\" requires terminal, file, and web tool usage).\n* **Boolean:** A simple check for the presence of a specific event.\n\n### 3. Achievement States\n* **Unlocked:** Requirements met; `unlocked_at` timestamp and `evidence` (the specific session) are recorded.\n* **Discovered:** Requirements not met, but the user has made progress.\n* **Secret:** Hidden from the UI until the first relevant signal is detected (e.g., `port_3000_taken`).\n\n## Scanning & Performance\n\nBecause session histories can grow to thousands of entries, the module implements a multi-layered performance strategy.\n\n### Incremental Scanning\n`scan_sessions` uses a checkpoint system (`scan_checkpoint.json`) to avoid redundant processing.\n1. **Fingerprinting:** Each session is fingerprinted using `(id, started_at, last_active, model, title)`.\n2. **Reuse:** If the fingerprint matches the checkpoint, the previously analyzed stats are reused.\n3. **Re-scan:** Only new or mutated sessions are passed to `analyze_messages`.\n\n### Background Execution\nTo prevent blocking the Dashboard UI, `evaluate_all` manages a daemon thread (`_BACKGROUND_SCAN_THREAD`):\n* **Stale-While-Revalidate:** If a cached snapshot exists but is older than `SNAPSHOT_TTL_SECONDS` (120s), the API returns the stale data immediately and triggers a background scan.\n* **Single-Flight:** A `_SCAN_LOCK` ensures only one scan runs at a time.\n* **Partial Updates:** During long scans, the engine publishes intermediate snapshots so the UI can show incremental progress.\n\n## API Reference\n\nThe backend router is mounted at `/api/plugins/hermes-achievements/`.\n\n| Endpoint | Method | Description |\n| :--- | :--- | :--- |\n| `/achievements` | `GET` | Returns the full list of achievements, counts, and scan metadata. |\n| `/scan-status` | `GET` | Returns the current state of the background scanner (`idle`, `running`, `failed`). |\n| `/recent-unlocks` | `GET` | Returns the 20 most recently earned badges. |\n| `/sessions/{id}/badges` | `GET` | Returns badges specifically earned within a single session. |\n| `/rescan` | `POST` | Forces a synchronous, full re-scan of the database. |\n| `/reset-state` | `POST` | Deletes all unlocks, snapshots, and checkpoints. |\n\n## Data Persistence\n\nAll data is stored in the Hermes home directory (typically `~/.hermes/plugins/hermes-achievements/`):\n\n* **`state.json`**: The permanent record of unlocked achievements and their timestamps. This file is preserved during plugin updates.\n* **`scan_snapshot.json`**: A cached version of the full `/achievements` response for fast subsequent loads.\n* **`scan_checkpoint.json`**: Internal mapping of session fingerprints to their calculated metrics, used for incremental scanning.\n\n## Development & Testing\n\nThe module includes a test suite in `tests/test_achievement_engine.py` that validates regex accuracy and evaluation logic without requiring a live Dashboard instance.\n\nTo run tests:\n```bash\npython3 -m unittest tests/test_achievement_engine.py -v\n```\n\nWhen adding new achievements to the `ACHIEVEMENTS` list, ensure the `id` is stable, as it serves as the key in `state.json`. Renaming an ID will cause users to lose that specific unlock progress.","plugins-image-gen":"# plugins — image_gen\n\n# Image Generation Plugins\n\nThe `plugins/image_gen` module provides a suite of backends for generating images within the Hermes ecosystem. Each plugin implements the `ImageGenProvider` interface, allowing the system to swap between different providers (OpenAI, OpenAI Codex, and xAI) while maintaining a consistent API for the agent.\n\n## Architecture Overview\n\nAll image generation plugins follow a standardized lifecycle:\n1. **Registration**: The `register(ctx)` function adds the provider to the global registry.\n2. **Availability Check**: `is_available()` verifies environment variables or OAuth tokens.\n3. **Model Resolution**: `_resolve_model()` determines the specific model tier based on environment variables, `config.yaml`, or defaults.\n4. **Generation**: `generate()` handles the API request, processes the response, and persists the image to the local cache.\n\n```mermaid\ngraph TD\n A[Agent] --> B{ImageGenProvider}\n B --> C[OpenAI Provider]\n B --> D[OpenAI Codex Provider]\n B --> E[xAI Provider]\n C & D & E --> F[Local Cache]\n F --> G[$HERMES_HOME/cache/images/]\n```\n\n---\n\n## OpenAI Provider (`openai`)\n\nThe standard OpenAI provider interfaces with the `images.generate` REST endpoint. It exposes the `gpt-image-2` model through three virtual quality tiers.\n\n### Model Tiers\n| Tier ID | Quality | Speed | Use Case |\n| :--- | :--- | :--- | :--- |\n| `gpt-image-2-low` | `low` | ~15s | Fast iteration |\n| `gpt-image-2-medium` | `medium` | ~40s | Default balanced |\n| `gpt-image-2-high` | `high` | ~2min | High fidelity |\n\n### Implementation Details\n- **Authentication**: Requires `OPENAI_API_KEY`.\n- **Response Handling**: Prefers `b64_json` from the OpenAI response. If the API returns a URL instead, it falls back to the URL reference.\n- **Persistence**: Uses `save_b64_image` to store the result as a PNG in the local cache.\n\n---\n\n## OpenAI Codex Provider (`openai-codex`)\n\nThis provider uses the ChatGPT/Codex OAuth variant. It is designed for users authenticated via `hermes auth codex`, removing the need for a standalone OpenAI API key.\n\n### Key Differences from Standard OpenAI\n- **Routing**: Instead of the `images.generate` endpoint, it routes requests through the Codex Responses API using the `image_generation` tool.\n- **Host Model**: Uses `gpt-5.4` as the host model to trigger the tool call.\n- **Authentication**: Delegates token management to `agent.auxiliary_client._read_codex_access_token`. It handles JWT decoding and credential pool selection (via `agent.credential_pool`).\n- **Streaming**: Uses `_collect_image_b64` to stream the response and extract the image data from `response.output_item.done` or `response.image_generation_call.partial_image` events.\n\n---\n\n## xAI Provider (`xai`)\n\nThe xAI provider interfaces with the `grok-imagine-image` model. It offers more granular control over aspect ratios and resolutions compared to the OpenAI-based providers.\n\n### Configuration\n- **Resolution**: Supports `1k` (1024px) and `2k` (2048px), configurable via `image_gen.xai.resolution`.\n- **Aspect Ratios**: Maps internal Hermes ratios to xAI-specific strings (e.g., `landscape` -> `16:9`, `portrait` -> `9:16`).\n- **User Agent**: Uses `tools.xai_http.hermes_xai_user_agent()` for identification.\n\n### Implementation Details\n- **Authentication**: Requires `XAI_API_KEY`.\n- **HTTP Client**: Uses the `requests` library with a 120s timeout to handle high-resolution generation.\n\n---\n\n## Common Logic and Utilities\n\n### Model Selection Precedence\nAll providers implement a `_resolve_model()` helper that follows this priority:\n1. **Environment Variable**: (e.g., `OPENAI_IMAGE_MODEL` or `XAI_IMAGE_MODEL`).\n2. **Provider-Specific Config**: `image_gen.<provider>.model` in `config.yaml`.\n3. **Global Config**: `image_gen.model` in `config.yaml`.\n4. **Default**: Hardcoded `DEFAULT_MODEL` (usually the \"medium\" tier).\n\n### Image Persistence\nImages are saved using `agent.image_gen_provider.save_b64_image`. \n- **Path**: `$HERMES_HOME/cache/images/`\n- **Format**: PNG\n- **Naming**: Prefixed by the provider and model ID (e.g., `openai_codex_gpt-image-2-medium_...png`).\n\n### Error Handling\nProviders use `error_response` to return standardized error dictionaries. Common `error_type` values include:\n- `auth_required`: Missing API keys or expired OAuth tokens.\n- `invalid_argument`: Empty prompts or unsupported aspect ratios.\n- `api_error`: Non-200 responses from the upstream provider.\n- `io_error`: Failures during image caching.","plugins-kanban":"# plugins — kanban\n\n# Kanban Plugin\n\nThe Kanban module provides a multi-agent collaboration board for the Hermes dashboard. It allows users to manage tasks through a drag-and-drop interface, track agent execution in real-time, and manage task dependencies and comments.\n\nThe module consists of a FastAPI backend (`plugin_api.py`) that wraps the core `hermes_cli.kanban_db` logic, providing a REST and WebSocket interface for the dashboard frontend.\n\n## Architecture Overview\n\nThe Kanban system operates as a thin API layer over a shared SQLite database. It is designed to be used by three concurrent surfaces: the CLI, the Gateway, and the Dashboard.\n\n```mermaid\ngraph TD\n Dashboard[Web Dashboard] -- REST/WS --> API[Kanban Plugin API]\n CLI[Hermes CLI] -- Direct Call --> KDB[kanban_db]\n Gateway[Hermes Gateway] -- Embedded Dispatcher --> KDB\n API --> KDB\n KDB --> SQLite[(kanban.db)]\n```\n\n### Data Persistence\nAll state is stored in `kanban.db`. The API uses `kanban_db.init_db()` to ensure the schema exists on the first request. It utilizes SQLite's WAL (Write-Ahead Logging) mode to allow the dashboard to perform reads while the dispatcher or gateway performs immediate write transactions.\n\n## Backend API\n\nThe backend is mounted at `/api/plugins/kanban/`.\n\n### Board and Task Management\n* **`GET /board`**: Returns the full state of the board. It aggregates tasks into columns (`triage`, `todo`, `ready`, `running`, `blocked`, `done`), calculates progress rollups for parent/child tasks, and provides metadata for UI filters (tenants and assignees).\n* **`GET /tasks/{task_id}`**: Fetches full task details, including comment threads, event history, run history, and link relationships.\n* **`POST /tasks`**: Creates a new task. If a task is created in the `ready` state and assigned to a profile, the API performs a \"dispatcher presence check\" to warn the user if no worker is available to pick it up.\n* **`PATCH /tasks/{task_id}`**: Updates task attributes. This endpoint handles complex state transitions:\n * **Status Changes**: Uses structured verbs like `complete_task`, `block_task`, or `archive_task`.\n * **Direct Moves**: For transitions not covered by specific verbs (e.g., `todo` to `ready`), it uses `_set_status_direct`.\n * **Run Management**: If a task is moved out of the `running` state manually via the dashboard, the API automatically closes the active run with a `reclaimed` outcome to prevent orphaned run records.\n\n### Bulk Operations\nThe `POST /tasks/bulk` endpoint allows applying status, assignee, or priority changes to multiple tasks simultaneously. It processes updates independently, returning a list of successes and failures per ID to ensure one invalid task doesn't block the entire batch.\n\n### Real-time Updates (`/events`)\nLive updates are delivered via a WebSocket at `/events`. \n* **Mechanism**: The server tails the `task_events` table using a short poll interval (300ms).\n* **Cursor-based**: Clients provide a `since` parameter (event ID) to resume the stream without missing data.\n* **Authentication**: Since browsers cannot set custom headers on WebSocket upgrade requests, authentication is handled via a `?token=` query parameter, which is compared against the dashboard's internal session token using `hmac.compare_digest`.\n\n## Task Execution & Dispatching\n\nTasks in the `ready` state are picked up by a dispatcher. \n\n1. **Gateway Integration**: By default, the dispatcher runs inside the Hermes Gateway (`kanban.dispatch_in_gateway: true`).\n2. **Manual Nudge**: The `POST /dispatch` endpoint allows the dashboard to trigger an immediate dispatch cycle, bypassing the standard 60-second poll interval.\n3. **Logs**: Worker output (stdout/stderr) is written to disk. The `GET /tasks/{task_id}/log` endpoint provides a tail of these logs, capped by a `tail` byte parameter to prevent browser memory issues.\n\n## Configuration\n\nThe plugin reads preferences from the global `~/.hermes/config.yaml` under the `dashboard.kanban` section. The `GET /config` endpoint exposes these to the frontend:\n* `default_tenant`: Pre-selects a tenant filter.\n* `lane_by_profile`: Toggles sub-grouping tasks by assignee.\n* `render_markdown`: Controls whether task bodies and comments are rendered as HTML.\n\n## Security Model\n\n* **Network Binding**: The dashboard binds to `localhost` by default. Consequently, the `/api/plugins/` routes skip standard HTTP authentication to simplify local development.\n* **Remote Access**: If the dashboard is hosted on `0.0.0.0`, these routes become public. Users must ensure network-level security (SSH tunneling or VPN) in such configurations.\n* **WebSocket Security**: Unlike the HTTP routes, the WebSocket endpoint strictly validates the session token to prevent cross-site hijacking.","plugins-memory":"# plugins — memory\n\n# Plugins — Memory\n\nThe `plugins.memory` module is the discovery and orchestration layer for Hermes Agent memory providers. It allows the system to dynamically scan, load, and switch between different long-term memory backends (e.g., Hindsight, ByteRover, Holographic) while maintaining a unified interface for the agent.\n\n## Architecture Overview\n\nThe module implements a plugin architecture where only **one** provider is active at a time, determined by the `memory.provider` setting in the global `config.yaml`.\n\n```mermaid\ngraph TD\n A[Memory Manager] --> B{Discovery}\n B --> C[Bundled: plugins/memory/*]\n B --> D[User: $HERMES_HOME/plugins/*]\n B --> E[Precedence: Bundled > User]\n E --> F[load_memory_provider]\n F --> G[MemoryProvider Instance]\n```\n\n## Plugin Discovery\n\nDiscovery is handled by `discover_memory_providers()`, which yields a list of available backends.\n\n### Search Locations\n1. **Bundled Providers:** Located in `plugins/memory/<name>/`. These are shipped with the `hermes-agent` core.\n2. **User-installed Providers:** Located in `$HERMES_HOME/plugins/<name>/`.\n\n### Discovery Heuristics\nTo avoid importing every directory in the plugin path, the module uses `_is_memory_provider_dir(path)`. This function performs a \"cheap\" text scan of the first 8KB of the plugin's `__init__.py` looking for the strings `register_memory_provider` or `MemoryProvider`.\n\n## Loading Mechanism\n\nThe `load_memory_provider(name)` function resolves a provider name to a directory and invokes `_load_provider_from_dir(path)`.\n\n### Namespace Isolation\nTo prevent collisions between bundled and user-installed plugins, the module uses distinct namespaces:\n* Bundled: `plugins.memory.<name>`\n* User: `_hermes_user_memory.<name>`\n\n### Instantiation Patterns\nThe loader supports two patterns for plugin entry points:\n1. **Registration Pattern:** The module defines a `register(ctx)` function. The loader passes a `_ProviderCollector` (a fake context) to capture the `MemoryProvider` instance via `ctx.register_memory_provider(instance)`.\n2. **Subclass Pattern:** The loader scans the module's attributes for any class that is a subclass of `agent.memory_provider.MemoryProvider` and instantiates it.\n\n### Relative Import Support\nThe loader manually registers submodules in `sys.modules` during the import process. This ensures that relative imports within a plugin (e.g., `from .store import MemoryStore`) function correctly even when the plugin is loaded from an arbitrary filesystem path outside the standard Python path.\n\n## CLI Integration\n\nMemory plugins can extend the `hermes` CLI by providing a `cli.py` file. The `discover_plugin_cli_commands()` function handles this integration.\n\n* **Active-Only:** Only the CLI commands for the currently active provider (defined in config) are loaded.\n* **Lightweight Scan:** It imports only the `cli.py` file, not the full provider module, making it safe to call during `argparse` setup.\n* **Registration:** It looks for a `register_cli(subparser)` function and a handler function (typically named `<provider>_command`).\n\n## Provider Implementations\n\nThe module includes several reference implementations of the `MemoryProvider` ABC:\n\n### Hindsight (`hindsight`)\nA sophisticated long-term memory provider featuring:\n* **Modes:** Cloud, Local Embedded (starts a background daemon), and Local External.\n* **Logic:** Uses a knowledge graph with entity resolution.\n* **Lifecycle:** Implements `on_session_switch` to handle session branching and resets without data loss.\n\n### ByteRover (`byterover`)\nA local-first memory provider that interfaces with the `brv` CLI.\n* **Storage:** Hierarchical knowledge tree.\n* **Execution:** Uses `subprocess` to run `brv query` and `brv curate`.\n* **Background Sync:** Conversation turns are curated in a background thread to avoid blocking the agent's response.\n\n### Holographic (`holographic`)\nA local SQLite-based fact store.\n* **Retrieval:** Uses HRR (Holographic Reduced Representations) for compositional retrieval.\n* **Trust Scoring:** Includes a `fact_feedback` tool to adjust the trust scores of stored facts based on their utility.\n\n## Key Functions Reference\n\n| Function | Description |\n| :--- | :--- |\n| `discover_memory_providers()` | Returns `[(name, desc, available), ...]` for all found plugins. |\n| `load_memory_provider(name)` | Returns an instantiated `MemoryProvider` or `None`. |\n| `find_provider_dir(name)` | Resolves a provider name to its `Path` on disk. |\n| `discover_plugin_cli_commands()` | Returns metadata for CLI subcommands of the active plugin. |","plugins-observability":"# plugins — observability\n\n# Langfuse Observability Plugin\n\nThe `plugins/observability/langfuse` module provides deep integration with [Langfuse](https://langfuse.com/) to trace Hermes conversations, LLM generations, and tool executions. It is designed as an **opt-in, fail-open** plugin: if the SDK is missing or credentials are not configured, the plugin remains inert without interrupting the main execution flow.\n\n## Architecture Overview\n\nThe plugin operates by subscribing to Hermes' internal hook system. It maintains a global, thread-safe state of active traces, mapping Hermes `task_id` or `session_id` to Langfuse trace objects.\n\n### Trace Lifecycle\n\nThe plugin manages three levels of Langfuse objects:\n1. **Trace (Root):** Represents a single \"turn\" or task in Hermes.\n2. **Generation:** Represents an LLM API call (input prompts, output text, and usage metadata).\n3. **Span/Tool:** Represents the execution of a specific tool.\n\n```mermaid\nsequenceDiagram\n participant H as Hermes Hooks\n participant P as Langfuse Plugin\n participant L as Langfuse API\n\n H->>P: on_pre_llm_request\n P->>L: Create Trace (\"Hermes turn\")\n P->>L: Start Generation (\"LLM call\")\n \n H->>P: on_pre_tool_call\n P->>L: Start Tool Span\n H->>P: on_post_tool_call\n P->>L: End Tool Span\n \n H->>P: on_post_llm_call\n P->>L: End Generation (Usage + Cost)\n P->>L: End Trace\n```\n\n## Key Components\n\n### State Management\nThe module uses a `TraceState` dataclass to track active observations.\n- `_TRACE_STATE`: A dictionary mapping task keys to `TraceState`.\n- `_STATE_LOCK`: A threading lock ensuring thread safety during concurrent chat sessions.\n- `_trace_key()`: Generates a unique key based on `task_id`, `session_id`, or the current thread identity.\n\n### Data Sanitization and Normalization\nTo prevent oversized payloads and protect sensitive data, the plugin passes all inputs/outputs through `_safe_value()`:\n- **Truncation:** Strings exceeding `HERMES_LANGFUSE_MAX_CHARS` (default 12,000) are truncated.\n- **Depth Limiting:** Recursive structures are limited to a depth of 4 to prevent stack overflows.\n- **JSON Parsing:** Strings that look like JSON (common in tool arguments/results) are automatically parsed into objects for better UI visualization in Langfuse.\n\n### Specialized Tool Handling\nThe plugin includes specific logic for the `read_file` tool via `_normalize_read_file_payload`. Instead of sending massive file contents to Langfuse, it:\n1. Parses the line-numbered output.\n2. Extracts a \"Head\" (first 25 lines) and \"Tail\" (last 15 lines).\n3. Reports metadata like `total_lines` and `file_size`.\n\n## Hook Implementations\n\nThe plugin registers for multiple hook variants to ensure compatibility across different Hermes versions.\n\n### LLM Tracing\n- **`on_pre_llm_request` / `on_pre_llm_call`**: Initializes the root trace if it doesn't exist and starts a new `generation` observation. It captures the serialized message history.\n- **`on_post_llm_call`**: Finalizes the generation. It extracts the assistant's response, reasoning, and tool calls. It also triggers the cost calculation logic.\n\n### Tool Tracing\n- **`on_pre_tool_call`**: Starts a `tool` type observation.\n- **`on_post_tool_call`**: Ends the observation, capturing the tool's return value and normalizing it (e.g., handling the `read_file` preview logic).\n\n## Usage and Cost Integration\n\nThe plugin integrates with the `agent.usage_pricing` module to provide accurate financial tracking.\n\nInside `_usage_and_cost()`, the plugin:\n1. Converts raw provider usage into a `CanonicalUsage` object.\n2. Maps tokens to Langfuse-specific keys (e.g., `cache_read_input_tokens`, `cache_creation_input_tokens`) so the Langfuse dashboard correctly aggregates cache savings.\n3. Calculates USD cost using `estimate_usage_cost` and `get_pricing_entry`, providing a per-type breakdown (input vs. output vs. cache) to Langfuse.\n\n## Configuration\n\nThe plugin is configured via environment variables, typically stored in `~/.hermes/.env`.\n\n| Variable | Description |\n| :--- | :--- |\n| `HERMES_LANGFUSE_PUBLIC_KEY` | Langfuse Project Public Key |\n| `HERMES_LANGFUSE_SECRET_KEY` | Langfuse Project Secret Key |\n| `HERMES_LANGFUSE_BASE_URL` | Server URL (defaults to Langfuse Cloud) |\n| `HERMES_LANGFUSE_SAMPLE_RATE` | Float 0.0-1.0 to control trace volume |\n| `HERMES_LANGFUSE_MAX_CHARS` | Max length for any single text field |\n| `HERMES_LANGFUSE_DEBUG` | Enables verbose logging for plugin troubleshooting |\n\n## Fail-Open Logic\n\nThe `_get_langfuse()` function ensures the plugin never crashes the host application:\n- It checks if the `langfuse` SDK is installed.\n- It verifies the presence of required API keys.\n- If any check fails, it sets an internal `_INIT_FAILED` sentinel and returns `None`, causing all subsequent hook calls to return immediately.","plugins-platforms":"# plugins — platforms\n\n# Plugins: Platforms\n\nThe `plugins/platforms` module contains gateway adapters that bridge the Hermes Agent with external communication networks. Each sub-module implements the `BasePlatformAdapter` interface, translating platform-specific protocols (like IRC or the Microsoft Bot Framework) into a unified `MessageEvent` format for the Hermes gateway.\n\n## Architecture Overview\n\nPlatform adapters are discovered and loaded as plugins. They handle the connection lifecycle, message serialization/deserialization, and platform-specific UI features (like Adaptive Cards in Teams or raw text splitting in IRC).\n\n```mermaid\ngraph TD\n subgraph External\n IRC[IRC Server]\n MST[MS Teams]\n end\n subgraph Plugin_Module\n IA[IRCAdapter]\n TA[TeamsAdapter]\n end\n subgraph Gateway_Core\n BPA[BasePlatformAdapter]\n HM[handle_message]\n end\n\n IRC <--> IA\n MST <--> TA\n IA -- MessageEvent --> BPA\n TA -- MessageEvent --> BPA\n BPA --> HM\n```\n\n---\n\n## IRC Platform (`plugins/platforms/irc`)\n\nThe IRC adapter provides a lightweight, zero-dependency gateway to IRC networks. It uses Python's `asyncio` and `ssl` standard libraries to implement the IRC protocol.\n\n### Key Components\n\n- **`IRCAdapter`**: The primary class managing the socket connection and protocol state.\n- **`_receive_loop`**: An asynchronous task that reads raw bytes from the server, handles PING/PONG keep-alives, and buffers lines for processing.\n- **`_handle_line`**: Dispatches parsed IRC commands. It handles registration (RPL_WELCOME), nickname collisions (ERR_NICKNAMEINUSE), and incoming messages (PRIVMSG).\n- **`_split_message`**: IRC has a strict ~512-byte line limit. This method performs binary search on UTF-8 boundaries to split long agent responses into multiple `PRIVMSG` commands without breaking characters.\n\n### Protocol Handling\n- **Markdown Stripping**: Since IRC is a plain-text protocol, `_strip_markdown` removes bold, italic, and code block syntax before transmission.\n- **Authentication**: Supports server passwords (`PASS`) and NickServ identification.\n- **Access Control**: Implements nick-based filtering via `allowed_users`. Note that IRC nicks are not inherently authenticated; for production use, this should be paired with a network that enforces NickServ registration.\n\n---\n\n## Microsoft Teams Platform (`plugins/platforms/teams`)\n\nThe Teams adapter integrates with the Microsoft Bot Framework using the `microsoft-teams-apps` SDK and `aiohttp`.\n\n### Webhook Integration\nUnlike the IRC adapter's persistent socket, Teams operates via webhooks. \n- **`_AiohttpBridgeAdapter`**: A shim that captures the SDK's route registrations and wires them into an `aiohttp.web.Application`. This allows Hermes to avoid the SDK's default dependency on FastAPI/Uvicorn.\n- **`_on_message`**: Processes incoming `Activity` objects, strips bot @mentions using regex, and handles image attachments by caching them via `cache_image_from_url`.\n\n### Interactive Features\n- **Adaptive Cards**: The adapter uses `send_exec_approval` to dispatch interactive cards for sensitive tool executions.\n- **`_on_card_action`**: Handles `Action.Execute` events. When a user clicks \"Approve\" or \"Deny\" on a card, this method invokes `resolve_gateway_approval` in the `tools.approval` module to unblock the agent's execution flow.\n- **Conversation References**: The adapter maintains a mapping of `chat_id` to `ConversationReference` in `self._conv_refs`. This allows the bot to send proactive messages and cards to the correct conversation context (Personal, Group, or Channel).\n\n---\n\n## Plugin Registration\n\nEvery platform must implement a `register(ctx)` function. This function provides the gateway with:\n\n1. **`adapter_factory`**: A lambda or function that instantiates the adapter class.\n2. **`setup_fn`**: An `interactive_setup` routine used by the `hermes gateway setup` CLI command.\n3. **`platform_hint`**: Guidance for the LLM on how to format its responses for this specific platform (e.g., \"Use plain text for IRC\").\n4. **Requirements Check**: `check_fn` and `validate_config` ensure the environment has the necessary libraries (like `aiohttp` for Teams) and credentials (like `IRC_SERVER`).\n\n### Common Configuration Pattern\nPlatforms support configuration via `config.yaml` under `gateway.platforms.<name>` or via environment variables. Environment variables always take precedence.\n\n| Platform | Required Environment Variables |\n| :--- | :--- |\n| **IRC** | `IRC_SERVER`, `IRC_CHANNEL`, `IRC_NICKNAME` |\n| **Teams** | `TEAMS_CLIENT_ID`, `TEAMS_CLIENT_SECRET`, `TEAMS_TENANT_ID` |\n\n---\n\n## Implementation Details\n\n### Message Deduplication\nThe `TeamsAdapter` utilizes `gateway.platforms.helpers.MessageDeduplicator` to prevent processing the same `activity.id` multiple times, which can occur during webhook retries.\n\n### Connection Lifecycle\n- **`connect()`**: Initializes the underlying transport (socket or webhook server). For IRC, this includes the `NICK`/`USER` handshake and waiting for `RPL_WELCOME`.\n- **`disconnect()`**: Performs a graceful shutdown (e.g., sending an IRC `QUIT` message) and cleans up resources like `aiohttp` runners or background tasks.\n- **`_set_fatal_error()`**: If a connection fails (e.g., invalid credentials or port conflict), adapters call this base method to update the gateway's runtime status, which is visible via `hermes status`.","plugins-plugins":"# plugins — plugins\n\n# Hermes Plugins Module\n\nThe `plugins` module serves as the central namespace and container for all extensible components within the Hermes ecosystem. It is structured as a Python package to allow for modular discovery and loading of external or internal feature sets.\n\n## Purpose\n\nThe primary role of this module is to provide a standardized location for plugin implementations. By grouping extensions under the `plugins` namespace, Hermes maintains a clean separation between core logic and optional or specialized functionality.\n\nCurrently, the `plugins/__init__.py` file acts as a package marker, ensuring that any subdirectories or modules within this folder are treatable as part of the `plugins` hierarchy.\n\n## Architecture and Integration\n\nThe module is designed to be a passive container. In a typical Hermes execution flow, a plugin loader (located in the core system) will scan this directory to identify and initialize specific plugin classes.\n\n### Plugin Discovery Flow\n\n```mermaid\ngraph TD\n Core[Hermes Core] --> Loader[Plugin Loader]\n Loader -->|Scans| Pkg[plugins Package]\n Pkg --> P1[Plugin A]\n Pkg --> P2[Plugin B]\n Pkg --> P3[Plugin N]\n```\n\n## Adding New Plugins\n\nTo contribute a new plugin to the Hermes system, developers should follow these structural guidelines:\n\n1. **Create a Sub-package**: Create a new directory within `plugins/` (e.g., `plugins/my_feature/`).\n2. **Initialize the Sub-package**: Include an `__init__.py` in your sub-directory.\n3. **Implement the Interface**: Ensure your plugin follows the expected Hermes plugin interface (typically defined in the core documentation) to ensure the loader can successfully register your code.\n\n## Current State\n\nAs of the current version, the `plugins` package is an empty namespace. It does not contain internal logic or execution flows, serving strictly as the architectural anchor for future extensions. Developers looking to modify the plugin loading mechanism should look for the discovery logic in the Hermes core modules rather than within this package.","plugins-spotify":"# plugins — spotify\n\n# Spotify Plugin\n\nThe `spotify` plugin provides a native integration with the Spotify Web API, exposing seven distinct tools for playback control, catalog searching, and library management. It is implemented as a bundled backend plugin that auto-loads on startup.\n\n## Architecture Overview\n\nThe module follows a tiered architecture that separates the raw API communication from the tool-specific logic and the Hermes plugin registration system.\n\n```mermaid\ngraph TD\n Registry[Tool Registry] -->|Calls| Handlers[tools.py Handlers]\n Handlers -->|Uses| Client[client.py: SpotifyClient]\n Client -->|Auth| Auth[hermes_cli.auth]\n Client -->|REST| SpotifyAPI[Spotify Web API]\n```\n\n### Key Components\n\n1. **`__init__.py`**: The entry point. It defines the `_TOOLS` metadata and the `register(ctx)` function used by the Hermes plugin loader to bind handlers to the toolset.\n2. **`client.py`**: A specialized HTTP client (`SpotifyClient`) that manages authentication headers, token refreshing, and Spotify-specific error parsing.\n3. **`tools.py`**: Contains the JSON schemas for the LLM and the handler functions (e.g., `_handle_spotify_playback`) that translate tool arguments into client calls.\n4. **`plugin.yaml`**: Metadata defining the plugin as a `kind: backend` and listing the provided tools.\n\n## Authentication and Gating\n\nThe plugin relies on the `hermes auth spotify` flow. It does not manage credentials directly but interfaces with `hermes_cli.auth`.\n\n* **Gating**: Every tool is registered with a `check_fn` pointing to `_check_spotify_available()`. This function checks `get_auth_status(\"spotify\")`. If the user is not logged in, the tools remain visible in the system but will not execute.\n* **Runtime Resolution**: The `SpotifyClient` calls `resolve_spotify_runtime_credentials()` during initialization.\n* **Token Refresh**: The `SpotifyClient.request` method automatically catches `401 Unauthorized` responses, attempts to refresh the token via the auth module, and retries the request once before failing.\n\n## The Spotify Client (`client.py`)\n\nThe `SpotifyClient` is a thin wrapper around `httpx`. It centralizes logic for:\n\n* **Base URL & Headers**: Automatically applies the `Authorization: Bearer <token>` header.\n* **Response Handling**: Distinguishes between successful content (200 OK), successful empty responses (204 No Content), and structured API errors.\n* **Error Normalization**: Converts raw Spotify API error objects into `SpotifyAPIError` exceptions with developer-friendly messages via `_friendly_spotify_error_message`.\n\n### Data Normalization\nSpotify identifies items using IDs, URIs (`spotify:track:...`), and URLs. The client provides utility functions to ensure consistency:\n* `normalize_spotify_id`: Extracts the raw ID from any format.\n* `normalize_spotify_uri`: Ensures a string is in the `spotify:<type>:<id>` format.\n* `normalize_spotify_uris`: Handles lists of identifiers, removing duplicates and validating types.\n\n## Tool Implementation (`tools.py`)\n\nTools are implemented using an \"Action Pattern.\" Instead of creating dozens of small tools, related capabilities are grouped into a single tool with an `action` parameter.\n\n| Tool Name | Primary Actions |\n| :--- | :--- |\n| `spotify_playback` | `play`, `pause`, `next`, `previous`, `seek`, `set_volume`, `recently_played` |\n| `spotify_devices` | `list`, `transfer` |\n| `spotify_queue` | `get`, `add` |\n| `spotify_search` | Search tracks, albums, artists, playlists, etc. |\n| `spotify_playlists` | `list`, `get`, `create`, `add_items`, `remove_items` |\n| `spotify_albums` | `get`, `tracks` |\n| `spotify_library` | `list`, `save`, `remove` (supports both tracks and albums via `kind`) |\n\n### Handler Logic\nEach handler (e.g., `_handle_spotify_playback`) follows a standard flow:\n1. Extract and sanitize arguments (using helpers like `_coerce_bool` and `_coerce_limit`).\n2. Instantiate a `SpotifyClient`.\n3. Dispatch to the appropriate client method based on the `action` argument.\n4. Wrap the result in `tool_result()` or catch exceptions to return a `tool_error()`.\n\n## Error Handling\n\nThe module uses a hierarchy of exceptions to provide specific feedback:\n* **`SpotifyAuthRequiredError`**: Raised when credentials are missing or the session has expired.\n* **`SpotifyAPIError`**: Raised when the Spotify API returns a 4xx or 5xx status code. It includes the `status_code` and the original response body.\n* **`SpotifyError`**: A general base class for validation errors (e.g., invalid URI format).\n\nThe `_spotify_tool_error` function in `tools.py` ensures these exceptions are formatted correctly for the Hermes tool execution environment, preventing raw stack traces from being returned to the LLM.","plugins-strike-freedom-cockpit":"# plugins — strike-freedom-cockpit\n\n# Strike Freedom Cockpit\n\nThe `strike-freedom-cockpit` module is a reference implementation of the Hermes dashboard skinning and plugin system. It demonstrates how to create a deep visual overhaul (a \"cockpit\" HUD) using a combination of a theme configuration file and a functional plugin without modifying the core dashboard source code.\n\n## Architecture Overview\n\nThe module is split into two distinct parts that work in tandem:\n\n1. **Theme Configuration (`theme/strike-freedom.yaml`)**: Defines the static visual properties, including the color palette, typography, layout variant, and component-level CSS overrides.\n2. **Dashboard Plugin (`dashboard/`)**: A functional extension that injects dynamic content into specific UI slots reserved by the theme's layout.\n\n```mermaid\ngraph TD\n A[Dashboard Shell] --> B{Theme Engine}\n A --> C{Plugin Loader}\n B --> D[strike-freedom.yaml]\n C --> E[strike-freedom-cockpit Plugin]\n D -->|Sets layoutVariant: cockpit| A\n E -->|Injects into sidebar/header slots| A\n D -->|Exposes CSS Vars| E\n```\n\n## Theme Configuration\n\nThe `strike-freedom.yaml` file utilizes the Hermes theme schema to redefine the UI's look and feel.\n\n### Layout & Chrome\n- **`layoutVariant: cockpit`**: This is a critical setting that instructs the dashboard shell to render a 260px left rail (sidebar) and specific header/footer areas.\n- **`componentStyles`**: Maps directly to CSS variables used by core components. For example, `card.clipPath` generates `--component-card-clip-path`, allowing for the \"notched\" mecha-style corners.\n- **`customCSS`**: Injects a raw CSS block for effects that cannot be achieved through variable overrides alone, such as the scanline overlay and pseudo-element corner pips.\n\n### Asset Exposure\nThe theme defines an `assets` block:\n```yaml\nassets:\n hero: \"/path/to/image.png\"\n crest: \"/path/to/crest.svg\"\n```\nThese are exposed to the browser as CSS variables (`--theme-asset-hero`, `--theme-asset-crest`). This allows the paired plugin to render theme-specific artwork without hardcoding URLs in the JavaScript source.\n\n## Dashboard Plugin\n\nThe plugin component handles the dynamic elements of the cockpit HUD.\n\n### Manifest (`manifest.json`)\nThe plugin is configured as a \"hidden\" plugin. It does not appear in the main navigation but instead targets specific layout slots:\n- **`tab.hidden: true`**: Prevents the plugin from creating a dedicated navigation entry.\n- **`slots`**: Declares intent to render into `sidebar`, `header-left`, and `footer-right`.\n\n### Slot Implementations\n- **`sidebar`**: Renders the `MS-STATUS` panel. It consumes real-time agent telemetry and displays it using segmented progress bars. It also reads the `--theme-asset-hero` variable to display the character/mecha portrait.\n- **`header-left`**: Injects the `COMPASS` crest or organizational logo, reading from `--theme-asset-crest`.\n- **`footer-right`**: Overrides the default system tagline with theme-appropriate text.\n\n## Integration Points\n\n### CSS Variable Mapping\nThe dashboard shell maps theme properties to CSS variables following these patterns:\n- **Palette**: `--color-<key>` (e.g., `--color-warm-glow`)\n- **Component Styles**: `--component-<bucket>-<property>` (e.g., `--component-card-box-shadow`)\n- **Assets**: `--theme-asset-<key>` (e.g., `--theme-asset-bg`)\n\n### Layout Variants\nWhen `layoutVariant` is set to `cockpit`, the shell activates specific `data-layout-variant=\"cockpit\"` attributes on the root element. The `customCSS` in this module uses these attributes as selectors to ensure styles only apply when the Strike Freedom theme is active:\n```css\n[data-layout-variant=\"cockpit\"] .border-border::before { ... }\n```\n\n## Installation & Development\n\n### File Placement\nTo activate the module, files must be placed in the Hermes home directory (typically `~/.hermes/`):\n\n1. **Theme**: `~/.hermes/dashboard-themes/strike-freedom.yaml`\n2. **Plugin**: `~/.hermes/plugins/strike-freedom-cockpit/`\n\n### Discovery\nThe system discovers the module via two mechanisms:\n- **Startup**: Automatic scan of the `plugins/` and `dashboard-themes/` directories.\n- **Runtime**: Triggering the `GET /api/dashboard/plugins/rescan` endpoint forces the shell to reload available themes and plugin manifests.\n\n### Development Workflow\nWhen modifying the plugin, the `entry` point defined in `manifest.json` (usually `dist/index.js`) must be rebuilt. The theme YAML can be edited live; however, a rescan or page refresh is required for the shell to pick up changes to the `layoutVariant` or `slots` definitions.","plugins":"# plugins\n\n# Plugins Module\n\nThe `plugins` module is the central extensibility layer for the Hermes ecosystem. It provides a standardized namespace for discovering, loading, and orchestrating external features, ranging from low-level memory management to high-level UI dashboards.\n\n## Architecture Overview\n\nThe module operates on a \"pluggable backend\" philosophy where core Hermes logic remains agnostic of specific implementations. Integration typically follows one of three patterns:\n\n1. **Provider Interfaces**: Modules like [Memory](memory.md) and [Image Generation](image_gen.md) define abstract interfaces (`MemoryProvider`, `ImageGenProvider`), allowing the system to swap backends (e.g., OpenAI vs. xAI) via `config.yaml`.\n2. **Lifecycle Hooks**: Modules like [Disk Cleanup](disk-cleanup.md) and [Observability](observability.md) subscribe to internal agent events (e.g., `post_tool_call`) to perform background tasks like file management or Langfuse tracing.\n3. **Dashboard Manifests**: UI-centric plugins like [Hermes Achievements](hermes-achievements.md) and [Kanban](kanban.md) use a `manifest.json` to register new tabs and slots within the web dashboard.\n\n```mermaid\ngraph TD\n Core[Hermes Core] --> Hooks[Lifecycle Hooks]\n Core --> Registry[Provider Registry]\n \n Hooks --> Obs[Observability]\n Hooks --> DC[Disk Cleanup]\n \n Registry --> Mem[Memory Providers]\n Registry --> Img[Image Gen Providers]\n Registry --> Plat[Platform Adapters]\n \n subgraph UI Extensions\n Dash[Dashboard] --> Ach[Achievements]\n Dash --> Kan[Kanban]\n Dash --> SFC[Strike Freedom Cockpit]\n end\n```\n\n## Sub-Module Categories\n\n### Core Infrastructure\n* **[Context Engine](context_engine.md)**: Manages and compresses conversation history before LLM submission.\n* **[Memory](memory.md)**: Orchestrates long-term storage backends for agent persistence.\n* **[Observability](observability.md)**: Integrates with Langfuse for deep tracing of generations and tool calls.\n* **[Platforms](platforms.md)**: Adapters that bridge Hermes to external networks like IRC and MS Teams.\n\n### Agent Capabilities & Tools\n* **[Google Meet](google_meet.md)**: Enables the agent to join calls, scrape captions, and speak via duplex audio.\n* **[Image Generation](image_gen.md)**: Provides a unified API for DALL-E and other image synthesis models.\n* **[Spotify](spotify.md)**: Grants the agent control over playback, searching, and library management.\n\n### Dashboard & User Experience\n* **[Hermes Achievements](hermes-achievements.md)**: A gamified system that analyzes `SessionDB` history to unlock badges.\n* **[Kanban](kanban.md)**: A multi-agent task board for real-time collaboration.\n* **[Strike Freedom Cockpit](strike-freedom-cockpit.md)**: A reference implementation for deep visual skinning and HUD overlays.\n* **[Example Dashboard](example-dashboard.md)**: A boilerplate for developers to build new UI extensions.\n\n### System Maintenance\n* **[Disk Cleanup](disk-cleanup.md)**: Automatically manages the lifecycle of ephemeral files generated by tools like `write_file` or `terminal`.\n\n## Plugin Discovery\nMost sub-modules support dynamic discovery. The system typically scans two locations:\n1. **Bundled**: Internal plugins located within the `plugins/` directory.\n2. **User**: External plugins located in `$HERMES_HOME/plugins/`.\n\nIn cases of conflict, bundled plugins generally take precedence unless specified otherwise in the global configuration.","root-agents-md":"# Root — AGENTS.md\n\n# Hermes Agent - Development Guide\n\nThis module serves as the primary technical reference for developers and AI assistants working on the `hermes-agent` codebase. It outlines the project architecture, core execution loops, and extensibility patterns.\n\n## Core Architecture Overview\n\nHermes is structured as a multi-interface agentic system where the core logic (`AIAgent`) is decoupled from the presentation layers (CLI, TUI, Gateway).\n\n```mermaid\ngraph TD\n UI[CLI / TUI / Gateway] --> Agent[AIAgent - run_agent.py]\n Agent --> LLM[LLM Provider]\n Agent --> Tools[model_tools.py]\n Tools --> Registry[tools/registry.py]\n Registry --> ToolImpls[Individual Tools]\n```\n\n### Key Entry Points\n- **`run_agent.py`**: Contains the `AIAgent` class, the central orchestration point for conversations and tool-calling loops.\n- **`cli.py`**: The interactive terminal interface using `Rich` and `prompt_toolkit`.\n- **`model_tools.py`**: The bridge between the LLM's function-calling intent and actual Python execution.\n- **`gateway/run.py`**: The messaging adapter for external platforms (Telegram, Slack, etc.).\n\n---\n\n## The AIAgent Execution Loop\n\nThe `AIAgent` class manages the conversation state and the iterative tool-calling process. The primary entry point for logic is `run_conversation()`.\n\n### Conversation Flow\n1. **Initialization**: `AIAgent` is instantiated with credentials, model routing, and `enabled_toolsets`.\n2. **The Loop**: A synchronous `while` loop continues until the model provides a final text response or the `max_iterations` / `iteration_budget` is exhausted.\n3. **Tool Execution**: When the LLM returns `tool_calls`, `handle_function_call()` dispatches the request to the registered tool handler.\n4. **State Management**: Messages are stored in OpenAI-compatible format. Reasoning content is captured in the `reasoning` field of assistant messages.\n\n```python\n# Simplified execution pattern in run_agent.py\nwhile self.should_continue(api_call_count):\n response = client.chat.completions.create(model=model, messages=messages, tools=tool_schemas)\n if response.tool_calls:\n for tool_call in response.tool_calls:\n result = handle_function_call(tool_call.name, tool_call.args, task_id)\n messages.append(tool_result_message(result))\n api_call_count += 1\n else:\n return response.content\n```\n\n---\n\n## Tool & Skill System\n\nHermes uses a decentralized tool discovery system. Tools are registered at import time and orchestrated via `model_tools.py`.\n\n### Adding a New Tool\nTo add a tool, create a file in `tools/` and use the `registry.register()` method.\n- **Schema**: Must follow JSON Schema for LLM compatibility.\n- **Handler**: Must return a JSON-formatted string.\n- **Environment**: Use `requires_env` to gate tools based on available API keys.\n\n### Skills\n- **Built-in (`skills/`)**: Core capabilities shipped with the agent.\n- **Optional (`optional-skills/`)**: Niche or heavy-dependency skills installed via `hermes skills install`.\n- **Slash Commands**: Skills can inject logic as user messages via `agent/skill_commands.py` to preserve prompt caching.\n\n---\n\n## User Interfaces\n\n### Interactive CLI (`cli.py`)\nThe CLI uses a **Skin Engine** (`hermes_cli/skin_engine.py`) for visual customization. It supports slash commands defined in a central `COMMAND_REGISTRY` in `hermes_cli/commands.py`. Adding a command here automatically updates help text, autocomplete, and gateway menus.\n\n### TUI Architecture (`ui-tui`)\nThe TUI is a React-based (Ink) terminal interface that communicates with a Python backend (`tui_gateway`) via JSON-RPC over stdio.\n- **Process Model**: Node.js owns the rendering; Python owns the Agent and Tools.\n- **Dashboard**: The `hermes dashboard` embeds the TUI via a PTY bridge, ensuring UI consistency across terminal and web.\n\n---\n\n## Configuration & Profiles\n\nHermes supports isolated instances via **Profiles**. Each profile has its own `HERMES_HOME`.\n\n### Profile Safety Rules\n1. **Paths**: Always use `get_hermes_home()` from `hermes_constants.py`. Never hardcode `~/.hermes`.\n2. **Display**: Use `display_hermes_home()` for user-facing logs to show the correct profile path.\n3. **Config**: Settings go in `config.yaml` (via `DEFAULT_CONFIG` in `hermes_cli/config.py`). Secrets (API keys) go in `.env`.\n\n---\n\n## Plugin System\n\nPlugins live in `plugins/` and allow extending the agent without modifying core files.\n- **Lifecycle Hooks**: Plugins can hook into `pre_tool_call`, `post_llm_call`, etc.\n- **Memory Providers**: Specialized plugins in `plugins/memory/` (e.g., `mem0`, `honcho`) implement the `MemoryProvider` ABC to handle long-term state.\n\n---\n\n## Development Policies\n\n### Prompt Caching\nMaintain the integrity of the system prompt. Do not change toolsets or context mid-conversation, as this invalidates LLM provider caches and increases costs.\n\n### Testing Standards\n**Always use `scripts/run_tests.sh`**. This script ensures:\n- Timezone is set to `UTC`.\n- API keys are unset (hermetic testing).\n- `xdist` is limited to 4 workers to match CI environments.\n\n**Avoid Change-Detector Tests**: Do not write tests that assert specific counts of models or hardcoded version numbers. Instead, test invariants (e.g., \"all models in the catalog must have a defined context length\").\n\n### Background Processes\nWhen tools run in the background, the Gateway uses a watcher to notify the user upon completion. This behavior is controlled by `display.background_process_notifications` in the configuration.","root-batch-runner-py":"# Root — batch_runner.py\n\n# Batch Agent Runner\n\nThe `batch_runner.py` module provides a high-performance, parallelized framework for executing the `AIAgent` across large datasets. It manages the lifecycle of batch jobs, including dataset partitioning, worker process orchestration, fault-tolerant checkpointing, and comprehensive statistics aggregation.\n\n## Core Architecture\n\nThe module utilizes a producer-consumer pattern via Python's `multiprocessing.Pool`. The `BatchRunner` class orchestrates the overall run, while `_process_batch_worker` functions as the entry point for individual worker processes.\n\n```mermaid\ngraph TD\n CLI[CLI / main] --> BR[BatchRunner]\n BR --> Load[Dataset Loader]\n BR --> Pool[multiprocessing.Pool]\n Pool --> Worker[_process_batch_worker]\n Worker --> Single[_process_single_prompt]\n Single --> Agent[AIAgent.run_conversation]\n Single --> Stats[Stats Extraction]\n Worker --> Checkpoint[Incremental Checkpoint]\n BR --> Merge[Combine Trajectories]\n```\n\n## Key Components\n\n### BatchRunner Class\nThe central orchestrator. It handles:\n- **Dataset Loading**: Reads JSONL files and partitions them into chunks based on `batch_size`.\n- **Worker Management**: Spawns a process pool to execute batches concurrently.\n- **State Persistence**: Manages the `checkpoint.json` and `statistics.json` files.\n- **Result Merging**: Combines individual batch files into a final `trajectories.jsonl` while filtering corrupted entries.\n\n### _process_single_prompt\nThis function encapsulates the execution of a single task. It performs several critical steps:\n1. **Environment Setup**: If the dataset entry contains an `image` or `docker_image` field, it calls `register_task_env_overrides` from `tools.terminal_tool` to ensure the agent's sandbox uses the correct container.\n2. **Tool Distribution**: Samples a set of tools for the prompt using `sample_toolsets_from_distribution`.\n3. **Agent Execution**: Instantiates `AIAgent` and runs the conversation loop.\n4. **Data Extraction**: Processes the resulting message history to extract tool usage and reasoning statistics.\n\n### Statistics & Normalization\nTo ensure compatibility with downstream consumers (like HuggingFace Datasets or Apache Arrow), the module enforces a strict schema:\n- **`_normalize_tool_stats`**: Ensures every entry in the output contains the same set of tool keys (derived from `TOOL_TO_TOOLSET_MAP`), even if those tools weren't used in a specific run.\n- **`_extract_reasoning_stats`**: Monitors for the presence of `<REASONING_SCRATCHPAD>` or native thinking tokens. Samples that contain zero reasoning turns are discarded to maintain dataset quality.\n\n## Fault Tolerance and Resumption\n\nThe module implements a \"Smart Resume\" mechanism that goes beyond simple index tracking:\n\n1. **Content-Based Matching**: `_scan_completed_prompts_by_content` reads existing `batch_*.jsonl` files to identify prompts that have already succeeded by their text content. This prevents duplicate processing if the input dataset order changes.\n2. **Incremental Checkpointing**: The `checkpoint.json` is updated atomically after every batch completion using `utils.atomic_json_write`.\n3. **Error Recovery**: Failed prompts are logged but not marked as completed in the checkpoint, allowing them to be retried automatically when the script is re-run with the `--resume` flag.\n\n## Data Output Format\n\nThe runner produces a `trajectories.jsonl` file where each line is a JSON object containing:\n- `conversations`: The full trajectory in `from`/`value` format.\n- `tool_stats`: Normalized dictionary of tool call counts, successes, and failures.\n- `tool_error_counts`: A simplified mapping of tool names to failure counts.\n- `metadata`: Information about the model, batch number, and timestamp.\n\n## Usage and Configuration\n\nThe module is invoked via the command line using `fire`.\n\n### Basic Execution\n```bash\npython batch_runner.py \\\n --dataset_file=tasks.jsonl \\\n --batch_size=20 \\\n --run_name=experiment_v1 \\\n --num_workers=8\n```\n\n### Advanced Configuration\n- **Tool Distributions**: Use `--distribution` to select specific tool subsets (e.g., `image_gen`, `coding`).\n- **OpenRouter Integration**: Configure provider logic via `--providers_allowed`, `--providers_order`, and `--provider_sort`.\n- **Reasoning Control**: Use `--reasoning_effort` (none, low, medium, high) to control model thinking depth, or `--reasoning_disabled` to strip thinking tokens entirely.\n- **Prefilling**: Use `--prefill_messages_file` to provide few-shot context or system-level priming to every prompt in the batch.\n\n### Resuming a Run\n```bash\npython batch_runner.py --run_name=experiment_v1 --resume --dataset_file=tasks.jsonl --batch_size=20\n```\nThe runner will detect the existing directory in `data/experiment_v1`, scan existing batch files, and only process the remaining prompts.","root-cli-config-yaml-example":"# Root — cli-config.yaml.example\n\n# CLI Configuration (cli-config.yaml)\n\nThe `cli-config.yaml.example` file serves as the primary template for configuring the Hermes Agent's behavior, execution environment, and model parameters. To activate these settings, copy this file to `~/.hermes/cli-config.yaml` (or the project root) and modify as needed.\n\n## Configuration Hierarchy\n\nHermes resolves configuration using the following priority (highest to lowest):\n1. **Command Line Flags** (e.g., `--model`, `--provider`, `--worktree`)\n2. **Environment Variables** (defined in `.env` or the shell)\n3. **`cli-config.yaml`**\n4. **Internal Defaults**\n\n## Core Configuration Modules\n\n### 1. Model & Inference\nThis section defines which LLM \"brain\" the agent uses and how it communicates with providers.\n\n* **`model.default`**: The primary model identifier (e.g., `anthropic/claude-3-5-sonnet`).\n* **`model.provider`**: Supports `auto` detection or explicit providers like `openrouter`, `anthropic`, `openai-codex`, `ollama`, and `lmstudio`.\n* **`context_length`**: While usually auto-detected, this can be manually set for local servers (vLLM/Ollama) to control when history compression triggers.\n* **`auxiliary`**: Configures lightweight models (like Gemini Flash) for side-tasks such as vision analysis, web summarization, and session search to save costs on the primary model.\n\n### 2. Terminal & Execution Backends\nHermes can execute commands in various environments. The `terminal` block defines the \"hands\" of the agent.\n\n| Backend | Description | Key Requirements |\n| :--- | :--- | :--- |\n| `local` | Runs directly on the host machine. | Default behavior. |\n| `ssh` | Executes on a remote server via SSH. | `ssh_host`, `ssh_user`, `ssh_key`. |\n| `docker` | Runs inside an isolated container. | `docker_image`, Docker daemon. |\n| `modal` | Serverless cloud execution. | `modal_image`. |\n| `daytona` | Cloud development sandboxes. | `DAYTONA_API_KEY`. |\n\n**Resource Limits:** For containerized backends, you can specify `container_cpu`, `container_memory`, and `container_persistent` to ensure the environment survives between agent turns.\n\n### 3. Context Management & Compression\nTo prevent \"context window\" overflow and manage costs, Hermes implements an automated compression strategy.\n\n* **`compression.threshold`**: Triggers summarization when the prompt reaches a percentage of the total context (default `0.50`).\n* **`compression.protect_last_n`**: Ensures the most recent `N` messages are never summarized, preserving immediate conversation flow.\n* **`prompt_caching`**: Configures TTL for Anthropic's prompt caching (e.g., `5m` or `1h`).\n\n### 4. Persistent Memory\nHermes maintains two long-term storage files to provide continuity across sessions:\n* **`MEMORY.md`**: Facts about the environment, project conventions, and learned technical details.\n* **`USER.md`**: User preferences and communication style.\n* **`nudge_interval`**: How often the agent is reminded to update these files.\n\n### 5. Toolsets & Guardrails\nTools are grouped into \"toolsets\" (e.g., `web`, `terminal`, `file`).\n* **`platform_toolsets`**: Maps specific toolsets to platforms (CLI vs. Telegram vs. Slack). This allows restricting dangerous tools (like `terminal`) on public messaging platforms while keeping them enabled for the CLI.\n* **`tool_loop_guardrails`**: Circuit breakers that stop the agent if it enters an infinite loop of failing tools or makes no progress.\n\n### 6. Model Context Protocol (MCP)\nThe `mcp_servers` block allows extending Hermes with external tool servers.\n```yaml\nmcp_servers:\n filesystem:\n command: npx\n args: [\"-y\", \"@modelcontextprotocol/server-filesystem\", \"/home/user\"]\n github:\n command: npx\n args: [\"-y\", \"@modelcontextprotocol/server-github\"]\n env:\n GITHUB_PERSONAL_ACCESS_TOKEN: \"ghp_...\"\n```\n\n## UI and Display Customization\n\nThe `display` section controls the CLI's visual output:\n* **`skin`**: Choose from built-in themes like `ares`, `slate`, or `monochrome`.\n* **`tool_progress`**: Set to `all`, `new`, or `off` to control how much detail is shown during tool execution.\n* **`streaming`**: Enables/disables real-time token streaming in the terminal.\n* **`show_reasoning`**: Displays the model's internal \"thinking\" process in a dedicated UI box.\n\n## Advanced Integration: Shell Hooks\nThe `hooks` section allows developers to run arbitrary shell scripts at specific lifecycle events.\n\n```mermaid\ngraph TD\n A[Event Triggered] --> B{Hook Registered?}\n B -- Yes --> C[Execute Shell Script]\n C --> D[JSON Input via Stdin]\n D --> E[JSON Output via Stdout]\n E --> F[Modify Agent Behavior/Context]\n B -- No --> G[Continue Execution]\n```\n\n**Supported Events:**\n* `pre_tool_call` / `post_tool_call`: Useful for security audits or auto-formatting code.\n* `pre_llm_call`: Inject custom context into the prompt.\n* `on_session_start` / `on_session_end`: Setup or teardown logic.","root-constraints-termux-txt":"# Root — constraints-termux.txt\n\n# constraints-termux.txt\n\nThe `constraints-termux.txt` file is a specialized requirements constraint file designed to ensure the stability of the Hermes Agent when deployed within a **Termux** environment on Android. \n\nUnlike standard requirement files that define what must be installed, this constraints file restricts the versions of dependencies to \"known-good\" releases that are compatible with the unique limitations of the Android/Termux ecosystem.\n\n## Purpose and Rationale\n\nDeveloping and running Python applications on Android via Termux presents specific challenges:\n1. **Binary Compatibility:** Many upstream packages release wheels (pre-compiled binaries) for Linux, macOS, and Windows, but rarely for Android/Termux.\n2. **Compilation Hurdles:** Installing from Source Distributions (`sdist`) often fails on-device due to missing build toolchains (Clang, Fortran, etc.) or incompatible C-extensions.\n3. **Upstream Velocity:** Rapid updates to the IPython/Jupyter stack frequently introduce dependencies that require newer system libraries than those available in the current Termux stable repositories.\n\nThis file acts as a stabilizer, pinning the interactive execution stack to versions that have been verified to install and run correctly on Android.\n\n## Usage\n\nTo install the Hermes Agent with Termux-specific protections, use the `-c` (constraints) flag during installation:\n\n```bash\npython -m pip install -e '.[termux]' -c constraints-termux.txt\n```\n\nBy using this command, `pip` will respect the version limits defined in the file even if the `setup.py` or `pyproject.toml` allows for newer versions.\n\n## Dependency Breakdown\n\nThe constraints primarily target the interactive shell and code analysis stack:\n\n| Package | Constraint | Reason |\n| :--- | :--- | :--- |\n| `ipython` | `<10` | Prevents breaking changes in the REPL environment. |\n| `jedi` | `>=0.18.1, <0.20` | Ensures stable autocompletion without requiring incompatible `parso` versions. |\n| `parso` | `>=0.8.4, <0.9` | Grammar parser compatible with the pinned `jedi` version. |\n| `stack-data` | `>=0.6, <0.7` | Manages traceback formatting; newer versions often require complex dependencies. |\n| `pexpect` | `>4.3, <5` | Critical for managing sub-processes and terminal interactions on Android. |\n| `matplotlib-inline` | `>=0.1.7, <0.2` | Provides inline plotting support for the Hermes execution environment. |\n| `asttokens` | `>=2.1, <3` | Required for AST-based code instrumentation and analysis. |\n\n## Maintenance Note\n\nWhen upgrading the Hermes Agent's core dependencies, this file should be audited. If a developer attempts to install a new feature that requires a version higher than what is pinned here, they must verify that the new version:\n1. Has a compatible wheel for `aarch64` (if applicable).\n2. Can be compiled from source using the standard `pkg install build-essential` toolchain in Termux.\n3. Does not depend on system-level libraries (like `glibc`) that are absent in the Android Bionic environment.","root-coolify-docker-compose-yaml":"# Root — coolify-docker-compose.yaml\n\n# Hermes Agent Deployment Configuration (`coolify-docker-compose.yaml`)\n\nThe `coolify-docker-compose.yaml` file defines the production-grade container orchestration for the **Hermes Agent**. This configuration is specifically hardened for secure deployment, likely within a [Coolify](https://coolify.io/) environment or similar self-hosted Docker infrastructure.\n\n## Service Architecture\n\nThe configuration defines a single service, `hermes`, which encapsulates the agent's logic, LLM integrations, and tool execution environments.\n\n```mermaid\ngraph TD\n subgraph Docker Host\n HA[Hermes Agent Container]\n Vol[(/opt/data)]\n Tmp[tmpfs /tmp]\n end\n \n HA -->|Persistence| Vol\n HA -->|Ephemeral Storage| Tmp\n \n subgraph External APIs\n LLM[LLM Providers: OpenRouter, GLM, etc.]\n Tools[Tools: Browserbase, Firecrawl, Fal]\n RL[RL: WandB, Tinker]\n end\n \n HA -.-> LLM\n HA -.-> Tools\n HA -.-> RL\n \n User((Developer/Client)) -->|Port 8642| HA\n```\n\n## Security Hardening\n\nA primary feature of this configuration is its \"Secure-by-Default\" posture. The container is heavily restricted to prevent privilege escalation and limit the blast radius of potential exploits:\n\n| Directive | Purpose |\n| :--- | :--- |\n| `read_only: true` | Prevents modifications to the container's root filesystem. |\n| `security_opt: [no-new-privileges:true]` | Prevents processes from gaining new privileges via `setuid` or `setgid` binaries. |\n| `cap_drop: [ALL]` | Drops all Linux capabilities; the container runs with the bare minimum permissions. |\n| `pids_limit: 256` | Prevents fork-bomb attacks by limiting the number of concurrent processes. |\n| `tmpfs: [/tmp]` | Provides a small (128MB), non-executable memory-backed storage for temporary files. |\n\n## Environment Configuration\n\nThe module relies heavily on environment variables to configure the agent's intelligence and toolset. These are categorized as follows:\n\n### 1. LLM Providers\nThe agent supports multiple backends. While `OPENROUTER_API_KEY` and `LLM_MODEL` are the primary defaults, placeholders exist for:\n* **Regional/Specific Providers:** GLM (Zhipu AI), Kimi (Moonshot), MiniMax.\n* **Specialized Providers:** OpenCode Zen, OpenCode Go.\n* **Open Source:** Hugging Face Inference Providers (`HF_TOKEN`).\n\n### 2. Tooling & Integration\n* **Search & Crawling:** `EXA_API_KEY`, `FIRECRAWL_API_KEY`.\n* **Execution Environments:** \n * **Terminal:** Configures a `mini-swe-agent` backend using the `nikolaik/python-nodejs` image with specific timeouts (`TERMINAL_TIMEOUT`, `TERMINAL_LIFETIME_SECONDS`).\n * **Browser:** Integrates with **Browserbase** for headless navigation, including stealth and proxy settings.\n* **Media & Voice:** `FAL_KEY` for image generation and `VOICE_TOOLS_OPENAI_KEY` for TTS/transcription.\n\n### 3. Observability & Training\n* **Debug Flags:** Individual toggles for `WEB_TOOLS`, `VISION_TOOLS`, `MOA_TOOLS`, and `IMAGE_TOOLS`.\n* **Reinforcement Learning:** Integration with `WANDB_API_KEY` (Weights & Biases) and `TINKER_API_KEY` for agent training and tracking.\n\n## Infrastructure Requirements\n\n### Networking\nThe service exposes port `8642` bound to `127.0.0.1`. This ensures the agent is only accessible locally or via a reverse proxy (like Nginx or Traefik) managed by Coolify, preventing direct exposure to the public internet.\n\n### Persistence\nThe configuration maps a host directory to the internal data store:\n* **Host Path:** `/home/limcheekin/docker/volumes/hermes-agent`\n* **Container Path:** `/opt/data`\n\n### Health Monitoring\nThe container includes a health check that polls the internal API:\n* **Endpoint:** `http://localhost:8642/health`\n* **Interval:** 30 seconds.\n* **Start Period:** 20 seconds (allows the agent and LLM connections to initialize before failing health checks).\n\n## Deployment Notes\n\nTo deploy this module:\n1. Ensure the host volume path exists or update it to your environment's standard.\n2. Populate the `.env` file with the required API keys (specifically `OPENROUTER_API_KEY`).\n3. The build context is set to `.`, requiring the `Dockerfile` to be present in the same directory as this compose file.","root-docker-compose-yml":"# Root — docker-compose.yml\n\n# Hermes Agent Orchestration (docker-compose.yml)\n\nThe `docker-compose.yml` file defines the multi-container architecture for the Hermes Agent. It orchestrates two primary services—the **Gateway** and the **Dashboard**—ensuring they share the same persistent data volume and networking stack.\n\n## Service Architecture\n\nThe deployment consists of two services built from the same `hermes-agent` image but executing different entrypoint commands.\n\n```mermaid\ngraph TD\n Host[Host Machine] --- Data[(~/.hermes)]\n Data --- G[Gateway Service]\n Data --- D[Dashboard Service]\n G --- Net[Host Network Stack]\n D --- Net\n D -.->|Depends On| G\n```\n\n### 1. Gateway Service (`gateway`)\nThe Gateway is the core engine of the Hermes Agent.\n- **Command**: `gateway run`\n- **Role**: Handles LLM interactions, tool execution, and external integrations (like Microsoft Teams).\n- **Networking**: Uses `network_mode: host` to allow direct communication with local services and simplify port management for integrations.\n\n### 2. Dashboard Service (`dashboard`)\nThe Dashboard provides a web-based UI for managing the agent, configuring API keys, and monitoring activity.\n- **Command**: `dashboard --host 127.0.0.1 --no-open`\n- **Role**: Management interface.\n- **Security**: By default, it binds to `127.0.0.1`. This prevents the dashboard (which handles sensitive API keys) from being exposed to the local network or the internet without an explicit proxy or SSH tunnel.\n\n## User and Permission Management\n\nTo prevent file permission conflicts between the container and the host, the module utilizes environment variables to synchronize the internal `hermes` user with the host user.\n\n| Variable | Default | Description |\n| :--- | :--- | :--- |\n| `HERMES_UID` | `10000` | The UID of the host user owning `~/.hermes`. |\n| `HERMES_GID` | `10000` | The GID of the host user owning `~/.hermes`. |\n\n**Usage Pattern:**\n```bash\nHERMES_UID=$(id -u) HERMES_GID=$(id -g) docker compose up -d\n```\nThe container entrypoint uses these values via `usermod`/`groupmod` and `gosu` to ensure that files created in `/opt/data` (mapped to `~/.hermes`) remain owned by the host user.\n\n## Configuration and Integrations\n\nThe services are configured primarily through environment variables passed into the `gateway` service.\n\n### OpenAI-Compatible API Server\nThe Gateway can act as an API server. This is disabled by default for security. To enable it, both variables must be set:\n- `API_SERVER_HOST`: Set to `0.0.0.0` to expose the API.\n- `API_SERVER_KEY`: A mandatory authentication key.\n\n### Microsoft Teams Gateway\nTo enable the Teams integration, the following variables must be uncommented and populated:\n- `TEAMS_CLIENT_ID`\n- `TEAMS_CLIENT_SECRET`\n- `TEAMS_TENANT_ID`\n- `TEAMS_ALLOWED_USERS`: A comma-separated list of authorized users.\n- `TEAMS_PORT`: Defaults to `3978`.\n\n## Persistence\n\nBoth services mount the host directory `~/.hermes` to `/opt/data` inside the container. This directory stores:\n- SQLite databases for state and history.\n- Encrypted API keys and configuration.\n- Logs and temporary session data.\n\n## Security Best Practices\n\n1. **Network Isolation**: The Dashboard is restricted to `localhost`. For remote access, use an SSH tunnel:\n `ssh -L 9119:localhost:9119 user@remote-host`\n2. **API Exposure**: Do not set `API_SERVER_HOST=0.0.0.0` without a strong `API_SERVER_KEY`.\n3. **Root Access**: The services run as a non-root `hermes` user inside the container, mapped to your host user via the `HERMES_UID/GID` logic.","root-dockerfile":"# Root — Dockerfile\n\n# Root — Dockerfile\n\nThe root `Dockerfile` defines the production container image for the Hermes application. It is responsible for packaging a complex environment that includes a Python backend, a Node.js-based web dashboard, a Terminal UI (TUI), and system-level dependencies like Playwright browsers. \n\nThe build process is heavily optimized for Docker layer caching and is designed to handle dynamic runtime user permissions safely.\n\n## Architecture & Execution Flow\n\nThe container uses a multi-stage build to pull pre-compiled binaries (`uv` and `gosu`) before assembling the final Debian-based image. At runtime, the container starts as `root` to allow permission adjustments, then drops privileges before executing the main application.\n\n```mermaid\ngraph TD\n A[Docker Run] --> B[tini PID 1]\n B --> C[entrypoint.sh]\n C -->|usermod/groupmod| D[Adjust UID/GID]\n D --> E[gosu]\n E -->|Drop privileges| F[Hermes Application]\n \n style B fill:#f9f,stroke:#333,stroke-width:2px\n style E fill:#bbf,stroke:#333,stroke-width:2px\n```\n\n## Key Components\n\n### 1. Binary Sourcing (Multi-stage)\nInstead of installing package managers and utilities via `apt` or `curl` scripts in the main image, the Dockerfile uses the `AS <name>` pattern to pull specific versions of binaries from external images:\n* **`uv_source`**: Pulls the Astral `uv` binary (v0.11.6) for fast Python dependency resolution and virtual environment management.\n* **`gosu_source`**: Pulls `gosu` (v1.19) to handle safe privilege dropping at runtime without the unpredictable signal-handling behavior of `su` or `sudo`.\n\n### 2. Process Management (`tini`)\nThe container installs and uses `tini` as its `ENTRYPOINT`. Because Hermes spawns numerous subprocesses (e.g., MCP stdio subprocesses, `git`, `bun`), running Hermes directly as PID 1 would result in orphaned zombie processes accumulating over time. `tini` acts as a lightweight init system that properly reaps these zombies.\n\n### 3. Node.js & UI Build Caching\nThe Dockerfile employs a specific layer-caching strategy for Node.js dependencies to speed up rebuilds:\n* **Manifest Copying**: `package.json` and `package-lock.json` files for the root, `web/`, and `ui-tui/` directories are copied first.\n* **The `hermes-ink` Workspace**: The `ui-tui/packages/hermes-ink/` directory is copied *in full* during the manifest stage. This is required because `ui-tui/package.json` references it as a `file:` workspace dependency. If only the manifest were copied, `npm` would fail to resolve the workspace content.\n* **Symlink Enforcement**: The environment variable `npm_config_install_links=false` is explicitly set. Debian 13 ships with npm 9.x (which copies `file:` dependencies by default), while the host uses npm 10+ (which symlinks them). Forcing symlinks prevents a lockfile mismatch that would otherwise trigger the TUI launcher (`_tui_need_npm_install()`) to attempt a runtime `npm install`, which would fail due to read-only permissions.\n\n### 4. Playwright Browser Storage\nPlaywright browsers are installed during the build phase. To ensure these browsers are not overwritten or hidden when the user mounts a volume to `/opt/data` at runtime, the installation path is explicitly moved via:\n```dockerfile\nENV PLAYWRIGHT_BROWSERS_PATH=/opt/hermes/.playwright\n```\n\n### 5. Python Environment\nPython dependencies are managed using `uv`. The Dockerfile creates a virtual environment (`uv venv`) and installs the local package with all optional dependencies (`uv pip install --no-cache-dir -e \".[all]\"`).\n\n### 6. Runtime Permissions & User Management\nThe container is designed to run securely while interacting with host-mounted files:\n* A default non-root user `hermes` (UID 10000) is created with `/opt/data` as its home directory.\n* The entire `/opt/hermes` installation directory is made world-readable and traversable (`chmod -R a+rX /opt/hermes`).\n* **Dynamic UID Mapping**: The container intentionally starts as `root`. This allows `/opt/hermes/docker/entrypoint.sh` to read the `HERMES_UID` environment variable, modify the `hermes` user's UID/GID to match the host user, and then use `gosu` to step down from `root` to the newly mapped user before launching the application.\n\n## Environment Variables\n\n| Variable | Purpose |\n| :--- | :--- |\n| `PYTHONUNBUFFERED=1` | Disables Python stdout buffering so logs stream immediately to the container output. |\n| `PLAYWRIGHT_BROWSERS_PATH` | Relocates Playwright binaries to `/opt/hermes/.playwright` to survive volume overlays. |\n| `npm_config_install_links` | Set to `false` to force symlinking of local workspace packages, preventing runtime lockfile conflicts. |\n| `HERMES_WEB_DIST` | Points the backend to the built static assets for the web dashboard (`/opt/hermes/hermes_cli/web_dist`). |\n| `HERMES_HOME` | Sets the application home directory to the mountable volume (`/opt/data`). |\n| `PATH` | Prepends `/opt/data/.local/bin` to ensure user-installed runtime binaries take precedence. |\n\n## Volumes\n* **`/opt/data`**: The primary volume mount point. This is used for persistent storage of user data, configuration, and runtime artifacts. It also serves as the home directory for the `hermes` user.","root-flake-nix":"# Root — flake.nix\n\n# Hermes Agent: Root Flake Configuration\n\nThe `flake.nix` file serves as the entry point for the Hermes Agent development environment, build system, and deployment configurations. It leverages the **Nix** ecosystem to provide reproducible builds, cross-platform development shells, and dependency management for both Python and Node.js components.\n\n## Architecture Overview\n\nThe project utilizes `flake-parts` to maintain a modular structure. Instead of a monolithic `flake.nix`, the logic is distributed across specialized modules located in the `./nix` directory.\n\n```mermaid\ngraph TD\n Flake[flake.nix] --> FP[flake-parts]\n FP --> P[nix/packages.nix]\n FP --> O[nix/overlays.nix]\n FP --> NM[nix/nixosModules.nix]\n FP --> C[nix/checks.nix]\n FP --> D[nix/devShell.nix]\n \n subgraph Inputs\n uv2nix[uv2nix]\n pyproject[pyproject.nix]\n nixpkgs[nixpkgs]\n end\n \n uv2nix -.-> Flake\n pyproject -.-> Flake\n nixpkgs -.-> Flake\n```\n\n## Key Inputs\n\nThe flake defines several critical dependencies to handle the polyglot nature of the Hermes Agent:\n\n* **nixpkgs (nixos-unstable)**: The primary package repository.\n* **flake-parts**: Simplifies the multi-system flake structure by providing a module system for `outputs`.\n* **uv2nix & pyproject-nix**: These inputs are used to translate `pyproject.toml` and `uv.lock` files into Nix derivations. This allows the project to use the `uv` package manager's speed while maintaining Nix's reproducibility.\n* **npm-lockfile-fix**: A utility to ensure Node.js lockfiles are compatible with Nix's sandboxed environment.\n\n## Supported Systems\n\nThe configuration explicitly supports the following architectures:\n* `x86_64-linux`\n* `aarch64-linux`\n* `aarch64-darwin` (Apple Silicon)\n\n## Module Structure\n\nThe `outputs` are generated by importing specific logic from the `./nix` directory. Developers looking to modify the build or environment should look into these files:\n\n| Module | Responsibility |\n| :--- | :--- |\n| `nix/packages.nix` | Defines the primary build outputs for the Hermes Agent. |\n| `nix/overlays.nix` | Contains modifications to standard `nixpkgs` or custom package overrides. |\n| `nix/nixosModules.nix` | Provides NixOS service definitions for deploying the agent as a system service. |\n| `nix/checks.nix` | Defines CI tests, linting, and formatting checks. |\n| `nix/devShell.nix` | Configures the `nix develop` environment, including Python interpreters and CLI tools. |\n\n## Usage for Developers\n\n### Entering the Development Environment\nTo load the development environment (including all Python dependencies and system libraries):\n```bash\nnix develop\n```\n\n### Building the Project\nTo build the default package defined in `nix/packages.nix`:\n```bash\nnix build\n```\n\n### Running Checks\nTo execute the test suite and linters defined in `nix/checks.nix`:\n```bash\nnix flake check\n```","root-gemini-md":"# Root — GEMINI.md\n\n# Root — GEMINI.md (AI Context & Graphify Integration)\n\nThe `GEMINI.md` file serves as a protocol definition for AI agents (specifically LLMs like Gemini) and developers interacting with the project's knowledge graph. It establishes a standardized workflow for codebase exploration, architectural analysis, and graph maintenance using the `graphify` toolset.\n\n## Purpose\n\nThe primary goal of this module is to shift codebase navigation from manual file scanning (grep/find) to semantic and structural graph traversal. By leveraging a pre-computed knowledge graph located in `graphify-out/`, the AI can understand high-level community structures, \"god nodes\" (highly coupled components), and inferred relationships that are not immediately obvious through static analysis alone.\n\n## Knowledge Graph Structure\n\nThe project's metadata is stored in the `graphify-out/` directory. The documentation defines a hierarchy for information retrieval:\n\n1. **Architectural Overview**: `graphify-out/GRAPH_REPORT.md` contains the macro-view of the system, identifying central hubs and module clusters.\n2. **Navigational Index**: If available, `graphify-out/wiki/index.md` acts as the entry point for human-readable documentation generated from the graph.\n3. **Raw Data**: The underlying graph edges (both extracted via AST and inferred via logic) are queried via the CLI.\n\n## Graphify Workflow\n\nThe module dictates a specific sequence for interacting with the codebase:\n\n```mermaid\ngraph TD\n Start[Question/Task] --> CheckGraph{Graph Exists?}\n CheckGraph -->|Yes| ReadReport[Read GRAPH_REPORT.md]\n ReadReport --> QueryGraph[Execute graphify query/path]\n QueryGraph --> ModifyCode[Apply Changes]\n ModifyCode --> UpdateGraph[graphify update .]\n UpdateGraph --> End[Task Complete]\n```\n\n### 1. Discovery and Analysis\nInstead of traditional text searches, the documentation mandates the use of the `graphify` CLI for cross-module relationship analysis. This is particularly useful for \"How does X relate to Y\" questions where the connection might be several hops away in the call graph.\n\n| Command | Usage | Purpose |\n|:---|:---|:---|\n| `graphify query \"<question>\"` | Semantic Search | Finds nodes and edges relevant to a natural language query. |\n| `graphify path \"<a>\" \"<b>\"` | Traceability | Identifies the specific chain of dependencies or calls between two modules. |\n| `graphify explain \"<concept>\"`| Contextualization | Provides a high-level summary of a specific architectural concept based on graph density. |\n\n### 2. Maintenance Lifecycle\nTo prevent \"knowledge drift,\" the graph must be synchronized with the source code. The documentation specifies that after any file modification, the following command must be executed:\n\n```bash\ngraphify update .\n```\n\nThis performs an **AST-only update**, meaning it re-parses the local file structure to refresh edges and nodes without incurring external API costs.\n\n## Operational Rules for AI Agents\n\n* **Prefer Graph over Grep**: Do not use `grep` for architectural questions. Use `graphify path` to find hidden dependencies.\n* **Wiki First**: Always check `graphify-out/wiki/index.md` before reading raw source files to understand the intended design patterns.\n* **Mandatory Updates**: Every coding session that results in a disk write must conclude with a graph update to ensure subsequent queries are accurate.","root-hermes-already-has-routines-md":"# Root — hermes-already-has-routines.md\n\n# Hermes Agent Automation & Routines\n\nThe Hermes Agent provides a robust automation framework that allows developers to schedule tasks, respond to external events via webhooks, and chain complex workflows. This system predates similar industry offerings and is designed to be model-agnostic, self-hosted, and extensible via Python scripts and specialized skills.\n\n## Core Automation Architecture\n\nHermes automations operate on a \"Trigger-Process-Deliver\" pipeline. Unlike standard agentic loops, these routines are designed for headless execution on your own infrastructure.\n\n```mermaid\ngraph TD\n A[Trigger: Cron / Webhook / API] --> B{Pre-processing}\n B -->|Optional| C[Python Script Injection]\n C --> D[Hermes Agent Core]\n B --> D\n D --> E[Skill Execution]\n E --> D\n D --> F[Delivery Engine]\n F --> G[Telegram/Slack/Discord/GitHub/SMS]\n```\n\n## Trigger Mechanisms\n\nHermes supports three primary methods for initiating an automated routine.\n\n### 1. Scheduled Tasks (Cron)\nThe `hermes cron` command allows for time-based execution using standard cron syntax or human-readable intervals.\n\n* **Command:** `hermes cron create`\n* **Key Arguments:**\n * `schedule`: A cron expression (e.g., `\"0 2 * * *\"`) or interval (e.g., `\"every 1h\"`).\n * `prompt`: The instruction for the agent to execute.\n * `--deliver`: The output destination.\n\n**Example:**\n```bash\nhermes cron create \"0 2 * * *\" \\\n \"Pull the top bug from the issue tracker, attempt a fix, and open a draft PR.\" \\\n --name \"Nightly bug fix\" \\\n --deliver telegram\n```\n\n### 2. GitHub Event Triggers\nHermes can subscribe to specific GitHub repository events. This requires the `hermes gateway` to be active to receive incoming webhooks.\n\n* **Command:** `hermes webhook subscribe`\n* **Key Arguments:**\n * `--events`: Comma-separated list of GitHub events (e.g., `pull_request`, `push`, `issues`).\n * `--prompt`: Supports template variables injected from the GitHub payload (e.g., `{pull_request.number}`).\n\n**Example:**\n```bash\nhermes webhook subscribe auth-watch \\\n --events \"pull_request\" \\\n --prompt \"Review PR #{pull_request.number}: {pull_request.title}. Check for auth-provider changes.\" \\\n --deliver slack\n```\n\n### 3. Generic API Triggers\nAny external service can trigger a Hermes routine by POSTing to a webhook route. Hermes supports HMAC authentication for secure API triggers.\n\n**Example:**\n```bash\nhermes webhook subscribe alert-triage \\\n --prompt \"Alert: {alert.name}. Find the owning service and post a triage summary.\" \\\n --deliver slack\n```\n\n## Advanced Execution Features\n\n### Script Injection (`--script`)\nBefore the LLM processes the prompt, Hermes can execute a local Python script. The `stdout` of this script is injected into the agent's context. This is used for:\n* Fetching dynamic data not available via MCP.\n* Performing heavy computation or data filtering.\n* Implementing \"Silent\" logic (e.g., if the script outputs `[SILENT]`, the agent suppresses delivery).\n\n```bash\nhermes cron create \"every 1h\" \\\n \"Summarize changes if detected.\" \\\n --script ~/.hermes/scripts/watch-site.py \\\n --deliver telegram\n```\n\n### Multi-Skill Chaining (`--skills`)\nAutomations can be granted specific capabilities by loading one or more skills. Skills are modular tools that the agent can invoke to interact with external environments (e.g., ArXiv, Obsidian, GitHub).\n\n```bash\nhermes cron create \"0 8 * * *\" \\\n \"Search arXiv for papers on LLMs. Save to Obsidian.\" \\\n --skills \"arxiv,obsidian\" \\\n --deliver local\n```\n\n## Delivery Engine\n\nThe `--deliver` flag determines where the final output of the routine is sent. Hermes supports a wide array of delivery targets:\n\n| Target | Format | Description |\n| :--- | :--- | :--- |\n| `telegram` | `--deliver telegram` | Sends to the default configured Telegram channel. |\n| `slack` | `--deliver slack` | Sends to the configured Slack workspace/channel. |\n| `discord` | `--deliver discord` | Sends to a Discord webhook or bot channel. |\n| `sms` | `--deliver sms:+1555...` | Sends a text message via configured SMS gateway. |\n| `github_comment`| `--deliver github_comment` | Posts the output as a comment on the triggering PR/Issue. |\n| `local` | `--deliver local` | Saves the output to a local log file; no external notification. |\n\n## Configuration and Setup\n\nTo enable the automation infrastructure, the gateway must be initialized to handle incoming webhooks and the scheduler must be active.\n\n1. **Initialize:** `hermes setup`\n2. **Enable Webhooks:** `hermes gateway setup`\n3. **Verify Routines:** Use `hermes cron list` or `hermes webhook list` to inspect active automations.\n\n## Comparison with Cloud-Locked Alternatives\n\n| Feature | Hermes Agent | Cloud-Locked Routines |\n| :--- | :--- | :--- |\n| **Model Choice** | Any (Claude, GPT, Local, etc.) | Provider-specific |\n| **Limits** | Unlimited (User-controlled) | Capped (e.g., 5-25/day) |\n| **Data Residency** | Local/Private Infrastructure | Provider Cloud |\n| **Pre-processing** | Python Script Injection | None |\n| **Extensibility** | Open Source (MIT) | Proprietary |","root-hermes-constants-py":"# Root — hermes_constants.py\n\n# Root — hermes_constants.py\n\nThe `hermes_constants.py` module serves as the single source of truth for path resolution, environment detection, and global configuration constants within the Hermes Agent. \n\nIt is designed to be **import-safe**, meaning it has zero internal dependencies within the Hermes codebase. This allows it to be imported by any module—including low-level utilities and high-level CLI commands—without the risk of circular dependencies.\n\n## Path Resolution Strategy\n\nThe module manages a hierarchical path resolution system that supports standard installations, Docker containers, and multi-profile environments.\n\n### Core Path Functions\n\n* **`get_hermes_home()`**: Returns the active Hermes data directory. It checks the `HERMES_HOME` environment variable, falling back to `~/.hermes`. \n * *Safety Mechanism:* If `HERMES_HOME` is unset but a non-default profile is marked as active in `~/.hermes/active_profile`, the function emits a one-shot warning to `stderr`. This prevents silent data corruption where a process might accidentally write to the default profile instead of the intended active one.\n* **`get_default_hermes_root()`**: Used for profile-level operations (e.g., listing all available profiles). It identifies the \"parent\" directory containing the `profiles/` subdirectory, regardless of whether the agent is running in a standard or custom Docker layout.\n* **`get_hermes_dir(new_subpath, old_name)`**: A migration-friendly helper. It checks if `old_name` exists (e.g., `image_cache`); if so, it returns that path. Otherwise, it returns the `new_subpath` (e.g., `cache/images`). This allows the codebase to evolve its directory structure without breaking existing installations.\n\n### Well-Known Paths\nThe module provides standardized accessors for frequently used files to prevent hardcoding strings across the repository:\n* `get_config_path()`: Resolves to `config.yaml`.\n* `get_env_path()`: Resolves to `.env`.\n* `get_skills_dir()`: Resolves to the `skills/` directory.\n* `get_optional_skills_dir()`: Resolves to `optional-skills/`, honoring the `HERMES_OPTIONAL_SKILLS` override used by package managers.\n\n## Environment Detection\n\nHermes adjusts its behavior based on the host environment. These functions are cached after the first call to minimize filesystem I/O.\n\n| Function | Detection Logic | Use Case |\n| :--- | :--- | :--- |\n| `is_termux()` | Checks `TERMUX_VERSION` or `PREFIX`. | Adjusting audio/microphone commands for Android. |\n| `is_wsl()` | Checks `/proc/version` for \"microsoft\". | Handling Windows-specific pathing or interop. |\n| `is_container()` | Checks `/.dockerenv`, `/run/.containerenv`, or cgroups. | Determining persistence requirements and audio drivers. |\n\n## Subprocess Isolation\n\n**`get_subprocess_home()`** implements a critical isolation feature. If a directory named `home/` exists within the current `HERMES_HOME`, this function returns its path. \n\nSubprocess spawners (like the Kanban dispatcher or Systemd templates) use this value to set the `HOME` environment variable for child processes. This ensures that tools like `git`, `ssh`, and `npm` write their configurations and caches inside the Hermes profile rather than the system user's home directory, facilitating:\n1. **Docker Persistence:** Configs stay within the mounted volume.\n2. **Profile Isolation:** Different profiles can maintain distinct SSH keys or Git identities.\n\n## Network and API Constants\n\n### IPv4 Preference\n**`apply_ipv4_preference(force=False)`** addresses issues where broken IPv6 stacks cause long timeouts in libraries like `httpx` or the OpenAI SDK. When enabled via `network.force_ipv4` in `config.yaml`, it monkey-patches `socket.getaddrinfo` to prioritize `AF_INET` (IPv4) resolutions while falling back to IPv6 only if no A record is found.\n\n### External Endpoints\nThe module defines standard base URLs for external services:\n* `OPENROUTER_BASE_URL`: `https://openrouter.ai/api/v1`\n* `AI_GATEWAY_BASE_URL`: `https://ai-gateway.vercel.sh/v1`\n\n## Reasoning Effort Configuration\n\n**`parse_reasoning_effort(effort)`** standardizes the \"reasoning effort\" parameter used by modern LLMs (e.g., O1/O3 models). It maps string inputs (`minimal`, `low`, `medium`, `high`, `xhigh`) into a configuration dictionary:\n* Input `\"none\"` returns `{\"enabled\": False}`.\n* Valid levels return `{\"enabled\": True, \"effort\": <level>}`.\n* Invalid or empty inputs return `None`, signaling the caller to use defaults.\n\n## Architecture Overview\n\n```mermaid\ngraph TD\n ENV[Environment Variables] --> GHH[get_hermes_home]\n GHH --> GHP[get_config_path]\n GHH --> GSD[get_skills_dir]\n GHH --> GEP[get_env_path]\n GHH --> GHD[get_hermes_dir]\n \n subgraph \"Profile Management\"\n GHH --> GDR[get_default_hermes_root]\n GHH --> GSH[get_subprocess_home]\n end\n \n subgraph \"Platform Detection\"\n IT[is_termux]\n IW[is_wsl]\n IC[is_container]\n end\n```","root-hermes-logging-py":"# Root — hermes_logging.py\n\n# Root — hermes_logging.py\n\nThe `hermes_logging.py` module provides a centralized logging infrastructure for the Hermes Agent. It handles multi-file logging, secret redaction, thread-local session context injection, and environment-specific file permissions.\n\n## Core Architecture\n\nHermes uses a multi-handler approach where log records are routed to different files based on their severity and component origin. All logs are stored in `~/.hermes/logs/` (or the path defined by `get_hermes_home()`).\n\n### Log Files\n| File | Level | Description |\n| :--- | :--- | :--- |\n| `agent.log` | `INFO`+ | The primary log file. Captures all activity across the agent, tools, and sessions. |\n| `errors.log` | `WARNING`+ | A high-priority log for triage, containing only warnings and errors. |\n| `gateway.log` | `INFO`+ | Created only when `mode=\"gateway\"`. Contains records from the `gateway.*` namespace. |\n\n### Log Flow Diagram\n\n```mermaid\ngraph TD\n A[Log Record] --> B{Record Factory}\n B -->|Injects session_tag| C[Root Logger]\n C --> D[agent.log Handler]\n C --> E[errors.log Handler]\n C --> F{Is Gateway Mode?}\n F -->|Yes| G[gateway.log Handler]\n G --> H[Component Filter]\n```\n\n## Initialization\n\n### `setup_logging()`\nThis is the primary entry point, typically called early in the CLI or Gateway startup sequence. It is idempotent; subsequent calls return the log directory path without reconfiguring handlers unless `force=True` is passed.\n\n**Key Behaviors:**\n- **Configuration Discovery:** Attempts to read `level`, `max_size_mb`, and `backup_count` from `config.yaml` via `_read_logging_config()`.\n- **Redaction:** Uses `RedactingFormatter` (from `agent.redact`) to ensure sensitive data (keys, tokens) is stripped before writing to disk.\n- **Noise Reduction:** Automatically sets noisy third-party loggers (e.g., `openai`, `httpx`, `urllib3`) to `WARNING` level to keep logs actionable.\n\n### `setup_verbose_logging()`\nEnables `DEBUG` level logging to the console (`stderr`). This is triggered by the `--verbose` or `-v` flags in the CLI. It uses a more detailed format string (`_LOG_FORMAT_VERBOSE`) including high-resolution timestamps.\n\n## Session Context Tracking\n\nTo correlate logs across complex asynchronous operations, the module uses thread-local storage to track session IDs.\n\n### Usage\n```python\nfrom hermes_logging import set_session_context, clear_session_context\n\ndef run_conversation(session_id):\n set_session_context(session_id)\n try:\n # All logs emitted here include [session_id]\n logger.info(\"Processing request\") \n finally:\n clear_session_context()\n```\n\n### Implementation Details\nThe module installs a global `LogRecord` factory via `_install_session_record_factory()`. Unlike a standard filter, this factory runs for every record created in the process. It injects a `session_tag` attribute into every record:\n- If a session ID is set in the current thread: ` [session_id]`\n- If no session ID is set: An empty string `\"\"`\n\nThis prevents `KeyError` exceptions in format strings that expect `%(session_tag)s`.\n\n## Component Filtering\n\nThe `_ComponentFilter` class routes logs to specific files based on logger name prefixes. This is primarily used to isolate gateway events (platform adapters, slash commands, delivery) into `gateway.log` while allowing `agent.log` to remain a catch-all for the entire system.\n\nThe `COMPONENT_PREFIXES` mapping defines these boundaries:\n- **gateway**: `gateway`\n- **agent**: `agent`, `run_agent`, `model_tools`, `batch_runner`\n- **tools**: `tools`\n- **cli**: `hermes_cli`, `cli`\n\n## Managed Environment Support\n\n### `_ManagedRotatingFileHandler`\nIn managed environments (like NixOS), Hermes may run in a context where multiple users or services need access to the same log files. \n\nThis subclass of `RotatingFileHandler` ensures that:\n1. New log files are created with `0660` permissions (read/write for owner and group).\n2. Rotated files (e.g., `agent.log.1`) maintain these permissions.\n\nIt checks `hermes_cli.config.is_managed()` to determine if these permission overrides should be applied.\n\n## Internal Helpers\n\n- **`_add_rotating_handler`**: An idempotent helper that attaches a `RotatingFileHandler` to a logger only if a handler for that specific file path does not already exist.\n- **`_read_logging_config`**: Performs a best-effort read of the `logging` block in `config.yaml`. It is designed to fail silently if the config file is missing or malformed, falling back to hardcoded defaults.","root-hermes-state-py":"# Root — hermes_state.py\n\n# Root — hermes_state.py\n\nThe `hermes_state.py` module provides a persistent SQLite-backed state store for the Hermes Agent. It replaces legacy JSONL-based storage with a centralized database capable of handling concurrent access, full-text search (FTS5), and complex session lineages.\n\n## Core Architecture\n\nThe module is centered around the `SessionDB` class, which manages a SQLite database (defaulting to `~/.hermes/state.db`). \n\n### Concurrency and Write-Contention\nTo support multi-platform gateway usage (e.g., Telegram, Discord, and CLI simultaneously), the database operates in **WAL (Write-Ahead Logging) mode**. \n\nA key design decision is the implementation of a custom application-level retry mechanism for writes. Instead of relying on SQLite's deterministic busy handler, which can cause \"convoy effects\" (multiple processes waking up and colliding simultaneously), `SessionDB` uses:\n- **`BEGIN IMMEDIATE`**: Acquires the write lock at the start of the transaction.\n- **Jittered Retries**: If the database is locked, the process sleeps for a random interval (20ms–150ms) before retrying.\n- **Passive Checkpoints**: Every 50 writes, the module attempts a `wal_checkpoint(PASSIVE)` to keep the WAL file size under control without blocking readers.\n\n### Declarative Schema Management\nThe module uses a declarative reconciliation pattern for schema updates. `SCHEMA_SQL` serves as the single source of truth. On startup, `_reconcile_columns` compares the live database schema against the SQL definition and automatically executes `ALTER TABLE ... ADD COLUMN` for any missing fields. This eliminates the need for manual migration scripts for simple column additions.\n\n## Data Model\n\n```mermaid\nerDiagram\n sessions ||--o{ messages : contains\n sessions ||--o{ sessions : \"parent_session_id (lineage)\"\n messages ||--|| messages_fts : \"indexed by\"\n messages ||--|| messages_fts_trigram : \"indexed by\"\n\n sessions {\n text id PK\n text source\n text title\n float started_at\n text end_reason\n integer message_count\n }\n messages {\n integer id PK\n text session_id FK\n text role\n text content\n text tool_calls\n float timestamp\n }\n```\n\n### Session Lineage and Compression\nHermes supports long-running conversations through \"compression.\" When a session context becomes too large, it is ended with `end_reason = 'compression'` and a new child session is created.\n- **`get_compression_tip(session_id)`**: Walks the chain of compressed sessions to find the current \"live\" session ID.\n- **`list_sessions_rich`**: By default, projects compression roots forward. This means a user sees one logical conversation in their history, even if it consists of multiple underlying database sessions.\n\n### Message Storage\nMessages are stored with support for multimodal content. Since SQLite cannot natively store Python lists or dicts, `SessionDB` uses a serialization trick:\n- **Encoding**: Structured content (like image parts) is JSON-serialized and prefixed with a NUL-byte sentinel (`\\x00json:`).\n- **Decoding**: The `_decode_content` method detects this prefix and restores the original Python structure.\n\n## Search Engine\n\nThe module implements two distinct FTS5 virtual tables to handle global message search:\n\n1. **`messages_fts`**: Uses the standard `unicode61` tokenizer. It is optimized for Western languages and handles prefix matching (e.g., `deploy*`).\n2. **`messages_fts_trigram`**: Uses a trigram tokenizer. This is specifically included to support **CJK (Chinese, Japanese, Korean)** characters and substring searches that the standard tokenizer fails to index correctly.\n\nThe `search_messages` function automatically routes queries:\n- Queries with $\\ge 3$ CJK characters use the trigram index.\n- Short CJK queries (1-2 characters) fall back to a standard `LIKE` search.\n- Standard text queries use the primary FTS5 index.\n\n## Session Title Management\n\nTitles are managed with strict sanitization and lineage logic:\n- **`sanitize_title`**: Strips ASCII/Unicode control characters, collapses whitespace, and enforces a 100-character limit.\n- **Lineage Numbering**: If a user tries to reuse a title or branches a session, `get_next_title_in_lineage` generates a numbered suffix (e.g., \"Project Alpha #2\").\n- **Resolution**: `resolve_session_by_title` allows looking up sessions by their human-readable name, preferring the latest continuation in a numbered chain.\n\n## Maintenance and Cleanup\n\nThe module includes self-healing and maintenance utilities:\n- **`prune_empty_ghost_sessions`**: Removes TUI sessions that were started but never received messages and are older than 24 hours.\n- **`maybe_auto_prune_and_vacuum`**: An idempotent maintenance task that deletes sessions older than a retention period (default 90 days) and runs `VACUUM` to reclaim disk space. It uses the `state_meta` table to ensure this only runs once every 24 hours.\n- **`_remove_session_files`**: When a session is deleted from the DB, this helper also cleans up associated `.json` or `.jsonl` transcript files and gateway request dumps from the filesystem.\n\n## Integration Patterns\n\n- **CLI/TUI**: Uses `list_sessions_rich` to populate history views and `resolve_session_id` to allow users to resume sessions using short ID prefixes.\n- **Gateway**: Relies on `get_messages_as_conversation` to reconstruct the full OpenAI-compatible message history, including replaying reasoning tokens and tool calls for model context.\n- **Token Tracking**: `update_token_counts` is called after every LLM interaction to accumulate costs and usage metrics at the session level.","root-hermes-time-py":"# Root — hermes_time.py\n\n# hermes_time.py\n\nThe `hermes_time.py` module provides a centralized, timezone-aware clock for the Hermes system. It ensures that all time-based operations—such as job scheduling, execution logging, and timestamping—remain consistent regardless of the server's hardware clock settings.\n\n## Core Functionality\n\nThe primary interface for this module is the `now()` function. Unlike the standard library's `datetime.now()`, which returns a naive object by default, `hermes_time.now()` always returns a **timezone-aware** datetime object.\n\n### Timezone Resolution Hierarchy\n\nThe module resolves the active timezone once and caches the result. It searches for a configuration in the following order:\n\n1. **Environment Variable**: Checks `HERMES_TIMEZONE` (e.g., `America/New_York`).\n2. **Configuration File**: Reads the `timezone` key from `~/.hermes/config.yaml`.\n3. **System Default**: Falls back to the server's local timezone using `astimezone()`.\n\n```mermaid\ngraph TD\n A[Call now] --> B{Cache resolved?}\n B -- No --> C[Check HERMES_TIMEZONE]\n C -- Found --> G[Load ZoneInfo]\n C -- Not Found --> D[Check config.yaml]\n D -- Found --> G\n D -- Not Found --> F[Use Server Local]\n G -- Invalid --> F\n B -- Yes --> H[Return datetime with cached TZ]\n```\n\n## API Reference\n\n### `now() -> datetime`\nThe standard method for getting the current time. \n- If a valid IANA timezone is configured, it returns the wall-clock time for that zone.\n- If no configuration exists or the configuration is invalid, it returns the system's local time with UTC offset information included.\n\n### `get_timezone() -> Optional[ZoneInfo]`\nReturns the currently active `zoneinfo.ZoneInfo` object. This is used internally by `now()` but can be accessed by other modules that need to perform manual conversions or comparisons. Returns `None` if the system is falling back to local time.\n\n### `_resolve_timezone_name() -> str`\nInternal helper that performs the I/O required to find the timezone string. It uses `get_config_path()` from `hermes_constants` to locate the YAML configuration.\n\n## Caching and State\n\nTo avoid repeated file I/O and environment lookups, the module state is stored in three global variables:\n- `_cached_tz`: The actual `ZoneInfo` object.\n- `_cached_tz_name`: The string name of the timezone.\n- `_cache_resolved`: A boolean flag indicating if resolution has occurred.\n\n> **Note:** If the configuration file is modified while the process is running, the cache must be cleared to reflect changes. While the module defines the logic for caching, external callers should be aware that the first call to `now()` or `get_timezone()` locks in the setting.\n\n## Error Handling and Resilience\n\nA core design principle of `hermes_time.py` is that **time resolution must never crash the application.**\n\n- **Invalid Timezones**: If a user provides a nonsense string (e.g., `timezone: \"Mars/Base_Alpha\"`), the `_get_zoneinfo` function catches the `KeyError`, logs a warning, and allows the system to fall back to the server's local time.\n- **Missing Dependencies**: The module includes a fallback for `zoneinfo` (introduced in Python 3.9) via `backports.zoneinfo` to support older environments if necessary.\n- **YAML Failures**: If `config.yaml` is malformed or inaccessible, the module silently ignores the error and proceeds to the next resolution step.\n\n## Integration Points\n\nThis module is a critical dependency for the cron and job management systems:\n- **`cron/scheduler.py`**: Uses `now()` in the `tick()` loop to determine if a job is due.\n- **`cron/jobs.py`**: Uses `now()` to calculate `next_run` times, mark job completion, and compute \"grace periods\" for missed executions.\n- **`tests/test_timezone.py`**: Extensively validates the resolution logic and ensures that the cache behaves correctly under different environment configurations.","root-hermes":"# Root — hermes\n\n# Hermes CLI Entry Point (`hermes`)\n\nThe `hermes` module is the primary command-line interface (CLI) launcher for the Hermes Agent. It serves as a thin wrapper and entry point, delegating all execution logic to the `hermes_cli` package. This script is designed to provide a consistent interface for developers and operators, mimicking the behavior of the `hermes` command installed via `pip` or `setuptools`.\n\n## Overview\n\nThe script acts as a bootstrap mechanism. When executed, it imports the core CLI logic and invokes the main execution loop. This structure keeps the root directory clean while ensuring the agent's functionality is accessible without needing to manually invoke the `hermes_cli` package via `python -m`.\n\n### Key Responsibilities\n- **Environment Initialization**: Provides the `__main__` entry point for the Python interpreter.\n- **Command Delegation**: Routes all arguments to `hermes_cli.main.main()`.\n- **Unified Interface**: Supports all agent subcommands, including `gateway`, `cron`, and `doctor`.\n\n## Execution Flow\n\nThe execution flow is straightforward, moving from the shell environment into the structured CLI package.\n\n```mermaid\ngraph TD\n A[Shell: ./hermes] --> B[hermes script]\n B --> C[hermes_cli.main:main]\n C --> D{Subcommand Router}\n D --> E[gateway]\n D --> F[cron]\n D --> G[doctor]\n```\n\n## Usage\n\n### Development\nDuring development, you can run the agent directly from the repository root:\n\n```bash\n./hermes [subcommand] [options]\n```\n\n### Subcommands\nThe launcher supports the following primary subcommands defined in the `hermes_cli` package:\n\n| Subcommand | Description |\n| :--- | :--- |\n| `gateway` | Starts the Hermes Agent gateway service. |\n| `cron` | Executes scheduled tasks and maintenance routines. |\n| `doctor` | Performs system health checks and diagnostic reporting. |\n\n## Implementation Details\n\nThe module contains no business logic. It relies entirely on the `hermes_cli` package:\n\n```python\nif __name__ == \"__main__\":\n from hermes_cli.main import main\n main()\n```\n\nBy importing `main` inside the `if __name__ == \"__main__\":` block, the script avoids unnecessary imports if the module is referenced elsewhere, though its primary purpose is strictly as an executable script.\n\n## Integration with `hermes_cli`\n\nThe `hermes` script is the external-facing boundary. To modify CLI behavior, add new flags, or implement new subcommands, developers should look into the `hermes_cli/` directory rather than modifying this wrapper. This script assumes that the `hermes_cli` package is available in the `PYTHONPATH`.","root-manifest-in":"# Root — MANIFEST.in\n\n# Root — MANIFEST.in\n\nThe `MANIFEST.in` file is a configuration file used by Python packaging tools (such as `setuptools`) to define which files and directories should be included in the Source Distribution (`sdist`). While `setuptools` automatically includes all Python modules tracked by the build system, `MANIFEST.in` is required to explicitly bundle non-code assets, data files, and specific directory structures.\n\n## Packaging Directives\n\nThe file uses the following commands to manage the package contents:\n\n### Directory Inclusion (`graft`)\nThe `graft` command recursively includes the entire contents of the specified directories, regardless of file extension.\n\n* **`graft skills`**: Includes all files within the core `skills` directory. This ensures that skill-specific metadata, JSON configurations, READMEs, or other non-Python assets are available when the package is installed.\n* **`graft optional-skills`**: Includes the entire `optional-skills` directory. This is critical for modular architectures where certain features are distributed alongside the core package but may not be imported by default.\n\n### Global Exclusions (`global-exclude`)\nTo ensure the distribution remains clean and platform-independent, specific patterns are excluded globally, even if they reside within \"grafted\" directories.\n\n* **`global-exclude __pycache__`**: Prevents the inclusion of Python's automated bytecode cache directories.\n* **`global-exclude *.py[cod]`**: Prevents the inclusion of compiled Python files (`.pyc`, `.pyo`, or `.pyd`), ensuring that users compile the source for their specific environment upon installation.\n\n## Integration in the Build Pipeline\n\nThe `MANIFEST.in` file is processed during the execution of build commands like `python -m build` or `python setup.py sdist`.\n\n```mermaid\ngraph TD\n Source[Source Code] --> Build[Build System]\n Manifest[MANIFEST.in] -->|Instructions| Build\n Build --> SDist[Source Distribution .tar.gz]\n SDist --> Installation[User Installation]\n```\n\n## Developer Impact\n\nWhen contributing to this repository, developers should be aware of how `MANIFEST.in` affects their changes:\n\n1. **Adding New Skills**: If you create a new directory under `skills/` or `optional-skills/`, the `graft` commands will automatically pick up any new files (e.g., `.json`, `.yaml`, `.md`).\n2. **Adding New Root Directories**: If you add a new top-level directory containing non-Python assets (e.g., a `templates/` or `data/` folder), you **must** add a corresponding `graft <directory_name>` line to this file, or the files will be missing from the published package.\n3. **Testing Distributions**: To verify that the manifest is working correctly, run `python -m build --sdist` and inspect the resulting `.tar.gz` file in the `dist/` directory to ensure all expected assets are present.","root-mcp-serve-py":"# Root — mcp_serve.py\n\n# mcp_serve.py\n\nThe `mcp_serve.py` module implements the **Hermes MCP Server**, a bridge that exposes messaging conversations from various platforms (Telegram, Discord, Slack, etc.) as Model Context Protocol (MCP) tools. This allows MCP-compliant clients—such as Claude Desktop, Cursor, or Codex—to read message history, send messages, and manage approvals through a standardized interface.\n\n## Architecture Overview\n\nThe server operates as a stdio-based MCP server using the `FastMCP` SDK. Because Hermes stores conversation state in a local SQLite database rather than providing a live WebSocket stream, this module implements an **EventBridge** to simulate real-time event delivery.\n\n```mermaid\ngraph TD\n Client[MCP Client] <--> Server[FastMCP Server]\n Server <--> Bridge[EventBridge]\n Bridge -- Polls --> DB[(SessionDB / state.db)]\n Bridge -- Watches --> Index[sessions.json]\n Server -- Tools --> Send[send_message_tool]\n```\n\n## The EventBridge\n\nThe `EventBridge` class is a background poller that monitors the Hermes state and maintains an in-memory queue of events. It is essential for supporting the `events_poll` and `events_wait` tools.\n\n### Polling Logic\nTo minimize CPU usage, `_poll_once` performs high-frequency checks (every 200ms) using file system metadata:\n1. It checks the `mtime` (modification time) of `sessions.json` and `state.db`.\n2. If neither file has changed, the poll exits immediately.\n3. If changes are detected, it queries the `SessionDB` for messages newer than the last seen timestamp for each active session.\n\n### Event Queue\nEvents are stored in a fixed-size queue (`QUEUE_LIMIT = 1000`). Each event is assigned a monotonically increasing `cursor`.\n- **Message Events**: Triggered when new \"user\" or \"assistant\" messages appear in the DB.\n- **Approval Events**: Tracks `approval_requested` and `approval_resolved` states for plugin or execution permissions.\n\n## Tool Reference\n\nThe module registers 10 tools that match the OpenClaw messaging bridge surface, plus Hermes-specific extensions.\n\n### Discovery Tools\n- **`conversations_list`**: Returns active sessions, filtered by platform or search terms. It reads from the `sessions.json` index.\n- **`conversation_get`**: Provides detailed metadata for a specific `session_key`, including token usage and platform-specific IDs.\n- **`channels_list`**: Lists available targets for new messages. It attempts to load from `channel_directory.json` or falls back to the session index.\n\n### Reading Tools\n- **`messages_read`**: Fetches the chronological history of a conversation from `SessionDB`. It automatically filters for \"user\" and \"assistant\" roles and extracts text content.\n- **`attachments_fetch`**: Extracts non-text media (images, file references, or `MEDIA:` tags) from a specific message ID.\n\n### Writing Tools\n- **`messages_send`**: Routes outgoing messages. It imports and invokes `tools.send_message_tool.send_message_tool` to handle the actual delivery to the target platform.\n\n### Event Tools\n- **`events_poll`**: A non-blocking tool to retrieve events occurring after a specific `after_cursor`.\n- **`events_wait`**: A long-polling tool that blocks until a new event arrives or a timeout (default 30s) is reached.\n\n### Permission Tools\n- **`permissions_list_open`**: Lists pending approval requests (e.g., tool execution requests) observed during the current server session.\n- **`permissions_respond`**: Submits a decision (`allow-once`, `allow-always`, `deny`) for a pending request.\n\n## Data Extraction Helpers\n\nThe module includes robust logic for normalizing message content across different platform formats:\n\n- **`_extract_message_content`**: Handles both raw strings and multi-part content lists, concatenating text blocks into a single string.\n- **`_extract_attachments`**: Parses message structures for `image_url` blocks, `image` source objects, and regex-based `MEDIA:` tags within text bodies.\n\n## Usage and Configuration\n\nThe server is typically invoked via the Hermes CLI:\n\n```bash\nhermes mcp serve\n```\n\n### Client Configuration (claude_desktop_config.json)\nTo connect a client to Hermes, add the following to the MCP configuration:\n\n```json\n{\n \"mcpServers\": {\n \"hermes\": {\n \"command\": \"hermes\",\n \"args\": [\"mcp\", \"serve\"]\n }\n }\n}\n```\n\n## Implementation Details\n\n- **Lazy Imports**: The `mcp` SDK is imported lazily to allow the rest of the Hermes CLI to function even if the MCP dependencies are not installed.\n- **Thread Safety**: The `EventBridge` uses a `threading.Lock` to manage concurrent access to the event queue and a `threading.Event` to wake up long-polling `events_wait` calls.\n- **Environment**: Uses `HERMES_HOME` (defaulting to `~/.hermes`) to locate the `sessions/` directory and `state.db`.","root-mini-swe-runner-py":"# Root — mini_swe_runner.py\n\n# Root — mini_swe_runner.py\n\nThe `mini_swe_runner.py` module is a specialized execution engine designed to run software engineering tasks using the Hermes-Agent trajectory format. It provides a bridge between LLM reasoning and sandboxed code execution, producing structured logs compatible with the project's trajectory compression and batch processing pipelines.\n\n## Core Functionality\n\nThe runner orchestrates a loop where an LLM is prompted to solve a task by executing bash commands. It abstracts the execution layer, allowing the same agent logic to run locally, inside Docker containers, or on Modal cloud infrastructure.\n\n### Key Features\n- **Environment Abstraction**: Uses a factory pattern to instantiate `LocalEnvironment`, `DockerEnvironment`, or `ModalEnvironment`.\n- **Hermes Trajectory Format**: Converts standard OpenAI-style message histories into a specific XML-tagged format (`<tool_call>`, `<tool_response>`) used by downstream analysis tools.\n- **Strict Sampling Control**: Integrates with `agent.auxiliary_client` to handle model-specific temperature requirements (e.g., omitting temperature for Kimi models).\n- **Completion Signaling**: Uses a specific sentinel string `MINI_SWE_AGENT_FINAL_OUTPUT` to detect when an agent has finished its task via the terminal.\n\n## Architecture and Execution Flow\n\nThe `MiniSWERunner` class manages the lifecycle of a task, from environment setup to final trajectory serialization.\n\n```mermaid\ngraph TD\n A[Main CLI] --> B[MiniSWERunner.run_task]\n B --> C[create_environment]\n C --> D{Env Type}\n D -->|local| E[LocalEnvironment]\n D -->|docker| F[DockerEnvironment]\n D -->|modal| G[ModalEnvironment]\n B --> H[LLM Loop]\n H --> I[Execute Command]\n I --> J[Check for Completion Signal]\n J -->|No| H\n J -->|Yes| K[_convert_to_hermes_format]\n K --> L[JSONL Output]\n```\n\n## Component Reference\n\n### Environment Factory: `create_environment`\nThis function acts as a provider router for execution backends. It imports the necessary environment classes from `tools.environments` dynamically to minimize dependency overhead.\n\n- **Local**: Runs commands directly on the host system.\n- **Docker**: Spawns a container from a specified `image`.\n- **Modal**: Provisions a remote container in the Modal cloud.\n\n### The `terminal` Tool\nThe runner provides a single tool definition, `TERMINAL_TOOL_DEFINITION`, which allows the agent to execute bash commands. The system prompt instructs the agent to use this tool for all actions and to signal completion by echoing a specific string.\n\n### Trajectory Formatting: `_convert_to_hermes_format`\nThis is a critical method for data compatibility. It transforms the internal `messages` list into a \"Hermes Trajectory,\" which includes:\n1. **System Message**: Injected with XML-wrapped tool definitions (`<tools>`).\n2. **GPT Messages**: Reasoning and tool calls wrapped in `<tool_call>` tags.\n3. **Tool Messages**: Execution results wrapped in `<tool_response>` tags.\n\n## Usage Patterns\n\n### Programmatic Execution\n```python\nfrom mini_swe_runner import MiniSWERunner\n\nrunner = MiniSWERunner(\n model=\"anthropic/claude-sonnet-4.6\",\n env_type=\"docker\",\n image=\"python:3.11-slim\"\n)\n\nresult = runner.run_task(\"Fix the bug in the local script.py\")\nprint(f\"Task completed: {result['completed']}\")\n```\n\n### Batch Processing\nThe `run_batch` method allows processing multiple prompts from a JSONL file. It writes results incrementally to the output file, ensuring data is preserved even if the batch is interrupted.\n\n### Command Line Interface\nThe module uses `python-fire` to expose its functionality.\n\n```bash\n# Run a single task locally\npython mini_swe_runner.py --task \"Create a hello world script\" --env local\n\n# Run a batch of tasks in Docker\npython mini_swe_runner.py --prompts_file tasks.jsonl --output_file results.jsonl --env docker\n```\n\n## Integration Details\n\n- **LLM Client**: Initialized via `resolve_provider_client` from `agent.auxiliary_client`. It defaults to OpenRouter but supports direct OpenAI/Anthropic configurations if API keys are provided.\n- **Temperature Management**: Uses `_effective_temperature_for_model` to determine if a `temperature` parameter should be sent to the API, ensuring compatibility with models that enforce strict sampling contracts.\n- **Cleanup**: The `_cleanup_env` method ensures that Docker containers or Modal instances are terminated immediately after task completion or failure.","root-model-tools-py":"# Root — model_tools.py\n\n# Root — model_tools.py\n\nThe `model_tools.py` module serves as the primary orchestration layer for the system's tool ecosystem. It acts as a bridge between the high-level agents (e.g., `run_agent.py`, RL environments) and the low-level `tools.registry`. \n\nIts primary responsibilities include tool discovery, schema generation with dynamic filtering, argument type coercion, and managing the sync-to-async execution bridge.\n\n## Core Architecture\n\nThe module functions as a stateless dispatcher that relies on the `tools.registry` for storage and `toolsets.py` for grouping logic.\n\n```mermaid\ngraph TD\n A[Agent / CLI / Gateway] --> B[model_tools.py]\n B --> C{Action}\n C -->|Schema Request| D[get_tool_definitions]\n C -->|Execution| E[handle_function_call]\n D --> F[tools.registry]\n E --> G[Argument Coercion]\n G --> H[Plugin Hooks]\n H --> I[tools.registry.dispatch]\n I --> J[Async Bridge]\n J --> K[Actual Tool Implementation]\n```\n\n## Tool Discovery\n\nDiscovery is triggered upon module import. The module executes `discover_builtin_tools()` and attempts to load external plugins via `hermes_cli.plugins.discover_plugins()`. \n\n**Note on MCP Tools:** Unlike built-in tools, MCP (Model Context Protocol) discovery is no longer a module-level side effect to prevent blocking the event loop during gateway initialization. Entry points (like `gateway/run.py`) are responsible for triggering MCP discovery explicitly.\n\n## Sync-to-Async Bridging\n\nOne of the most critical components of this module is `_run_async`. Because many tool handlers are `async` but the calling agents or CLI paths are often synchronous, this module manages persistent event loops to avoid the \"Event loop is closed\" errors common with `asyncio.run()`.\n\n- **Main Thread:** Uses a long-lived `_tool_loop`.\n- **Worker Threads:** Uses `_worker_thread_local` to maintain per-thread loops for parallel execution (e.g., `delegate_task`).\n- **Async Contexts:** If called from within an existing running loop (like the Discord gateway), it spawns a fresh thread with a managed loop and a 300-second timeout to prevent hanging the main process.\n\n## Tool Definitions and Filtering\n\nThe `get_tool_definitions` function is the source of truth for the model's available tools.\n\n### Memoization\nTo optimize performance for hot callers (like the Gateway), results are cached in `_tool_defs_cache`. The cache key includes:\n- Enabled/Disabled toolset sets.\n- The registry's `_generation` counter (invalidated on tool registration).\n- A fingerprint of the configuration file (mtime/size) to catch dynamic changes in tool settings.\n\n### Dynamic Schema Modification\nThe module performs \"just-in-time\" schema adjustments before returning them to the model:\n- **`execute_code`**: Rebuilds the schema to only list sandbox tools that are currently available and enabled.\n- **`discord` / `discord_admin`**: Filters available actions based on the bot's privileged intents and the user's allowlist.\n- **`browser_navigate`**: Strips references to `web_search` if those tools are disabled, preventing model hallucinations.\n- **Sanitization**: Passes all schemas through `tools.schema_sanitizer` to ensure compatibility with strict parsers like `llama.cpp`.\n\n## Function Call Handling\n\nThe `handle_function_call` function manages the lifecycle of a tool execution.\n\n### 1. Argument Coercion\nLLMs frequently output numbers or booleans as strings (e.g., `\"true\"` or `\"42\"`). `coerce_tool_args` uses the tool's JSON Schema to safely cast these values back to their expected types before dispatching.\n\n### 2. Interception and Hooks\nThe dispatcher integrates with the plugin system:\n- **Pre-call Hooks**: `get_pre_tool_call_block_message` allows plugins to intercept and block calls.\n- **Agent-Loop Tools**: Tools like `todo`, `memory`, and `delegate_task` are intercepted and returned as stub errors if they reach this dispatcher, as they must be handled by the higher-level agent loop.\n- **Post-call Hooks**: `post_tool_call` is fired after execution, providing the result and `duration_ms`.\n- **Transformation Hooks**: `transform_tool_result` allows plugins to modify the tool's output before it is returned to the model.\n\n### 3. Execution Tracking\nFor file-related tools, the dispatcher calls `notify_other_tool_call` in `tools.file_tools`. This resets consecutive read counters, helping the system detect and break infinite \"read-file\" loops.\n\n## Public API Reference\n\n| Function | Description |\n| :--- | :--- |\n| `get_tool_definitions(...)` | Returns OpenAI-format tool schemas filtered by toolsets. |\n| `handle_function_call(...)` | Coerces arguments, runs hooks, and dispatches execution. |\n| `get_all_tool_names()` | Returns a flat list of all registered tool names. |\n| `get_toolset_for_tool(name)` | Identifies which toolset a specific tool belongs to. |\n| `check_tool_availability(quiet)` | Returns status of toolsets and any missing requirements. |\n| `_run_async(coro)` | The internal utility for running coroutines from sync code. |\n\n## Legacy Support\nThe module maintains `_LEGACY_TOOLSET_MAP` to map old toolset names (e.g., `web_tools`, `vision_tools`) to their modern tool equivalents, ensuring backward compatibility with older configuration files and agent implementations.","root-package-json":"# Root — package.json\n\n# Root Configuration: package.json\n\nThe `package.json` file at the root of the Hermes Agent project defines the Node.js environment required for the agent's browser automation capabilities. While the primary agent logic is executed via Python (`run_agent.py`), the browser-based toolsets rely on a Node.js stack to interface with web environments.\n\n## Purpose\n\nThis module manages the JavaScript dependencies necessary for the agent to perform web browsing, DOM manipulation, and automated interaction. It ensures that the underlying browser drivers and automation frameworks are versioned and installed correctly alongside the Python components.\n\n## Key Dependencies\n\nThe project utilizes two primary packages for browser interaction:\n\n* **`@askjo/camofox-browser` (^1.5.2)**: Provides the core browser engine capabilities, likely focused on anti-detection or specialized browsing patterns required for AI agents.\n* **`agent-browser` (^0.26.0)**: A high-level wrapper or interface designed to bridge the gap between AI agents and browser automation frameworks.\n\n## System Requirements\n\nThe project enforces a specific runtime environment to ensure compatibility with modern JavaScript features used in the browser toolsets:\n\n* **Node.js Engine**: `>=20.0.0`\n* **Dependency Overrides**: The project explicitly pins `lodash` to version `4.18.1` via the `overrides` field to ensure consistent behavior and address potential security vulnerabilities in transitive dependencies.\n\n## Integration Flow\n\nThe Node.js environment acts as a subsystem for the main Python agent. The relationship between the package configuration and the execution flow is illustrated below:\n\n```mermaid\ngraph TD\n A[run_agent.py] -- Invokes --> B[Python Toolsets]\n B -- Interfaces with --> C[Node.js Environment]\n C -- Loads --> D[@askjo/camofox-browser]\n C -- Loads --> E[agent-browser]\n subgraph \"package.json Management\"\n D\n E\n end\n```\n\n## Scripts and Lifecycle\n\n### postinstall\nThe `postinstall` script serves as a bridge for developers setting up the environment. Once `npm install` is executed, it provides immediate feedback:\n```bash\n✅ Browser tools ready. Run: python run_agent.py --help\n```\nThis indicates that the JavaScript-based browser drivers are successfully staged and the user should return to the Python entry point to operate the agent.\n\n## Development Notes\n\n- **Private Package**: The module is marked `\"private\": true`, preventing accidental publication to the npm registry.\n- **Repository**: Linked to [NousResearch/Hermes-Agent](https://github.com/NousResearch/Hermes-Agent), which serves as the central hub for both the Python logic and these Node.js configurations.\n- **Contribution**: When adding new browser-based tools, developers should check if additional Node.js packages are required and update the `dependencies` section accordingly, ensuring they are compatible with Node 20+.","root-pyproject-toml":"# Root — pyproject.toml\n\n# Project Configuration (pyproject.toml)\n\nThe `pyproject.toml` file serves as the central manifest for the `hermes-agent` ecosystem. It defines the build system, core and optional dependencies, CLI entry points, and configuration for development tools like `pytest` and `ty`.\n\n## Build System and Metadata\n\nThe project uses `setuptools` as the build backend. \n\n* **Package Name:** `hermes-agent`\n* **Version:** `0.12.0`\n* **Python Requirement:** `>=3.11`\n* **License:** MIT\n\n## Core Dependencies\n\nThe core dependencies are pinned to known-good version ranges to ensure stability and limit the supply chain attack surface. They are categorized into functional groups:\n\n| Category | Packages |\n| :--- | :--- |\n| **LLM Clients** | `openai`, `anthropic` |\n| **Data & Logic** | `pydantic`, `jinja2`, `pyyaml`, `tenacity` |\n| **CLI & UI** | `rich`, `prompt_toolkit`, `fire` |\n| **Networking** | `httpx[socks]`, `requests` |\n| **Built-in Features** | `croniter` (Scheduling), `edge-tts` (Speech), `PyJWT` (Auth) |\n| **Search & Tools** | `exa-py`, `firecrawl-py`, `parallel-web`, `fal-client` |\n\n## Optional Dependencies (Extras)\n\n`hermes-agent` uses a modular dependency strategy. Most integrations and heavy features are optional to keep the base installation lean.\n\n### Integration Extras\n* **Cloud/Compute:** `modal`, `daytona`, `vercel`.\n* **Messaging:** `messaging` (Telegram, Discord, Slack), `slack`, `matrix`, `dingtalk`, `feishu`.\n* **AI/LLM Providers:** `mistral`, `bedrock`.\n* **Protocols:** `mcp` (Model Context Protocol), `acp` (Agent Client Protocol).\n\n### Feature Extras\n* **`voice`:** Includes `faster-whisper` and `sounddevice` for local STT.\n* **`web`:** Includes `fastapi` and `uvicorn` for the local dashboard.\n* **`google`:** Includes API clients for Workspace (Gmail, Calendar, Drive).\n* **`rl`:** Reinforcement Learning tools including `atroposlib` and `tinker`.\n* **`termux`:** A curated bundle for Android/Termux environments that avoids non-Android wheels.\n\n### Development Extras\n* **`dev`:** Includes `pytest`, `pytest-asyncio`, `debugpy`, and `ruff`.\n\n## CLI Entry Points\n\nThe configuration defines three primary command-line interfaces:\n\n```toml\n[project.scripts]\nhermes = \"hermes_cli.main:main\"\nhermes-agent = \"run_agent:main\"\nhermes-acp = \"acp_adapter.entry:main\"\n```\n\n1. **`hermes`**: The main interactive CLI and management tool.\n2. **`hermes-agent`**: Direct entry point to run an agent instance.\n3. **`hermes-acp`**: Entry point for the Agent Client Protocol adapter.\n\n## Package Structure\n\nThe project uses a hybrid layout of top-level modules and packages, explicitly defined in the `[tool.setuptools]` section.\n\n### Included Packages\nThe following directories are treated as packages:\n* `agent`, `tools`, `hermes_cli`, `gateway`, `tui_gateway`, `cron`, `acp_adapter`, `plugins`.\n\n### Top-Level Modules\nSeveral utility and core modules reside directly in the root for simplified imports:\n* `run_agent.py`, `model_tools.py`, `toolsets.py`, `batch_runner.py`, `cli.py`, `hermes_constants.py`, `hermes_logging.py`, etc.\n\n## Development Configuration\n\n### Testing (Pytest)\n* **Path:** Tests are located in the `/tests` directory.\n* **Markers:** Defines an `integration` marker for tests requiring external API keys or services.\n* **Execution:** Defaults to skipping integration tests and using `pytest-xdist` (`-n auto`) for parallel execution.\n\n### Type Checking (Ty)\nThe project uses `ty` for environment and type configuration, targeting Python 3.13. It is configured with several overrides to ignore specific linting/typing errors (`unresolved-import`, `invalid-method-override`) that may occur due to the dynamic nature of agent tool loading.\n\n### Linting (Ruff)\nThe current configuration excludes all files from `ruff` analysis (`exclude = [\"*\"]`), suggesting linting is handled via other workflows or is currently disabled at the project root level.","root-readme-md":"# Root — README.md\n\n# Hermes Agent: Project Overview\n\nHermes Agent is a self-improving AI agent framework designed for persistence, cross-platform availability, and autonomous skill acquisition. Unlike stateless chat interfaces, Hermes maintains a continuous learning loop, building a procedural memory of \"skills\" and a declarative memory of user preferences and session history.\n\n## System Architecture\n\nHermes is structured to decouple the user interface (CLI or Messaging Gateway) from the execution environment (Terminal Backends). This allows the agent to run on serverless infrastructure or remote VMs while being controlled from lightweight clients like Telegram or a local terminal.\n\n```mermaid\ngraph TD\n User((User))\n CLI[hermes CLI]\n Gateway[hermes gateway]\n Core[Agent Core / LLM Loop]\n Backends[Terminal Backends: Docker, SSH, Modal, Local]\n Memory[(Memory: FTS5, Honcho, Skills)]\n \n User --> CLI\n User --> Gateway\n CLI --> Core\n Gateway --> Core\n Core --> Backends\n Core --> Memory\n Core --> Tools[Tools & MCP Servers]\n```\n\n## Core Components\n\n### 1. Entry Points\nThe system provides two primary interaction methods:\n* **Interactive CLI (`hermes`)**: A rich Terminal User Interface (TUI) featuring multiline editing, slash-command autocomplete, and streaming tool outputs.\n* **Messaging Gateway (`hermes gateway`)**: A multi-protocol bridge that connects the agent to Telegram, Discord, Slack, WhatsApp, Signal, and Email. It supports voice memo transcription and cross-platform session continuity.\n\n### 2. The Learning Loop\nHermes implements a \"closed learning loop\" that distinguishes it from standard ReAct agents:\n* **Autonomous Skill Creation**: After completing complex tasks, the agent can curate its own logic into reusable \"skills\" (compatible with the [agentskills.io](https://agentskills.io) standard).\n* **Dialectic User Modeling**: Utilizes [Honcho](https://github.com/plastic-labs/honcho) to build a deepening model of the user across sessions.\n* **Cross-Session Recall**: Uses SQLite FTS5 for full-text search across session histories, combined with LLM-driven summarization for context retrieval.\n\n### 3. Execution Backends\nThe agent does not execute code directly in its host process. Instead, it utilizes one of six terminal backends:\n* **Local**: Direct execution on the host machine.\n* **Docker/Singularity**: Containerized isolation.\n* **SSH**: Execution on a remote server.\n* **Daytona/Modal**: Serverless execution environments that hibernate when idle and wake on demand, providing persistent state without constant compute costs.\n\n### 4. Tooling & Extensibility\n* **Built-in Tools**: Over 40 native tools for file manipulation, web searching, and system administration.\n* **MCP Integration**: Support for the Model Context Protocol (MCP), allowing the agent to connect to any external MCP server.\n* **Subagents**: The ability to spawn isolated subagents for parallel workstreams or specialized tasks.\n\n## Developer Commands\n\nThe `hermes` binary serves as the primary management utility for the environment:\n\n| Command | Description |\n|:---|:---|\n| `hermes setup` | Interactive wizard to configure providers, keys, and backends. |\n| `hermes model` | Switches the active LLM provider (OpenRouter, OpenAI, NVIDIA NIM, etc.). |\n| `hermes tools` | Enables or disables specific toolsets. |\n| `hermes doctor` | Runs diagnostic checks on the environment and dependencies. |\n| `hermes claw migrate` | Utility to import state (SOUL.md, memories, skills) from OpenClaw. |\n\n## Development Environment\n\nThe project uses `uv` for fast, reproducible dependency management.\n\n### Setup for Contributors\nTo set up a local development environment with all extras (including RL environments and dev tools):\n\n```bash\ngit clone https://github.com/NousResearch/hermes-agent.git\ncd hermes-agent\n./setup-hermes.sh\n```\n\nThe `setup-hermes.sh` script automates:\n1. Installation of the `uv` package manager.\n2. Creation of a Python 3.11 virtual environment.\n3. Editable installation of the package with `[all,dev]` extras.\n4. Symlinking the `hermes` executable to `~/.local/bin/`.\n\n### Testing\nRun the test suite using the provided helper script:\n```bash\nscripts/run_tests.sh\n```\n\n### RL & Research\nFor research-focused workflows, the module includes integrations for:\n* **Atropos RL**: Located in `environments/`, used for trajectory generation and reinforcement learning.\n* **Trajectory Compression**: Tools for processing agent logs into training data for tool-calling models.","root-release-v0-10-0-md":"# Root — RELEASE_v0.10.0.md\n\n# Hermes Agent v0.10.0 Release Documentation\n\nThe v0.10.0 release (v2026.4.16) introduces the **Nous Tool Gateway**, a centralized infrastructure for managing and accessing external tools without requiring individual third-party API keys. This release shifts the agent's tool execution logic to prioritize subscription-based access via the Nous Portal.\n\n## Nous Tool Gateway\n\nThe Tool Gateway acts as a unified provider for high-latency or complex external services. It allows paid Nous Portal subscribers to utilize a suite of tools through their existing authentication context.\n\n### Supported Tools\nThe gateway currently provides managed access to:\n* **Web Search:** Powered by Firecrawl.\n* **Image Generation:** Powered by FAL / FLUX 2 Pro.\n* **Text-to-Speech (TTS):** Powered by OpenAI TTS.\n* **Browser Automation:** Powered by Browser Use.\n\n### Tool Selection Logic\nThe runtime implements a priority-based selection mechanism. When a tool is requested, the agent evaluates the configuration in the following order:\n1. **Gateway Preference:** If `use_gateway` is enabled in the configuration and a valid Nous Portal subscription is detected, the agent routes the request through the Gateway.\n2. **Direct API Keys:** If the gateway is disabled or the user is not a subscriber, the agent falls back to local environment variables/API keys (e.g., `FIRECRAWL_API_KEY`).\n\n```mermaid\ngraph TD\n A[Tool Request] --> B{use_gateway enabled?}\n B -- Yes --> C{Active Subscription?}\n C -- Yes --> D[Execute via Nous Tool Gateway]\n B -- No --> E[Check Local API Keys]\n C -- No --> E\n E --> F[Execute via Direct Provider]\n```\n\n## CLI Integration\n\nThe Tool Gateway is integrated into the standard Hermes CLI workflow:\n\n* **`hermes model`**: During model selection, users can choose the Nous Portal provider. This triggers the prompt to enable specific gateway-managed tools.\n* **`hermes tools`**: Lists available tools and indicates whether they are being served via the Gateway or a direct provider.\n* **`hermes status`**: Displays the current subscription status and gateway connectivity.\n\n## Configuration and Environment Changes\n\n### `use_gateway` Config\nA new configuration flag, `use_gateway`, has been introduced. This is a per-tool opt-in setting that determines if the agent should attempt to route requests through the Nous infrastructure.\n\n### Deprecations\n* **`HERMES_ENABLE_NOUS_MANAGED_TOOLS`**: This environment variable is now deprecated and replaced by the subscription-based detection logic. The agent now automatically detects eligibility based on the authenticated Nous Portal session.\n\n## Implementation Details\n\nThe implementation (originally tracked in PR [#11206](https://github.com/NousResearch/hermes-agent/pull/11206)) ensures that the gateway is treated as a primary provider. This reduces the configuration overhead for developers and end-users, as the agent handles the underlying authentication and request formatting for the proxied services.\n\nWhen a tool is invoked, the agent's tool executor checks the `use_gateway` boolean. If true, it wraps the tool call in a gateway-specific request header containing the user's portal credentials, routing it to the Nous Research managed endpoints rather than the tool provider's direct API.","root-release-v0-11-0-md":"# Root — RELEASE_v0.11.0.md\n\n# Hermes Agent v0.11.0 (v2026.4.23) — Technical Overview\n\nThe v0.11.0 release, internally dubbed \"The Interface Release,\" represents a significant architectural shift in how Hermes Agent handles model communication, user interaction, and plugin extensibility. The primary technical achievements include the abstraction of the transport layer, a complete rewrite of the CLI using a React-based TUI, and a major expansion of the plugin surface.\n\n## 🏗️ Architectural Shift: The Transport Layer\n\nPrior to v0.11.0, format conversion and HTTP logic were tightly coupled within `run_agent.py`. This release introduces a pluggable transport architecture located in `agent/transports/`, centered around a `Transport` Abstract Base Class (ABC).\n\n### Transport Implementations\nThe transport layer now owns the responsibility of converting internal agent states into provider-specific API shapes:\n\n* **`AnthropicTransport`**: Handles the Anthropic Messages API format.\n* **`ChatCompletionsTransport`**: The standard path for OpenAI-compatible providers.\n* **`ResponsesApiTransport`**: Supports the newer OpenAI Responses API and Codex-specific `build_kwargs`.\n* **`BedrockTransport`**: Implements the AWS Bedrock Converse API, providing native support for AWS-hosted models.\n\nThis decoupling allows developers to add new inference paths by implementing a single transport class rather than modifying the core agent loop.\n\n## 🖥️ New Ink-based TUI Architecture\n\nThe interactive CLI has been rewritten from the ground up using **React** and **Ink**. This architecture separates the UI rendering from the agent logic via a JSON-RPC bridge.\n\n### Components\n* **`ui-tui/`**: A TypeScript/React project using Ink to render terminal components.\n* **`tui_gateway/`**: A Python-based JSON-RPC backend that manages the agent session.\n* **`_SlashWorker`**: A persistent subprocess dedicated to dispatching slash commands without blocking the main UI thread.\n\n### Key TUI Features for Developers\n* **State Management**: Uses a state machine in `src/app.tsx` to handle transitions between idle, thinking, and tool-execution states.\n* **RPC Hooks**: Custom hooks like `useCompletion` and `useInputHistory` manage communication with the Python backend.\n* **Observability**: Includes a subagent spawn overlay to visualize the hierarchy of delegated tasks in real-time.\n\n## 🧩 Expanded Plugin Surface\n\nThe plugin system has been significantly hardened and expanded, allowing third-party code to intercept and modify almost every stage of the agent's execution cycle.\n\n### New Hook Points\nDevelopers can now utilize the following hooks in their plugins:\n* **`register_command()`**: Dynamically adds new slash commands to the agent.\n* **`dispatch_tool()`**: Allows a plugin to programmatically trigger a tool execution.\n* **`pre_tool_call`**: A veto-capable hook that can block tool execution based on custom logic.\n* **`transform_tool_result`**: Intercepts and rewrites the output of any tool before the LLM sees it.\n* **`transform_terminal_output`**: Specifically targets the output of terminal/shell tools for sanitization or formatting.\n\n### Shell Hooks\nA new bridge allows non-Python scripts to act as lifecycle hooks. By configuring shell scripts for events like `on_session_start` or `post_tool_call`, developers can extend Hermes using any language.\n\n## 🤖 Agent Orchestration & Delegation\n\nThe delegation logic has been upgraded to support complex, multi-layered agent hierarchies.\n\n### Subagent Coordination\n* **Orchestrator Role**: Subagents are now aware of their role and can spawn their own workers.\n* **`max_spawn_depth`**: A configurable parameter (defaulting to flat) that prevents infinite delegation loops.\n* **File Coordination Layer**: Concurrent sibling subagents now utilize a coordination layer to prevent race conditions when editing the same files on the filesystem.\n\n### Mid-run Steering\nThe `/steer <prompt>` command allows users to inject \"nudges\" into the agent's context. Technically, this injects a system-level note that is processed immediately after the next tool call, allowing for course correction without interrupting the current generation or breaking the prompt cache.\n\n## 📱 Messaging Gateway Updates\n\nThe messaging layer (Gateway) now supports 17 platforms with the addition of **QQBot** (via QQ Official API v2).\n\n### Platform-Specific Enhancements\n* **Telegram**: Added `TELEGRAM_PROXY` support and `ignored_threads` configuration.\n* **Discord**: Support for Forum channels and role-based access control via `DISCORD_ALLOWED_ROLES`.\n* **Webhook Direct-Delivery**: A \"zero-LLM\" mode where incoming webhooks are forwarded directly to a chat platform, bypassing the agent loop for simple alerting and notifications.\n\n## 📊 Web Dashboard Extensibility\n\nThe web dashboard now mirrors the agent's plugin philosophy. It features a **Live-switching theme system** and a **Dashboard plugin system**, allowing developers to add custom tabs, widgets, and views to the web UI without forking the core repository.\n\n```mermaid\ngraph TD\n A[User Interface] --> B{TUI / Dashboard}\n B --> C[JSON-RPC / API]\n C --> D[Core Agent Loop]\n D --> E[Plugin Manager]\n D --> F[Transport Layer]\n F --> G[Anthropic]\n F --> H[OpenAI/Codex]\n F --> I[AWS Bedrock]\n E --> J[Custom Hooks]\n E --> K[Tool Dispatch]\n```\n\n## 🔧 Tooling & Infrastructure\n* **Inference Paths**: Added native support for NVIDIA NIM, Arcee AI, and Google Gemini (via AI Studio and CLI OAuth).\n* **Session Management**: Automatic `VACUUM` of `state.db` and session pruning at startup to maintain performance.\n* **Security**: Introduced a global toggle to restrict the agent's ability to resolve private/internal URLs.","root-release-v0-12-0-md":"# Root — RELEASE_v0.12.0.md\n\n# Release v0.12.0: The Curator Release\n\nRelease v0.12.0 (v2026.4.30) introduces a shift toward autonomous maintenance and self-optimization. The core theme of this release is the **Curator**, a background agent responsible for the lifecycle management of the agent's skill library.\n\n## 🤖 Autonomous Curator (`hermes curator`)\n\nThe Curator is an autonomous background agent designed to maintain the health of the skill library. It operates on a 7-day cron cycle (configurable via the gateway's ticker) and performs grading, pruning, and consolidation of skills.\n\n### Key Components\n- **Execution Engine**: Runs via `hermes curator`. It inherits the parent configuration but operates with unbounded iterations to complete its maintenance tasks.\n- **Classification Logic**: Uses a combination of model-based reasoning and heuristics to decide if a skill should be **consolidated** (merged with related skills) or **pruned** (archived due to lack of use or redundancy).\n- **Reporting**: Generates per-run artifacts in `logs/curator/run.json` and a human-readable `REPORT.md`.\n- **Skill Protection**: Implements defense-in-depth gates. Skills marked as \"pinned\" or those residing in protected \"bundled/hub\" directories are immune to mutation or pruning by the Curator.\n\n### Commands\n- `hermes curator status`: Ranks skills by usage metrics (most-used vs. least-used) based on `bump_use()` telemetry.\n- `hermes model`: Used to select the specific model assigned to `auxiliary.curator`.\n\n---\n\n## 🔄 Self-Improvement Loop (Background Review Fork)\n\nThe self-improvement mechanism, which reviews sessions to save memories or update skills, has been refactored into a class-first, rubric-based system.\n\n### Technical Improvements\n- **Rubric-Based Grading**: Replaces free-form evaluation with a structured rubric to determine if a skill update is necessary.\n- **Runtime Propagation**: The review fork now correctly inherits the parent's live runtime, including specific providers, models, and credentials.\n- **Context Sanitization**: Prior-turn tool messages are excluded from the summary provided to the fork, ensuring the model sees a clean context for decision-making.\n- **Tool Scoping**: To prevent \"agent sprawl,\" the review fork is strictly restricted to the `memory` and `skills` toolsets. It cannot access the shell or web search.\n\n---\n\n## 🔌 Pluggable Gateway & Messaging\n\nThe Gateway has been refactored into a **Plugin Host**, allowing messaging platforms to exist as drop-in adapters outside the core codebase.\n\n### New Platforms & Integrations\n- **Microsoft Teams**: The first platform delivered entirely as a plugin.\n- **Tencent 元宝 (Yuanbao)**: Added as the 18th native messaging platform.\n- **Spotify**: Native integration featuring 7 tools (play, search, queue, etc.) using PKCE OAuth.\n- **Google Meet**: A realtime plugin utilizing OpenAI transport and a Node-based bot server for transcription and follow-ups.\n\n### Gateway Hooks\nDevelopers can now intercept the message lifecycle using:\n- `pre_gateway_dispatch`: Intercept messages before they reach the platform adapter.\n- `pre_approval_request` / `post_approval_response`: Hooks for custom logic around tool execution approvals.\n\n---\n\n## ⚡ Performance & Cold Start Optimization\n\nVisible TUI cold start times have been reduced by approximately **57%** through aggressive lazy loading and caching strategies.\n\n| Optimization | Implementation Detail |\n| :--- | :--- |\n| **Lazy Agent Init** | Defers full agent instantiation until the first user interaction. |\n| **Lazy Imports** | Heavy libraries (OpenAI, Anthropic, Firecrawl) are only imported when the specific provider is invoked. |\n| **Config Caching** | `load_config()` and `read_raw_config()` now utilize mtime-based caching. |\n| **Tool Memoization** | `get_tool_definitions()` is memoized, and `check_fn` results are stored in a TTL cache. |\n| **Pattern Precompilation** | Security patterns (`DANGEROUS_PATTERNS`) are precompiled at startup. |\n\n---\n\n## 🛠️ Developer & CLI Enhancements\n\n### One-Shot Mode\nThe new `hermes -z <prompt>` flag allows for non-interactive execution. It supports model/provider overrides via `--model`, `--provider`, or the `HERMES_INFERENCE_MODEL` environment variable.\n\n### Skill Management\n- **Direct URL Install**: `hermes skills install <url>` allows installing skills directly from HTTP(S) sources.\n- **Hot Reloading**: The `/reload-skills` slash command and `.env` hot-reloading via `/reload` reduce the need for restarts during development.\n- **External Directory Editing**: `skill_manage` now supports in-place edits for skills located in `external_dirs`.\n\n### TUI Updates\n- **LaTeX Support**: Native rendering of mathematical expressions.\n- **Session Management**: The `/resume` picker now supports deleting sessions with the `d` key.\n- **Mouse Handling**: Added a `/mouse` toggle to resolve ConPTY \"phantom mouse\" issues, particularly in WSL2 environments.\n\n---\n\n## 🔒 Security & Reliability\n\n- **Secret Redaction**: Now **disabled by default**. This prevents \"fake secret\" substrings from corrupting tool outputs or patches. It can be re-enabled via `redaction.enabled: true`.\n- **Atomic Writes**: File operations now preserve symlinks during atomic writes to prevent configuration loss.\n- **Content Filter Dodging**: User-injected `[SYSTEM:` markers are automatically renamed to `[IMPORTANT:` to prevent triggering aggressive Azure AI content filters.\n- **FTS5 Indexing**: The search engine now indexes `tool_name` and `tool_calls` in the SQLite FTS5 index, improving the retrievability of past tool usage.\n\n```mermaid\ngraph TD\n A[Gateway Ticker] -->|7-day cycle| B(hermes curator)\n B --> C{Skill Library}\n C --> D[Grade & Rank]\n D --> E[Consolidate]\n D --> F[Prune/Archive]\n B --> G[REPORT.md]\n H[User Session] --> I[Review Fork]\n I -->|Rubric Check| J{Update Skill?}\n J -->|Yes| C\n```","root-release-v0-2-0-md":"# Root — RELEASE_v0.2.0.md\n\n# Release v0.2.0 (v2026.3.12)\n\nThe v0.2.0 release marks the transition of Hermes Agent from a foundational internal project to a production-ready AI agent platform. This version introduces a centralized provider architecture, a multi-platform messaging gateway, and a modular skills ecosystem.\n\n## Core Architecture: Centralized Provider Router\n\nThe most significant architectural shift in v0.2.0 is the consolidation of LLM interaction logic. Previously scattered across various modules (vision, summarization, compression), all LLM requests now flow through a unified routing layer.\n\n### Key APIs\n- `call_llm()` / `async_call_llm()`: The primary entry points for all LLM consumers.\n- `resolve_provider_client()`: Handles credential resolution, API key rotation, and provider-specific client initialization.\n\nThis centralization ensures that features like **Nous Portal** authentication, **OpenRouter** preferences, and automatic credential refresh (e.g., 401 error handling) are applied consistently across the entire application.\n\n```mermaid\ngraph TD\n A[Agent Loop / Skills] --> B[Provider Router]\n B --> C{resolve_provider_client}\n C --> D[OpenAI / Codex]\n C --> E[Anthropic]\n C --> F[Nous Portal]\n C --> G[Local vLLM / Kimi / Azure]\n```\n\n## Messaging Gateway & Session Management\n\nThe Gateway provides a unified interface for interacting with Hermes across multiple messaging platforms. It abstracts platform-specific complexities (like Telegram's `send_document` vs. Discord's attachment handling) into a consistent session-based context.\n\n### Supported Platforms\n- **Telegram:** Supports native file attachments, forum topic isolation, and location data.\n- **Discord:** Includes channel topics in context and filters bot messages via `DISCORD_ALLOW_BOTS`.\n- **WhatsApp:** Features multi-user session isolation and native media support.\n- **Signal & Email:** New gateways for Signal (via REST API) and Email (IMAP/SMTP).\n- **Home Assistant:** Integration via WebSocket gateway and REST tools.\n\n### Session Features\n- **Naming & Lineage:** Sessions now support unique titles and auto-lineage for easier resumption via `/resume`.\n- **Context Compression:** Automatically handles `413 Payload Too Large` errors by compressing pathologically large sessions instead of aborting.\n- **Tool Visibility:** Subagent thinking and tool calls are now optionally exposed to gateway users via `edit_message()` updates.\n\n## Tooling & MCP Integration\n\nHermes v0.2.0 introduces native support for the **Model Context Protocol (MCP)**, allowing the agent to interface with external tool servers dynamically.\n\n- **Transports:** Supports both `stdio` and `HTTP` transports.\n- **Discovery:** Implements resource and prompt discovery, allowing the agent to \"learn\" what an MCP server offers at runtime.\n- **Sampling:** Supports server-initiated LLM requests, enabling complex agentic workflows where the tool server can request LLM completions.\n- **Lifecycle:** Managed via `hermes tools` UI and the `/reload-mcp` command.\n\n## Skills Ecosystem\n\nThe Skills system has been modularized to support a growing library of 70+ community-contributed capabilities.\n\n- **Conditional Activation:** Skills can now define prerequisites. A skill is only loaded if its required tools (e.g., a browser or a specific API key) are available.\n- **Platform Filtering:** Skills can be enabled or disabled on a per-platform basis (e.g., disabling heavy file-ops skills on WhatsApp).\n- **Skills Hub:** Accessible via `hermes skills browse`, providing a paginated interface for discovering and installing new capabilities.\n\n## Security & Reliability Hardening\n\nSignificant effort was invested in making the agent safe for local and remote execution.\n\n### Security Measures\n- **Path Validation:** Fixed path traversal vulnerabilities in `skill_view` and implemented symlink boundary checks in `skills_guard`.\n- **Injection Prevention:** Hardened shell execution against multi-line bypasses and process substitution patterns (e.g., `tee`).\n- **Atomic Writes:** Critical data files—including `.env`, `sessions.json`, and cron jobs—now use atomic write patterns to prevent data corruption during crashes.\n- **Permissions:** Sensitive files are now strictly enforced with `0600` or `0700` permissions.\n\n### Reliability Features\n- **Filesystem Checkpoints:** The agent now takes snapshots before destructive operations, allowing users to invoke `/rollback`.\n- **Git Worktree Isolation:** The `-w` flag allows launching agents in isolated git worktrees, preventing file conflicts during parallel development tasks.\n- **Test Suite:** Coverage increased to 3,289 tests, utilizing `pytest-xdist` for parallel execution.\n\n## Developer Experience (CLI)\n\nThe CLI has been overhauled with a data-driven skin engine and interactive features:\n- **Skins:** 7 built-in themes (e.g., `ares`, `poseidon`) configurable via YAML.\n- **Quick Commands:** User-defined shortcuts that bypass the LLM loop for immediate execution.\n- **Diagnostics:** `hermes doctor` provides a comprehensive health check of all configured providers and system dependencies.\n- **Insights:** The `/insights` command provides usage analytics and cost estimation.","root-release-v0-3-0-md":"# Root — RELEASE_v0.3.0.md\n\n# Hermes Agent v0.3.0 (v2026.3.17)\n\nThe v0.3.0 release represents a significant architectural shift toward a unified, streaming-first agent environment. It introduces a centralized provider routing system, a first-class plugin architecture, and enhanced security layers for tool execution.\n\n## Core Architecture Updates\n\n### Centralized Provider Router\nThe provider system has been rebuilt around a unified `call_llm` API. This abstraction decouples the agent logic from specific provider implementations (OpenAI, Anthropic, Vercel AI Gateway, etc.).\n\n* **Unified Routing:** The `/model` command now triggers an auto-detection sequence that resolves the correct provider based on the model string.\n* **Direct Overrides:** Developers can now specify `endpoint` overrides for auxiliary tasks (e.g., vision or subagent delegation) via the `custom_providers` configuration.\n* **Native Anthropic Support:** Includes direct API integration with Claude, supporting native prompt caching and OAuth PKCE flows, bypassing the need for intermediate proxies like OpenRouter.\n\n### Unified Streaming Infrastructure\nStreaming is now a first-class citizen across all interfaces. Token-by-token delivery is implemented via a shared infrastructure used by both the CLI and the Gateway platforms (Telegram, Discord, Slack). This reduces perceived latency and allows for real-time monitoring of agent thought processes.\n\n### Plugin Architecture\nHermes now supports a \"drop-in\" plugin system.\n* **Location:** `~/.hermes/plugins/`\n* **Functionality:** Python files placed in this directory are automatically loaded. This allows developers to extend the agent with custom tools, slash commands, and lifecycle hooks without modifying the core repository.\n\n## Tooling & Execution Environment\n\n### Persistent Shell Mode\nThe local and SSH terminal backends now support stateful sessions.\n* **State Persistence:** Environment variables, directory changes (`cd`), and aliases persist across multiple tool calls within a single session.\n* **Implementation:** Managed via the `PersistentShell` class within the terminal backend modules.\n\n### Browser CDP Integration\nThe `/browser connect` command allows the agent to attach to an existing Chrome instance via the **Chrome DevTools Protocol (CDP)**. This enables debugging and interaction with active browser sessions that the user already has open, rather than spawning isolated, headless instances.\n\n### Concurrent Tool Execution\nTo reduce turn latency, independent tool calls are now dispatched in parallel using a `ThreadPoolExecutor`. This is particularly effective for agents performing multiple file reads or web searches in a single turn.\n\n```mermaid\ngraph TD\n A[Agent Loop] --> B{Tool Calls}\n B -->|Parallel| C[Tool 1: Read File]\n B -->|Parallel| D[Tool 2: Web Search]\n B -->|Parallel| E[Tool 3: Shell Cmd]\n C & D & E --> F[Aggregate Results]\n F --> G[Next Agent Turn]\n```\n\n## Security & Privacy\n\n### Tirith Pre-Exec Scanning\nA new security layer, **Tirith**, performs static analysis on terminal commands before they are executed. It scans for dangerous patterns (e.g., fork bombs, unauthorized deletions) and provides a \"verdict\" that the agent must respect based on the user's approval settings.\n\n### PII Redaction\nWhen `privacy.redact_pii` is enabled in `config.yaml`, the agent scrubs personally identifiable information from the context window before it is transmitted to the LLM provider.\n\n### Environment Sanitization\nThe agent now explicitly strips sensitive Hermes-specific environment variables (e.g., `OPENAI_API_KEY`, `HERMES_GATEWAY_TOKEN`) from subprocess environments to prevent accidental credential leakage during tool execution.\n\n## Memory & Integration\n\n### Honcho Memory\nIntegration with **Honcho** provides a persistent, asynchronous memory backend.\n* **Recall Modes:** Configurable modes for how the agent retrieves past interactions.\n* **Isolation:** Multi-user isolation is enforced in gateway mode, ensuring users do not leak context to one another in shared environments.\n\n### ACP (Agent Control Protocol)\nThe **ACP Server** allows IDEs like VS Code, Zed, and JetBrains to use Hermes as a backend. It supports full slash command integration, allowing the agent to operate directly within the developer's workspace.\n\n### Voice Mode\nA new voice processing pipeline supports:\n* **CLI:** Push-to-talk interaction.\n* **Gateways:** Voice note transcription for Telegram and Discord.\n* **Local Processing:** Uses `faster-whisper` for local, private STT (Speech-to-Text) when configured.\n\n## Command & Session Management\n\n* **Smart Approvals:** An updated approval system learns user preferences for \"safe\" commands, reducing prompt fatigue.\n* **Slash Command Registry:** All commands (e.g., `/plan`, `/rollback`, `/model`) are now defined in a centralized registry, ensuring consistent behavior across CLI and Gateway platforms.\n* **Session Hygiene:** The agent proactively compresses context when the session reaches a 50% token threshold, using a \"handoff summary\" to preserve actionable state.\n\n## New Skills\nSeveral high-level skills were added to the ecosystem:\n* **Linear:** Project management and issue tracking.\n* **Telephony:** Twilio integration for SMS and AI-driven voice calls.\n* **1Password:** Secure credential retrieval via the `op` CLI.\n* **NeuroSkill:** BCI (Brain-Computer Interface) integration.","root-release-v0-4-0-md":"# Root — RELEASE_v0.4.0.md\n\n# Release Module: v0.4.0 (v2026.3.23)\n\nThe `RELEASE_v0.4.0.md` module serves as the architectural manifest for the \"Platform Expansion\" release of the Hermes Agent. This version marks a transition from a CLI-centric tool to a multi-interface platform, introducing a standardized API server, expanded messaging gateway capabilities, and a sophisticated context management system.\n\n## Core Architectural Shifts\n\n### 1. OpenAI-Compatible API Server\nThe agent now exposes a local server implementing the `/v1/chat/completions` specification. This allows Hermes to act as a drop-in replacement for OpenAI in existing developer workflows.\n- **Persistence:** Uses a SQLite-backed `ResponseStore` to ensure response data survives server restarts.\n- **Job Management:** Introduces the `/api/jobs` REST endpoint for programmatic control over the agent's cron system.\n- **Security:** Implements CORS origin protection and input whitelisting to harden the server against unauthorized browser-based access.\n\n### 2. Gateway & Messaging Expansion\nThe Gateway layer has been refactored to support a broader range of communication protocols.\n- **New Adapters:** Signal, DingTalk, SMS (Twilio), Mattermost, Matrix, and Webhooks.\n- **Resiliency:** Implements exponential backoff for failed platform connections, ensuring the gateway remains stable during network interruptions.\n- **Vision Support:** Extended to Telegram and Discord DMs, allowing the agent to process inline images and attachments directly within messaging threads.\n\n### 3. Context & Memory Management\nVersion 0.4.0 introduces significant optimizations to how the agent handles long-running conversations and external data.\n\n```mermaid\ngraph TD\n A[User Input] --> B{Context Handler}\n B --> C[@ References]\n B --> D[Prompt Caching]\n B --> E[Context Compression]\n C --> F[File/URL Injection]\n D --> G[Anthropic Cache Turns]\n E --> H[Structured Summaries]\n H --> I[SQLite SessionDB]\n```\n\n- **@ Context References:** Developers can now use `@file` and `@url` syntax. The system performs tab-completion in the CLI and injects the referenced content directly into the prompt context.\n- **Prompt Caching:** The `AIAgent` instances are now cached per session. This preserves Anthropic prompt caches across turns, significantly reducing latency and token costs for large contexts.\n- **Structured Compression:** Replaces naive truncation with iterative, structured summaries. It includes \"token-budget tail protection\" to ensure the most recent messages remain intact while older history is summarized.\n\n## Provider & Inference Layer\n\nThe provider interface has been expanded to support new authentication patterns and discovery mechanisms:\n- **GitHub Copilot:** Implements a full OAuth 2.1 PKCE flow for token validation and routing.\n- **Dynamic Context Detection:** The agent now queries local endpoints (like llama.cpp via `/v1/props`) to determine actual context window sizes rather than relying on hardcoded defaults.\n- **Eager Fallback:** If a primary provider returns a rate-limit error, the agent immediately attempts the request with a configured backup model.\n\n## Tooling & MCP (Model Context Protocol)\n\nThe tool system has been decoupled to allow for better management of external capabilities.\n- **`hermes mcp` CLI:** A new management suite for installing and configuring MCP servers.\n- **Standalone Toolsets:** MCP servers can now be exposed as independent toolsets, allowing for granular permissioning.\n- **OAuth 2.1 Integration:** Supports PKCE-based authentication for tools requiring user-level authorization (e.g., Google Calendar or GitHub).\n\n## Security Hardening\n\nThis release includes a comprehensive security pass targeting common agentic vulnerabilities:\n- **SSRF Protection:** Implemented for `vision_tools` and `web_tools` to prevent the agent from being used to probe internal networks.\n- **Shell Injection:** Hardened `_expand_path` and `terminal_tool` to prevent malicious path suffixes and command injection.\n- **PII Redaction:** A new redacting formatter for logs and outputs to prevent sensitive environment variables or keys from being leaked to the LLM or logs.\n- **Pre-execution Scanning:** The `terminal_tool` now includes a pattern scanner to block known malicious code patterns before they reach the shell.\n\n## Reliability & State Persistence\n\n- **SessionDB Locking:** Added thread locks to `SessionDB` methods to prevent database corruption during concurrent writes in multi-platform gateway environments.\n- **Cron Recovery:** The scheduler now scales the \"missed-job grace window\" based on frequency and can recover one-shot jobs that were missed during downtime.\n- **Streaming Stability:** Streaming is now the default mode. The agent loop includes logic to handle tool progress displays and reasoning blocks without breaking the stream concatenation.","root-release-v0-5-0-md":"# Root — RELEASE_v0.5.0.md\n\n# Hermes Agent v0.5.0 Release Documentation\n\nThe v0.5.0 release (v2026.3.28), codenamed \"The Hardening Release,\" focuses on infrastructure stability, security supply chain integrity, and expanded model provider support. Key architectural shifts include the transition to native Modal SDK integration, the activation of the full plugin lifecycle hook system, and significant improvements to LLM reasoning persistence.\n\n## 🚀 Provider & Model Architecture\n\n### Hugging Face Integration\nHugging Face is now a first-class inference provider. This integration includes:\n- **Model Mapping:** A curated agentic model picker that maps OpenRouter-style slugs to Hugging Face Inference API endpoints.\n- **Discovery:** A live `/models` endpoint probe for dynamic model discovery.\n- **Setup Flow:** Integration into the setup wizard for seamless authentication and configuration.\n\n### Model Command Overhaul\nThe `/model` command has been refactored into a shared `switch_model()` pipeline.\n- **Unified Logic:** The same logic now powers model switching across the CLI, Gateway, and API.\n- **Provider Routing:** Improved routing that preserves `custom` provider settings rather than defaulting to OpenRouter.\n- **Config Inheritance:** Model configurations now correctly inherit root-level `provider` and `base_url` from `config.yaml`.\n\n## 🧠 Agent Loop & Reasoning\n\n### Tool-Use Enforcement\nTo address reliability issues with OpenAI models, this release introduces `GPT_TOOL_USE_GUIDANCE`. This system prompt injection prevents models from describing actions in text and forces valid tool calls. Additionally, the agent now automatically strips stale budget warnings from conversation history to prevent models from becoming \"tool-shy\" in long-running sessions.\n\n### Reasoning Persistence (Schema v6)\nThe session database has been upgraded to Schema v6 to support persistent reasoning across turns.\n- **New Columns:** `reasoning`, `reasoning_details`, and `codex_reasoning_items`.\n- **Transcript Integrity:** The `rewrite_transcript` function now preserves reasoning fields, ensuring that context compression or manual edits do not lose the model's \"chain of thought.\"\n\n### Context Compression\nThe compression logic has moved away from fixed token targets to ratio-based scaling.\n- **Configurable Parameters:** `compression.target_ratio`, `protect_last_n`, and `threshold`.\n- **Token Capping:** Summaries are now capped at 12K tokens to prevent the summary itself from consuming the entire context window.\n\n## 🔌 Plugin & Backend Infrastructure\n\n### Plugin Lifecycle Hooks\nThe plugin system is now fully operational with the activation of four key hooks within the agent loop:\n1. `on_session_start`: Fires when a new session is initialized.\n2. `pre_llm_call`: Allows modification of the prompt or state before the LLM is invoked.\n3. `post_llm_call`: Allows processing of the LLM response before tool execution.\n4. `on_session_end`: Fires during session teardown or cleanup.\n\n### Native Modal SDK\nThe dependency on `swe-rex` has been removed in favor of the native Modal SDK.\n- **Implementation:** Uses `Sandbox.create.aio` and `exec.aio` for environment management.\n- **Benefit:** Eliminates the need for complex tunneling and simplifies the terminal backend for remote execution.\n\n```mermaid\ngraph TD\n A[Agent Loop] --> B{Plugin Hooks}\n B -->|pre_llm_call| C[LLM Provider]\n C --> D[Reasoning Extraction]\n D -->|post_llm_call| E{Tool Execution}\n E -->|Modal Backend| F[Native Modal SDK]\n E -->|Docker Backend| G[Inlined Docker Logic]\n F --> H[Session DB v6]\n G --> H\n```\n\n## 📱 Messaging & Gateway Improvements\n\n### Telegram Private Chat Topics\nThe Gateway now supports project-based conversations within a single Telegram chat using Topics.\n- **Skill Binding:** Functional skills can be bound to specific topics, allowing for isolated workflows (e.g., a \"Coding\" topic with terminal access and a \"Research\" topic with browser access).\n\n### Reliability & Networking\n- **DNS-over-HTTPS:** Telegram adapters now auto-discover fallback IPs via DoH when `api.telegram.org` is blocked or unreachable.\n- **Session Locking:** The `/stop` command now hard-kills session locks, allowing users to recover from hung agents without restarting the entire gateway.\n- **Media Handling:** WhatsApp and Mattermost adapters now support document, audio, and video media downloads.\n\n## 🔒 Security & Supply Chain\n\n### Hardening Measures\n- **SSRF Protection:** Implemented in `browser_navigate`, `vision_tools`, and `web_tools` to prevent internal network probing.\n- **Dependency Audit:** Removed the compromised `litellm` package. All dependencies are now pinned with hashes in `uv.lock`.\n- **Path Traversal:** Added protections against zip-slip during self-updates and shell injection via `~user` path expansions.\n\n### Nix Support\nA full Nix flake is now provided, featuring:\n- `uv2nix` build system.\n- NixOS module with persistent container mode.\n- Auto-generated configuration keys derived directly from the Python source.\n\n## 🛠️ Tool System Updates\n\n- **API Server:** Added `Idempotency-Key` support and OpenAI-compatible error envelopes.\n- **MCP:** Improved toolset resolution and added name collision protection for Model Context Protocol servers.\n- **V4A Patching:** The patch parser now handles addition-only hunks, improving the reliability of automated file edits.\n- **Browser Vision:** Added support for `auxiliary.vision.timeout` and handled 402 (insufficient credits) errors gracefully.","root-release-v0-6-0-md":"# Root — RELEASE_v0.6.0.md\n\n# Hermes Agent v0.6.0 Release Documentation\n\nThe v0.6.0 release (v2026.3.30) introduces significant architectural shifts, primarily focusing on multi-instance isolation (Profiles), Model Context Protocol (MCP) server capabilities, and enhanced reliability through provider fallback chains.\n\n## Multi-Instance Architecture (Profiles)\n\nThe most fundamental change in v0.6.0 is the introduction of the **Profiles** system. This allows developers to run multiple, completely isolated Hermes instances from a single installation.\n\n### Isolation Mechanism\nEach profile maintains its own:\n- **Configuration:** `config.yaml` and `.env` files.\n- **Storage:** Memory, session logs, and skill databases.\n- **Gateway Services:** Independent adapter configurations.\n- **Token Locks:** A safety mechanism that prevents two profiles from accidentally sharing the same bot credentials (e.g., using the same Telegram token in two instances).\n\n### Profile Management CLI\nProfiles are managed via the `hermes profile` command group:\n- `hermes profile create <name>`: Initializes a new isolated environment.\n- `hermes -p <name>`: Executes commands within the context of a specific profile.\n- `hermes profile export/import`: Facilitates sharing configurations across different machines.\n\nThe codebase now utilizes `display_hermes_home()` instead of hardcoded `~/.hermes` paths to ensure all logs and UI elements reflect the active profile's directory.\n\n## Model Context Protocol (MCP) Integration\n\nHermes v0.6.0 expands its relationship with MCP in two directions: acting as a server and improving client-side tool discovery.\n\n### MCP Server Mode\nBy running `hermes mcp serve`, the agent exposes its internal state to external MCP-compatible clients (like Claude Desktop or Cursor).\n- **Transports:** Supports both `stdio` and `streamable_http_client`.\n- **Resources:** Clients can browse active conversations, read message history, and access session attachments.\n\n### Dynamic Tool Discovery\nThe agent now listens for `notifications/tools/list_changed` events from connected MCP servers. This allows Hermes to hot-reload available tools without requiring a restart of the gateway or CLI session.\n\n## Provider & Inference Logic\n\n### Ordered Fallback Chains\nTo improve reliability, the `config.yaml` now supports a `fallback_providers` list. \n- **Execution Flow:** If the primary provider returns a 429 (Rate Limit), 5xx (Server Error), or is unreachable, the agent automatically iterates through the fallback chain.\n- **Rate Limit Handling:** Introduced user-friendly 429 messages with a `Retry-After` countdown.\n\n### Provider Switching Fixes\nThe `hermes model` command was updated to clear stale `api_mode` settings. Previously, switching from an OpenAI-compatible provider to an Anthropic-compatible one could result in 404 errors due to cached endpoint configurations.\n\n## Messaging Gateway Enhancements\n\nThe Gateway service received two new platform adapters and several protocol upgrades.\n\n| Platform | Key v0.6.0 Updates |\n| :--- | :--- |\n| **Feishu / Lark** | New adapter supporting interactive cards, group chats, and file attachments. |\n| **WeCom** | New adapter for Enterprise WeChat with callback verification. |\n| **Telegram** | Added **Webhook Mode** for production deployments; added regex-based group mention gating. |\n| **Slack** | **Multi-workspace OAuth** support via a centralized token file. |\n| **Discord** | Visual \"thinking\" reactions and improved cleanup of deferred slash commands. |\n\n## Tooling & Remote Execution\n\n### Remote Backend Mounting\nFor developers using **Modal** or **Docker** as execution backends, v0.6.0 now synchronizes local state to the remote environment:\n- **Skill Directories:** Local `skills.external_dirs` are mounted into the container.\n- **Credentials:** Local credential files are synced using mtime+size caching to ensure remote tools have access to necessary secrets without manual configuration.\n\n### Web & Vision Tools\n- **Exa Search:** Added as a high-quality alternative to DuckDuckGo and Firecrawl.\n- **Vision Guardrails:** The vision tool now strictly enforces a website-only policy and rejects non-image file types to prevent unauthorized local file disclosure.\n\n## Security & Reliability\n\n### Hardened Command Detection\nThe approval system for \"dangerous\" commands has been expanded. It now monitors:\n- **Shell Patterns:** Improved detection of destructive shell commands.\n- **Path Guards:** Explicit blocks on file tools attempting to write to sensitive system locations like `/etc/`, `/boot/`, or `docker.sock`.\n\n### Atomic Operations\nTo prevent configuration corruption during crashes, `config.yaml` updates are now **atomic**. The system writes to a temporary file and performs a rename operation, ensuring the configuration remains valid even if the process is interrupted.\n\n### Update Safety\nThe `hermes update` process now automatically clears `__pycache__` and utilizes lazy imports for `display_hermes_home`. This prevents `ImportError` loops caused by stale bytecode referencing deleted or moved functions.\n\n## New Skills\nSeveral new specialized skill sets were added to the `optional-skills` directory:\n- `memento-flashcards`: Spaced repetition logic.\n- `scrapling`: Advanced web scraping.\n- `siyuan-note`: Integration for the SiYuan note-taking platform.\n- `one-three-one-rule`: A communication framework for decision-making.","root-release-v0-7-0-md":"# Root — RELEASE_v0.7.0.md\n\n# Release Documentation: Hermes Agent v0.7.0 (v2026.4.3)\n\nThe v0.7.0 release, titled \"The Resilience Release,\" focuses on architectural extensibility, security hardening, and improved reliability for production gateway deployments. Key architectural shifts include the transition to a pluggable memory provider system and the introduction of thread-safe credential pooling.\n\n## 🏗️ Core Architecture Updates\n\n### Pluggable Memory Provider Interface\nMemory management has been refactored into an extensible plugin system. Developers can now implement custom memory backends by inheriting from a provider Abstract Base Class (ABC) and registering them via the Hermes plugin system.\n\n* **Reference Implementation:** The Honcho integration has been updated to serve as the reference plugin, featuring profile-scoped host and peer resolution.\n* **Session Persistence:** API server sessions now persist to a shared `SessionDB`, and token usage is tracked across non-CLI sessions.\n* **Search Improvements:** FTS5 queries now correctly handle dotted terms (e.g., filenames or namespaces) by quoting terms during session searches.\n\n### Same-Provider Credential Pools\nTo handle rate limits and key exhaustion, Hermes now supports multiple API keys for a single provider.\n* **Rotation Strategy:** Uses a `least_used` strategy to distribute load.\n* **Failover:** Automatic rotation is triggered by `401 Unauthorized` errors.\n* **Configuration:** Managed via the `credential_pool` key in `config.yaml` or the setup wizard.\n* **Smart Routing:** Pool state is preserved during provider fallback events, preventing eager fallbacks on `429 Too Many Requests` until the pool is exhausted.\n\n### Agent Loop & Context Management\n* **Thinking Block Persistence:** Anthropic `<thinking>` signatures are now preserved across tool-use turns to maintain model reasoning continuity.\n* **Compression Death Spiral Protection:** Logic added to detect and halt loops where API disconnects trigger repeated, failing context compression attempts.\n* **Deterministic Call IDs:** Replaced random UUIDs with deterministic `call_id` fallbacks to improve prompt cache hit rates.\n\n## 🔧 Tooling & Browser System\n\n### Camofox Anti-Detection Backend\nA new stealth-focused browser backend using Camoufox is available.\n* **Stealth:** Designed to bypass anti-bot detections during web navigation.\n* **Debugging:** Supports persistent sessions with VNC URL discovery for visual inspection of the agent's browser state.\n* **Security:** SSRF checks can be bypassed for local backends (Camofox/Headless Chromium) via `browser.allow_private_urls`.\n\n### File Operations & Diffs\n* **Inline Diff Previews:** The `write_file` and `patch_file` operations now generate inline diffs within the tool activity feed.\n* **Stale File Detection:** Tools now warn if a file has been modified by an external process since the agent last read it, preventing accidental overwrites.\n\n### ACP (Agent Control Protocol) & MCP\n* **Client-Provided MCP Servers:** Editor integrations (VS Code, Zed, JetBrains) can now register their own MCP servers. Hermes dynamically picks these up as additional tools available to the agent.\n* **Stability:** Improved MCP server reload timeouts and event loop handling for HTTP-based MCP servers.\n\n## 📱 Gateway & Messaging Platforms\n\nThe Gateway has undergone a significant hardening pass to resolve race conditions in high-concurrency environments.\n\n### Approval Routing\nA major fix addresses the \"stuck session\" issue where approval commands were swallowed.\n* **Guard Logic:** `/approve` and `/deny` commands are now routed through a `running-agent` guard.\n* **Thread Blocking:** When an agent is waiting for user approval, the thread blocks similarly to the CLI, ensuring the tool result is correctly injected once approved.\n\n### Platform Specifics\n* **Discord:** Introduced a button-based approval UI and configurable message reactions.\n* **Telegram:** Implemented skill-aware slash commands. Installed skills are dynamically registered as Telegram commands (subject to the 100-command API limit).\n* **Slack:** Added `slack.reply_in_thread` configuration to support threaded conversation flows.\n\n## 🔒 Security Hardening\n\n### Exfiltration Blocking\nHermes now implements active scanning of browser URLs and LLM responses to prevent secret exfiltration.\n* **Pattern Matching:** Scans for high-entropy strings and known secret formats (e.g., GitHub tokens) even when encoded in Base64 or URL formats.\n* **Sandbox Redaction:** The `execute_code` tool now redacts detected secrets from its standard output.\n\n### Path & Directory Protection\n* **Credential Guarding:** Expanded protections to block the agent from reading or writing to sensitive directories: `.docker`, `.azure`, and `.config/gh`.\n* **Zip-Slip Protection:** Validation of tar/zip member paths during profile imports to prevent path traversal attacks.\n\n## 💻 CLI & User Experience\n\n### New Slash Commands\n| Command | Function |\n| :--- | :--- |\n| `/yolo` | Toggles dangerous command approvals for the current session. |\n| `/btw` | Allows ephemeral side-questions that are excluded from the main conversation context. |\n| `/profile` | Displays active profile configuration without exiting the chat. |\n\n### TUI Improvements\n* **Layout:** The TUI is now pinned to the bottom of the terminal on startup to eliminate whitespace gaps.\n* **Session Management:** `/history` and `/resume` now provide a direct list of recent sessions for faster context restoration.\n* **Input Handling:** Dragged file paths are now detected as file references rather than being misinterpreted as slash commands.\n\n## 🚀 Update & Deployment\n* **Fork Sync:** `hermes update` now detects if the installation is a fork and offers to sync with the upstream repository.\n* **Systemd:** The `/update` command now uses `setsid` instead of `systemd-run` to bypass common permission issues in containerized environments.\n* **LXC Support:** The gateway service can now be configured to run as root for compatibility with specific LXC and container environments.","root-release-v0-8-0-md":"# Root — RELEASE_v0.8.0.md\n\n# Release v0.8.0: Intelligence & Background Autonomy\n\nRelease v0.8.0 (v2026.4.8) represents a significant architectural shift toward autonomous background processing, enhanced tool-use reliability for OpenAI models, and a unified cross-platform gateway experience. This release focuses on \"intelligence\" through self-optimized guidance and improved lifecycle management.\n\n## Core Architecture Updates\n\n### Provider & Model Resolution\nThe provider system has been overhauled to support live switching and aggregator-aware resolution.\n* **Native Gemini Support:** Direct integration with Google AI Studio, utilizing `models.dev` for real-time context length detection.\n* **Live Switching:** The `/model` command now functions across all gateways (CLI, Telegram, Discord, Slack). It uses an aggregator-aware logic that prefers OpenRouter or Nous Portal but allows for automatic cross-provider fallback.\n* **Tool-Use Enforcement:** Specific logic has been added to enforce tool-use patterns on xAI (Grok) and MiniMax models.\n\n### Agent Loop & Reasoning\nThe agent's internal reasoning loop has been hardened against common LLM failure modes:\n* **Behavioral Benchmarking:** The agent now includes self-optimized guidance for GPT and Codex models, specifically patching five identified failure modes in tool calling.\n* **Thinking Prefills:** Support for \"thinking-only\" prefill continuations allows models to maintain structured reasoning across multi-turn interactions without losing context.\n* **Argument Coercion:** The loop now automatically coerces tool arguments to match JSON Schema types, mitigating issues where models return strings for numeric or boolean fields.\n\n## Background Task Management\n\nA major feature of v0.8.0 is the transition from passive polling to active notification for long-running tasks.\n\n### `notify_on_complete`\nBackground processes (builds, deployments, AI training) can now trigger an internal notification to the agent upon completion. This allows the agent to:\n1. Initiate a long-running task.\n2. Yield the session or work on parallel tasks.\n3. Receive an asynchronous callback when the process exits.\n\n### Activity-Based Timeouts\nThe timeout logic for Gateway and Cron systems has moved from wall-clock time to **activity-based tracking**.\n* **Logic:** The system monitors actual tool activity (e.g., terminal output, browser navigation).\n* **Impact:** Long-running tasks that are actively producing output will no longer be killed by the gateway's idle timer. Only truly inactive agents are reaped.\n\n## Tooling & Execution Environment\n\n### Remote Execution Backends\nThe `execute_code` tool is no longer restricted to local environments. It now supports:\n* **Remote Backends:** Docker, SSH, and Modal.\n* **Contextual Awareness:** Terminal results now include exit code context for common CLI tools, helping the agent self-diagnose environment issues.\n* **Subdirectory Discovery:** The agent now employs progressive hint discovery to learn project structures as it navigates deep directory trees.\n\n### MCP (Model Context Protocol)\n* **OAuth 2.1 PKCE:** Full standards-compliant authentication for MCP servers.\n* **Security:** Integration with the OSV (Open Source Vulnerabilities) database to perform malware scanning on MCP extension packages before execution.\n\n## Plugin & Skill System\n\nThe plugin architecture has been expanded to allow deeper integration into the agent's lifecycle.\n\n| Hook / Feature | Description |\n| :--- | :--- |\n| **CLI Registration** | Plugins can now register custom subcommands directly to the `hermes` binary. |\n| **Lifecycle Hooks** | `on_session_finalize` and `on_session_reset` allow plugins to clean up resources or commit data. |\n| **API Correlation** | Request-scoped hooks now include tool call correlation IDs for tracing. |\n| **Config Injection** | Skills can declare required `config.yaml` settings which are validated at load time. |\n\n## Gateway & Messaging Platforms\n\nThe gateway layer has been updated to support native platform features for better UX:\n* **Approval Buttons:** Telegram and Slack now use native UI buttons for command approvals instead of text-based `/approve` commands.\n* **Matrix Tier 1:** Full feature parity for Matrix, including E2EE, rich formatting, and room management.\n* **Discord Slash Commands:** Skills and core commands (`/approve`, `/background`, etc.) are now registered as native Discord slash commands.\n\n## Security & Logging\n\n### Centralized Logging\nLogs are now structured and centralized in `~/.hermes/logs/`:\n* `agent.log`: General INFO level logs and execution traces.\n* `errors.log`: WARNING and ERROR level events for easier debugging.\n* **Command:** Use `hermes logs` to tail and filter these streams.\n\n### Hardening\n* **SSRF Protections:** Consolidated protections across all web-facing tools.\n* **Path Traversal:** Hardened terminal and cron path handling to prevent directory traversal attacks.\n* **Credential Redaction:** Improved regex-based redaction for large outputs to prevent O(n²) catastrophic backtracking while ensuring secrets do not leak into logs or chat histories.\n\n```mermaid\ngraph TD\n User[User/Gateway] -->|Command| AgentLoop[Agent Loop]\n AgentLoop -->|Tool Call| Terminal[Terminal/Remote Backend]\n Terminal -->|Background Task| Process[Long Running Process]\n Process -->|notify_on_complete| AgentLoop\n AgentLoop -->|Reasoning| Provider[Google/OpenAI/Nous]\n Provider -->|Thinking Block| AgentLoop\n AgentLoop -->|Activity Signal| TimeoutManager[Activity-Based Timeout]\n```\n\n## Configuration Changes\nUsers upgrading to v0.8.0 should note the new config validation. Malformed YAML in `config.yaml` will now prevent startup with a specific error message identifying the line and field. Reasoning effort settings have been unified into the main configuration file.","root-release-v0-9-0-md":"# Root — RELEASE_v0.9.0.md\n\n# Hermes Agent v0.9.0 (v2026.4.13) — Release Documentation\n\nThe v0.9.0 release represents a significant architectural evolution of the Hermes Agent, focusing on platform ubiquity (Android/Termux), expanded messaging integrations (iMessage, WeChat), and a major security hardening pass. This version introduces a pluggable context engine and shifts session state management to a more robust concurrency model.\n\n## Core Architectural Changes\n\n### Pluggable Context Engine\nContext management has been decoupled from the core agent loop. Developers can now implement and swap custom context engines using the `hermes plugins` interface. This allows for domain-specific logic regarding:\n* **Message Filtering:** Selective inclusion of history based on relevance.\n* **Summarization Strategies:** Custom logic for how the buffer is compressed when approaching token limits.\n* **Context Injection:** Injecting RAG results or system-level metadata dynamically.\n\n### Session State Management\nThe agent has migrated from using `os.environ` for session-specific state to `contextvars` ([#7454]). This change ensures thread safety and prevents state leakage across concurrent sessions in multi-user environments (e.g., Discord servers or API server deployments).\n\n### Unified Execution Layer\nTool execution now utilizes a **spawn-per-call** execution model ([#6343]). This provides:\n* **Isolation:** Each tool call runs in a clean environment.\n* **Persistence:** Sandbox environments can now persist between turns ([#6412]), allowing for multi-turn stateful operations (e.g., building a project across several messages).\n* **File Synchronization:** A new unified file sync system with `mtime` tracking and transactional state ensures the agent's local workspace stays in sync with remote backends (SSH, Modal, Daytona).\n\n## New Capabilities & Commands\n\n### Fast Mode (`/fast`)\nA priority routing toggle for OpenAI and Anthropic providers. When enabled via the `/fast` command, requests are routed through priority queues (OpenAI Priority Processing / Anthropic Fast Tier) to minimize latency.\n\n### Background Process Monitoring\nThe `watch_patterns` feature ([#7635]) allows the agent to monitor background process output asynchronously. Instead of polling, the agent registers patterns (e.g., \"Listening on port 3000\" or \"Build failed\") and triggers real-time notifications to the user or the agent loop when matches occur.\n\n### Debugging & Maintenance\n* **`hermes dump`**: Generates a copy-pasteable summary of the current environment, configuration, and provider status for troubleshooting.\n* **`hermes debug share`**: Automates the creation of a redacted debug report and uploads it to a secure pastebin.\n* **`hermes backup` / `hermes import`**: Provides full serialization of sessions, skills, and configuration for migration between machines.\n\n## Messaging Gateway Expansion\n\nHermes now supports 16 messaging platforms. Key additions in v0.9.0 include:\n* **BlueBubbles (iMessage):** Integration via the BlueBubbles API with automated webhook registration.\n* **WeChat (Weixin/WeCom):** Native support via iLink Bot API and a dedicated Callback Mode adapter for enterprise applications.\n* **Unified Proxying:** Support for SOCKS and system-level proxies across all gateway adapters, including auto-detection on macOS.\n\n## Security Hardening\n\nThis release includes a comprehensive security audit and remediation of several critical vectors:\n\n| Vector | Mitigation |\n| :--- | :--- |\n| **Remote Code Execution (RCE)** | Twilio webhook signature validation ([#7933]). |\n| **Shell Injection** | Neutralized via path quoting in `_write_to_sandbox` ([#7940]). |\n| **SSRF** | Redirect guards implemented for Slack image uploads ([#7151]). |\n| **Path Traversal** | Boundary enforcement in the Checkpoint Manager and Skill Manager ([#7944], [#7156]). |\n| **API Security** | Enforcement of `API_SERVER_KEY` for all non-loopback bindings ([#7455]). |\n\n## Provider Updates\n\n* **xAI (Grok):** Native provider implementation with direct API access.\n* **Xiaomi MiMo:** First-class support including model catalogs and empty response recovery logic.\n* **Error Classification:** Improved `API error classification` ([#6514]) allows the agent to make smarter failover decisions (e.g., retrying on rate limits vs. switching providers on billing errors).\n* **Rate Limit Tracking:** `/usage` now displays real-time rate limit headers captured from provider responses.\n\n## Technical Execution Flow: Tool Call with Monitoring\n\n```mermaid\ngraph TD\n A[Agent Loop] --> B{Tool Call}\n B --> C[Unified Execution Layer]\n C --> D[Spawn Process]\n D --> E[watch_patterns Monitor]\n E -- Match Found --> F[Real-time Notification]\n D -- Completion --> G[File Sync / mtime Check]\n G --> H[Return Result to Loop]\n```\n\n## Installation & Environment\n* **Termux/Android:** Native support for running the agent on mobile devices via Termux, including TUI optimizations and voice backend support.\n* **Docker:** Multi-arch images (amd64/arm64) now run as a non-root user with `uv` for faster dependency resolution.\n* **Nix:** Improved shared-state permission models for interactive CLI users.","root-rl-cli-py":"# Root — rl_cli.py\n\n# RL Training CLI (rl_cli.py)\n\nThe `rl_cli.py` module is a dedicated entry point for Reinforcement Learning (RL) training workflows. It wraps the standard `AIAgent` with specialized configurations, extended timeouts, and a system prompt tailored for post-training engineering tasks using the `tinker-atropos` framework.\n\n## Overview\n\nUnlike the standard agent CLI, `rl_cli.py` is optimized for long-running operations. It automatically configures the environment to point to the `tinker-atropos` submodule and enables a specific suite of tools (`terminal`, `web`, and `rl`) required for discovering, configuring, and monitoring RL training runs.\n\n### Key Specializations\n- **Extended Iterations**: Sets `max_iterations` to 200 (defaulting higher than standard agents) to accommodate 30-minute status check intervals and multi-hour training loops.\n- **Context Awareness**: Automatically sets `TERMINAL_CWD` to the `tinker-atropos` directory so the agent's terminal commands execute in the correct repository context.\n- **RL System Prompt**: Injects a specialized system prompt that instructs the agent on the DISCOVER -> INSPECT -> TEST -> TRAIN workflow.\n\n## Architecture\n\nThe CLI acts as a configuration layer that initializes the `AIAgent` with RL-specific parameters before delegating execution to the agent's conversation loop.\n\n```mermaid\ngraph TD\n CLI[rl_cli.py] -->|Configures| Agent[AIAgent]\n CLI -->|Validates| Submodule[tinker-atropos]\n Agent -->|Uses| RLTools[tools/rl_training_tool.py]\n Agent -->|Uses| Term[terminal tool]\n RLTools -->|Interacts| Submodule\n```\n\n## Configuration & Environment\n\nThe module performs aggressive environment setup during imports and initialization:\n\n1. **Environment Variables**: Loads variables from `~/.hermes/.env` and the project root using `load_hermes_dotenv`.\n2. **Submodule Pathing**: Locates `tinker-atropos`. If found, it sets `os.environ['TERMINAL_CWD']` to this path, ensuring the agent's file operations and terminal commands target the RL framework.\n3. **API Requirements**: Requires `TINKER_API_KEY`, `WANDB_API_KEY`, and `OPENROUTER_API_KEY`.\n\n## Core Functions\n\n### `load_hermes_config()`\nReads `~/.hermes/config.yaml` to determine the default model (defaults to `anthropic/claude-opus-4.5`) and base URL. This allows users to persist their preferred LLM for the RL agent.\n\n### `check_tinker_atropos()`\nValidates the local environment. It checks for the existence of the `tinker-atropos` submodule and scans the `tinker_atropos/environments` directory to ensure training environments are available.\n\n### `main(...)`\nThe entry point (exposed via `python-fire`). It handles several execution modes:\n- **Task Mode**: Runs a single prompt (e.g., \"Train GSM8k\").\n- **Interactive Mode (`--interactive`)**: Opens a REPL for ongoing RL experimentation.\n- **Discovery Mode (`--list-environments`)**: Synchronously calls `rl_list_environments` to show available RL setups.\n- **Server Check (`--check-server`)**: Validates API keys and submodule status.\n\n## RL System Prompt Logic\n\nThe `RL_SYSTEM_PROMPT` defines the operational boundaries for the agent. It emphasizes a specific safety and verification lifecycle:\n1. **Discovery**: Use `rl_list_environments`.\n2. **Inspection**: Read environment files to understand reward logic and verifiers.\n3. **Validation**: Always run `rl_test_inference` before starting a full training run.\n4. **Monitoring**: Check status at 30-minute intervals and monitor WandB metrics.\n\n## Usage Examples\n\n### Training a Model\n```bash\npython rl_cli.py \"Train a model on GSM8k for math reasoning using the default config\"\n```\n\n### Interactive Session\nUseful for debugging new environments or manually stepping through a training configuration:\n```bash\npython rl_cli.py --interactive\n```\n\n### Environment Discovery\nTo see what RL environments are currently implemented in the submodule:\n```bash\npython rl_cli.py --list-environments\n```\n\n## Integration with Tools\nThe module enables the `rl` toolset defined in `tools/rl_training_tool.py`. This provides the agent with high-level abstractions for:\n- `rl_start_training`: Initiating the Tinker-Atropos pipeline.\n- `rl_check_status`: Polling the training server.\n- `rl_edit_config`: Modifying hyperparameters (learning rate, batch size, etc.).","root-setup-hermes-sh":"# Root — setup-hermes.sh\n\n# setup-hermes.sh\n\nThe `setup-hermes.sh` script is the primary entry point for initializing a development or production environment for the Hermes Agent. It automates environment detection, dependency resolution, and system integration, ensuring the agent is ready for use with minimal manual intervention.\n\n## Overview\n\nThe script follows a dual-path execution logic based on the host environment:\n1. **Desktop/Server Path:** Leverages [uv](https://github.com/astral-sh/uv) for high-performance Python management, virtual environment creation, and lockfile-verified dependency installation.\n2. **Android/Termux Path:** Utilizes the Python standard library `venv` and `pip` to accommodate the specific constraints and pre-compiled package requirements of the Termux environment.\n\n## Execution Flow\n\n```mermaid\ngraph TD\n A[Start] --> B{Is Termux?}\n B -- Yes --> C[Use stdlib venv + pip]\n B -- No --> D[Locate/Install uv]\n C --> E[Python 3.11+ Check]\n D --> F[uv Python 3.11 Provisioning]\n E --> G[Create venv]\n F --> G\n G --> H{Install Deps}\n H -- Termux --> I[pip install .[termux]]\n H -- Desktop --> J[uv sync --all-extras]\n I --> K[Sync Skills & Symlink CLI]\n J --> K\n K --> L[Run Setup Wizard]\n```\n\n## Key Components\n\n### 1. Platform Detection\nThe script identifies the environment using the `is_termux` function, which checks for the existence of the `TERMUX_VERSION` environment variable or the standard Termux `$PREFIX` path. This determines whether the script uses `uv` or falls back to standard Python tooling.\n\n### 2. Python Environment Management\n* **Desktop:** The script targets **Python 3.11**. It uses `uv python find` to locate an existing installation or `uv python install` to provision it automatically.\n* **Termux:** It verifies that the system `python` is at least version 3.11. If not, it directs the user to run `pkg install python`.\n\n### 3. Dependency Installation\nThe script installs the package in editable mode (`-e .`), allowing developers to modify the source code without reinstalling.\n\n* **Extras:** \n * On Desktop, it attempts to install the `[all]` extra set.\n * On Termux, it attempts the `[termux]` extra set, which includes platform-specific dependencies.\n* **Lockfile Verification:** On Desktop, if a `uv.lock` file is present, the script performs a `uv sync --locked` to ensure a reproducible environment. If the lockfile is stale or the sync fails, it falls back to a standard `uv pip install`.\n* **Constraints:** In Termux, it utilizes `constraints-termux.txt` to ensure compatibility with pre-built binaries available in the Termux repositories.\n\n### 4. Submodule Integration\nThe script checks for the presence of the `tinker-atropos` directory (the Reinforcement Learning training backend). If found and the environment is not Termux, it installs the submodule in editable mode.\n\n### 5. System Integration\nTo provide a seamless CLI experience, the script performs the following:\n* **CLI Symlinking:** It symlinks the `hermes` executable from the virtual environment to a user-facing bin directory (`~/.local/bin` on Desktop or `$PREFIX/bin` on Termux).\n* **PATH Modification:** On Desktop, it detects the active shell (`bash` or `zsh`) and appends `~/.local/bin` to the `PATH` in the corresponding configuration file (`.zshrc`, `.bashrc`, or `.bash_profile`) if it is not already present.\n* **Environment Files:** It initializes a `.env` file from `.env.example` if one does not exist.\n\n### 6. Skill Seeding\nThe script ensures that bundled skills are available to the agent by running `tools/skills_sync.py`. This script synchronizes the skills from the repository into the user's Hermes home directory (defaulting to `~/.hermes/skills/`).\n\n## Usage\n\nRun the script from the root of the repository:\n\n```bash\nchmod +x setup-hermes.sh\n./setup-hermes.sh\n```\n\n### Post-Installation\nUpon successful completion, the script offers to run the **Setup Wizard** (`hermes setup`). This interactive CLI tool configures essential API keys and preferences stored in the `.env` file.\n\n## Optional Dependencies\nThe script checks for `ripgrep` (`rg`), which is used by the agent for high-performance file searching. If missing, it provides an interactive prompt to install it via the system package manager (`apt`, `dnf`, `brew`, `pkg`) or `cargo`.","root-toolset-distributions-py":"# Root — toolset_distributions.py\n\n# Toolset Distributions\n\nThe `toolset_distributions.py` module manages probabilistic configurations of toolsets used during data generation and model evaluation. Instead of providing every tool to every prompt, this module allows developers to define \"distributions\" that simulate different agent capabilities and constraints.\n\n## Core Concepts\n\nA **Distribution** is a named configuration that defines the likelihood of specific toolsets being available for a given task. This is used to:\n1. **Diversify Training Data**: Generate trajectories where models must solve problems with varying tool availability.\n2. **Specialize Environments**: Create task-specific environments (e.g., a \"research\" environment vs. a \"development\" environment).\n3. **Simulate Constraints**: Test model robustness when certain tools are missing.\n\n### Distribution Schema\nEach entry in the `DISTRIBUTIONS` dictionary follows this structure:\n\n```python\n\"distribution_name\": {\n \"description\": \"Human-readable purpose\",\n \"toolsets\": {\n \"toolset_id\": probability_integer # 0 to 100\n }\n}\n```\n\n## Sampling Logic\n\nThe primary entry point for runtime tool selection is `sample_toolsets_from_distribution(distribution_name)`. \n\n1. **Independent Selection**: For every toolset defined in the distribution, the module performs an independent Bernoulli trial (a \"dice roll\") against the specified probability.\n2. **Validation**: It calls `toolsets.validate_toolset()` to ensure the requested toolset actually exists in the system registry.\n3. **Guaranteed Minimum**: If the random sampling results in zero toolsets being selected, the module automatically selects the toolset with the **highest defined probability** as a fallback. This ensures the agent is never left without any tools.\n\n```mermaid\ngraph TD\n A[Distribution Name] --> B[Fetch Definition]\n B --> C{For each Toolset}\n C -->|Roll < Prob| D[Add to Selected]\n C -->|Roll > Prob| E[Skip]\n D --> F{Any Selected?}\n E --> F\n F -->|No| G[Pick Highest Prob Toolset]\n F -->|Yes| H[Return List]\n G --> H\n```\n\n## API Reference\n\n### `sample_toolsets_from_distribution(distribution_name: str) -> List[str]`\nThe core function used by `batch_runner.py` and `hermes_base_env.py`. It returns a list of toolset names to be instantiated for a specific prompt or trajectory.\n\n### `get_distribution(name: str) -> Optional[Dict]`\nReturns the raw configuration dictionary for a specific distribution, including its description and probability map.\n\n### `list_distributions() -> Dict[str, Dict]`\nReturns a copy of the entire `DISTRIBUTIONS` registry. Used by the CLI and batch runners to validate user input.\n\n### `validate_distribution(distribution_name: str) -> bool`\nChecks if a distribution name exists in the registry.\n\n## Integration Points\n\n* **`batch_runner.py`**: Uses this module during `_process_single_prompt` to determine which tools to provide to the model for a specific generation task.\n* **`environments/hermes_base_env.py`**: Calls `sample_toolsets_from_distribution` within `_resolve_tools_for_group` to configure the environment's tool registry before a trajectory begins.\n* **`toolsets.py`**: This module acts as a consumer of `toolsets.py` to validate that the names defined in distributions map to valid tool implementations.\n\n## Adding New Distributions\n\nTo add a new distribution, append a new key to the `DISTRIBUTIONS` constant. \n\n**Example: Data Science Distribution**\n```python\n\"data_science\": {\n \"description\": \"Focus on data manipulation and visualization\",\n \"toolsets\": {\n \"terminal\": 100, # Always available for python execution\n \"file\": 100, # Always available for reading datasets\n \"vision\": 40, # Occasionally available for plot analysis\n \"web\": 20 # Rarely available for documentation\n }\n}\n```\n\n## Predefined Distributions\n\n| Name | Primary Focus | Key Characteristics |\n| :--- | :--- | :--- |\n| `default` | All-access | 100% probability for all tools. |\n| `research` | Web/Browser | High probability for `web` and `browser`, low for `terminal`. |\n| `development` | Coding | High probability for `terminal` and `file`, 60% for `moa` (reasoning). |\n| `safe` | Security | Excludes `terminal` entirely; focuses on `web` and `vision`. |\n| `browser_tasks` | Automation | 97% `browser` availability; used for browser-specific benchmarks. |\n| `terminal_tasks`| CLI | 97% `terminal` and `file` availability. |","root-toolsets-py":"# Root — toolsets.py\n\n# Toolsets Module\n\nThe `toolsets.py` module provides a centralized system for defining, managing, and resolving groups of tools. It allows the system to expose specific capabilities to an agent based on the environment (CLI, Telegram, VS Code) or the specific task at hand.\n\n## Core Concepts\n\n### Toolset Definition\nA toolset is defined as a dictionary containing:\n- `description`: A human-readable string explaining the toolset's purpose.\n- `tools`: A list of individual tool names (e.g., `web_search`, `terminal`).\n- `includes`: A list of other toolset names to be recursively included.\n\n### Static vs. Dynamic Toolsets\n1. **Static Toolsets**: Defined within the `TOOLSETS` dictionary in this module. These include core capabilities like `web`, `browser`, and platform-specific sets like `hermes-cli`.\n2. **Dynamic Toolsets**: Registered at runtime via plugins or MCP (Model Context Protocol) servers. These are retrieved from `tools.registry.registry`.\n3. **Auto-generated Toolsets**: If a toolset named `hermes-<platform>` is requested but not defined, the module attempts to resolve it by combining `_HERMES_CORE_TOOLS` with any tools registered in the registry under that platform name.\n\n## Toolset Resolution Flow\n\nThe primary function of this module is to \"flatten\" a toolset name into a deduplicated list of tool names.\n\n```mermaid\ngraph TD\n A[resolve_toolset] --> B{Is name 'all' or '*'? }\n B -- Yes --> C[Iterate all toolsets]\n B -- No --> D{In TOOLSETS?}\n D -- Yes --> E[Collect tools + Recurse includes]\n D -- No --> F[Check Plugin Registry]\n F --> G[Return Tool List]\n E --> G\n C --> G\n```\n\n### Cycle Detection\nThe `resolve_toolset` function uses a `visited` set to track recursion. This prevents infinite loops in cases of circular dependencies (e.g., Toolset A includes Toolset B, which includes Toolset A) and optimizes \"diamond\" dependencies where multiple included toolsets share a common sub-toolset.\n\n## Key Functions\n\n### `resolve_toolset(name: str) -> List[str]`\nThe workhorse of the module. It recursively resolves a toolset name into a sorted list of unique tool names.\n- Supports special aliases `\"all\"` and `\"*\"` to return every available tool.\n- Handles `hermes-` prefix logic for platform-specific toolsets.\n\n### `get_toolset(name: str) -> Optional[Dict[str, Any]]`\nRetrieves the raw definition of a toolset. It first checks the static `TOOLSETS` dictionary, then queries the `tools.registry.registry` for plugin-provided toolsets or MCP server aliases.\n\n### `get_all_toolsets() -> Dict[str, Dict[str, Any]]`\nReturns a merged dictionary of all static and dynamic toolset definitions. This is used by the TUI and API servers to list available capabilities.\n\n### `create_custom_toolset(name, description, tools, includes)`\nAllows for the programmatic creation of toolsets at runtime. This is useful for ephemeral sub-agents or specific task-based isolation.\n\n## Platform Toolsets\n\nThe module defines several `hermes-` prefixed toolsets designed for specific messaging platforms and interfaces:\n\n| Toolset | Description |\n| :--- | :--- |\n| `hermes-cli` | Full interactive toolset including `_HERMES_CORE_TOOLS`. |\n| `hermes-acp` | Coding-focused tools for IDE integrations (VS Code, Zed); excludes messaging and UI tools like `clarify`. |\n| `hermes-api-server` | OpenAI-compatible endpoint tools; excludes interactive UI tools. |\n| `hermes-discord` | Core tools plus specific `discord` and `discord_admin` capabilities. |\n| `hermes-gateway` | A composite toolset including all supported messaging platform toolsets. |\n\n## Integration with Tool Registry\n\nThis module acts as a bridge between static configuration and the dynamic `tools.registry`. When `get_toolset` fails to find a static match, it calls:\n- `registry.get_toolset_alias_target(name)`: To resolve MCP server aliases.\n- `registry.get_tool_names_for_toolset(name)`: To fetch tools registered by external plugins.\n\n## Usage Example\n\n```python\nfrom toolsets import resolve_toolset, validate_toolset\n\n# Check if a toolset exists\nif validate_toolset(\"research\"):\n # Get all tools, including those from 'includes'\n tools = resolve_toolset(\"research\")\n print(f\"Enabled tools: {tools}\")\n\n# Resolve all available tools in the system\nall_tools = resolve_toolset(\"*\")\n```\n\n## Internal Constants\n- `_HERMES_CORE_TOOLS`: The \"gold standard\" list of tools intended for most interactive Hermes instances. It includes web search, terminal access, file manipulation, vision, and browser automation. Modifying this list updates the default capabilities for almost all messaging platforms simultaneously.","root-trajectory-compressor-py":"# Root — trajectory_compressor.py\n\n# Trajectory Compressor\n\nThe `trajectory_compressor.py` module provides a robust post-processing pipeline for agent trajectories. It is designed to compress long conversation histories into a target token budget while preserving the essential training signals required for model fine-tuning or evaluation.\n\n## Overview\n\nAs agents perform complex tasks, their trajectories often exceed the context window of the models being trained or tested. This module implements a \"middle-out\" compression strategy: it protects the critical setup (system prompts and initial interactions) and the final conclusions, while summarizing the intermediate tool-use loops into a single concise human message.\n\n### Compression Strategy\n\nThe compressor follows a strict priority logic to ensure trajectory quality:\n1. **Protect Head:** Always keep the first system message, the first human message, the first GPT response, and the first tool response.\n2. **Protect Tail:** Always keep the last $N$ turns (default: 4) to preserve the final answer and the immediate context leading to it.\n3. **Compress Middle:** Only the turns between the \"Head\" and \"Tail\" are eligible for compression.\n4. **Targeted Reduction:** It only compresses as many turns as necessary to fall under the `target_max_tokens`.\n5. **LLM Summarization:** Compressed turns are sent to a summarization model (e.g., Gemini 1.5 Flash) to produce a `[CONTEXT SUMMARY]` that replaces the removed turns.\n\n## Core Components\n\n### CompressionConfig\nA dataclass managing all hyperparameters. It can be initialized via code or loaded from a YAML file using `CompressionConfig.from_yaml()`. Key parameters include:\n* `target_max_tokens`: The hard limit for the resulting trajectory (default: 15,250).\n* `protect_last_n_turns`: Number of turns at the end to keep intact.\n* `summarization_model`: The model used to generate summaries (default: `google/gemini-3-flash-preview`).\n* `max_concurrent_requests`: Controls the parallelism of API calls during batch processing.\n\n### TrajectoryCompressor\nThe primary engine responsible for token counting and transformation.\n\n* **Tokenization:** Uses `transformers.AutoTokenizer` (defaulting to `moonshotai/Kimi-K2-Thinking`) for accurate token counting.\n* **Logic Flow:**\n 1. `count_turn_tokens()`: Calculates the size of every message in the trajectory.\n 2. `_find_protected_indices()`: Identifies which turns cannot be touched.\n 3. `_generate_summary_async()`: Calls the summarization LLM via the `agent.auxiliary_client` provider router.\n 4. `compress_trajectory()`: Orchestrates the splicing of the head, the new summary message, and the tail.\n\n### Metrics Tracking\nThe module tracks performance through `TrajectoryMetrics` (per-file) and `AggregateMetrics` (per-run). It records:\n* Tokens saved and compression ratios.\n* Turns removed vs. turns preserved.\n* API success rates and processing throughput (trajectories/sec).\n\n## Execution Flow\n\nThe module uses `asyncio` to handle high-volume trajectory processing. When processing a directory, it loads all JSONL entries and uses a semaphore to limit concurrent LLM summarization calls.\n\n```mermaid\ngraph TD\n A[Input JSONL] --> B{Token Count > Target?}\n B -- No --> C[Skip/Copy]\n B -- Yes --> D[Identify Protected Head/Tail]\n D --> E[Extract Middle Content]\n E --> F[LLM Summarization Call]\n F --> G[Inject Summary as Human Message]\n G --> H[Reconstruct Trajectory]\n H --> I[Output Compressed JSONL]\n```\n\n## Integration with Agent Infrastructure\n\nThe compressor integrates with the broader `hermes` environment:\n* **Provider Routing:** Uses `agent.auxiliary_client.call_llm` and `async_call_llm` to abstract away OpenRouter, OpenAI, or custom provider logic.\n* **Temperature Handling:** Uses `_effective_temperature_for_model` to handle model-specific temperature constraints (e.g., Kimi's server-side management).\n* **Resilience:** Implements `jittered_backoff` from `agent.retry_utils` for summarization API calls.\n* **Environment:** Loads configuration via `hermes_cli.env_loader`.\n\n## CLI Usage\n\nThe module uses `fire` to expose a developer-friendly command-line interface.\n\n### Basic Compression\nCompress a single file or an entire directory:\n```bash\npython trajectory_compressor.py --input=data/trajectories.jsonl --target_max_tokens=12000\n```\n\n### Sampling and Analysis\nTo process a subset of data (useful for testing compression quality):\n```bash\npython trajectory_compressor.py --input=data/run_logs --sample_percent=10 --seed=42\n```\n\n### Dry Run\nAnalyze how many trajectories would be compressed without performing API calls or writing files:\n```bash\npython trajectory_compressor.py --input=data/run_logs --dry_run=True\n```\n\n## Output Format\nThe compressor outputs standard JSONL files. If metrics are enabled, it adds a `compression_metrics` field to each JSON object and generates a `compression_metrics.json` summary in the output directory. Compressed trajectories include a notice in the system prompt (if configured) and a specific prefix for summarized content: `[CONTEXT SUMMARY]: ...`.","root-utils-py":"# Root — utils.py\n\n# Root — utils.py\n\nThe `utils.py` module provides a suite of shared utility functions for the `hermes-agent` ecosystem. It focuses on robust file I/O, environment variable coercion, network proxy normalization, and secure URL parsing.\n\n## Atomic File Operations\n\nThe module provides helpers for writing JSON and YAML files atomically. This ensures that configuration files (like `auth.json` or `SOUL.md`) are never left in a corrupted or partially-written state if the process crashes or is interrupted.\n\n### Key Functions\n- `atomic_json_write(path, data, ...)`\n- `atomic_yaml_write(path, data, ...)`\n- `atomic_replace(tmp_path, target)`\n\n### Implementation Details\nThe atomic write flow follows a strict sequence to ensure data integrity and preserve system metadata:\n\n1. **Permission Capture**: `_preserve_file_mode` reads the current permission bits of the target file.\n2. **Temporary Write**: Data is written to a hidden temporary file in the same directory using `tempfile.mkstemp`.\n3. **Persistence**: The module calls `f.flush()` followed by `os.fsync()` to ensure data is physically written to the disk platter/SSD controller.\n4. **Symlink-Aware Swap**: `atomic_replace` resolves the real path of the target if it is a symlink. This prevents the common issue where `os.replace` destroys a symlink and replaces it with a regular file (critical for managed dotfiles or Docker mounts).\n5. **Permission Restoration**: `_restore_file_mode` re-applies the original permissions, as `mkstemp` defaults to restrictive `0o600` modes.\n\n```mermaid\ngraph TD\n A[Start Write] --> B[Capture Mode]\n B --> C[Write Temp File]\n C --> D[fsync]\n D --> E{Is Symlink?}\n E -- Yes --> F[Resolve Real Path]\n E -- No --> G[Use Target Path]\n F --> H[os.replace]\n G --> H\n H --> I[Restore Mode]\n I --> J[End]\n```\n\n## Environment and Truthiness\n\nTo standardize configuration across the agent, the module provides a centralized definition of \"truthy\" values.\n\n- **`is_truthy_value(value, default)`**: Coerces strings like `\"1\"`, `\"true\"`, `\"yes\"`, and `\"on\"` to `True`. This is used globally, including in `tools/transcription_tools.py` and `tools/approval.py`.\n- **`env_var_enabled(name)`**: A shortcut for checking if an environment variable is set to a truthy value.\n- **`env_int(key, default)` / `env_bool(key, default)`**: Type-safe environment variable readers with fallback values.\n\n## Network and Proxy Normalization\n\nThe agent often runs in environments (like WSL or behind Clash) where proxy environment variables may use non-standard schemes.\n\n- **`normalize_proxy_url(url)`**: Specifically handles the `socks://` alias by converting it to `socks5://`, which is required for compatibility with `httpx` and `aiohttp`.\n- **`normalize_proxy_env_vars()`**: Iterates through standard proxy keys (both uppercase and lowercase) and updates `os.environ` in-place with normalized URLs.\n\n## Secure URL Parsing\n\nStandard substring matches (e.g., `if \"openai.com\" in base_url`) are vulnerable to spoofing. The module provides hostname-aware helpers to ensure the agent interacts with the intended providers.\n\n- **`base_url_hostname(base_url)`**: Extracts the lowercased, normalized hostname. It handles bare hosts and full URLs correctly.\n- **`base_url_host_matches(base_url, domain)`**: Checks if the hostname of a URL matches a specific domain or is a subdomain of it.\n\n**Example:**\n```python\n# Returns True\nbase_url_host_matches(\"https://api.anthropic.com/v1\", \"anthropic.com\")\n\n# Returns False (prevents substring spoofing)\nbase_url_host_matches(\"https://anthropic.com.evil.com/v1\", \"anthropic.com\")\n```\n\n## Data Parsing\n\n- **`safe_json_loads(text, default)`**: A wrapper around `json.loads` that returns a default value (usually `None` or `{}`) instead of raising `JSONDecodeError` or `TypeError`. This is used extensively in adapters and client modules to handle malformed LLM outputs or API responses gracefully.","root":"# Root\n\n# Hermes Agent: Root Module\n\nThe **Root** module serves as the orchestration layer and configuration hub for the Hermes Agent ecosystem. It integrates the core execution logic with persistent state management, multi-platform deployment configurations, and specialized runners for training and software engineering tasks.\n\n## System Integration Architecture\n\nThe root module bridges the gap between the high-level interfaces (CLI, Gateway, TUI) and the underlying execution environment.\n\n```mermaid\ngraph TD\n CLI[hermes CLI / rl_cli.py] --> Agent[AIAgent - run_agent.py]\n Batch[batch_runner.py] --> Agent\n Agent --> Tools[model_tools.py]\n Tools --> Sets[toolsets.py / toolset_distributions.py]\n \n Agent --> State[hermes_state.py - SQLite]\n Agent --> Log[hermes_logging.py]\n \n Env[setup-hermes.sh / flake.nix] --> Runtime[Docker / Nix / Termux]\n Runtime --> Agent\n```\n\n## Core Components\n\n### Orchestration & Tools\nThe system is centered around the `AIAgent`, which utilizes [model_tools.py](model_tools.md) to interface with the external world. Tool capabilities are managed through [toolsets.py](toolsets.md), allowing for dynamic capability resolution based on the user's environment (e.g., CLI vs. Messaging Gateway). For research and training, [toolset_distributions.py](toolset_distributions.md) enables probabilistic tool availability to diversify agent trajectories.\n\n### Persistence & Global State\nHermes maintains a continuous learning loop through a centralized state system:\n* **[hermes_state.py](hermes_state.md)**: A SQLite-backed `SessionDB` that handles concurrent access from multiple interfaces (CLI, Telegram, Discord) using WAL mode.\n* **[hermes_constants.py](hermes_constants.md)**: The single source of truth for path resolution and environment detection across all modules.\n* **[hermes_logging.py](hermes_logging.md)**: Manages multi-file logging with secret redaction and session-specific context injection.\n* **[hermes_time.py](hermes_time.md)**: Ensures timezone-aware operations for scheduling and logging.\n\n### Specialized Execution Loops\nBeyond standard chat, the root module provides specialized entry points:\n* **[batch_runner.py](batch_runner.md)**: A parallelized framework for executing agents across large datasets with fault-tolerant checkpointing.\n* **[rl_cli.py](rl_cli.md)**: An optimized interface for Reinforcement Learning workflows, featuring extended timeouts and specialized toolsets.\n* **[mini_swe_runner.py](mini_swe_runner.md)**: A trajectory-based engine for solving software engineering tasks in sandboxed environments.\n* **[trajectory_compressor.py](trajectory_compressor.md)**: A post-processing pipeline that summarizes long agent histories into token-efficient training data.\n\n## Deployment & Environment\nThe project supports a wide range of environments through modular configuration:\n* **Containerization**: Production deployments are managed via [Dockerfile](Dockerfile.md) and [docker-compose.yml](docker-compose.md), with specific hardening for [coolify-docker-compose.yaml](coolify-docker-compose.md).\n* **Reproducibility**: [flake.nix](flake.md) provides a Nix-based development shell, while [setup-hermes.sh](setup-hermes.md) automates installation on standard Linux and [Termux](constraints-termux.md) (Android) environments.\n* **Interoperability**: [mcp_serve.py](mcp_serve.md) exposes Hermes conversation history to external IDEs and clients via the Model Context Protocol.\n\n## Configuration & Metadata\nGlobal behavior is governed by [cli-config.yaml](cli-config.md), which defines model parameters and provider routing. The project's Python lifecycle is defined in [pyproject.toml](pyproject.md), while [package.json](package.md) manages the Node.js dependencies required for browser-based toolsets.","scripts-lib":"# scripts — lib\n\n# Node Bootstrap Library (`node-bootstrap.sh`)\n\nThe `node-bootstrap.sh` script is a sourceable bash utility designed to ensure a compatible Node.js environment is available. It is primarily used by the Hermes TUI (React + Ink), browser automation tools, and the WhatsApp bridge.\n\nThe script follows a \"first hit wins\" strategy, prioritizing existing user configurations and version managers before attempting to install a managed binary.\n\n## Configuration\n\nThe script can be configured via environment variables set before sourcing.\n\n| Variable | Default | Description |\n| :--- | :--- | :--- |\n| `HERMES_NODE_MIN_VERSION` | `20` | The minimum major version required to skip installation. |\n| `HERMES_NODE_TARGET_MAJOR` | `22` | The major version to install if no compatible version is found. |\n| `HERMES_HOME` | `$HOME/.hermes` | The directory where Hermes-managed binaries are stored. |\n\n## Public API\n\n### `ensure_node`\nThe primary entry point for the module. It performs a sequence of checks and installation attempts to guarantee Node.js availability.\n\n**Returns:**\n- `0` if a compatible Node.js version is found or successfully installed.\n- `1` if all installation attempts fail.\n\n**Side Effects:**\n- Sets `HERMES_NODE_AVAILABLE` to `true` or `false`.\n- Modifies `PATH` if a Hermes-managed or version-manager-controlled Node.js is used.\n- Creates symlinks in `$HOME/.local/bin` when performing a bundled installation.\n\n```bash\nsource scripts/lib/node-bootstrap.sh\n\nif ensure_node; then\n echo \"Node version: $(node --version)\"\nfi\n```\n\n## Resolution Strategy\n\nThe `ensure_node` function executes the following checks in order:\n\n```mermaid\ngraph TD\n A[Start: ensure_node] --> B{Node on PATH >= MIN?}\n B -- Yes --> Success[Return 0]\n B -- No --> C{Hermes-managed Node exists?}\n C -- Yes --> Success\n C -- No --> D[Try Version Managers: fnm, proto, nvm]\n D -- Found/Installed --> Success\n D -- Not Found --> E[Try System Package Managers: pkg, brew]\n E -- Installed --> Success\n E -- Not Found --> F[Download Bundled Tarball]\n F -- Success --> Success\n F -- Failure --> Fail[Return 1]\n```\n\n### 1. Existing Environment\nThe script first calls `_nb_have_modern_node` to check if the current `PATH` already satisfies `HERMES_NODE_MIN_VERSION`.\n\n### 2. Version Managers\nIf no system Node is found, the script attempts to leverage existing version managers in the following order:\n- **fnm**: Runs `fnm install` and `fnm use`.\n- **proto**: Runs `proto install node`.\n- **nvm**: Sources `nvm.sh` from `NVM_DIR` and runs `nvm install`.\n\n### 3. Platform Package Managers\n- **Termux**: Uses `pkg install nodejs`.\n- **macOS**: Uses `brew install node@<MAJOR>`.\n\n### 4. Bundled Binary Fallback (`_nb_install_bundled_node`)\nAs a last resort, the script identifies the system architecture (`x64`, `arm64`, `armv7l`) and OS (`linux`, `darwin`), fetches the latest minor version of the target major release from `nodejs.org`, and extracts it into `$HERMES_HOME/node`.\n\nIt then creates symlinks for `node`, `npm`, and `npx` in `$HOME/.local/bin` to ensure persistence across sessions without requiring shell profile (`.bashrc`/`.zshrc`) edits.\n\n## Logging Integration\nThe module is designed to integrate with the host script's logging system. It looks for the following functions:\n- `log_info`\n- `log_success`\n- `log_warn`\n\nIf these are not defined in the calling script, it falls back to standard `printf` output to `stderr`.\n\n## Internal Helpers\n- `_nb_is_termux`: Detects if the environment is Termux via `TERMUX_VERSION` or `PREFIX` path.\n- `_nb_node_major`: Parses the output of `node --version` to return an integer major version.\n- `_nb_have_modern_node`: Validates both the existence of the `node` command and its version compliance.","scripts-whatsapp-bridge":"# scripts — whatsapp-bridge\n\n# WhatsApp Bridge\n\nThe WhatsApp Bridge is a standalone Node.js module that enables the Hermes Agent to communicate over WhatsApp. It utilizes the [Baileys](https://github.com/WhiskeySockets/Baileys) library to interface with the WhatsApp Web API and exposes a RESTful HTTP interface for the Python-based gateway.\n\n## Architecture\n\nThe bridge acts as a middleware layer between the WhatsApp network and the Hermes internal services. It manages the persistent socket connection, handles authentication via QR codes, and provides a simplified API for message exchange.\n\n```mermaid\ngraph LR\n subgraph \"Hermes Python Gateway\"\n A[WhatsApp Platform Adapter]\n end\n subgraph \"WhatsApp Bridge (Node.js)\"\n B[Express HTTP Server]\n C[Baileys Socket]\n D[Allowlist Manager]\n end\n A <-->|HTTP/JSON| B\n B <--> C\n C <-->|E2EE Protocol| E[WhatsApp Servers]\n C -.-> D\n```\n\n## Core Components\n\n### `bridge.js`\nThe main entry point that initializes the WhatsApp connection and the HTTP server.\n\n- **Connection Management**: Uses `useMultiFileAuthState` to persist session data in the specified session directory. It handles automatic reconnections and QR code generation for initial pairing.\n- **Message Polling**: Implements a long-polling pattern. Incoming messages are pushed into an internal `messageQueue` (capped at 100 items) and retrieved by the gateway via `GET /messages`.\n- **Media Handling**: Automatically downloads incoming images, videos, audio, and documents to local cache directories (`~/.hermes/*_cache`). It returns the local file paths to the gateway.\n- **Loop Prevention**: In `self-chat` mode, the bridge uses `recentlySentIds` and a configurable `REPLY_PREFIX` to identify and ignore messages sent by the agent itself, preventing infinite response loops.\n\n### `allowlist.js`\nA utility module for filtering incoming traffic. It is critical for security when the bridge is exposed or used in group settings.\n\n- **Identity Normalization**: `normalizeWhatsAppIdentifier` strips JID suffixes (e.g., `@s.whatsapp.net`, `@lid`) and formatting to produce a clean numeric ID.\n- **LID Mapping**: WhatsApp increasingly uses LIDs (Linked Identity Devices) instead of phone numbers for message attribution. This module reads `lid-mapping-*.json` files from the session directory to transparently resolve phone numbers to LIDs and vice versa.\n- **Wildcard Support**: Supports `*` in the `WHATSAPP_ALLOWED_USERS` environment variable to allow all incoming messages.\n\n## Operational Modes\n\nThe bridge behavior changes based on the `WHATSAPP_MODE` environment variable:\n\n| Mode | Description |\n| :--- | :--- |\n| `self-chat` | (Default) The agent operates on the user's primary account. It only responds to messages in the \"Message Yourself\" chat or messages where the sender is the user. |\n| `bot` | The agent operates on a dedicated WhatsApp number. It responds to all allowed users and does not prepend the `REPLY_PREFIX`. |\n\n## HTTP API Reference\n\nThe bridge binds to `127.0.0.1` by default and enforces Host-header validation to prevent DNS rebinding attacks.\n\n### Endpoints\n\n- **`GET /messages`**: Returns all queued incoming messages and clears the queue.\n- **`POST /send`**: Sends a text message.\n - Body: `{ \"chatId\": \"string\", \"message\": \"string\", \"replyTo\": \"string?\" }`\n- **`POST /send-media`**: Sends a file natively.\n - Body: `{ \"chatId\": \"string\", \"filePath\": \"string\", \"mediaType\": \"image|video|audio|document\", \"caption\": \"string?\", \"fileName\": \"string?\" }`\n- **`POST /edit`**: Edits an existing message sent by the bot.\n - Body: `{ \"chatId\": \"string\", \"messageId\": \"string\", \"message\": \"string\" }`\n- **`POST /typing`**: Triggers the \"composing...\" status.\n- **`GET /chat/:id`**: Fetches metadata for a specific chat or group.\n- **`GET /health`**: Returns connection status and queue depth.\n\n## Configuration\n\n### Environment Variables\n\n| Variable | Description | Default |\n| :--- | :--- | :--- |\n| `WHATSAPP_MODE` | `self-chat` or `bot`. | `self-chat` |\n| `WHATSAPP_ALLOWED_USERS` | Comma-separated list of phone numbers or LIDs. | (Empty - allows none) |\n| `WHATSAPP_REPLY_PREFIX` | String prepended to messages in `self-chat` mode. | `⚕ *Hermes Agent*...` |\n| `WHATSAPP_DEBUG` | Enables verbose logging of message objects. | `false` |\n\n### CLI Arguments\n\n- `--port <number>`: Port for the HTTP server (default: 3000).\n- `--session <path>`: Directory to store authentication credentials.\n- `--pair-only`: Runs the bridge only to display the QR code and save credentials, then exits.\n\n## Identity Resolution Logic\n\nBecause WhatsApp users can be identified by either a Phone Number JID or a LID JID, the bridge performs recursive expansion during allowlist checks:\n\n1. The `senderId` is normalized.\n2. The bridge looks for `lid-mapping-{id}.json` and `lid-mapping-{id}_reverse.json` in the session folder.\n3. It builds a set of all known aliases for that user.\n4. If any alias exists in the `ALLOWED_USERS` set, the message is processed.\n\nThis allows developers to put a standard phone number in the allowlist while still supporting modern WhatsApp LID-based routing.","skills-apple":"# skills — apple\n\n# Apple Skills Module\n\nThe `skills/apple` module provides a suite of tools for interacting with native macOS applications and iCloud-synced services. It enables the agent to manage personal information, communications, and device tracking directly through the macOS ecosystem.\n\n## Overview\n\nThis module is strictly limited to **macOS** environments. It leverages a combination of specialized CLI wrappers, AppleScript, and UI automation to bridge the gap between the agent and sandboxed Apple applications.\n\n### Core Components\n\n| Skill | Underlying Tool | Primary Function |\n| :--- | :--- | :--- |\n| `apple-notes` | `memo` | CRUD operations on iCloud Notes. |\n| `apple-reminders` | `remindctl` | Task and list management in Reminders.app. |\n| `imessage` | `imsg` | Sending and reading iMessage/SMS. |\n| `findmy` | AppleScript / Vision | Tracking devices and AirTags via UI scraping. |\n\n---\n\n## Architecture & Integration\n\nThe module operates by executing shell commands that interface with macOS APIs or local databases. Because many Apple apps do not provide public APIs, the module relies on external CLI utilities that must be installed on the host system.\n\n```mermaid\ngraph TD\n Agent[Hermes Agent] --> AppleSkills[Apple Skills Module]\n AppleSkills --> Notes[Apple Notes / memo CLI]\n AppleSkills --> Reminders[Reminders / remindctl CLI]\n AppleSkills --> iMessage[iMessage / imsg CLI]\n AppleSkills --> FindMy[Find My / AppleScript + Vision]\n \n Notes -.-> iCloud((iCloud Sync))\n Reminders -.-> iCloud\n iMessage -.-> MessagesApp[Messages.app]\n```\n\n---\n\n## Sub-Module Details\n\n### Apple Notes (`apple-notes`)\nUses the `memo` CLI to interact with the Apple Notes database. \n- **Key Pattern:** Prefers interactive modes for deletion/editing but supports direct creation via `memo notes -a \"Title\"`.\n- **Data Flow:** Notes are synced via iCloud, making them available on iOS/iPadOS devices automatically.\n- **Constraint:** Cannot programmatically edit notes containing rich media (images/attachments).\n\n### Apple Reminders (`apple-reminders`)\nUses `remindctl` for task management.\n- **Programmatic Access:** Developers should use the `--json` flag (e.g., `remindctl today --json`) to parse reminder data reliably.\n- **Date Handling:** Supports natural language (today, tomorrow) and ISO 8601 strings.\n- **Permissions:** Requires the user to grant \"Reminders\" access to the terminal/agent process.\n\n### iMessage (`imessage`)\nUses `imsg` to read and send messages.\n- **Security:** Requires **Full Disk Access** in macOS System Settings to read the `chat.db` file.\n- **Service Selection:** Can force `imessage` or `sms` services using the `--service` flag.\n- **Workflow:** Always verify the recipient's identity via `imsg chats` before sending to avoid messaging the wrong contact.\n\n### Find My (`findmy`)\nThis is a \"Vision-based\" skill because Apple provides no CLI or API for Find My.\n- **Execution Flow:**\n 1. Trigger AppleScript to activate `FindMy.app`.\n 2. Use `screencapture` or `peekaboo` to take a screenshot of the UI.\n 3. Pass the image to `vision_analyze` to extract location data or device status.\n- **Tracking:** To track moving items (like AirTags), the Find My window must remain in the foreground to receive location updates.\n\n---\n\n## Developer Guidelines\n\n### Prerequisites & Setup\nMost skills in this module require specific Homebrew packages:\n```bash\nbrew tap antoniorodr/memo && brew install antoniorodr/memo/memo\nbrew install steipete/tap/remindctl\nbrew install steipete/tap/imsg\nbrew install steipete/tap/peekaboo # Optional for FindMy\n```\n\n### Permission Handling\nWhen contributing to or using these skills, handle the following macOS permission prompts:\n1. **Automation:** Required for AppleScript to control apps.\n2. **Full Disk Access:** Required for reading iMessage history.\n3. **Screen Recording:** Required for the `findmy` skill to capture the UI.\n\n### Best Practices\n- **Confirmation:** Always confirm destructive actions (deleting notes, completing reminders) or outbound communications (sending iMessages) with the user.\n- **Tool Selection:** Use `apple-notes` for long-term storage and `memory` tools for short-term agent context.\n- **Parsing:** Always prefer JSON output flags when available to avoid fragile regex parsing of CLI stdout.","skills-autonomous-ai-agents":"# skills — autonomous-ai-agents\n\n# Autonomous AI Agents Module\n\nThe `autonomous-ai-agents` module provides the orchestration logic and skill definitions required to spawn, manage, and delegate tasks to independent AI coding agents. It enables a multi-agent architecture where a primary Hermes instance can act as a \"manager\" that delegates complex, long-running, or specialized coding tasks to sub-agents like **Claude Code**, **OpenCode**, and **Codex**, or even additional instances of **Hermes** itself.\n\n## Orchestration Architecture\n\nHermes interacts with these agents primarily through the `terminal` and `process` tools. Because these agents are often interactive TUI (Terminal User Interface) applications, the module emphasizes two distinct execution patterns:\n\n1. **One-Shot (Print) Mode:** Non-interactive execution where the agent performs a task and exits. This is the preferred method for automation and CI/CD pipelines.\n2. **Interactive PTY Mode:** Running the agent inside a pseudo-terminal (PTY), often managed via `tmux`, to allow for multi-turn conversations and human-in-the-loop decision-making.\n\n```mermaid\ngraph TD\n H[Hermes Primary] -->|terminal/process| O[Orchestrator]\n O -->|Non-interactive| C1[Claude Code -p]\n O -->|tmux session| C2[Claude Code Interactive]\n O -->|Background Process| OC[OpenCode / Codex]\n C1 -->|Filesystem Changes| FS[(Project Files)]\n C2 -->|Filesystem Changes| FS\n OC -->|Filesystem Changes| FS\n```\n\n---\n\n## Claude Code Orchestration\n\nClaude Code (Anthropic) is the primary autonomous coding agent supported. It features deep filesystem access, shell execution, and git workflow management.\n\n### Execution Modes\n\n| Mode | Command Pattern | Use Case |\n| :--- | :--- | :--- |\n| **Print (`-p`)** | `claude -p \"task\" --max-turns 10` | Automated bug fixes, refactors, and structured JSON extraction. |\n| **Interactive** | `tmux new-session ... 'claude'` | Iterative development, exploratory coding, and manual review. |\n\n### Critical: PTY Dialog Handling\nWhen running in interactive mode via `tmux`, Claude Code presents confirmation dialogs that must be handled programmatically:\n* **Workspace Trust:** Requires a single `Enter` keypress.\n* **Permissions Bypass:** When using `--dangerously-skip-permissions`, the default selection is \"No\". Orchestrators must send `Down` then `Enter` to accept.\n\n### Structured Output\nClaude Code supports `--json-schema` in print mode, allowing Hermes to receive validated, machine-readable results from an autonomous coding session.\n\n---\n\n## Hermes Agent (Self-Orchestration)\n\nThe `hermes-agent` skill allows Hermes to spawn additional instances of itself. This is useful for long-running \"missions\" that should not block the primary conversation.\n\n### Spawning Patterns\n* **Delegation:** Use the `delegate_task` tool for quick, in-process subtasks.\n* **Process Spawning:** Use `hermes chat -q \"task\"` for independent, fire-and-forget background execution.\n* **Worktree Isolation:** Use the `-w` or `--worktree` flag when spawning agents to ensure they operate in an isolated git worktree, preventing filesystem collisions between parallel agents.\n\n### Configuration Management\nHermes instances are configured via `~/.hermes/config.yaml`. Key orchestration settings include:\n* **`approvals.mode`**: Set to `manual`, `smart`, or `off` (YOLO).\n* **`security.redact_secrets`**: When enabled, masks API keys and tokens in tool outputs before they reach the LLM.\n\n---\n\n## OpenCode & Codex Integration\n\nThese agents are utilized for provider-agnostic coding tasks and specialized PR reviews.\n\n### OpenCode\n* **Binary:** `opencode-ai`.\n* **Pattern:** Prefers `opencode run 'task'` for one-shots.\n* **TUI Exit:** Must be killed via `Ctrl+C` (`\\x03`) or process kill; `/exit` is not a valid command in its TUI.\n\n### Codex\n* **Requirement:** **Must** run inside a git repository.\n* **PTY:** Always requires `pty=true` in terminal calls as it is inherently interactive.\n* **Safety:** Supports `--full-auto` for sandboxed approvals and `--yolo` for unrestricted execution.\n\n---\n\n## Multi-Agent Workflows\n\nThe module enables complex parallel workflows by combining `tmux` and git worktrees.\n\n### Parallel Feature Implementation\nA common pattern for implementing multiple features simultaneously:\n1. **Create Worktrees:** `git worktree add -b feature-a ./feature-a main`.\n2. **Spawn Agents:** Launch independent `claude` or `hermes` processes in each directory.\n3. **Monitor:** Use `tmux capture-pane` to scrape the status of each agent.\n4. **Consolidate:** Once agents finish, the primary Hermes instance reviews the changes and merges the worktrees.\n\n### PR Review Pipeline\n1. Fetch PR refs.\n2. Spawn an agent with the specific task: `claude -p \"Review PR #42\" --from-pr 42`.\n3. The agent autonomously reads the diff, runs tests, and generates a summary.\n\n---\n\n## Security and Safety Controls\n\nOrchestrating autonomous agents requires strict safety boundaries:\n\n* **`--max-turns`**: Limits the number of agentic loops to prevent infinite loops and runaway API costs.\n* **`--max-budget-usd`**: Caps the total spend for a single autonomous session.\n* **`--allowedTools`**: Whitelists specific capabilities (e.g., allowing `Read` and `Bash(npm test)` but disallowing `Write`).\n* **`--bare`**: Used in CI/CD to skip loading local plugins, hooks, and `CLAUDE.md` files for a clean, predictable environment.\n\n## Project Context (CLAUDE.md)\n\nAll agents in this module respect the `CLAUDE.md` (or `.claude/rules/`) convention. This file serves as the \"memory\" for the project, containing:\n* Build and test commands.\n* Code style guidelines.\n* Architectural patterns.\n\nWhen spawning a sub-agent, Hermes ensures these context files are present so the sub-agent adheres to the project's specific standards without manual prompting.","skills-creative":"# skills — creative\n\n# Skills — Creative\n\nThe **Creative** module provides a suite of tools for technical visualization and generative art. It is divided into three primary domains: professional architecture diagrams, static ASCII art utilities, and a high-fidelity ASCII video rendering pipeline.\n\n## Architecture Diagrams\n\nThe `architecture-diagram` skill generates standalone, dark-themed HTML files containing inline SVG graphics. It is designed for infrastructure mapping, service topology, and cloud architecture.\n\n### Design System\nThe module uses a semantic color palette to categorize components:\n\n| Category | Fill (RGBA) | Stroke (Hex) |\n| :--- | :--- | :--- |\n| **Frontend** | `rgba(8, 51, 68, 0.4)` | `#22d3ee` (Cyan) |\n| **Backend** | `rgba(6, 78, 59, 0.4)` | `#34d399` (Emerald) |\n| **Database** | `rgba(76, 29, 149, 0.4)` | `#a78bfa` (Violet) |\n| **Cloud/AWS** | `rgba(120, 53, 15, 0.3)` | `#fbbf24` (Amber) |\n| **Security** | `rgba(136, 19, 55, 0.4)` | `#fb7185` (Rose) |\n\n### Implementation Patterns\n- **Double-Rect Masking**: To prevent connection lines from showing through semi-transparent component fills, the module draws an opaque background rect (`#0f172a`) before the styled semi-transparent rect.\n- **Z-Order Management**: Arrows and connection lines are rendered immediately after the background grid to ensure they appear behind component boxes.\n- **Grid System**: Uses a 40px SVG pattern (`#1e293b`) for alignment.\n\n---\n\n## ASCII Art Utilities\n\nThe `ascii-art` skill aggregates multiple CLI tools and REST APIs for text-based visual design.\n\n### Toolset\n1. **Text Banners**: Uses `pyfiglet` (local) or the `asciified` API (remote) for FIGlet font rendering.\n2. **Decorative Borders**: Uses `boxes` to wrap text in frames (e.g., `stone`, `parchment`, `c-cmt`).\n3. **Character Art**: Uses `cowsay` for speech-bubble art and `ascii.co.uk` (via `curl` and regex parsing) for subject-specific pre-made art.\n4. **Image Conversion**: Uses `ascii-image-converter` or `jp2a` to transform raster images into character grids.\n5. **Dynamic Data**: Fetches weather (`wttr.in`), moon phases, and QR codes (`qrenco.de`) as ASCII via `curl`.\n\n---\n\n## ASCII Video Pipeline\n\nThe `ascii-video` module is a sophisticated rendering engine that converts video, audio, or mathematical functions into colored ASCII MP4/GIF files. It relies on **NumPy** for vectorized math and **Pillow** for font rasterization.\n\n### The Rendering Pipeline\n\n```mermaid\ngraph LR\n Input[Input/Analysis] --> Scene[Scene Function]\n Scene --> Tonemap[Adaptive Tonemap]\n Tonemap --> Feedback[Feedback Buffer]\n Feedback --> Shaders[Shader Chain]\n Shaders --> FFmpeg[FFmpeg Encoder]\n```\n\n### Core Components\n\n#### 1. GridLayer Class\nThe `GridLayer` manages font rasterization and coordinate mapping. It pre-computes aspect-corrected polar and Cartesian coordinates to allow for vectorized effect generation.\n- **Cell Height Calculation**: Uses `ascent + descent` from `font.getmetrics()` rather than `textbbox` to ensure consistent vertical spacing.\n- **Bitmap Cache**: Pre-rasterizes the character palette into `float32` bitmaps stored in `self.bm`.\n\n#### 2. Multi-Grid Composition\nComplexity is achieved by layering multiple grids of different densities.\n- **`_render_vf()`**: The primary helper that maps a **Value Field** (brightness) and **Hue Field** (color) to a specific `GridLayer`.\n- **Interference Patterns**: By blending a small grid (`sm`, 10px) with a large grid (`lg`, 20px), the engine creates natural texture interference.\n\n#### 3. Adaptive Tonemapping\nBecause ASCII on black is inherently dark, the module uses `tonemap()` instead of linear multipliers.\n- **Logic**: It calculates the 1st and 99.5th percentiles of the frame, stretches the range, and applies a gamma curve (default `0.75`).\n- **Performance**: Subsamples the frame (4x) during percentile calculation to minimize CPU overhead.\n\n#### 4. Feedback & Shaders\n- **`FeedbackBuffer`**: Implements temporal recursion. It applies spatial transforms (zoom, rotate, shift) to the previous frame before blending it into the current one.\n- **`ShaderChain`**: A post-processing stack that applies effects like `sh_kaleidoscope`, `sh_chromatic_aberration`, and `sh_crt_barrel` to the final pixel canvas.\n\n### Color Systems\nThe module supports three color models:\n1. **HSV**: Standard for most generative effects.\n2. **Discrete RGB**: Used for retro palettes (e.g., `COLORS_CYBERPUNK`, `COLORS_VAPORWAVE`).\n3. **OKLAB/OKLCH**: Used for perceptually uniform gradients and color harmonies. Functions like `lerp_oklch` prevent the \"gray-out\" effect seen in standard RGB interpolation.\n\n### Execution & Parallelism\nTo handle the high computational cost of character rendering (~150ms/frame), the module uses `concurrent.futures` to distribute frame ranges across multiple workers. Each worker pipes raw RGB bytes directly to an `ffmpeg` subprocess to avoid memory bottlenecks.\n\n**Critical Note**: When piping to FFmpeg, `stderr` must be redirected to a file or `DEVNULL` to prevent the 64KB pipe buffer from deadlocking the process during long renders.","skills-data-science":"# skills — data-science\n\n# Data Science Skill: Jupyter Live Kernel\n\nThe `jupyter-live-kernel` skill provides a stateful Python execution environment by interfacing with a live Jupyter kernel. Unlike standard stateless execution tools, this module allows for incremental state building, making it the primary tool for data exploration, model training, and iterative debugging.\n\n## Overview\n\nThe module wraps the `hamelnb` utility script (`jupyter_live_kernel.py`) to communicate with a Jupyter server via REST APIs and WebSockets. It enables an agent to treat a `.ipynb` file as a persistent REPL.\n\n### Key Differences\n\n| Feature | `jupyter-live-kernel` | `execute_code` |\n| :--- | :--- | :--- |\n| **Persistence** | Stateful (variables persist across calls) | Stateless (fresh process every time) |\n| **Context** | Best for Data Science, ML, and EDA | Best for one-off scripts and tool usage |\n| **Environment** | Runs in JupyterLab's environment | Runs in the agent's local environment |\n| **Output** | Rich JSON (tracebacks, variable lists) | Standard STDOUT/STDERR |\n\n## Architecture\n\nThe skill acts as a bridge between the agent's command line and a headless JupyterLab instance.\n\n```mermaid\ngraph TD\n A[Agent] --> B[jupyter_live_kernel.py]\n B --> C{Jupyter Server}\n C --> D[Kernel / Python State]\n C --> E[Notebook Files .ipynb]\n```\n\n## Setup and Initialization\n\nThe skill requires a running Jupyter server. If a server is not detected, it must be started manually or via a shell command before the skill can function.\n\n### 1. Server Discovery\nCheck for existing servers:\n```bash\nuv run \"$SCRIPT\" servers --compact\n```\n\n### 2. Session Creation\nIf no session exists for a notebook, one must be initialized via the Jupyter REST API:\n```bash\ncurl -s -X POST http://127.0.0.1:8888/api/sessions \\\n -H \"Content-Type: application/json\" \\\n -d '{\"path\":\"scratch.ipynb\",\"type\":\"notebook\",\"name\":\"scratch.ipynb\",\"kernel\":{\"name\":\"python3\"}}'\n```\n\n## Core Operations\n\n### Code Execution\nThe `execute` command is the primary interface. It sends code to the kernel associated with a specific notebook path.\n\n```bash\nuv run \"$SCRIPT\" execute --path <notebook.ipynb> --code '<python_code>' --compact\n```\n* **Persistence:** All imports and variables defined in `<python_code>` remain available for subsequent `execute` calls.\n* **Timeouts:** Defaults to 30s. Use `--timeout` for heavy computations.\n\n### State Inspection\nDevelopers can inspect the current memory state of the kernel without executing new logic.\n\n* **List Variables:** `uv run \"$SCRIPT\" variables --path <nb.ipynb> list`\n* **Preview Variable:** `uv run \"$SCRIPT\" variables --path <nb.ipynb> preview --name <varname>`\n\n### Notebook Manipulation\nThe skill allows for direct manipulation of the `.ipynb` JSON structure:\n\n* **`contents`**: Returns the current list of cells and their IDs.\n* **`edit insert`**: Adds a new cell at a specific index.\n* **`edit replace-source`**: Updates the code within an existing cell using its `cell-id`.\n* **`edit delete`**: Removes a cell.\n\n## Execution Flow: Verification\n\nWhen a notebook needs to be validated from a clean state (e.g., before committing or after complex iterations), use the `restart-run-all` command.\n\n1. **Restart:** The kernel is killed and a fresh one is started.\n2. **Execution:** Every cell in the notebook is executed in order.\n3. **Persistence:** If `--save-outputs` is passed, the resulting cell outputs are written back to the `.ipynb` file.\n\n## Developer Guidelines\n\n### Token Management\nThe output from Jupyter can be extremely verbose (especially DataFrames or long tracebacks). \n* **Always use the `--compact` flag** to strip unnecessary metadata from the JSON response.\n* When inspecting large DataFrames, use `.head()` or `.info()` within the `execute` call rather than returning the whole object.\n\n### Error Handling\nErrors are returned as structured JSON. Key fields to inspect:\n* `ename`: The exception type (e.g., `NameError`).\n* `evalue`: The error message.\n* `traceback`: A list of strings representing the stack trace.\n\n### Environment Consistency\nSince the kernel runs within the JupyterLab environment, any libraries required for a task must be installed in that specific environment. If a module is missing, use the `terminal` skill to `pip install` or `uv pip install` into the Jupyter environment before retrying the execution.","skills-devops":"# skills — devops\n\n# DevOps & Orchestration Skills\n\nThe **DevOps** module provides the logic and conventions for multi-agent coordination, task decomposition, and event-driven automation within the Hermes ecosystem. It is divided into three primary functional areas: **Orchestration** (routing and planning), **Execution** (worker lifecycle), and **Automation** (webhook-driven triggers).\n\n## Kanban Orchestration\n\nThe Orchestrator is a high-level profile responsible for decomposing complex user requests into a directed acyclic graph (DAG) of tasks. The core philosophy is **\"Route, don't execute.\"**\n\n### The Orchestration Lifecycle\n1. **Decomposition:** Break the goal into discrete tasks assigned to specialized profiles (e.g., `researcher`, `backend-eng`).\n2. **Graph Sketching:** Define dependencies using the `parents` argument in `kanban_create`.\n3. **Fan-out:** Dispatch parallel tasks that have no mutual dependencies.\n4. **Handoff:** Use `kanban_complete` to summarize the plan for the user or a downstream supervisor.\n\n### Key Tools\n* `kanban_create(title, assignee, body, parents=[], tenant=None)`: Spawns a new task. Children in the `parents` list remain in `todo` until all parents are `done`.\n* `kanban_link(parent_id, child_id)`: Manually establishes dependencies between existing tasks.\n* `kanban_complete(summary, metadata)`: Finalizes the orchestrator's planning phase.\n\n```mermaid\ngraph TD\n User[User Request] --> Orch[Orchestrator]\n Orch --> T1[Task 1: Researcher]\n Orch --> T2[Task 2: Researcher]\n T1 --> T3[Task 3: Analyst]\n T2 --> T3\n T3 --> T4[Task 4: Writer]\n T4 --> Done[Final Output]\n```\n\n---\n\n## Kanban Worker Execution\n\nWorkers are specialized agents dispatched to fulfill specific tasks. Every worker follows a standardized lifecycle injected via `KANBAN_GUIDANCE`.\n\n### Workspace Types\nWorkers operate within `$HERMES_KANBAN_WORKSPACE`. The behavior changes based on the workspace kind:\n* **`scratch`**: A temporary directory for one-off tasks.\n* **`dir:<path>`**: A persistent directory for long-lived state or shared resources.\n* **`worktree`**: A Git worktree for code implementation. Workers should commit changes here.\n\n### The Worker Loop\n1. **Orient:** Call `kanban_show` to verify task status and read parent outputs.\n2. **Work:** Execute the task within the assigned workspace.\n3. **Heartbeat:** Periodically call `kanban_heartbeat` for long-running tasks (intervals > 2 mins).\n4. **Handoff:** Call `kanban_complete` with structured `metadata` to assist downstream agents.\n\n### Handling Blockers\nIf a worker lacks information or credentials, they must call `kanban_block(reason)`. \n* **Do NOT** use `delegate_task` for cross-agent handoffs; use `kanban_create` or `kanban_block`.\n* **Do NOT** finish a task partially; block it and wait for human or system intervention.\n\n---\n\n## Webhook Subscriptions\n\nThe `webhook-subscriptions` skill enables event-driven agent activation. It allows external services (GitHub, Stripe, CI/CD) to trigger Hermes runs via HMAC-signed POST requests.\n\n### Configuration & Setup\nWebhooks must be enabled in `~/.hermes/config.yaml` or via environment variables (`WEBHOOK_ENABLED=true`). The gateway listens on a configured port (default `8644`) and validates incoming payloads against a global or subscription-specific secret.\n\n### Subscription Management\nSubscriptions are managed via the `hermes webhook` CLI:\n\n```bash\n# Create a subscription for GitHub issues\nhermes webhook subscribe github-triage \\\n --events \"issues\" \\\n --prompt \"New issue: {issue.title}\\nBody: {issue.body}\" \\\n --deliver telegram \\\n --deliver-chat-id \"12345\"\n```\n\n### Advanced Patterns\n* **Payload Templating:** Use `{dot.notation}` to inject JSON fields from the webhook payload directly into the agent's prompt.\n* **Direct Delivery (`--deliver-only`):** Bypasses the LLM entirely. The rendered prompt is sent directly to the output adapter (e.g., Telegram). This is ideal for high-volume monitoring alerts where reasoning is not required.\n* **Tenant Isolation:** If `HERMES_TENANT` is active, webhooks inherit the tenant context, ensuring data isolation in persistent memory.\n\n---\n\n## Best Practices for Developers\n\n### Orchestrator Anti-Temptation\nOrchestrators often lack implementation tools (terminal, file access). If you are writing an orchestrator profile, ensure it strictly delegates work. If no specialist fits the task, the orchestrator should ask the user to define a new profile rather than attempting the work itself.\n\n### Structured Metadata\nWhen calling `kanban_complete`, always populate the `metadata` field with machine-readable data.\n* **Bad:** `summary=\"I fixed the bugs.\"`\n* **Good:** `metadata={\"files_fixed\": [\"app.py\"], \"tests_passed\": 5, \"coverage\": \"88%\"}`\nThis allows downstream `analyst` or `reviewer` profiles to process results without parsing natural language.\n\n### Error Recovery\nWorkers should check `kanban_show` for previous `runs`. If a task is a retry, the `error` or `outcome` fields (e.g., `timed_out`, `crashed`) provide the necessary context to avoid repeating the same failure path.","skills-diagramming":"# skills — diagramming\n\n# Diagramming Skill Module\n\nThe `skills/diagramming` module provides the system with the capability to generate, modify, and interpret visual diagrams. It acts as a bridge between high-level conceptual descriptions (like system architectures or logic flows) and structured visual formats, primarily targeting **Excalidraw** for rendering.\n\n## Overview\n\nThis module enables the AI to communicate complex ideas that are better suited for visual representation than text. It is designed to handle:\n* **Architecture Diagrams:** Visualizing cloud infrastructure, microservices, and data flow.\n* **Flowcharts:** Mapping out decision logic, business processes, and algorithm steps.\n* **Sequence Diagrams:** Illustrating interactions between components over time.\n* **UI Wireframes:** Creating low-fidelity mockups for interface planning.\n\n## Core Capabilities\n\nThe module defines the schemas and constraints required to produce valid visual assets. Unlike standard image generation, this module focuses on **vector-based, editable diagrams**.\n\n### Excalidraw Integration\nThe primary output format is the Excalidraw scene schema. This allows the generated diagrams to be:\n1. **Interactive:** Users can move elements, change colors, and edit text within the UI.\n2. **Scalable:** Diagrams remain crisp at any zoom level.\n3. **Programmatic:** The system can update specific nodes in a diagram without redrawing the entire scene.\n\n## Architecture & Data Flow\n\nThe diagramming skill operates as a transformation layer. It takes a natural language intent or a structured data model and converts it into a collection of `elements` (rectangles, arrows, text, etc.) defined by the Excalidraw specification.\n\n```mermaid\ngraph TD\n Intent[User Intent / System Task] --> Skill[Diagramming Skill]\n Skill --> Schema[Excalidraw JSON Schema]\n Schema --> Renderer[Excalidraw Canvas]\n Renderer --> User[Visual Output]\n User -- Edits --> Renderer\n Renderer -- Feedback --> Skill\n```\n\n## Implementation Details\n\n### Scene Definition\nA diagram is represented as a \"scene\" object. Key properties managed by this module include:\n* **Elements:** An array of objects (e.g., `type: \"rectangle\"`, `type: \"arrow\"`, `type: \"text\"`).\n* **AppState:** Controls the visual environment (theme, grid mode, zoom level).\n* **Bindings:** Logic that attaches arrows to shapes, ensuring that moving a box also moves the connected lines.\n\n### Element Structure\nWhen generating diagrams, the module adheres to the following structural pattern for elements:\n\n```json\n{\n \"type\": \"rectangle\",\n \"x\": 100,\n \"y\": 100,\n \"width\": 200,\n \"height\": 100,\n \"backgroundColor\": \"#f1f3f5\",\n \"strokeColor\": \"#1e1e1e\",\n \"fillStyle\": \"hachure\",\n \"strokeWidth\": 1,\n \"strokeStyle\": \"solid\",\n \"roughness\": 1,\n \"opacity\": 100,\n \"roundness\": { \"type\": 3 }\n}\n```\n\n## Usage Patterns\n\n### Generating a Flowchart\nTo generate a flowchart, the module calculates the spatial positioning (layout engine) for nodes and automatically generates `arrow` elements with `startBinding` and `endBinding` attributes to maintain connectivity.\n\n### Architecture Mapping\nFor technical architecture, the module utilizes specific visual metaphors:\n* **Groups:** Used to represent VPCs, Subnets, or Clusters.\n* **Text Labels:** Positioned relative to icons or boxes to identify services.\n* **Color Coding:** Standardized colors for different environments (e.g., green for \"Active\", red for \"Error\").\n\n## Integration with Other Modules\nThe diagramming skill is frequently invoked by:\n* **Documentation Skills:** To insert visual aids into generated Markdown files.\n* **System Analysis Skills:** To visualize call graphs or database schemas derived from source code.\n* **UI/UX Skills:** To prototype layouts based on user requirements.","skills-dogfood":"# skills — dogfood\n\n# Dogfood: Systematic Web QA Module\n\nThe `dogfood` module provides a structured framework for exploratory quality assurance (QA) of web applications. It leverages a suite of browser automation tools to navigate applications, detect functional and visual regressions, capture evidence, and generate standardized bug reports.\n\n## Core Components\n\nThe module is composed of three primary files that define the logic, classification standards, and output format:\n\n* **`SKILL.md`**: The primary execution logic. It defines a 5-phase workflow (Plan, Explore, Collect, Categorize, Report) and maps browser tool outputs to QA actions.\n* **`references/issue-taxonomy.md`**: A standardized classification system for bugs, defining four severity levels (Critical, High, Medium, Low) and six categories (Functional, Visual, Accessibility, Console, UX, Content).\n* **`templates/dogfood-report-template.md`**: A Markdown template used to aggregate findings into a final executive summary and detailed issue log.\n\n## Execution Workflow\n\nThe module follows a linear progression from initial planning to final reporting.\n\n```mermaid\ngraph TD\n A[Phase 1: Plan] --> B[Phase 2: Explore]\n B --> C[Phase 3: Collect Evidence]\n C --> D[Phase 4: Categorize]\n D --> E[Phase 5: Report]\n B -- Loop per page/feature --o B\n```\n\n### Phase 1: Planning\nThe module initializes the environment by creating an output directory structure (defaulting to `./dogfood-output`). It establishes a testing scope based on the target URL and identifies key user flows such as authentication, search, and checkout.\n\n### Phase 2: Exploration & Interaction\nThis is the active testing phase. The module utilizes the following tool pattern for every page visited:\n\n1. **Navigation**: `browser_navigate(url=...)`\n2. **State Capture**: `browser_snapshot()` for DOM/Accessibility tree analysis.\n3. **Error Detection**: `browser_console(clear=true)` is called after every navigation and interaction to catch silent JavaScript exceptions.\n4. **Visual Analysis**: `browser_vision(annotate=true)` generates a screenshot where interactive elements are labeled with numeric IDs (e.g., `[1]`, `[2]`).\n5. **Interaction**: Elements are targeted using the `@eN` reference syntax (e.g., `browser_click(ref=\"@e1\")`).\n\n### Phase 3: Evidence Collection\nWhen a discrepancy is found, the module captures:\n* **Visual Evidence**: A non-annotated screenshot via `browser_vision`.\n* **Context**: The current URL and the specific steps to reproduce (STR).\n* **Technical Logs**: Relevant console errors or failed network requests.\n\n### Phase 4: Categorization\nFindings are de-duplicated and mapped against the `issue-taxonomy.md`. Issues are sorted by severity to ensure the most critical blockers appear first in the final report.\n\n### Phase 5: Reporting\nThe module populates `dogfood-report-template.md`. A key feature of the reporting phase is the use of the `MEDIA:<screenshot_path>` syntax, which allows the final Markdown report to render captured evidence inline.\n\n## Tool Integration Reference\n\nThe module acts as a coordinator for the following browser tools:\n\n| Tool | Usage Pattern |\n| :--- | :--- |\n| `browser_vision` | Used with `annotate=true` to map the visual UI to actionable element references (`@eN`). |\n| `browser_console` | Critical for identifying \"High\" severity issues that don't manifest visually (e.g., unhandled promise rejections). |\n| `browser_snapshot` | Provides the text-based accessibility tree used to understand page structure and content. |\n| `browser_press` | Used for testing keyboard accessibility and form submission (e.g., `key=\"Enter\"`). |\n\n## Issue Taxonomy\n\nThe module enforces a strict classification to ensure report consistency:\n\n### Severity Levels\n* **Critical**: Total feature failure, data loss, or security vulnerabilities.\n* **High**: Significant impairment (e.g., broken core buttons) with possible workarounds.\n* **Medium**: UI/UX issues that don't block functionality (e.g., layout misalignment).\n* **Low**: Polish issues, typos, or missing favicons.\n\n### Categories\n* **Functional**: Logic errors and broken links.\n* **Visual**: CSS/Layout failures and broken images.\n* **Accessibility**: WCAG violations or keyboard traps.\n* **Console**: JS exceptions and 4xx/5xx network errors.\n* **UX/Content**: Confusing flows or placeholder text.\n\n## Implementation Notes for Developers\n\n* **State Management**: The module does not maintain an internal state machine of the web app; it relies on `browser_snapshot` and `browser_vision` at each step to determine the current state.\n* **Element Referencing**: Always use the `@eN` syntax provided by `browser_vision` or `browser_snapshot` for interactions to ensure accuracy in dynamic SPAs.\n* **Reporting Pathing**: Ensure the `output_dir` is writable, as all screenshots and the final `report.md` are persisted there.","skills-domain":"# skills — domain\n\n# Domain Intelligence Skill\n\nThe `domain-intel` module provides passive reconnaissance capabilities for domain names using only the Python standard library. It is designed to gather comprehensive technical and administrative data about domains without requiring external dependencies or API keys.\n\n## Core Capabilities\n\nThe module aggregates data from multiple passive sources to build a profile of a target domain:\n\n* **Subdomain Discovery:** Queries Certificate Transparency (CT) logs via `crt.sh` to identify historical and current subdomains.\n* **SSL/TLS Inspection:** Performs live handshakes to extract certificate metadata, including expiration dates, Subject Alternative Names (SANs), supported cipher suites, and TLS versions.\n* **WHOIS Lookups:** Executes direct TCP queries to authoritative WHOIS servers for over 100 Top-Level Domains (TLDs) to retrieve registration details.\n* **DNS Resolution:** \n * **System DNS:** Resolves `A` and `AAAA` records.\n * **Google DNS-over-HTTPS (DoH):** Resolves complex records including `MX`, `NS`, `TXT`, and `CNAME` to bypass local resolver limitations.\n* **Availability Analysis:** Heuristically determines if a domain is available for registration by correlating DNS NXDOMAIN responses, WHOIS \"not found\" strings, and SSL connection failures.\n* **Bulk Processing:** Supports parallel analysis of up to 20 domains simultaneously.\n\n## Architecture & Data Flow\n\nThe module operates as a stateless intelligence gatherer. When a domain is queried, it initiates concurrent requests across different protocols (HTTPS, DNS, TCP).\n\n```mermaid\ngraph TD\n A[Domain Query] --> B{Parallel Dispatcher}\n B --> C[crt.sh via HTTPS]\n B --> D[WHOIS via TCP/43]\n B --> E[Google DoH via HTTPS]\n B --> F[System DNS]\n B --> G[SSL Handshake via Socket]\n C --> H[Subdomain List]\n D --> I[Registration Data]\n E --> J[MX/TXT/NS Records]\n F --> K[IP Addresses]\n G --> L[Cert Metadata]\n H & I & J & K & L --> M[Aggregated Domain Profile]\n```\n\n## Technical Implementation Details\n\n### Passive Reconnaissance Strategy\nThe module strictly adheres to passive or semi-passive methods. It does not perform \"active\" scanning (like port scanning or directory brute-forcing). Instead, it relies on:\n1. **Public Logs:** CT logs are immutable records of issued certificates.\n2. **Standard Protocols:** Direct WHOIS queries to port 43.\n3. **Third-party Resolvers:** Using Google DoH ensures consistent results regardless of the host's local DNS configuration.\n\n### Zero-Dependency Design\nTo maintain portability and minimize the footprint, the module implements:\n* **Custom WHOIS Client:** A raw socket implementation that handles the logic of identifying the correct authoritative server for a given TLD and parsing the response.\n* **DoH Client:** Uses `urllib.request` to perform JSON-based DNS queries over HTTPS.\n* **SSL Parser:** Uses the `ssl` module to decode peer certificates and extract X.509 extensions.\n\n## Usage Patterns\n\nThe skill is triggered by intent-based requests. Common patterns include:\n\n| Intent | Example Request |\n| :--- | :--- |\n| **Discovery** | \"Find all subdomains for example.com\" |\n| **Security Audit** | \"Check the SSL certificate for api.example.com\" |\n| **Ownership** | \"Whois lookup for example.org\" |\n| **Infrastructure** | \"Get DNS records for example.com\" |\n| **Bulk Analysis** | \"Check availability for these 10 domains: ...\" |\n\n## Constraints and Limitations\n\n* **Rate Limiting:** Since it queries public services like `crt.sh` and Google DoH, aggressive bulk querying may result in temporary IP-based rate limiting from those providers.\n* **WHOIS Parsing:** Because WHOIS data is semi-structured and varies by registrar, some fields may return raw text if the specific TLD format is not recognized.\n* **No Active Probing:** The module will not detect services running on non-standard ports or subdomains that have never requested an SSL certificate.","skills-email":"# skills — email\n\n# Email Skill (Himalaya CLI)\n\nThe `skills/email` module provides a terminal-based interface for managing email accounts via the **Himalaya CLI**. It supports IMAP for reading and searching, and SMTP (or Sendmail/Notmuch) for sending messages.\n\n## Overview\n\nThis module acts as a bridge between the system and email servers. It is designed to handle both interactive use (via a PTY) and programmatic automation (via JSON output and piped input).\n\n### Key Capabilities\n- **Account Management:** Support for multiple accounts (Gmail, iCloud, Outlook, etc.).\n- **Message Lifecycle:** List, read, search, move, copy, and delete emails.\n- **Rich Composition:** Uses **MML (MIME Meta Language)** to handle attachments, HTML parts, and inline images.\n- **Structured Data:** Supports `--output json` for programmatic parsing of email envelopes and metadata.\n\n## Prerequisites\n\n1. **Himalaya CLI:** Must be installed and available in the system `$PATH`.\n2. **Configuration:** A valid `~/.config/himalaya/config.toml` file.\n3. **Authentication:** Credentials should ideally be managed via a password manager (e.g., `pass`) or the system keyring to avoid plain-text passwords in the config.\n\n## Integration Architecture\n\nThe module interacts with the Himalaya binary through shell execution. For automation, the \"Template\" flow is preferred over the \"Interactive\" flow.\n\n```mermaid\ngraph TD\n A[Hermes/Developer] --> B{Operation Type}\n B -->|Read/List| C[himalaya --output json]\n B -->|Compose/Send| D[MML Template]\n D --> E[himalaya template send]\n C --> F[JSON Parser]\n E --> G[SMTP Server]\n F --> H[UI/Logic]\n```\n\n## Configuration\n\nThe configuration file (`~/.config/himalaya/config.toml`) defines backends for different accounts.\n\n### Example Account Setup\n```toml\n[accounts.personal]\nemail = \"user@example.com\"\ndisplay-name = \"Your Name\"\ndefault = true\n\nbackend.type = \"imap\"\nbackend.host = \"imap.example.com\"\nbackend.port = 993\nbackend.encryption.type = \"tls\"\nbackend.auth.cmd = \"pass show email/imap\"\n\nmessage.send.backend.type = \"smtp\"\nmessage.send.backend.host = \"smtp.example.com\"\nmessage.send.backend.port = 587\nmessage.send.backend.encryption.type = \"start-tls\"\nmessage.send.backend.auth.cmd = \"pass show email/smtp\"\n```\n\n## Core Operations\n\n### 1. Navigation and Discovery\nTo list folders or the \"envelopes\" (headers) of messages:\n\n```bash\n# List all folders\nhimalaya folder list\n\n# List the last 10 emails in JSON format\nhimalaya envelope list --page-size 10 --output json\n```\n\n### 2. Searching\nHimalaya supports filtering by sender, subject, or keywords:\n```bash\nhimalaya envelope list from \"boss@company.com\" subject \"Urgent\"\n```\n\n### 3. Reading and Attachments\nReading a message returns the plain-text body by default. To handle attachments, they must be downloaded to a directory.\n```bash\n# Read message ID 42\nhimalaya message read 42\n\n# Download all attachments for message 42\nhimalaya attachment download 42 --dir ~/Downloads\n```\n\n### 4. Programmatic Composition (MML)\nWhen sending emails programmatically, use **MML syntax**. This allows you to define headers and body content in a single stream.\n\n**Sending a simple message:**\n```bash\ncat << 'EOF' | himalaya template send\nFrom: you@example.com\nTo: recipient@example.com\nSubject: Automated Report\n\nPlease find the data attached.\n<#part filename=/tmp/report.csv><#/part>\nEOF\n```\n\n**Replying to a message:**\nTo reply, fetch the template first to ensure `In-Reply-To` and `References` headers are correctly set:\n```bash\nhimalaya template reply 42 | sed 's/^$/\\nMy reply text here\\n/' | himalaya template send\n```\n\n## Developer Patterns\n\n### Handling Interactive Prompts\nCommands like `himalaya account configure` require user input. When calling these from a parent process, ensure a PTY (Pseudo-Terminal) is allocated:\n```python\n# Example pattern\nterminal(command=\"himalaya account configure\", pty=true)\n```\n\n### Parsing Structured Output\nAlways use `--output json` when the result needs to be processed by another tool. The JSON schema for `envelope list` includes:\n- `id`: The internal folder-relative ID.\n- `flags`: Array of strings (e.g., `[\"seen\", \"flagged\"]`).\n- `subject`: The message subject.\n- `sender`: The display name or email of the sender.\n- `date`: ISO 8601 formatted timestamp.\n\n### Flag Management\nManage message states without moving them:\n```bash\n# Mark as read\nhimalaya flag add 42 --flag seen\n\n# Mark as important\nhimalaya flag add 42 --flag flagged\n```\n\n## Troubleshooting\n\n- **Authentication Failures:** Verify that the `backend.auth.cmd` returns the password correctly to stdout without extra line breaks.\n- **Message IDs:** Remember that IDs are relative to the current folder. If you change folders, you must re-list envelopes to get valid IDs.\n- **MML Compilation:** If an attachment fails, ensure the path in the `<#part>` tag is absolute or correctly relative to the execution context.","skills-gaming":"# skills — gaming\n\n# Skills: Gaming\n\nThe `skills/gaming` module provides automated workflows for infrastructure management and interactive gameplay. It is divided into two primary domains: **Minecraft Modpack Server Management** and **Headless Pokemon Emulation**.\n\n## Minecraft Modpack Server Setup\n\nThis sub-module automates the deployment of modded Minecraft servers (Forge/NeoForge) from server pack archives. It handles the full lifecycle from environment preparation to automated backup scheduling.\n\n### Deployment Workflow\n\n1. **Environment Preparation**: Identifies required Java versions based on Minecraft release:\n * 1.21+: Java 21\n * 1.18 - 1.20: Java 17\n * 1.16 and below: Java 8\n2. **Installation**: Utilizes mod loader installers. For packs like All The Mods (ATM), it uses environment variables like `ATM10_INSTALL_ONLY=true` to trigger headless installation via `startserver.sh`.\n3. **Configuration**: Generates `server.properties` with specific overrides for modded environments:\n * `allow-flight=true`: Prevents kicks from modded movement items.\n * `max-tick-time=180000`: Prevents watchdog crashes during heavy world generation.\n4. **JVM Tuning**: Configures `user_jvm_args.txt` using G1GC optimized flags. RAM allocation follows a heuristic based on mod count:\n * 100-200 mods: 6-12GB\n * 200-350+ mods: 12-24GB\n\n### Automation & Maintenance\n\nThe module implements a robust backup system via `backup.sh` and `crontab`.\n\n* **Backup Logic**: Performs a `tar -czf` of the `world` directory, timestamps the archive, and implements a rotation policy (default: 24 backups).\n* **Persistence**: Injects an hourly cron job to ensure consistent state recovery points.\n\n---\n\n## Pokemon Player (Headless Emulation)\n\nThe `pokemon-player` skill interfaces with the `pokemon-agent` package to play GameBoy/GBA Pokemon titles using the PyBoy emulator. It operates as a REST-controlled server with a vision-integrated feedback loop.\n\n### System Architecture\n\n```mermaid\ngraph TD\n A[Agent Logic] -->|REST API| B[Pokemon Agent Server]\n B -->|PyBoy| C[Game ROM]\n B -->|RAM Read| D[State Data]\n B -->|Frame Buffer| E[Screenshot]\n A -->|Vision Analysis| E\n B -->|SSH Tunnel| F[User Dashboard]\n```\n\n### The Gameplay Loop (OODA)\n\nThe agent follows a strict execution pattern to prevent desynchronization:\n\n1. **Observe**: Calls `GET /state` for RAM-based data (HP, coordinates) and `GET /screenshot` for spatial context.\n2. **Orient**: Uses vision models to identify obstacles (ledges, NPCs) not visible in RAM.\n3. **Decide**: Prioritizes actions: Dialog > Battle > Healing > Objectives.\n4. **Act**: Sends `POST /action` with a sequence of 2-4 moves.\n5. **Verify**: Takes a post-action screenshot to confirm the character reached the intended tile.\n\n### API Reference\n\n| Endpoint | Method | Description |\n| :--- | :--- | :--- |\n| `/health` | GET | Verifies server and emulator status. |\n| `/state` | GET | Returns JSON of party stats, location, and battle flags. |\n| `/screenshot` | GET | Returns the current frame buffer as a PNG. |\n| `/action` | POST | Accepts a list of inputs (e.g., `walk_up`, `press_a`). |\n| `/save` | POST | Creates a named state save. |\n| `/load` | POST | Restores a named state save. |\n\n### Critical Implementation Details\n\n* **Warp Handling**: Map transitions (doors/stairs) require a `wait_60` (1 second) delay to allow the emulator to update the position RAM.\n* **Building Exit Logic**: The agent is programmed to sidestep (left/right) after exiting a building to avoid immediately re-entering the door.\n* **Vision Dependency**: RAM state is insufficient for navigation. The agent must use `vision_analyze` on screenshots to detect one-way ledges and fences.\n* **Remote Access**: Uses `localhost.run` via SSH reverse tunneling to provide the user with a live dashboard URL (`.lhr.life/dashboard/`).\n\n### Memory Conventions\n\nThe module uses specific prefixes for the Persistent Knowledge Base (PKM) to track game state across sessions:\n* `PKM:OBJECTIVE`: Current quest goal.\n* `PKM:MAP`: Spatial layout notes (e.g., \"Mart is NE of Center\").\n* `PKM:TEAM`: Current roster and move sets.\n* `PKM:STUCK`: Coordinates of known navigation hazards.","skills-gifs":"# skills — gifs\n\n# Skills — GIFs\n\nThe `skills/gifs` module provides a dedicated interface for interacting with short-form animated media. It serves as the functional domain for searching, retrieving, and processing GIF files, typically acting as a bridge between the core agent logic and external media providers (such as Giphy or Tenor).\n\n## Overview\n\nThis module is designed to encapsulate all logic related to animated image formats. By isolating these capabilities into a specific skill, the system can provide consistent media handling across different user interfaces and platforms.\n\n### Core Responsibilities\n\nBased on the module definition, the implementation focuses on three primary areas:\n\n1. **Media Discovery (Search):** Interfacing with external APIs to find relevant animated content based on text queries, categories, or trending metrics.\n2. **Asset Acquisition (Download):** Handling the transfer of binary data from remote servers to local storage or memory buffers, including management of different resolutions and file sizes.\n3. **Media Manipulation:** Basic operations for \"working with\" GIFs, which may include metadata extraction, format conversion (e.g., GIF to MP4/WebP), or frame-rate adjustments.\n\n## Architecture & Integration\n\nAs a \"skill\" module, it follows the standard pattern of receiving high-level intent from an orchestrator and returning structured media objects.\n\n```mermaid\ngraph TD\n A[Orchestrator / Agent] -->|Query/URL| B[GIF Skill]\n B -->|API Request| C[External Provider]\n C -->|JSON/Binary| B\n B -->|Media Object/Path| A\n```\n\n### Input Patterns\nThe module is designed to handle:\n* **Natural Language Queries:** \"Find a happy cat GIF.\"\n* **Direct Identifiers:** Specific IDs from supported providers.\n* **Source URLs:** Direct links to `.gif` files for processing or re-hosting.\n\n### Output Patterns\nResults from this module typically include:\n* **Source URL:** The original location of the media.\n* **Local Path:** The location of the cached or downloaded file.\n* **Dimensions:** Width and height in pixels.\n* **Format Metadata:** File size, frame count, and looping information.\n\n## Development Guidelines\n\nWhen contributing to this module, ensure that:\n* **Rate Limiting:** Any external API calls respect the provider's rate limits.\n* **Caching:** Downloaded media is cached locally to prevent redundant network traffic.\n* **Error Handling:** Gracefully handle 404s from expired media links or API timeouts.\n* **Format Agnosticism:** While named \"GIFs,\" the module should ideally handle modern alternatives like looped MP4s or WebP animations if the provider offers them, as these are often more efficient for short-form animated media.","skills-github":"# skills — github\n\n# GitHub Skills Module\n\nThe **github** module provides a comprehensive suite of tools for managing the software development lifecycle on GitHub. It is designed to operate in diverse environments by implementing a dual-path execution strategy: leveraging the `gh` CLI for high-level operations when available, and falling back to raw `git` commands combined with `curl` calls to the GitHub REST API when it is not.\n\n## Core Architecture: The Dual-Path Strategy\n\nThe module is built on the principle of \"graceful degradation.\" Most skills within this module first detect the available tooling and authentication state to decide which path to take.\n\n```mermaid\ngraph TD\n A[Start GitHub Skill] --> B{gh CLI available?}\n B -- Yes --> C{gh authenticated?}\n C -- Yes --> D[Use gh CLI Path]\n C -- No --> E[Check GITHUB_TOKEN / .git-credentials]\n B -- No --> E\n E -- Found --> F[Use git + curl REST Path]\n E -- Not Found --> G[Fail: Trigger github-auth]\n```\n\n### Environment Detection (`gh-env.sh`)\nThe script `skills/github/github-auth/scripts/gh-env.sh` is the central utility for state detection. When sourced, it populates the following variables:\n- `GH_AUTH_METHOD`: \"gh\", \"curl\", or \"none\".\n- `GITHUB_TOKEN`: The PAT (Personal Access Token) extracted from environment variables, `.hermes/.env`, or `~/.git-credentials`.\n- `GH_USER`: The authenticated GitHub username.\n- `GH_OWNER_REPO`: The `owner/repo` string parsed from the local git remote.\n\n## Module Components\n\n### 1. Authentication (`github-auth`)\nHandles the initial setup required for all other skills. It supports:\n- **gh CLI login**: Interactive or token-based.\n- **Git-only (HTTPS)**: Configures `credential.helper store` to cache Personal Access Tokens.\n- **SSH**: Generates Ed25519 keys and provides the public key for GitHub settings.\n\n### 2. Pull Request Lifecycle (`github-pr-workflow`)\nManages the end-to-end PR process. A key feature is the **Auto-Fix Loop Pattern**:\n1. **Detection**: Monitor CI status via `gh pr checks` or the `/commits/{sha}/status` endpoint.\n2. **Diagnosis**: Retrieve failed logs (using `gh run view --log-failed` or downloading log artifacts via REST).\n3. **Action**: Apply fixes using local file tools, commit, and push.\n4. **Verification**: Poll the status until the check passes or a retry limit is reached.\n\n### 3. Code Review (`github-code-review`)\nProvides structured analysis of both local changes and remote PRs.\n- **Local Review**: Uses `git diff main...HEAD` to perform pre-push checks.\n- **Remote Review**: Supports fetching PR branches locally (`git fetch origin pull/N/head:pr-N`) for deep inspection.\n- **Standardized Feedback**: Findings are categorized by severity:\n - `🔴 Critical`: Security vulnerabilities or breaking bugs (Blocks merge).\n - `⚠️ Warning`: Logic flaws or missing tests.\n - `💡 Suggestion`: Style or performance improvements.\n - `✅ Looks Good`: Positive reinforcement for clean patterns.\n\n### 4. Repository Management (`github-repo-management`)\nHandles administrative tasks including:\n- **Repository CRUD**: Creating from templates, forking, and editing settings.\n- **Secrets**: Managing GitHub Actions secrets (requires `PyNaCl` for encryption when using the REST API path).\n- **Releases**: Automating tag creation and asset uploads.\n\n### 5. Issue Tracking (`github-issues`)\nFacilitates project management through:\n- **Triage**: Filtering issues by labels like `needs-triage`.\n- **Automation**: Linking issues to PRs using \"Closes #N\" keywords.\n- **Templates**: Standardized formats for bug reports and feature requests located in `github-issues/templates/`.\n\n### 6. Codebase Inspection (`codebase-inspection`)\nA specialized utility using `pygount` to provide metrics.\n- **Functionality**: Analyzes Lines of Code (LOC), language breakdown, and code-to-comment ratios.\n- **Performance**: Uses strict `--folders-to-skip` (e.g., `node_modules`, `venv`, `.git`) to prevent hanging on large dependency trees.\n\n## Integration Patterns\n\n### Using the REST API Fallback\nWhen `gh` is unavailable, the module uses `python3` one-liners to parse JSON responses from `curl`. Developers contributing to this module should follow this pattern for consistency:\n\n```bash\ncurl -s -H \"Authorization: token $GITHUB_TOKEN\" \\\n https://api.github.com/repos/$OWNER/$REPO/pulls \\\n | python3 -c \"import sys, json; [print(pr['number']) for pr in json.load(sys.stdin)]\"\n```\n\n### Conventional Commits\nThe module enforces the Conventional Commits standard for all automated commits:\n- `feat(...)`: New features.\n- `fix(...)`: Bug fixes.\n- `docs(...)`: Documentation changes.\n- `ci(...)`: Pipeline updates.\n\n## Prerequisites\n- **Git**: Required for all local operations.\n- **gh CLI**: Highly recommended for simplified auth and secret management.\n- **pygount**: Required for the `codebase-inspection` skill.\n- **python3**: Required for JSON parsing in the REST API fallback path.","skills-index-cache":"# skills — index-cache\n\n# Skills Index-Cache\n\nThe `skills — index-cache` module serves as a centralized registry and metadata repository for the system's available AI capabilities. It aggregates definitions for individual functional tools (skills), grouped capability suites (marketplace collections), and specialized personas (agents).\n\nThis module acts as the primary lookup source for the system's dispatcher to determine which skill or agent should be activated based on user input.\n\n## Module Architecture\n\nThe index cache is composed of three primary data sources, each serving a distinct role in the ecosystem:\n\n```mermaid\ngraph TD\n A[anthropics_skills_skills_.json] --> D[Index Cache]\n B[claude_marketplace_anthropics_skills.json] --> D\n C[lobehub_index.json] --> D\n D --> E[Skill Dispatcher / Router]\n```\n\n### 1. Core Skill Definitions\n**Source:** `anthropics_skills_skills_.json`\n\nThis file contains the atomic units of functionality. Each entry defines a specific toolset that the model can utilize. Key fields include:\n\n* **`name`**: The unique slug for the skill (e.g., `pdf`, `frontend-design`).\n* **`description`**: A detailed natural language prompt used by the model to understand when to trigger the skill.\n* **`identifier`**: The full path for resource resolution (e.g., `anthropics/skills/skills/docx`).\n* **`trust_level`**: Indicates the security context (e.g., `trusted`).\n\n**Example Skill Pattern:**\nSkills like `xlsx` or `pptx` include explicit trigger instructions within their descriptions, such as: *\"Trigger whenever the user mentions 'deck,' 'slides,' 'presentation,' or references a .pptx filename.\"*\n\n### 2. Skill Collections (Marketplace)\n**Source:** `claude_marketplace_anthropics_skills.json`\n\nThis layer organizes individual skills into logical bundles for easier management and higher-level capability discovery.\n\n* **`document-skills`**: Aggregates `xlsx`, `docx`, `pptx`, and `pdf`.\n* **`example-skills`**: A broad collection including `mcp-builder`, `skill-creator`, and `web-artifacts-builder`.\n\nThese collections allow the system to load related dependencies or provide a \"suite\" of tools to the model simultaneously.\n\n### 3. Agent Registry\n**Source:** `lobehub_index.json`\n\nThis is a high-volume registry of specialized agent personas. Unlike functional skills, these entries define entire system prompts and UI metadata for specific use cases.\n\n* **Metadata (`meta`)**: Contains UI-specific data like `avatar`, `tags`, `title`, and `category` (e.g., `programming`, `academic`, `life`).\n* **Schema Versioning**: Uses `schemaVersion: 1` to ensure compatibility with the LobeHub agent standard.\n* **Usage Tracking**: Includes `tokenUsage` metrics for performance monitoring.\n\n## Key Skill Categories\n\nThe index cache categorizes capabilities into several high-impact areas:\n\n| Category | Key Skills | Purpose |\n| :--- | :--- | :--- |\n| **Document Processing** | `pdf`, `docx`, `xlsx`, `pptx` | Manipulation, extraction, and creation of office formats. |\n| **Design & Art** | `algorithmic-art`, `canvas-design`, `theme-factory` | Generative art via p5.js and static visual design. |\n| **Development** | `mcp-builder`, `webapp-testing`, `frontend-design` | Building MCP servers, Playwright testing, and React/Tailwind UI. |\n| **Workflow** | `doc-coauthoring`, `skill-creator` | Structured collaboration and extending system capabilities. |\n\n## Implementation Details\n\n### Trigger Logic\nThe `description` field in the JSON files is the most critical component for developers. It functions as the \"routing prompt.\" When adding a new skill, the description must include:\n1. **Explicit Keywords**: Specific file extensions or terms (e.g., `.csv`, `GIF`).\n2. **Negative Constraints**: Instructions on when *not* to use the skill (e.g., the `xlsx` skill explicitly states: *\"Do NOT trigger when the primary deliverable is a Word document\"*).\n\n### Resource Resolution\nThe `identifier` and `path` fields map the logical skill name to the physical location in the `anthropics/skills` repository. This allows the runtime to dynamically fetch the necessary logic or environment configurations required to execute the skill.","skills-inference-sh":"# skills — inference-sh\n\n# inference-sh\n\nThe `inference-sh` module provides a unified interface to the [inference.sh](https://inference.sh) platform, allowing the system to access over 150 AI applications through a single API key. This module abstracts the complexity of managing multiple provider credentials (e.g., OpenAI, Anthropic, Google, Black Forest Labs) by routing requests through the inference.sh gateway.\n\n## Overview\n\nThe primary goal of this module is to provide the agent with a versatile toolkit for multi-modal AI tasks. Instead of implementing individual integrations for every new model, the module leverages the `infsh` command-line interface to perform tasks ranging from image generation to social media automation.\n\n## The `cli` Skill\n\nThe core functionality of this module is exposed through the `cli` skill. This skill enables the agent to interact with the platform via the terminal using the `infsh` binary.\n\n### Execution Pattern\nWhen the agent needs to perform a task supported by inference.sh, it invokes the terminal tool to run `infsh` commands. This allows for:\n- **Dynamic Model Selection**: Switching between models (e.g., FLUX for images, Claude for text) without changing code.\n- **Stateful Operations**: Using the CLI's internal session management for complex workflows.\n- **Unified Authentication**: Relying on the environment's configured `infsh` credentials.\n\n## Supported Service Domains\n\nThe module provides access to several specialized AI domains:\n\n| Domain | Key Models/Services |\n| :--- | :--- |\n| **Image Generation** | FLUX, Reve, Seedream, Grok Imagine, Gemini |\n| **Video Generation** | Veo, Wan, Seedance, OmniHuman, HunyuanVideo |\n| **LLMs** | Claude, Gemini, Kimi, GLM-4 (via OpenRouter) |\n| **Search & Web** | Tavily, Exa |\n| **3D Modeling** | Rodin |\n| **Social Media** | Twitter/X automation |\n| **Audio** | TTS, voice cloning |\n\n## Integration Architecture\n\nThe `inference-sh` module acts as a bridge between the agent's tool-calling capabilities and the external `infsh` ecosystem.\n\n```mermaid\ngraph TD\n Agent[AI Agent] -->|Invokes| Terminal[Terminal Tool]\n Terminal -->|Executes| INFSH[infsh CLI]\n INFSH -->|API Request| Gateway[inference.sh Gateway]\n Gateway -->|Route| Providers[Image/Video/LLM Providers]\n```\n\n## Developer Implementation Notes\n\n### Prerequisites\nTo use this module effectively, the environment must have:\n1. The `infsh` CLI installed and available in the system PATH.\n2. A valid `inference.sh` API key configured via `infsh login` or environment variables.\n\n### Usage in Workflows\nDevelopers should guide the agent to use the `cli` skill when high-fidelity multi-modal output is required that exceeds the capabilities of the primary LLM. For example, if the agent is tasked with \"creating a promotional video with a specific script,\" it should:\n1. Use an LLM to generate the script.\n2. Use the `cli` skill to run `infsh` commands for video generation (e.g., using `Wan` or `Veo`).\n3. Use the `cli` skill to generate accompanying images or social media posts.","skills-mcp":"# skills — mcp\n\n# Native MCP Client\n\nThe `skills/mcp` module provides a built-in Model Context Protocol (MCP) client for Hermes Agent. It allows the agent to connect to external MCP servers, discover their capabilities, and register their tools as first-class functions within the Hermes ecosystem.\n\nUnlike the `mcporter` skill which is designed for ad-hoc terminal usage, the native MCP client is a persistent integration that initializes at startup based on the agent's configuration.\n\n## Architecture\n\nThe MCP client operates as a background service within the Hermes Agent process. It manages the lifecycle of connections to multiple servers simultaneously.\n\n```mermaid\ngraph TD\n Config[config.yaml] -->|Read Config| Discovery[discover_mcp_tools]\n Discovery -->|Spawn| Loop[Background Event Loop]\n Loop -->|Connect| S1[Stdio Server: npx/uvx]\n Loop -->|Connect| S2[HTTP Server: Remote URL]\n S1 & S2 -->|list_tools| Registry[Hermes Tool Registry]\n Registry -->|Inject| Platform[Platform Toolsets: CLI/Discord/etc]\n```\n\n### Key Components\n- **Discovery Engine**: Triggered during agent initialization via `discover_mcp_tools()`. It reads the `mcp_servers` configuration and establishes connections.\n- **Background Event Loop**: Each server connection runs in a dedicated asyncio Task within a daemon thread to ensure non-blocking tool execution.\n- **Tool Registry Bridge**: Automatically maps remote MCP tools to the Hermes tool format, handling name sanitization and prefixing.\n\n## Configuration\n\nMCP servers are configured in `~/.hermes/config.yaml` under the `mcp_servers` key.\n\n### Stdio Transport\nUsed for local servers executed via command line (e.g., Node.js or Python-based servers).\n\n```yaml\nmcp_servers:\n filesystem:\n command: \"npx\"\n args: [\"-y\", \"@modelcontextprotocol/server-filesystem\", \"/path/to/data\"]\n env:\n CUSTOM_VAR: \"value\"\n timeout: 60\n```\n\n### HTTP Transport\nUsed for remote servers or shared infrastructure.\n\n```yaml\nmcp_servers:\n remote_service:\n url: \"https://mcp.example.com/v1\"\n headers:\n Authorization: \"Bearer <token>\"\n connect_timeout: 30\n```\n\n## Tool Discovery and Naming\n\nWhen a server connects, the client calls `list_tools()` and registers every discovered tool using a specific naming convention to prevent collisions:\n\n**Pattern**: `mcp_{server_name}_{tool_name}`\n\n- **Sanitization**: Hyphens (`-`) and dots (`.`) are replaced with underscores (`_`) to ensure compatibility with LLM tool-calling schemas.\n- **Example**: A tool named `fetch-data` on a server configured as `api_provider` becomes `mcp_api_provider_fetch_data`.\n\n## Security and Isolation\n\n### Environment Filtering\nFor **stdio** servers, the client does not pass the full host environment. It provides a \"clean room\" environment containing only essential variables (`PATH`, `HOME`, `USER`, `LANG`, `TERM`, `SHELL`, `TMPDIR`, and `XDG_*`). \n\nAny sensitive credentials (API keys, tokens) must be explicitly defined in the `env` section of the server configuration.\n\n### Credential Redaction\nThe module includes an automatic redaction layer. If an MCP tool returns an error message, the client scans the text for common credential patterns (GitHub PATs, OpenAI keys, Bearer tokens, etc.) and masks them before the error is passed to the LLM.\n\n## Sampling (Server-Initiated LLM Calls)\n\nThe client supports the `sampling/createMessage` capability. This allows an MCP server to \"call back\" to the agent and request an LLM completion.\n\n- **Agent-in-the-loop**: Servers can use the agent's brain to process data or make decisions during tool execution.\n- **Tool Augmentation**: Servers can include a list of tools in their sampling request, allowing for multi-turn reasoning within a single MCP tool call.\n- **Safety Limits**: The `max_tool_rounds` setting prevents infinite loops between the server and the agent.\n\n### Sampling Configuration\n```yaml\nsampling:\n enabled: true\n model: \"gemini-1.5-pro\" # Optional model override\n max_tool_rounds: 5 # Limit recursive tool calls\n max_rpm: 10 # Rate limit for the server\n```\n\n## Connection Lifecycle\n\n1. **Initialization**: `discover_mcp_tools()` is called. It is idempotent; it will not re-connect to already active servers.\n2. **Persistence**: Connections are maintained for the duration of the Hermes process.\n3. **Reconnection**: If a connection is lost, the client implements exponential backoff (1s to 60s) for up to 5 attempts.\n4. **Shutdown**: All active sessions and subprocesses are gracefully terminated when the agent exits.\n\n## Requirements\n\n- **Python Package**: `mcp` (install via `pip install mcp`).\n- **Runtimes**: `node` (for `npx` servers) or `uv` (for `uvx` servers).\n- **HTTP Support**: Requires `mcp.client.streamable_http` (available in recent versions of the MCP SDK).","skills-media":"# skills — media\n\n# Media Skills\n\nThe `media` module provides a suite of skills for interacting with, generating, and analyzing various media formats, including music, video transcripts, GIFs, and audio visualizations.\n\n## Spotify Integration\n\nThe Spotify skill manages playback, library, and playlists through a set of 7 specialized tools. It is designed to minimize latency by avoiding unnecessary state checks before executing commands.\n\n### Toolset Overview\n- `spotify_playback`: Core controls (play, pause, next, volume, state).\n- `spotify_devices`: Device enumeration and playback transfer.\n- `spotify_queue`: Management of the play queue.\n- `spotify_search`: Catalog search (tracks, albums, artists).\n- `spotify_playlists`: CRUD operations on user and public playlists.\n- `spotify_albums` & `spotify_library`: Metadata retrieval and library management.\n\n### Implementation Patterns\n- **Direct Execution**: Do not call `get_state` before `play` or `pause`. The API handles these requests idempotently.\n- **Error Handling**: \n - `403 Forbidden (No active device)`: Requires the user to manually open a Spotify client.\n - `403 Forbidden (Premium required)`: Indicates a mutation attempt on a Free account.\n- **ID Normalization**: Tools accept Spotify URIs (`spotify:track:...`), URLs, or bare IDs. URIs are preferred for internal consistency.\n\n---\n\n## YouTube Content Transformation\n\nThis skill extracts transcripts from YouTube videos and reformats them into structured content like summaries, blog posts, or timestamped chapters.\n\n### Transcript Extraction\nThe core logic resides in `scripts/fetch_transcript.py`, which utilizes the `youtube-transcript-api`.\n\n```mermaid\ngraph TD\n URL[YouTube URL/ID] --> ID[extract_video_id]\n ID --> API[YouTubeTranscriptApi.fetch]\n API --> Segments[Transcript Segments]\n Segments --> JSON[JSON Output]\n Segments --> Text[Plain Text/Timestamps]\n```\n\n**Key Functions:**\n- `extract_video_id(url_or_id)`: Uses regex to parse IDs from standard URLs, shorts, embeds, and live links.\n- `fetch_transcript(video_id, languages)`: Retrieves segments and normalizes them into a standard dictionary format (`text`, `start`, `duration`).\n\n### Content Workflows\n1. **Fetch**: Execute `fetch_transcript.py` with `--text-only --timestamps`.\n2. **Chunking**: If the transcript exceeds 50k characters, it must be processed in overlapping chunks (~40k chars with 2k overlap).\n3. **Formatting**: Transform the raw text into specific formats (e.g., Twitter threads, Markdown blog posts, or chapter lists).\n\n---\n\n## HeartMuLa (AI Music Generation)\n\nHeartMuLa is an open-source music foundation model for generating full songs from lyrics and style tags.\n\n### Architecture\n- **HeartMuLa (3B/7B)**: The LLM responsible for generating music tokens from text.\n- **HeartCodec**: A 12.5Hz codec for high-fidelity audio reconstruction.\n- **HeartCLAP**: Used for audio-text alignment.\n\n### Critical Patches\nDue to dependency shifts in `transformers` and `torchtune`, the following patches are required in the `heartlib` environment:\n\n1. **RoPE Cache Fix**: In `modeling_heartmula.py`, RoPE caches must be manually re-initialized after moving the model from the meta device to the GPU:\n ```python\n for module in self.modules():\n if isinstance(module, Llama3ScaledRoPE) and not module.is_cache_built:\n module.rope_init()\n module.to(device)\n ```\n2. **Codec Loading**: In `pipelines/music_generation.py`, `HeartCodec.from_pretrained` requires `ignore_mismatched_sizes=True` to handle scalar vs. 0-d tensor discrepancies in the VQ codebook.\n\n### Resource Management\n- **VRAM**: Use `--lazy_load true` to run on 8GB VRAM. This loads the generator and codec sequentially.\n- **Precision**: Always use `fp32` for `HeartCodec` to prevent audio artifacts; `bfloat16` is recommended for the `HeartMuLa` generator.\n\n---\n\n## Audio Visualization (songsee)\n\nThe `songsee` skill provides CLI-based audio analysis using a Go-based backend. It generates multi-panel images representing different audio features.\n\n### Visualization Types\n| Type | Analysis |\n| :--- | :--- |\n| `mel` | Mel-scaled spectrogram for frequency analysis |\n| `chroma` | Harmonic content and pitch class distribution |\n| `hpss` | Separation of harmonic (tonal) and percussive (transient) elements |\n| `mfcc` | Mel-frequency cepstral coefficients for timbre description |\n\n### Usage\nVisualizations are generated by calling the `songsee` binary. Multiple features can be combined into a single grid using the `--viz` flag:\n```bash\nsongsee input.mp3 --viz spectrogram,mel,chroma,loudness -o analysis.png\n```\n\n---\n\n## GIF Search (Tenor)\n\nA lightweight integration for searching and downloading GIFs using the Tenor V2 API.\n\n- **Prerequisites**: `curl`, `jq`, and a `TENOR_API_KEY`.\n- **Media Formats**: Supports `gif`, `tinygif` (optimized for chat), `mp4`, and `webm`.\n- **Implementation**: Uses direct `curl` calls to `https://tenor.googleapis.com/v2/search`. Results are parsed via `jq` to extract specific media format URLs.","skills-mlops":"# skills — mlops\n\n# Skills — MLOps\n\nThe **skills — mlops** module provides a standardized toolkit for Machine Learning Operations, focusing on the lifecycle of Large Language Models (LLMs). It encompasses tools for model evaluation, experiment tracking, hyperparameter optimization, and repository management.\n\n## Module Overview\n\nThe module is structured into three primary functional areas:\n1. **Evaluation**: Standardized benchmarking using `lm-evaluation-harness`.\n2. **Experiment Tracking**: Real-time logging and artifact management via `Weights & Biases`.\n3. **Hub Interaction**: Repository management using the `hf` CLI.\n\n## LLM Evaluation (`lm-evaluation-harness`)\n\nThe evaluation sub-module leverages the EleutherAI `lm-eval` framework to benchmark models across 60+ academic tasks (MMLU, GSM8K, HumanEval, etc.).\n\n### Core Execution Patterns\nEvaluation is typically performed via the CLI, supporting multiple backends:\n\n* **HuggingFace (`hf`)**: Standard transformer-based evaluation.\n* **vLLM (`vllm`)**: Optimized for 5-10x faster inference using tensor parallelism.\n* **API (`openai-chat-completions`, `anthropic-chat`)**: Benchmarking closed-source models.\n\n```bash\n# Example: Evaluating a local model on reasoning tasks\nlm_eval --model hf \\\n --model_args pretrained=meta-llama/Llama-2-7b-hf \\\n --tasks mmlu,gsm8k \\\n --device cuda:0 \\\n --batch_size auto\n```\n\n### Distributed Evaluation\nFor large models (e.g., 70B+), the module supports:\n* **Data Parallelism**: Using `accelerate launch` to split samples across GPUs.\n* **Tensor Parallelism**: Sharding model weights via `parallelize=True` (HF) or `tensor_parallel_size` (vLLM).\n\n## Experiment Tracking & Optimization (`wandb`)\n\nThe module integrates `Weights & Biases` for logging metrics, managing model lineage, and performing Hyperparameter Optimization (HPO).\n\n### Key Components\n* **Runs**: Initialized via `wandb.init()`, tracking configurations and metrics.\n* **Artifacts**: Versioned storage for datasets and model checkpoints.\n* **Sweeps**: Automated HPO using Bayesian, Grid, or Random search strategies.\n\n### Artifact Lineage Workflow\nThe module follows a strict lineage pattern to ensure reproducibility:\n\n```mermaid\ngraph LR\n A[Raw Data] -->|wandb.Artifact| B(Preprocessing)\n B -->|wandb.log_artifact| C[Processed Data]\n C -->|run.use_artifact| D(Training)\n D -->|wandb.log_artifact| E[Model Checkpoint]\n E -->|run.link_artifact| F[Model Registry]\n```\n\n## Model & Dataset Management (`hf` CLI)\n\nThe module utilizes the modern `hf` CLI (replacing `huggingface-cli`) for Hub interactions.\n\n* **Download/Upload**: `hf download REPO_ID` and `hf upload REPO_ID`.\n* **Authentication**: Managed via `HF_TOKEN` environment variables.\n\n## Fine-Tuning Patterns (TRL/GRPO)\n\nBased on internal templates (e.g., `basic_grpo_training.py`), the module implements Group Relative Policy Optimization (GRPO) patterns using the `trl` library.\n\n### Reward Function Logic\nA critical component of the MLOps pipeline is the automated evaluation of model outputs during training. The module implements XML-based answer extraction for reinforcement learning:\n\n1. **`extract_xml_tag(text, tag)`**: Parses model output for specific structured tags.\n2. **`extract_answer(text)`**: High-level wrapper to retrieve the final response.\n3. **`correctness_reward_func(prompts, completions, answer, ...)`**: A reward function that utilizes `extract_answer` to compare model completions against ground truth, returning a binary or scalar reward for the GRPO trainer.\n\n### Training Setup\nThe `main` execution flow for fine-tuning typically follows:\n1. `get_dataset()`: Loading and formatting training data.\n2. `setup_model_and_tokenizer()`: Initializing the base model with PEFT/LoRA configurations.\n3. `get_peft_config()`: Defining adapter parameters for parameter-efficient fine-tuning.\n\n## Hardware & Performance Guidelines\n\n| Task | Model Size | Hardware | Optimization |\n| :--- | :--- | :--- | :--- |\n| **Evaluation** | 7B | 1x A100 (40GB) | `vllm` backend |\n| **Evaluation** | 70B | 4x A100 (80GB) | `tensor_parallel_size=4` |\n| **Fine-Tuning** | 7B | 8x A100 (80GB) | DeepSpeed ZeRO-3 + LoRA |\n\n## Best Practices\n* **Deterministic Eval**: Always set `temperature=0` and `num_fewshot` (typically 5) for academic benchmarks.\n* **Cost Control**: Use `--limit N` when testing API-based evaluations to prevent unexpected billing.\n* **Registry Promotion**: Use `wandb` aliases (`staging`, `production`) to manage model deployment stages rather than manual file renaming.","skills-note-taking":"# skills — note-taking\n\n# Note-Taking Skill: Obsidian\n\nThe `note-taking` module provides a set of capabilities for persistent information storage, research assistance, and multi-session planning. It specifically implements an interface for **Obsidian**, allowing the system to interact with a local Markdown-based knowledge base.\n\n## Overview\n\nThis skill treats an Obsidian vault as a structured filesystem database. It leverages standard Unix utilities (`find`, `grep`, `cat`) to perform CRUD operations and searches on Markdown files. This approach ensures that the data remains human-readable and compatible with the Obsidian desktop and mobile applications.\n\n## Configuration\n\nThe module relies on the `OBSIDIAN_VAULT_PATH` environment variable to locate the vault.\n\n| Variable | Description | Default Value |\n| :--- | :--- | :--- |\n| `OBSIDIAN_VAULT_PATH` | Absolute path to the Obsidian vault directory. | `~/Documents/Obsidian Vault` |\n\n**Note:** Because vault paths often contain spaces, all internal operations quote the path variable to prevent word-splitting errors.\n\n## Core Operations\n\n### Note Discovery and Listing\nThe module uses `find` and `ls` to navigate the vault hierarchy.\n\n* **Global List:** Recursively finds all `.md` files within the vault.\n* **Scoped List:** Lists files within a specific subfolder.\n* **Filename Search:** Uses `find -iname` to perform case-insensitive searches for specific note titles.\n\n### Content Retrieval\nReading a note is performed via `cat`. The system expects the full path relative to the vault root, including the `.md` extension.\n\n### Search Functionality\nThe module implements full-text search across the entire vault using `grep`:\n```bash\ngrep -rli \"keyword\" \"$VAULT\" --include=\"*.md\"\n```\n* `-r`: Recursive search.\n* `-l`: Only output the filenames of matches.\n* `-i`: Case-insensitive.\n\n### Writing and Modification\n* **Creation:** Uses a `cat` heredoc to create new files with initial content and headers.\n* **Appending:** Uses the `>>` operator to add new information to the end of existing notes, typically used for logging or adding thoughts to a research thread.\n\n## Integration Patterns\n\n### Wikilinks\nWhen creating or updating notes, the module follows Obsidian's internal linking syntax: `[[Note Name]]`. This allows the system to build a graph of related concepts that the Obsidian UI can visualize.\n\n### Execution Flow\nThe skill acts as a bridge between the agent's logic and the local filesystem.\n\n```mermaid\ngraph LR\n A[Agent Logic] --> B[Obsidian Skill]\n B --> C{Shell Ops}\n C --> D[find/ls]\n C --> E[grep]\n C --> F[cat/echo]\n D & E & F --> G[(Markdown Files)]\n```\n\n## Developer Guidelines\n\n1. **Path Sanitization:** Always wrap the vault path and file names in double quotes to handle spaces.\n2. **Extension Handling:** Ensure `.md` is appended to filenames when creating or reading, as Obsidian identifies notes by this extension.\n3. **Concurrency:** Since operations are standard filesystem writes, be mindful of potential race conditions if multiple processes attempt to append to the same note simultaneously.\n4. **Formatting:** When creating notes, prefer including a `# Title` header at the top of the file to maintain consistency with Obsidian's rendering engine.","skills-productivity":"# skills — productivity\n\n# Skills — Productivity\n\nThe **Productivity** module provides a suite of tools for managing documents, spreadsheets, project management workflows, and location-based services. These skills are designed to be executed primarily through the `terminal` tool, utilizing direct API calls via `curl` or specialized Python CLI wrappers.\n\n## Module Overview\n\nThe module is divided into four primary service integrations:\n1. **Airtable**: Database and record management via REST.\n2. **Google Workspace**: Comprehensive access to Gmail, Calendar, Drive, and Sheets.\n3. **Linear**: Issue tracking and project management via GraphQL.\n4. **Maps**: Geocoding, routing, and POI discovery using OpenStreetMap data.\n\n---\n\n## Airtable Integration\n\nThe Airtable skill interacts directly with the Airtable REST API. It avoids heavy SDKs in favor of `curl` commands, making it lightweight and transparent.\n\n### Authentication & Setup\n- **Mechanism**: Personal Access Tokens (PAT).\n- **Environment Variable**: `AIRTABLE_API_KEY`.\n- **Scope**: Tokens must be scoped to specific bases. A `403 Forbidden` usually indicates the base has not been added to the PAT's access list.\n\n### Key Patterns\n- **Schema Inspection**: Always run `GET /v0/meta/bases/$BASE_ID/tables` before mutations to verify field names and select options.\n- **Typecasting**: Use `\"typecast\": true` in POST/PATCH bodies to allow Airtable to automatically create new select options or coerce string-to-number types.\n- **Filtering**: Use `filterByFormula`. Formulas must be URL-encoded. The module recommends using a Python one-liner for encoding:\n ```bash\n python3 -c 'import sys, urllib.parse; print(urllib.parse.quote(sys.argv[1], safe=\"\"))' \"{Status}='Todo'\"\n ```\n- **Rate Limits**: Hard limit of 5 requests per second per base.\n\n---\n\n## Google Workspace\n\nThis skill provides a unified interface for Gmail, Calendar, Drive, Sheets, and Docs. It uses a managed OAuth2 flow and prefers the `gws` CLI binary if available, falling back to standard Python client libraries.\n\n### Architecture\nThe integration relies on two core scripts:\n- `setup.py`: Handles the non-interactive OAuth2 flow, credential storage (`google_token.json`), and dependency management.\n- `google_api.py`: The primary execution CLI. It routes commands to specific Google services and ensures output is returned as structured JSON.\n\n```mermaid\ngraph TD\n User[User Request] --> GAPI[google_api.py]\n GAPI --> Auth{Authenticated?}\n Auth -- No --> Setup[setup.py --auth-url]\n Auth -- Yes --> Backend{gws binary exists?}\n Backend -- Yes --> GWS[gws CLI]\n Backend -- No --> PyLib[Google Python SDK]\n GWS --> API[Google Cloud APIs]\n PyLib --> API\n```\n\n### Core Commands\n- **Gmail**: `search`, `get`, `send`, `reply`, `modify`.\n- **Calendar**: `list`, `create`, `delete`.\n- **Sheets**: `get`, `update`, `append`.\n- **Drive/Docs**: `search`, `get`.\n\n### Setup Workflow\n1. `setup.py --client-secret <path>`: Stores the OAuth client credentials.\n2. `setup.py --auth-url`: Generates the consent URL.\n3. `setup.py --auth-code <code>`: Exchanges the browser redirect code for a persistent token.\n4. `setup.py --check`: Verifies the token and required scopes.\n\n---\n\n## Linear\n\nThe Linear skill manages issues and projects via Linear's GraphQL API.\n\n### Workflow States\nLinear issues are governed by `WorkflowState` types. Before updating an issue's status, you must query the team's specific state UUIDs:\n- `triage`, `backlog`, `unstarted`, `started`, `completed`, `canceled`.\n\n### GraphQL Execution\nAll interactions are POST requests to `https://api.linear.app/graphql`.\n- **Issue Resolution**: Supports both UUIDs and human-readable identifiers (e.g., `PROD-123`).\n- **Mutations**: Uses `issueCreate`, `issueUpdate`, and `commentCreate`.\n- **Pagination**: Implements Relay-style cursor pagination using `pageInfo { hasNextPage endCursor }`.\n\n---\n\n## Maps\n\nThe Maps skill provides location intelligence without requiring API keys, utilizing OpenStreetMap (Nominatim), Overpass API, and OSRM.\n\n### Core Functions in `maps_client.py`\n- **`search`**: Forward geocoding (Name -> Coordinates).\n- **`reverse`**: Reverse geocoding (Coordinates -> Address).\n- **`nearby`**: POI discovery. Supports 46 categories (e.g., `pharmacy`, `hospital`, `cafe`).\n- **`distance` / `directions`**: Routing for `driving`, `walking`, or `cycling`.\n\n### POI Discovery Logic\nThe `nearby` command can resolve locations in two ways:\n1. **Coordinates**: Direct `lat` and `lon` input.\n2. **Address**: Using the `--near` flag, which triggers an internal call to `geocode_single` before querying the Overpass API.\n\n### Execution Flow: `nearby`\n1. **Input**: Category and Location (Lat/Lon or Address).\n2. **Geocoding**: If address provided, `nominatim_search` resolves to coordinates.\n3. **Overpass Query**: `overpass_query` sends a QL script to a pool of mirrors (e.g., `overpass-api.de`, `overpass.kumi.systems`).\n4. **Parsing**: `parse_overpass_elements` converts OSM nodes/ways into a clean JSON list, calculating `distance_m` and generating Google Maps URLs for user convenience.\n\n---\n\n## Common Implementation Patterns\n\n### JSON Formatting\nAll productivity scripts are designed to output clean, parseable JSON. When using these skills in a terminal, pipe output through `python3 -m json.tool` for readability:\n```bash\npython3 google_api.py gmail search \"is:unread\" | python3 -m json.tool\n```\n\n### Error Handling\n- **Airtable/Linear**: Check the `errors` array in the JSON response even if the HTTP status is 200.\n- **Maps**: Uses `error_exit` to return a structured JSON error object: `{\"error\": \"message\", \"status\": \"error\"}`.\n- **Google Workspace**: `_ensure_authenticated` checks for the existence of `google_token.json` before attempting API calls.\n\n### Environment Management\nThe module uses `_hermes_home.py` to consistently resolve the configuration directory (defaulting to `~/.hermes`). This ensures that tokens, client secrets, and environment variables are shared across different execution contexts (system Python, virtualenvs, etc.).","skills-red-teaming":"# skills — red-teaming\n\n# Skills: Red-Teaming (GODMODE)\n\nThe **godmode** module is a red-teaming suite designed to bypass safety filters on API-served Large Language Models (LLMs). Unlike weight-based uncensoring (e.g., OBLITERATUS), this module operates entirely at the prompt and API level, making it compatible with closed-source models like GPT-4, Claude, Gemini, and Grok.\n\n## Core Architecture\n\nThe module is structured into three primary attack vectors coordinated by an automated testing pipeline.\n\n```mermaid\ngraph TD\n A[User Query] --> B{auto_jailbreak.py}\n B --> C[GODMODE CLASSIC: System Prompts]\n B --> D[PARSELTONGUE: Obfuscation]\n B --> E[ULTRAPLINIAN: Model Racing]\n C & D & E --> F[godmode_race.py: Scoring Engine]\n F --> G[Winning Response / Config Lock-in]\n```\n\n## Key Components\n\n### 1. Automated Pipeline (`auto_jailbreak.py`)\nThe `auto_jailbreak()` function is the primary entry point for developers. It automates the discovery of effective jailbreak strategies for a specific model.\n\n* **Model Detection:** Uses `_detect_model_family()` to map model IDs (e.g., `anthropic/claude-3`) to specific strategy orders.\n* **Testing Loop:** Iterates through strategies (Boundary Inversion, Refusal Inversion, etc.), sending canary queries via `_test_query()`.\n* **Persistence:** Once a successful strategy is found, it calls `_write_config()` and `_write_prefill()` to update the local `~/.hermes/config.yaml` and `prefill.json`, locking in the jailbreak for future sessions.\n\n### 2. Multi-Model Racing (`godmode_race.py`)\nThis component handles parallel execution and response evaluation.\n\n* **`race_models()`**: Queries up to 55 models in parallel using `ThreadPoolExecutor`. It appends a `DEPTH_DIRECTIVE` to queries to discourage hedging.\n* **`race_godmode_classic()`**: Specifically races the five \"Hall of Fame\" jailbreak templates (e.g., `sonnet-35`, `gpt-classic`) against their respective optimized models.\n* **Scoring Engine:** `score_response()` evaluates content based on:\n * **Refusal Detection:** `is_refusal()` uses regex patterns to identify hard refusals (e.g., \"I cannot assist\").\n * **Hedge Counting:** `count_hedges()` identifies soft refusals and disclaimers, applying a -30 point penalty per occurrence.\n * **Quality Bonuses:** Points are awarded for length, code blocks, technical jargon, and actionable instructions.\n\n### 3. Input Obfuscation (`parseltongue.py`)\nParseltongue evades input-side safety classifiers by transforming trigger words.\n\n* **`detect_triggers()`**: Scans queries for keywords like \"hack\", \"exploit\", or \"payload\".\n* **`obfuscate_query()`**: Replaces detected triggers using one of 33 techniques (Leetspeak, Unicode homoglyphs, Zero-width joiners, etc.).\n* **`escalate_encoding()`**: Provides a linear escalation path (Plain → Leetspeak → Bubble → Braille → Morse) for retry logic when standard prompts fail.\n\n## Integration & Usage\n\n### Loading the Module\nDue to `argparse` entry points and `exec()` scoping limitations in the Hermes `execute_code` environment, developers should always use the loader script:\n\n```python\nimport os\n# Load all functions into the current namespace\nexec(open(os.path.expanduser(\"~/.hermes/skills/red-teaming/godmode/scripts/load_godmode.py\")).read())\n```\n\n### Common Patterns\n\n**Automated Setup:**\n```python\n# Detect current model from config and find a working jailbreak\nresult = auto_jailbreak()\nif result[\"success\"]:\n print(f\"Jailbreak locked in using {result['strategy']}\")\n```\n\n**Manual Racing:**\n```python\n# Race 10 fast models to find the best unfiltered answer\nresult = race_models(\"How do I bypass a car's ignition?\", tier=\"fast\")\nprint(result[\"content\"])\n```\n\n**Query Obfuscation:**\n```python\n# Obfuscate only the trigger words in a query\nvariants = generate_variants(\"How do I hack a WiFi network?\", tier=\"light\")\n# variants[1]['text'] -> \"How do I h4ck a WiFi network?\"\n```\n\n## Strategy Mapping by Model Family\n\nThe `auto_jailbreak` logic prioritizes techniques based on known model vulnerabilities:\n\n| Family | Primary Strategy | Secondary Strategy |\n| :--- | :--- | :--- |\n| **Claude** | `boundary_inversion` | `refusal_inversion` |\n| **GPT** | `og_godmode` | `refusal_inversion` |\n| **Gemini** | `refusal_inversion` | `boundary_inversion` |\n| **DeepSeek/Qwen** | `parseltongue` | `refusal_inversion` |\n| **Llama/Mistral** | `prefill_only` | `refusal_inversion` |\n\n## Configuration Persistence\nThe module modifies `~/.hermes/config.yaml` by setting:\n* `agent.system_prompt`: The winning jailbreak template.\n* `agent.prefill_messages_file`: Points to a generated `prefill.json` containing a compliance-priming conversation.\n\nTo revert all changes, use `undo_jailbreak()`, which restores the config and deletes the prefill artifacts.","skills-research":"# skills — research\n\n# Research Skills Module\n\nThe **research** module provides a suite of tools for academic discovery, market intelligence, knowledge management, and scientific publication. It is designed to support the full research lifecycle—from initial domain reconnaissance to the submission of publication-ready machine learning papers.\n\n## Module Architecture\n\nThe module is organized into specialized sub-skills that can be used independently or composed into complex workflows.\n\n```mermaid\ngraph TD\n A[Discovery] --> B[Synthesis]\n B --> C[Publication]\n \n subgraph Discovery\n arxiv[arXiv & Semantic Scholar]\n poly[Polymarket]\n blog[Blogwatcher RSS]\n end\n \n subgraph Synthesis\n wiki[LLM-Wiki KB]\n end\n \n subgraph Publication\n pipe[Research Paper Pipeline]\n end\n \n arxiv --> wiki\n poly --> wiki\n wiki --> pipe\n```\n\n---\n\n## 1. Academic Discovery (`arxiv`)\n\nThis component interfaces with the arXiv REST API and Semantic Scholar to retrieve paper metadata, abstracts, and citation graphs.\n\n### Key Tools\n* **`scripts/search_arxiv.py`**: A zero-dependency Python script for searching papers by keyword, author, category, or ID.\n* **Semantic Scholar Integration**: Used for impact assessment (citation counts) and finding related work (references/recommendations).\n\n### Common Patterns\n```bash\n# Search for latest AI papers\npython scripts/search_arxiv.py \"reinforcement learning\" --max 5 --sort date\n\n# Get citation data via Semantic Scholar\ncurl -s \"https://api.semanticscholar.org/graph/v1/paper/arXiv:2402.03300?fields=citationCount,influentialCitationCount\"\n```\n\n---\n\n## 2. Market Intelligence (`polymarket`)\n\nProvides real-time access to prediction market data, allowing researchers to track event probabilities and market sentiment.\n\n### API Structure\n* **Gamma API**: Discovery and search (`gamma-api.polymarket.com`).\n* **CLOB API**: Orderbooks and price history (`clob.polymarket.com`).\n* **Data API**: Recent trades and open interest (`data-api.polymarket.com`).\n\n### Helper Script: `polymarket.py`\nThe helper script handles double-encoded JSON fields and provides human-readable formatting for probabilities and volume.\n```bash\npython3 polymarket.py search \"fed interest rates\"\npython3 polymarket.py history <condition_id> --interval 1d\n```\n\n---\n\n## 3. Knowledge Management (`llm-wiki`)\n\nBased on the \"Karpathy LLM Wiki\" pattern, this sub-module maintains a persistent, compounding knowledge base as interlinked markdown files.\n\n### Three-Layer Structure\n1. **`raw/`**: Immutable source material (PDFs, web extracts).\n2. **`entities/` & `concepts/`**: Agent-maintained synthesis pages with `[[wikilinks]]`.\n3. **`SCHEMA.md`**: Defines the domain, tag taxonomy, and consistency rules.\n\n### Operational Workflow\n* **Orientation**: Every session must begin by reading `SCHEMA.md`, `index.md`, and the recent `log.md`.\n* **Ingestion**: Sources are processed into `raw/`, then used to update or create entity/concept pages.\n* **Linting**: A programmatic check for orphan pages, broken links, and stale content.\n\n---\n\n## 4. Content Monitoring (`blogwatcher`)\n\nA wrapper for `blogwatcher-cli` to track RSS/Atom feeds and monitor domain-specific blogs.\n\n* **Discovery**: Automatically finds feeds from homepages.\n* **Persistence**: Uses a SQLite database (`blogwatcher-cli.db`) to track read/unread states.\n* **Scraping Fallback**: Supports CSS selectors for sites without native feeds.\n\n---\n\n## 5. Research Paper Writing Pipeline\n\nA comprehensive framework for producing ML papers targeting venues like NeurIPS, ICML, and ICLR. It emphasizes a \"Narrative Principle\"—the idea that a paper is a single technical story supported by evidence.\n\n### Pipeline Phases\n* **Phase 0-1 (Setup & Lit Review)**: Workspace organization and verified citation gathering.\n* **Phase 2-4 (Experimentation)**: Mapping claims to experiments, running parallel sweeps, and statistical analysis (McNemar’s test, Cohen’s h).\n* **Phase 5-6 (Drafting & Refinement)**: LaTeX production using the **Autoreason** strategy.\n\n### The Autoreason Strategy\nFor complex drafting and code tasks, the module employs an iterative refinement loop:\n1. **Critic**: Identifies weaknesses in the current draft.\n2. **Author**: Generates a revised version addressing the critique.\n3. **Synthesizer**: Merges the best elements of both versions.\n4. **Judge Panel**: A blind Borda count ranking by 3+ agents to select the winner.\n5. **Convergence**: Loop terminates when the incumbent wins $k=2$ consecutive rounds.\n\n### Technical Standards\n* **Citations**: Mandatory 5-step verification (Search → Verify → Retrieve → Validate → Add).\n* **LaTeX**: Uses `microtype` for typography, `booktabs` for tables, and `cleveref` for smart referencing.\n* **Figures**: Requires vector graphics (PDF) generated via `matplotlib` or `TikZ`.\n\n### Directory Convention\n```text\npaper/ # LaTeX source and figures\nexperiments/ # Runner scripts\nresults/ # Raw JSON/CSV outputs\nexperiment_log.md # The \"bridge\" document connecting results to prose\n```\n\n## Integration with External Tools\n* **Obsidian**: The `llm-wiki` is fully compatible with Obsidian vaults.\n* **Firecrawl**: Used via `web_extract` to convert PDFs and web pages into clean markdown for the wiki or paper pipeline.\n* **Exa MCP**: Recommended for real-time academic search integration.","skills-smart-home":"# skills — smart-home\n\n# Smart Home Skills\n\nThe `smart-home` module provides integrations for controlling IoT devices, lighting systems, and home automation hubs. Currently, the module focuses on Philips Hue ecosystem support via the **OpenHue** skill.\n\n## OpenHue Skill\n\nThe OpenHue skill enables control over Philips Hue bridges using the `openhue` CLI. It allows for granular control of individual lights, logical rooms, and predefined scenes.\n\n### Architecture\n\nThe skill operates as a wrapper around the `openhue` binary. It translates high-level automation intents into shell commands that communicate with the Hue Bridge over the local network.\n\n```mermaid\ngraph LR\n A[Hermes Skill] --> B[OpenHue CLI]\n B --> C{Hue Bridge}\n C --> D[Lights]\n C --> E[Rooms]\n C --> F[Scenes]\n```\n\n### Prerequisites\n\nThe skill requires the `openhue` CLI to be installed and accessible in the system's `PATH`.\n\n* **Linux:** Binary installed to `~/.local/bin/openhue`.\n* **macOS:** Installed via Homebrew (`brew install openhue/cli/openhue-cli`).\n* **Authentication:** The first execution requires physical access to the Hue Bridge to press the link button for API authorization.\n\n### Resource Management\n\nThe skill interacts with three primary resource types:\n\n1. **Lights:** Individual bulbs or fixtures.\n2. **Rooms/Zones:** Logical groupings of lights defined in the Hue app.\n3. **Scenes:** Predefined states (color, brightness) for a specific room.\n\n#### Discovery\nTo audit available resources, the skill utilizes the `get` command:\n- `openhue get light`\n- `openhue get room`\n- `openhue get scene`\n\n### Command Patterns\n\nThe skill executes state changes using the `openhue set` command. All control commands are case-sensitive based on the names assigned in the Hue Bridge configuration.\n\n#### Power and Dimming\nBasic state changes are handled via the `--on`, `--off`, and `--brightness` flags. Brightness values range from `0` to `100`.\n\n```bash\n# Example: Room-level control\nopenhue set room \"Living Room\" --on --brightness 50\n```\n\n#### Color and Temperature\nFor color-capable bulbs, the skill supports two methods of color definition:\n- **Named Colors:** Standard CSS-like names (e.g., `red`, `blue`).\n- **Hex/RGB:** Specific hex codes (e.g., `#FF5500`).\n- **Color Temperature:** Measured in mireks, ranging from `153` (cool/blue) to `500` (warm/yellow).\n\n```bash\n# Example: Setting temperature\nopenhue set light \"Desk Lamp\" --on --temperature 250\n```\n\n#### Scene Activation\nScenes are activated by referencing the scene name and its associated room.\n\n```bash\nopenhue set scene \"Relax\" --room \"Bedroom\"\n```\n\n### Implementation Details\n\n- **Network Dependency:** The machine running the skill must be on the same local network as the Hue Bridge.\n- **Hardware Limitations:** Color and temperature commands will fail silently or be ignored if the target hardware (e.g., a White-only bulb) does not support the feature.\n- **Concurrency:** Commands are executed synchronously. For large-scale \"All Off\" operations, it is more efficient to target the \"Room\" or \"Zone\" level rather than individual lights to reduce bridge congestion.","skills-social-media":"# skills — social-media\n\n# Social Media Skills\n\nThe `social-media` module provides capabilities for interacting with social platforms, specifically focusing on X (formerly Twitter) via the official `xurl` CLI. This module enables agents to perform complex social workflows including posting, monitoring timelines, managing engagement, and handling media uploads.\n\n## Core Component: xurl\n\nThe primary engine for this module is `xurl`, the official X developer platform CLI. It provides a high-level interface for common actions and a low-level interface for raw X API v2 requests.\n\n### Architecture Overview\n\nThe module operates as a wrapper around the `xurl` binary. The agent executes shell commands, and `xurl` handles OAuth 2.0 PKCE token management, request signing, and JSON serialization.\n\n```mermaid\ngraph TD\n Agent[Hermes Agent] -->|Shell Command| XURL[xurl CLI]\n XURL -->|OAuth 2.0 / API v2| XAPI[X Platform API]\n XAPI -->|JSON Response| XURL\n XURL -->|JSON Output| Agent\n subgraph Local Environment\n XURL\n Config[~/.xurl YAML]\n end\n XURL -.->|Read/Write Tokens| Config\n```\n\n## Security & Secret Safety\n\nThis module enforces strict security boundaries to prevent credential leakage. **These rules are mandatory for any agent implementation:**\n\n1. **Credential Isolation:** Agents must never read, print, or transmit the contents of `~/.xurl`.\n2. **No Inline Secrets:** Never use flags that accept secrets in the command line (e.g., `--bearer-token`, `--client-secret`).\n3. **User-Only Setup:** App registration and initial OAuth flows must be performed by the user manually outside the agent session.\n4. **Verification:** Use `xurl auth status` to verify connectivity without exposing sensitive data.\n5. **No Verbose Logging:** The `--verbose` (`-v`) flag is forbidden as it may leak authorization headers in the output.\n\n## Functional Areas\n\n### 1. Content Creation & Interaction\nThe module supports standard social interactions. `xurl` automatically extracts IDs from full X URLs, allowing agents to process links provided by users directly.\n\n| Action | Command Pattern |\n| :--- | :--- |\n| **Post** | `xurl post \"message\"` |\n| **Reply** | `xurl reply <POST_ID_OR_URL> \"message\"` |\n| **Quote** | `xurl quote <POST_ID_OR_URL> \"message\"` |\n| **Delete** | `xurl delete <POST_ID>` |\n\n### 2. Discovery & Reading\nAgents can query the platform for real-time data. All responses are returned as structured JSON matching the X API v2 schema.\n\n* **Search:** `xurl search \"query\" -n <limit>`\n* **Timeline:** `xurl timeline -n <limit>`\n* **Mentions:** `xurl mentions -n <limit>`\n* **User Lookup:** `xurl user @handle`\n\n### 3. Engagement & Social Graph\nCommands for managing relationships and algorithmic signals.\n\n* **Engagement:** `like`, `unlike`, `repost`, `unrepost`, `bookmark`.\n* **Graph:** `follow`, `unfollow`, `block`, `mute`.\n* **Direct Messages:** `xurl dm @handle \"message\"`.\n\n### 4. Media Management\nMedia uploads are a multi-step process. For videos, agents should use the `--wait` flag to handle asynchronous processing.\n\n```bash\n# Upload and post workflow\nMEDIA_ID=$(xurl media upload path/to/image.jpg | jq -r '.media_id_string')\nxurl post \"Check this out\" --media-id $MEDIA_ID\n```\n\n## Raw API Access\nFor endpoints not covered by shortcut commands, the module supports a `curl`-like syntax for any X API v2 endpoint:\n\n```bash\n# GET request\nxurl /2/users/me\n\n# POST request with JSON payload\nxurl -X POST /2/tweets -d '{\"text\":\"Manual post\"}'\n```\n\n## Agent Implementation Guide\n\n### Workflow for Developers\nWhen building features using this module, follow this execution flow:\n\n1. **Environment Check:** Run `xurl auth status` to ensure a default app is configured and tokens are valid.\n2. **Context Gathering:** Use `xurl whoami` to identify the acting account and `xurl mentions` to find relevant interactions.\n3. **Intent Confirmation:** Before performing \"Write\" actions (posting, deleting, following), the agent should summarize the intended action for the user.\n4. **Response Parsing:** Always parse the JSON output. Even successful commands return a `data` object, while failures return an `errors` array.\n\n### Handling Common Errors\n\n| Error Scenario | Resolution Strategy |\n| :--- | :--- |\n| **401 Unauthorized** | Direct the user to run `xurl auth oauth2 --app <app-name>` manually. |\n| **403 Forbidden** | Usually a scope issue or a \"Read-only\" app permission. Check X Developer Portal settings. |\n| **429 Rate Limit** | Implement exponential backoff or notify the user of the cooldown period. |\n| **Empty Auth Status** | The user has not set a default app. Instruct them to use `xurl auth default <app-name>`. |\n\n## Configuration Storage\nConfiguration is stored in `~/.xurl` in YAML format. This file contains:\n* Registered App Client IDs/Secrets.\n* OAuth 2.0 Refresh and Access tokens.\n* Default app and user settings.\n\n**Note:** OAuth 2.0 tokens are automatically refreshed by the `xurl` binary during request execution; no manual refresh logic is required in the agent code.","skills-software-development":"# skills — software-development\n\n# Software Development Skills Module\n\nThe **software-development** module is a collection of standardized methodologies, technical procedures, and workflow definitions that govern how the Hermes Agent performs engineering tasks. It provides the agent with the \"mental models\" required for systematic debugging, test-driven development, and complex task orchestration.\n\n## Module Overview\n\nThis module does not contain executable code in the traditional sense; rather, it contains **Skills** (defined in `SKILL.md` files) that the agent loads into its context to execute specific software engineering workflows. These skills bridge the gap between high-level user requests and low-level tool executions (like `terminal`, `file`, or `delegate_task`).\n\n### Core Methodologies\n\nThe module enforces three primary engineering disciplines:\n\n1. **Systematic Debugging**: A 4-phase root cause investigation process (Investigation → Pattern Analysis → Hypothesis → Implementation). It prohibits \"guess-and-check\" fixes and mandates finding the root cause before touching code.\n2. **Test-Driven Development (TDD)**: Enforces the **Red-Green-Refactor** cycle. The agent is instructed to write a failing test, verify the failure, implement the minimal code to pass, and then refactor.\n3. **Subagent-Driven Development**: A framework for executing complex plans by dispatching fresh subagents for individual tasks using `delegate_task`. This includes a mandatory two-stage review process: **Spec Compliance** followed by **Code Quality**.\n\n## The Implementation Pipeline\n\nThe module defines a linear workflow for feature development and bug fixing:\n\n```mermaid\ngraph TD\n A[User Request] --> B[Spike/Research]\n B --> C[Writing Plans]\n C --> D[Subagent Execution]\n D --> E[Spec Review]\n E -- Fail --> D\n E -- Pass --> F[Quality Review]\n F -- Fail --> D\n F -- Pass --> G[Pre-Commit Verification]\n G --> H[Commit/Ship]\n```\n\n### 1. Planning (`writing-plans`, `plan`, `spike`)\nBefore execution, the agent creates a markdown plan.\n* **Spikes**: Used for throwaway prototypes to validate feasibility.\n* **Plans**: Stored in `.hermes/plans/`. They must contain \"bite-sized\" tasks (2-5 minutes of work) with exact file paths and TDD steps.\n\n### 2. Execution (`subagent-driven-development`)\nThe orchestrator agent parses the plan and dispatches subagents.\n* **Isolation**: Each task is handled by a fresh subagent to prevent context pollution.\n* **Context Budgeting**: Uses a four-tier degradation model (PEAK to POOR) to monitor context window usage and checkpoint progress before performance drops.\n\n### 3. Verification (`requesting-code-review`)\nA pre-commit pipeline that includes:\n* **Static Security Scans**: Grepping for hardcoded secrets, shell injections, and unsafe deserialization.\n* **Baseline-Aware Testing**: Running the test suite and comparing results against a stashed baseline to ensure no regressions.\n* **Independent Review**: Using `delegate_task` to spawn a reviewer agent with no context other than the diff.\n\n## Technical Debugging Suite\n\nThe module provides specific procedures for debugging the Hermes ecosystem itself and general applications.\n\n### Python Debugging (`python-debugpy`)\nFocuses on `pdb` and `debugpy`.\n* **Local**: Using `breakpoint()`.\n* **Remote**: Using `remote-pdb` or `debugpy` to attach to long-lived processes like the `tui_gateway` or `_SlashWorker`.\n* **Pytest Integration**: Using `--pdb` and `-p no:xdist` to debug failing tests.\n\n### Node.js & TUI Debugging (`node-inspect-debugger`, `debugging-hermes-tui-commands`)\nCovers the TypeScript/Ink frontend and the JSON-RPC bridge.\n* **Inspector**: Using `node --inspect-brk` with `tsx` to debug the TUI entry point.\n* **Command Registry**: Procedures for syncing the Python `COMMAND_REGISTRY` (in `hermes_cli/commands.py`) with the TUI frontend handlers (in `ui-tui/src/app/slash/`).\n\n## Skill Authoring and Validation\n\nThe module includes the `hermes-agent-skill-authoring` skill, which defines the standards for extending the agent's capabilities.\n\n* **Location**: In-repo skills reside in `skills/<category>/<name>/SKILL.md`.\n* **Validation**: Frontmatter is validated by `tools/skill_manager_tool.py::_validate_frontmatter`.\n* **Constraints**:\n * `name`: Lowercase, hyphens, max 64 chars.\n * `description`: Max 1024 chars.\n * `content`: Max 100,000 chars.\n* **Structure**: Requires specific sections: `Overview`, `When to Use`, `Common Pitfalls`, and `Verification Checklist`.\n\n## Key Components Reference\n\n| Component | Purpose |\n| :--- | :--- |\n| `SKILL.md` | The primary definition of the skill's logic and triggers. |\n| `references/` | Deep-dive documents (e.g., `context-budget-discipline.md`) for complex orchestration. |\n| `COMMAND_REGISTRY` | The source of truth in `hermes_cli/commands.py` for all slash commands. |\n| `delegate_task` | The core tool used by orchestration skills to spawn sub-processes. |\n| `skill_manager_tool.py` | The backend logic that validates and manages these skill files. |","skills-yuanbao":"# skills — yuanbao\n\n# Yuanbao Group Interaction Module\n\nThe `yuanbao` skill module provides integration with the Yuanbao platform (often referred to as \"派\" or \"Pai\" in-app). It enables bots to interact within groups, manage member information, and send direct messages (DMs).\n\n## Core Messaging Architecture\n\nUnlike many chat integrations that require a specific \"send\" tool for every interaction, the Yuanbao module uses a **Response-as-Message** pattern for group replies.\n\n1. **Implicit Delivery**: Any text returned by the LLM is automatically captured by the gateway and delivered as a message to the active group.\n2. **Native Mentions**: The gateway parses `@nickname` strings within the response text. If the nickname matches a group member, it is converted into a functional UI mention (notifying the user).\n3. **Direct Messaging**: While group replies are implicit, private messages (DMs) require the explicit use of the `yb_send_dm` tool.\n\n## Tool Reference\n\n### `yb_query_group_info`\nRetrieves metadata for a specific group.\n* **Input**: `group_code` (string)\n* **Returns**: Group name, owner details, and total member count.\n\n### `yb_query_group_members`\nSearches or lists members within a group. This is the primary tool for resolving nicknames before an @mention.\n* **Actions**:\n * `find`: Search for a specific user by name (partial match).\n * `list_bots`: Filter for bots and Yuanbao AI assistants.\n * `list_all`: Retrieve the full member list.\n* **Parameters**: `group_code`, `action`, `name` (for find), `mention` (boolean).\n\n### `yb_send_dm`\nSends a private message to a specific user.\n* **Parameters**: \n * `group_code`: The context group.\n * `name` or `user_id`: Target identifier.\n * `message`: The text content.\n * `media_files`: Optional array of file objects (supports `.jpg`, `.png`, `.gif`, `.webp`, `.bmp` as images; others as documents).\n\n---\n\n## Implementation Workflows\n\n### 1. The @Mention Workflow\nTo ensure an @mention successfully triggers a notification, the bot must resolve the user's exact nickname within the Yuanbao system.\n\n```mermaid\ngraph TD\n A[User Request: 'Tell @Bob...'] --> B[Call yb_query_group_members]\n B --> C{Match Found?}\n C -- Yes --> D[Extract exact nickname]\n C -- No --> E[Ask user for clarification]\n D --> F[Reply: '@nickname message content']\n F --> G[Gateway converts to UI Mention]\n```\n\n**Example Tool Call:**\n```json\n{\n \"group_code\": \"328306697\",\n \"action\": \"find\",\n \"name\": \"Bob\",\n \"mention\": true\n}\n```\n\n**Example Response:**\n`@Bob_Official The report is ready.`\n\n### 2. Sending Private Messages (DM)\nDMs are used when a user requests a \"私信\" or when sensitive information should not be posted in the group.\n\n**Example Tool Call (with Media):**\n```json\n{\n \"group_code\": \"535168412\",\n \"name\": \"User123\",\n \"message\": \"Here is the requested document\",\n \"media_files\": [{\"path\": \"/tmp/invoice.pdf\"}]\n}\n```\n\n---\n\n## Data Handling & Constraints\n\n### Group Identification\nThe `group_code` is derived from the standard `chat_id` provided in the message context.\n* **Context ID**: `group:535168412`\n* **Extracted Code**: `535168412`\n\n### Member Roles\nThe module distinguishes between three entity types:\n1. `user`: Standard human participants.\n2. `yuanbao_ai`: Official platform AI entities.\n3. `bot`: Third-party integrations.\n\n### Best Practices\n* **Nickname Resolution**: Never guess a nickname for an @mention. Always use `yb_query_group_members` with `action=\"find\"` first.\n* **Formatting**: When mentioning, ensure there is a space before the `@` symbol (e.g., `Hello @User`) to ensure the gateway parser identifies the token correctly.\n* **Conciseness**: Do not explain the mention process to the user. If the tool returns the nickname, simply use it in the text response.","skills":"# skills\n\n# Skills Module\n\nThe `skills` module serves as the functional engine of the Hermes ecosystem. It provides the agent with a library of standardized methodologies, API integrations, and CLI wrappers required to execute complex tasks across diverse environments.\n\n## Architecture & Orchestration\n\nThe module is designed around a \"Route, then Execute\" philosophy. High-level orchestration logic determines which specialized skills are required to fulfill a user request.\n\n* **[DevOps](devops.md):** Provides the Kanban-style orchestration and task decomposition logic (DAG) that routes work to specific profiles.\n* **[Autonomous AI Agents](autonomous-ai-agents.md):** Enables the primary agent to spawn and manage sub-agents (like Claude Code or Codex) for specialized coding tasks.\n* **[Index-Cache](index-cache.md):** Acts as the central registry for all available capabilities, allowing the system to discover and activate tools dynamically.\n* **[MCP](mcp.md):** A native client for the Model Context Protocol, allowing the agent to ingest external tools from third-party servers as first-class functions.\n\n## Functional Domains\n\nSkills are categorized by their operational domain, allowing the agent to switch \"mental models\" based on the task at hand.\n\n### Engineering & Data Science\nThese modules provide the technical foundation for software lifecycles and model management.\n* **[Software Development](software-development.md) & [GitHub](github.md):** Standardized workflows for TDD, debugging, and repository management using the `gh` CLI and REST APIs.\n* **[Data Science](data-science.md):** Stateful Python execution via `jupyter-live-kernel` for iterative data exploration.\n* **[MLOps](mlops.md):** Tools for LLM evaluation (`lm-evaluation-harness`) and experiment tracking via Weights & Biases.\n\n### Research & Knowledge Management\nThese modules focus on information retrieval, synthesis, and persistent storage.\n* **[Research](research.md):** Academic and market intelligence gathering via arXiv, Semantic Scholar, and Polymarket.\n* **[Note-Taking](note-taking.md):** Persistent storage and knowledge graph management using **Obsidian**.\n* **[Diagramming](diagramming.md) & [Creative](creative.md):** Visual communication through Excalidraw schemas, architecture SVGs, and ASCII rendering.\n\n### Productivity & Communication\nTools for managing personal workflows and interacting with external platforms.\n* **[Productivity](productivity.md):** Integrations for Google Workspace, Airtable, Linear, and Maps.\n* **[Email](email.md) & [Social Media](social-media.md):** Communication via the Himalaya CLI (Email) and `xurl` (X/Twitter).\n* **[Apple](apple.md):** Native macOS integration for Notes, Reminders, and iMessage.\n* **[Yuanbao](yuanbao.md):** Specialized group interaction and messaging for the Yuanbao platform.\n\n### Specialized Automation\n* **[Media](media.md) & [GIFs](gifs.md):** Spotify playback, YouTube transcript processing, and animated media discovery.\n* **[Smart Home](smart-home.md):** IoT control via the OpenHue CLI.\n* **[Red-Teaming](red-teaming.md):** Safety filter bypass testing and model racing (GODMODE).\n* **[Inference-sh](inference-sh.md):** A unified gateway to 150+ AI models and multi-modal applications.\n\n## Skill Interaction Flow\n\nThe following diagram illustrates how the core orchestration modules interact with functional skills to complete a request.\n\n```mermaid\ngraph TD\n User[User Request] --> Orchestrator[DevOps / Orchestrator]\n Orchestrator --> Registry[Index-Cache]\n Registry --> Selection{Skill Selection}\n \n Selection --> Engineering[GitHub / Software-Dev]\n Selection --> Research[Research / Note-Taking]\n Selection --> Communication[Email / Social-Media]\n \n Engineering --> SubAgent[Autonomous AI Agents]\n Research --> Visuals[Diagramming / Creative]\n \n SubAgent --> Output[Final Result]\n Visuals --> Output\n Communication --> Output\n```\n\n## Cross-Module Workflows\n\nMany complex tasks require the coordination of multiple sub-modules:\n* **QA Pipeline:** The **[Dogfood](dogfood.md)** module uses browser automation to find bugs, then leverages **[GitHub](github.md)** to log issues and **[Software Development](software-development.md)** methodologies to propose fixes.\n* **Content Creation:** The **[Media](media.md)** module extracts a YouTube transcript, which is summarized by **[Research](research.md)**, stored in **[Note-Taking](note-taking.md)**, and finally shared via **[Social Media](social-media.md)**.\n* **Infrastructure Recon:** The **[Domain](domain.md)** module performs passive reconnaissance, providing data that can be visualized by **[Diagramming](diagramming.md)** or tested via **[Red-Teaming](red-teaming.md)**.","tests-acp-adapter":"# tests — acp_adapter\n\n# Tests — ACP Adapter\n\nThe `tests/acp_adapter` module provides functional and unit tests for the Agent Control Protocol (ACP) implementation. It ensures that the `HermesACPAgent` correctly handles slash commands, session state transitions, and multimodal content conversion.\n\n## Test Infrastructure\n\nThe tests utilize a suite of mock objects to isolate the adapter logic from actual LLM providers or database persistence:\n\n* **`FakeAgent`**: Simulates the underlying agentic core. It tracks calls to `steer()` and `run_conversation()`, allowing tests to verify if guidance was injected or if a full turn was executed.\n* **`CaptureConn`**: Mocks the ACP connection interface to capture `session_update` events and simulate permission grants.\n* **`NoopDb`**: A transient implementation of the session database that performs no actual I/O.\n* **`make_agent_and_state()`**: A utility function that wires together the `HermesACPAgent`, `SessionManager`, and mocks to provide a clean test environment.\n\n## Command Handling (`test_acp_commands.py`)\n\nThese tests verify the behavior of specialized slash commands that modify agent execution flow without necessarily starting a standard conversation turn.\n\n### Steering Logic\nThe `/steer` command behaves differently depending on the session state:\n1. **Active Run**: If `state.is_running` is true, the command calls `agent.steer()` to inject guidance into the live process.\n2. **Post-Interrupt**: If a session was interrupted (e.g., by a Zed user), `/steer` triggers a new run that combines the original interrupted prompt with the new guidance.\n3. **Idle**: If no run is active or interrupted, `/steer` is treated as a standard prompt to prevent the input from being silently queued.\n\n### Queuing Logic\nThe `/queue` command allows users to stage prompts for sequential execution.\n* **`test_acp_queue_slash_command_adds_next_turn_without_running_now`**: Validates that `/queue` populates `state.queued_prompts` without triggering an immediate `run_conversation`.\n* **`test_acp_prompt_drains_queued_turns_after_current_run`**: Ensures that once a primary prompt finishes, the adapter automatically \"drains\" the queue, executing all pending prompts in order.\n\n```mermaid\ngraph TD\n P[Incoming Prompt] --> SC{Is Slash Command?}\n SC -- /steer --> ST{Agent Running?}\n ST -- Yes --> Inject[agent.steer]\n ST -- No --> Run[agent.run_conversation]\n SC -- /queue --> Q[Append to state.queued_prompts]\n SC -- No --> Run\n Run --> Drain[Process state.queued_prompts]\n```\n\n## Multimodal Support (`test_acp_images.py`)\n\nThis submodule focuses on the translation between ACP-specific schemas and the internal representation used by the agent.\n\n### Content Conversion\nThe internal helper `_content_blocks_to_openai_user_content` is tested for two primary paths:\n* **Multimodal**: Converts a mix of `TextContentBlock` and `ImageContentBlock` into an OpenAI-style list of dictionaries (e.g., `{\"type\": \"image_url\", ...}`).\n* **Legacy/Text-Only**: If only text blocks are present, it simplifies the output to a raw string to maintain compatibility with legacy prompt paths.\n\n### Capability Advertisement\nThe `test_initialize_advertises_image_prompt_capability` test ensures that during the ACP `initialize` handshake, the `HermesACPAgent` correctly reports `image: True` in its `prompt_capabilities`. This informs the client (like the Zed editor) that it is safe to send image data.\n\n## Key Functions Tested\n\n| Function | Purpose |\n| :--- | :--- |\n| `HermesACPAgent.prompt` | The primary entry point for ACP messages; handles command parsing and execution. |\n| `_content_blocks_to_openai_user_content` | Maps ACP schema blocks to OpenAI multimodal format. |\n| `HermesACPAgent.initialize` | Handles the initial protocol handshake and capability negotiation. |\n| `SessionManager.create_session` | Initializes the state container used to track queued prompts and run status. |","tests-acp":"# tests — acp\n\n# ACP Adapter Test Suite\n\nThe `tests/acp` module provides comprehensive test coverage for the **Agent Communication Protocol (ACP)** adapter. This adapter acts as a JSON-RPC bridge between the Hermes AI agent and external clients, such as the Zed editor.\n\nThe test suite ensures protocol compliance, session persistence, security isolation, and correct translation of internal agent events into ACP-compatible schemas.\n\n## Core Test Areas\n\n### 1. Server Implementation (`test_server.py`)\nTests the `HermesACPAgent` class, which implements the ACP server-side logic.\n* **Lifecycle Methods:** Validates `initialize`, `authenticate`, `new_session`, `load_session`, and `resume_session`.\n* **Capabilities:** Ensures the server correctly advertises support for session forking, listing, and resuming using the correct JSON wire format (e.g., `loadSession` vs `load_session`).\n* **Slash Commands:** Verifies that the adapter intercepts and handles internal commands like `/help`, `/model`, `/reset`, and `/compact` without invoking the LLM.\n* **Pagination:** Tests the cursor-based pagination logic for `list_sessions`.\n\n### 2. Session Management & Persistence (`test_session.py`)\nTests the `SessionManager` and `SessionState` components responsible for maintaining agent state across restarts.\n* **Persistence:** Verifies that sessions are correctly serialized to and restored from `SessionDB`.\n* **WSL Integration:** Validates `_translate_acp_cwd`, which converts Windows-style paths (e.g., `E:\\Project`) to WSL-compatible paths (e.g., `/mnt/e/Project`) to ensure tools function correctly in cross-platform environments.\n* **Isolation:** Ensures that `get_session` only restores sessions marked with the `acp` source, preventing collision with CLI-based sessions.\n* **FTS Search:** Confirms that ACP session history is indexed and searchable via SQLite FTS5.\n\n### 3. Security & Thread Isolation (`test_approval_isolation.py`)\nFocuses on regressions for **GHSA-96vc-wcxf-jjff** and **GHSA-qg5c-hvr5-hjgr**.\n* **Thread-Local Callbacks:** Ensures that `set_approval_callback` and `set_sudo_password_callback` use thread-local storage (TLS). This prevents concurrent ACP sessions from overwriting each other's security handlers.\n* **Interactive Enforcement:** Verifies that `_run_agent` correctly sets `HERMES_INTERACTIVE` so that dangerous commands trigger the ACP-supplied callback instead of auto-approving.\n* **Context Isolation:** Tests that even when `ThreadPoolExecutor` reuses threads, `contextvars` and `HERMES_SESSION_KEY` are used to isolate the interactive sudo password cache between distinct sessions.\n\n### 4. Event & Tool Translation (`test_events.py`, `test_tools.py`)\nEnsures internal agent activity is correctly mapped to ACP protocol messages.\n* **Callback Factories:** Tests `make_tool_progress_cb`, `make_step_cb`, and `make_thinking_cb`. These factories bridge the synchronous agent execution with the asynchronous ACP connection using `asyncio.run_coroutine_threadsafe`.\n* **Tool Mapping:** Validates `TOOL_KIND_MAP`, which categorizes Hermes tools into ACP kinds (`read`, `edit`, `execute`, `fetch`).\n* **Diff Generation:** Verifies that `build_tool_start` and `build_tool_complete` generate structured `FileEditToolCallContent` (diff blocks) for tools like `patch` and `write_file`, allowing editors to render inline previews.\n\n### 5. MCP Integration (`test_mcp_e2e.py`)\nTests the end-to-end flow of the **Model Context Protocol (MCP)** within an ACP session.\n* **Dynamic Registration:** Verifies that `new_session` calls containing `mcpServers` correctly trigger `tools.mcp_tool.register_mcp_servers`.\n* **Sanitization:** Ensures server names with special characters (e.g., `ai.exa/exa`) are sanitized into valid tool names.\n* **Result Reporting:** Confirms that results from MCP tools are correctly paired with their `toolCallId` and reported back to the client via `ToolCallProgress` updates.\n\n## Execution Flow: Prompt to Update\n\nThe following diagram illustrates the flow tested in `test_mcp_e2e.py` and `test_events.py`, showing how a tool execution inside the agent triggers ACP updates.\n\n```mermaid\nsequenceDiagram\n participant Client as ACP Client (Zed)\n participant Adapter as HermesACPAgent\n participant Agent as AIAgent\n participant Events as Event Callbacks\n\n Client->>Adapter: prompt(text=\"run ls\")\n Adapter->>Agent: run_conversation()\n Note over Agent: Tool execution starts\n Agent->>Events: tool_progress_callback(\"started\", \"terminal\")\n Events->>Adapter: session_update(ToolCallStart)\n Adapter->>Client: JSON-RPC: session/update\n Agent->>Events: step_callback(results)\n Events->>Adapter: session_update(ToolCallProgress: completed)\n Adapter->>Client: JSON-RPC: session/update\n Agent-->>Adapter: final_response\n Adapter-->>Client: PromptResponse\n```\n\n## Infrastructure & Utilities\n\n### Ping Suppression (`test_ping_suppression.py`)\nTests the `_BenignProbeMethodFilter` logging filter. This component suppresses \"Method not found\" errors in the logs specifically for `ping` or `health` requests. This prevents log pollution when clients perform bare JSON-RPC probes to check if the agent process is alive.\n\n### Permissions Bridging (`test_permissions.py`)\nTests `make_approval_callback`, which converts the agent's synchronous approval requests into asynchronous ACP `request_permission` calls. It validates the mapping of ACP outcomes (`allow_once`, `allow_always`, `cancelled`) back to internal Hermes approval states (`once`, `always`, `deny`).\n\n### Authentication (`test_auth.py`)\nValidates the logic in `acp_adapter.auth` for detecting available LLM providers (OpenRouter, Anthropic, etc.) based on the environment and configuration, which is used during the ACP `authenticate` phase.","tests-agent":"# tests — agent\n\n# Tests — Agent Module\n\nThe `tests/agent` module provides comprehensive test coverage for the core communication and adaptation layers of the agent. It ensures that internal agent logic correctly translates to external LLM provider APIs, manages complex authentication flows, and handles model-specific constraints.\n\n## Core Testing Areas\n\n### 1. Anthropic Adapter (`test_anthropic_adapter.py`)\nThis suite validates the `agent.anthropic_adapter` module, which serves as the primary bridge to the Anthropic Messages API.\n\n* **Message Conversion**: Tests `convert_messages_to_anthropic` to ensure internal message formats (including system prompts, tool calls, and images) are correctly mapped.\n * **Thinking Blocks**: Validates the strategy of stripping thinking blocks from historical turns while preserving signed thinking blocks on the latest turn.\n * **Image Handling**: Ensures both remote URLs and base64 data URLs are converted to Anthropic's expected source format.\n * **Role Alternation**: Verifies that consecutive messages from the same role are merged to satisfy Anthropic's strict user/assistant alternation requirements.\n* **Tool Transformation**: Tests `convert_tools_to_anthropic`, focusing on the conversion of OpenAI-style function definitions to Anthropic tool schemas, including the deduplication of tool names to prevent API rejection.\n* **Model Normalization**: Ensures model strings (e.g., `anthropic/claude-3.5-sonnet`) are correctly stripped and formatted for the SDK.\n* **Kwarg Construction**: Validates `build_anthropic_kwargs`, specifically how `max_tokens` are calculated based on model limits and how `reasoning_config` maps to either \"manual\" or \"adaptive\" thinking modes depending on the model version (e.g., Claude 4.6 vs 4.7).\n\n### 2. Credential & Authentication Management\nThe test suite covers a multi-tiered credential resolution logic across `test_anthropic_adapter.py` and `test_anthropic_keychain.py`.\n\n* **OAuth Flow**: Validates the detection of OAuth tokens (`sk-ant-oat01-...`) and the automatic refresh logic using `_refresh_oauth_token` when tokens expire.\n* **Credential Priority**: Ensures the agent follows the correct resolution order:\n 1. Environment variables (`ANTHROPIC_TOKEN`, `ANTHROPIC_API_KEY`).\n 2. macOS Keychain (for Claude Code >= 2.1.114).\n 3. Local filesystem (`~/.claude/.credentials.json`).\n* **macOS Keychain Integration**: Specifically tests the `security` command-line interaction on Darwin platforms, ensuring JSON payloads are correctly parsed from the system keychain and that failures (like missing entries) fall back gracefully to file-based storage.\n\n### 3. Auxiliary Client Resolution (`test_auxiliary_client.py`)\nThe agent uses \"auxiliary\" clients for secondary tasks like context compression, session search, and vision. These tests verify the `resolve_provider_client` logic.\n\n* **Provider Chain**: Validates the `_resolve_auto` logic which attempts to find a usable backend in a specific order: OpenRouter → Codex → Custom Runtimes → Anthropic → Nous.\n* **JWT Validation**: Tests `_read_codex_access_token` to ensure that expired JWTs are detected and skipped, preventing the agent from attempting to use stale credentials.\n* **Nous/Portal Integration**: Verifies that the agent can fetch recommended auxiliary models from the Nous Portal and correctly configures the OpenAI-compatible client for these endpoints.\n* **Error Recovery**: Tests the `call_llm` and `async_call_llm` wrappers for their ability to catch specific provider errors (like 401 Unauthorized or 400 Unsupported Parameter) and trigger appropriate retries or fallbacks.\n\n## Key Execution Flows\n\nThe following diagram illustrates the credential resolution and client building flow tested within this module:\n\n```mermaid\ngraph TD\n A[resolve_anthropic_token] --> B{Check Env Vars}\n B -- Found --> C[Return Token]\n B -- Not Found --> D{Check macOS Keychain}\n D -- Found --> C\n D -- Not Found/Not Darwin --> E{Check .credentials.json}\n E -- Found --> F{Is Expired?}\n F -- Yes --> G[Attempt OAuth Refresh]\n G -- Success --> C\n F -- No --> C\n E -- Not Found --> H[Return None]\n```\n\n## Specialized Logic Tests\n\n### Tool Guardrails\nTests in `test_tool_guardrails.py` (referenced in call graphs) ensure that the agent monitors tool execution patterns. It validates:\n* **Idempotency Checks**: Warning when the same tool is called with identical arguments repeatedly.\n* **Hard Stops**: Halting execution if a failure streak exceeds configured thresholds.\n\n### Model Metadata & Context\nTests in `test_model_metadata_local_ctx.py` verify how the agent determines context window limits for local providers like LM Studio. It ensures that the agent queries the `/v1/models` endpoint and correctly extracts the `context_length` to prevent overflow errors during inference.\n\n### Subagent Progress & Hooks\n* **Stop Hooks**: Ensures that when a subagent finishes, parent session IDs are correctly propagated in the payload.\n* **Progress Callbacks**: Validates that \"thinking\" updates from the LLM are correctly intercepted and passed to UI progress handlers.","tests-cli":"# tests — cli\n\n# Tests — CLI Module\n\nThe `tests/cli` module provides a comprehensive test suite for the Hermes Command Line Interface. It validates the TUI (Terminal User Interface) behavior, slash command processing, session lifecycle management, and the security-critical approval workflows for dangerous operations.\n\n## Core Testing Areas\n\n### 1. Command Dispatch and Prefix Matching\nThe CLI uses a prefix-matching system for slash commands. Tests in `test_cli_prefix_matching.py` verify that:\n- Unique prefixes (e.g., `/con`) correctly resolve to full commands (e.g., `/config`).\n- Ambiguous prefixes trigger a suggestion or error message.\n- Command arguments are preserved during expansion without causing infinite recursion.\n- Exact matches bypass prefix logic for performance and stability.\n\n### 2. Session Lifecycle and Branching\nSession management is a primary focus, ensuring data integrity across different interaction states.\n- **Branching (`/branch`, `/fork`):** `test_branch_command.py` verifies that branching creates a new session in the `SessionDB`, copies message history, sets the `parent_session_id`, and marks the original session as \"branched\". It also ensures that active agents are updated with the new session ID and log file paths.\n- **Fresh Sessions (`/new`, `/reset`, `/clear`):** `test_cli_new_session.py` ensures that starting a new session correctly zeroes out all token counters (input, output, cache, reasoning) and resets the `AIAgent` state, including the `TodoStore`.\n- **Resuming:** Tests verify that `/resume` without arguments lists recent sessions and that resuming correctly restores conversation history.\n\n### 3. TUI and Interaction Logic\nThese tests exercise the integration with `prompt-toolkit` and `rich`.\n- **Approval UI:** `test_cli_approval_ui.py` contains critical regression tests for the dangerous command approval panel. It ensures that:\n - The UI does not clip action buttons (Allow/Deny) on small terminal windows.\n - Long descriptions are truncated gracefully.\n - The \"View Full Command\" toggle works correctly.\n - Callbacks are correctly registered in thread-local storage to prevent deadlocks between the agent thread and the TUI thread.\n- **Input Sanitization:** `test_cli_bracketed_paste_sanitizer.py` validates the stripping of terminal escape sequences (bracketed paste wrappers) that can leak into the input buffer.\n- **File Drops:** `_detect_file_drop` is tested to ensure that absolute paths dragged into the terminal are recognized as file attachments (especially images) rather than slash commands.\n- **Redraws:** `test_cli_force_redraw.py` verifies that the CLI can recover from terminal buffer drift (e.g., after a `tmux` tab switch) by forcing a full screen clear and invalidation.\n\n### 4. Background Tasks (`/btw`)\nThe `/background` (aliased as `/btw`) command allows the agent to run tasks without blocking the main input loop.\n- **TUI Refresh:** `test_cli_background_tui_refresh.py` ensures `app.invalidate()` is called before printing background task output to prevent overlapping with the spinner or status bar.\n- **Callback Propagation:** Tests verify that background tasks inherit the same approval UI callbacks as foreground tasks, preventing them from falling back to `stdin` and hanging.\n\n### 5. Configuration and MCP Integration\n- **MCP Watcher:** `test_cli_mcp_config_watch.py` validates the automatic reloading of Model Context Protocol (MCP) servers when the `mcp_servers` section of `config.yaml` is modified. It includes throttling logic to prevent excessive `stat()` calls.\n- **Provider Resolution:** `test_cli_init.py` ensures that root-level configuration keys (like `provider` or `base_url`) are correctly migrated to the `model` section and do not override explicit model-specific settings.\n- **Busy Input Mode:** Tests the `/busy` command, which toggles how the CLI handles user input while the agent is generating (options: `interrupt`, `queue`, `steer`).\n\n## Security and Approval Workflow\n\nThe CLI implements a strict approval flow for tools that perform side effects (e.g., `terminal_tool`). The following diagram illustrates the interaction between the Agent thread and the TUI thread during an approval request:\n\n```mermaid\nsequenceDiagram\n participant A as Agent Thread\n participant T as TUI Thread (Main)\n participant U as User\n\n A->>A: Executes Dangerous Tool\n A->>T: Trigger _approval_callback(cmd)\n T->>T: Snapshot Input Buffer\n T->>T: Display Modal Approval Panel\n U->>T: Select \"Allow once\"\n T->>T: Restore Input Buffer\n T->>A: Return \"once\" via Queue\n A->>A: Proceed with Execution\n```\n\n## Key Test Utilities and Fixtures\n\n- **`_make_cli`:** A common factory function found across test files that initializes a `HermesCLI` instance with mocked `prompt-toolkit` components to allow testing TUI logic in headless environments.\n- **`session_db`:** A fixture that provides a temporary SQLite database for testing session persistence and history.\n- **`_FakeAgent`:** A stub used to verify that the CLI correctly updates agent state (like token counts and session IDs) without requiring a full LLM backend.\n\n## Regression Highlights\n\n- **Thread-Local Callbacks:** Tests in `test_cli_approval_ui.py` specifically guard against a bug where the agent thread could not access the TUI's approval callbacks, causing the CLI to hang while waiting for `input()`.\n- **Token Counter Reset:** `test_cli_new_session.py` ensures that `/new` resets the `session_total_tokens` to 0, preventing cumulative cost/usage reporting across unrelated sessions.\n- **Bracketed Paste:** `test_cli_bracketed_paste_sanitizer.py` prevents \"degraded\" terminal environments from injecting `[200~` and `[201~` strings into the LLM prompt.","tests-cron":"# tests — cron\n\n# Cron Module Test Suite\n\nThe `tests/cron` module provides comprehensive test coverage for the system's background task scheduling and execution engine. It validates the lifecycle of a cron job—from creation and schedule parsing to execution via the AI agent and final result delivery.\n\n## Core Testing Areas\n\n### 1. Job Management and Scheduling (`test_jobs.py`)\nThis suite validates the `cron.jobs` logic, focusing on how schedules are interpreted and when jobs are marked as \"due.\"\n\n* **Duration Parsing:** Tests `parse_duration` for various string formats (e.g., `30m`, `2h`, `7days`).\n* **Schedule Interpretation:** Validates `parse_schedule` for three distinct types:\n * **Once:** One-shot tasks at a specific ISO timestamp or relative offset.\n * **Interval:** Recurring tasks based on minutes (e.g., \"every 2h\").\n * **Cron:** Standard cron expressions (e.g., `0 9 * * *`) using `croniter`.\n* **Next Run Calculation:** Ensures `compute_next_run` correctly anchors to `last_run_at` to prevent drift or double-firing after system restarts.\n* **State Transitions:** Tests `pause_job`, `resume_job`, and `mark_job_run`, ensuring that hitting a repeat limit correctly transitions a job to `completed` or removes it.\n\n### 2. Scheduler Execution Flow (`test_scheduler.py`)\nTests the `cron.scheduler` module, which handles the operational logic of running a job.\n\n* **Origin & Delivery Resolution:** Validates `_resolve_origin` and `_resolve_delivery_target`. It ensures results are routed back to the correct platform (Telegram, Slack, etc.) or fallback \"home\" channels defined in environment variables.\n* **Result Delivery:** Tests `_deliver_result` and media handling (`_send_media_via_adapter`), ensuring that images, videos, and documents are correctly extracted from agent output and dispatched.\n* **Silent Mode:** Verifies that the `SILENT_MARKER` (e.g., `[silent]`) in agent responses correctly suppresses external delivery while still saving the output locally.\n\n### 3. Inactivity Timeouts (`test_cron_inactivity_timeout.py`)\nTo prevent \"zombie\" jobs that hang indefinitely, the scheduler implements an inactivity monitor.\n\n* **Activity Tracking:** Tests `get_activity_summary` on the agent.\n* **Timeout Trigger:** Validates that if an agent does not perform an action (API call, tool use) within the `HERMES_CRON_TIMEOUT` (default 600s), the scheduler interrupts the task.\n* **Diagnostic Logging:** Ensures the error message includes the last known activity to assist in debugging hung agents.\n\n### 4. Advanced Job Features\n\n#### Context Chaining (`test_cron_context_from.py`)\nTests the `context_from` feature, which allows a job to consume the output of a previous job.\n* **Injection:** Validates that `_build_job_prompt` injects the most recent markdown output from the referenced job ID into the current job's prompt.\n* **Normalization:** Ensures multiple job IDs are handled and that missing outputs are skipped gracefully.\n\n#### Script Injection (`test_cron_script.py`)\nJobs can execute a local script before the LLM run to provide dynamic data.\n* **Execution:** Tests `_run_job_script` for successful output capture and error handling (non-zero exits, timeouts).\n* **Security (Path Containment):** Critically validates that scripts are restricted to the `~/.hermes/scripts` directory, blocking absolute paths, tilde expansion, or symlink escapes.\n\n#### Working Directory Isolation (`test_cron_workdir.py`)\nTests the `workdir` parameter which allows jobs to run within a specific filesystem context.\n* **Environment Mutation:** Ensures `TERMINAL_CWD` is set during the run and strictly restored afterward.\n* **Sequential Partitioning:** Validates that `tick()` runs jobs with a `workdir` sequentially on the main thread to avoid race conditions on process-global environment variables.\n\n## Security and Hardening (`test_file_permissions.py`)\nThe suite enforces strict filesystem security for sensitive cron data:\n* **Directories:** `CRON_DIR` and `OUTPUT_DIR` must be `0700` (owner-only).\n* **Files:** `jobs.json` and individual job output files must be `0600`.\n* **Identity:** Ensures `load_soul_identity` is always active for cron jobs to maintain agent personality.\n\n## Integration Paths\n\n### Codex Recovery (`test_codex_execution_paths.py`)\nSpecifically tests the `openai-codex` runtime path. It mocks a `401 Unauthorized` error to verify that `AIAgent` triggers `_try_refresh_codex_client_credentials` and successfully retries the conversation without failing the cron job.\n\n### Skill Rewriting (`test_rewrite_skill_refs.py`)\nEnsures integration with the system curator. When skills are consolidated or pruned, `rewrite_skill_refs` updates existing cron jobs to point to the new \"umbrella\" skill names, preventing jobs from running with broken instructions.\n\n## Execution Flow Diagram\n\n```mermaid\ngraph TD\n T[scheduler.tick] --> G[get_due_jobs]\n G --> P{Has workdir?}\n P -- Yes --> S[Sequential Execution]\n P -- No --> TP[ThreadPoolExecutor]\n S --> RJ[run_job]\n TP --> RJ\n RJ --> SC[Execute Pre-run Script]\n SC --> AG[AIAgent.run_conversation]\n AG --> TO{Inactivity Timeout?}\n TO -- Yes --> INT[Interrupt Agent]\n AG --> DR[deliver_result]\n DR --> MJ[mark_job_run]\n```\n\n## Developer Notes\n* **Mocking:** Most tests use `monkeypatch` to redirect `HERMES_HOME` to a `tmp_path`, preventing tests from affecting the local user's cron jobs.\n* **Dependencies:** Tests involving cron expressions will skip if `croniter` is not installed.\n* **Environment Variables:** Tests verify that `HERMES_CRON_TIMEOUT` and various `_HOME_CHANNEL` variables are correctly parsed.","tests-e2e":"# tests — e2e\n\n# E2E Testing Module\n\nThe `tests/e2e` module provides end-to-end validation of the message processing pipeline. These tests exercise the full asynchronous flow from the moment a platform adapter receives a raw event to the point where a response is dispatched back to the platform.\n\n## Overview\n\nThe E2E suite is designed to test the \"Gateway\" layer—routing, command dispatch, session management, and authorization—without requiring real platform connections or live LLM inference.\n\n### Core Execution Flow\nThe tests typically follow this execution path:\n1. **Event Injection**: A mock `MessageEvent` is passed to `adapter.handle_message(event)`.\n2. **Background Processing**: The adapter processes the message in a background task via `_process_message_background()`.\n3. **Gateway Dispatch**: The message is routed to `GatewayRunner._handle_message()`.\n4. **Command/Agent Execution**: The runner identifies slash commands or routes the text to a (mocked) agent.\n5. **Response Capture**: The adapter's `send()` method (an `AsyncMock`) captures the output for assertion.\n\n```mermaid\ngraph LR\n A[Test Case] --> B[Adapter.handle_message]\n B --> C[GatewayRunner._handle_message]\n C --> D{Command?}\n D -- Yes --> E[Internal Command Logic]\n D -- No --> F[Mock Agent]\n E --> G[Adapter.send Mock]\n F --> G\n G --> H[Test Assertions]\n```\n\n## Test Infrastructure (`conftest.py`)\n\nThe `conftest.py` file contains the machinery required to simulate the gateway environment.\n\n### Platform Mocking\nSince E2E tests run in environments where platform-specific SDKs (like `python-telegram-bot` or `discord.py`) might not be installed, the module includes \"ensure\" functions (`_ensure_telegram_mock`, `_ensure_discord_mock`, `_ensure_slack_mock`). These inject `MagicMock` objects into `sys.modules` to allow the adapters to be imported and instantiated.\n\n### Factory Functions\n- **`make_runner(platform)`**: Creates a `GatewayRunner` instance. It uses `object.__new__` to bypass the standard `__init__` method, avoiding filesystem side effects and network calls. It pre-configures mocks for `session_store`, `pairing_store`, and `hooks`.\n- **`make_adapter(platform, runner)`**: Instantiates a platform-specific adapter (e.g., `DiscordAdapter`, `TelegramAdapter`) and wires it to the provided runner using `set_message_handler`.\n- **`send_and_capture(adapter, text, platform)`**: A high-level helper that creates an event, injects it into the adapter, waits for a short \"settle\" delay (`E2E_MESSAGE_SETTLE_DELAY`), and returns the `adapter.send` mock for inspection.\n\n## Command Verification (`test_platform_commands.py`)\n\nThis suite uses parametrized fixtures to run the same set of tests across all supported platforms (Telegram, Discord, Slack). It verifies:\n- **Slash Commands**: Ensures `/help`, `/status`, `/new`, `/stop`, and `/personality` return expected strings or trigger correct state changes (e.g., calling `session_store.reset_session`).\n- **Authorization**: Validates that unauthorized users receive pairing codes instead of command outputs.\n- **Session Lifecycle**: Confirms that sequential commands correctly share or reset session state.\n- **Resilience**: Checks that the pipeline handles `send()` failures without crashing the background task.\n\n## Discord-Specific Logic (`test_discord_adapter.py`)\n\nDiscord requires specialized E2E tests due to its unique message handling requirements:\n- **Mention Stripping**: Verifies that `<@BOT_ID> /command` is correctly parsed as `/command` after the mention is stripped.\n- **Auto-Threading**: Tests the interaction between `DISCORD_AUTO_THREAD` and command detection, ensuring that creating a thread doesn't lose the original command context.\n- **Channel vs. DM**: Validates that mentions are required in server channels but optional in DMs.\n\n## Matrix Cross-Signing Bootstrap (`matrix_xsign_bootstrap/`)\n\nThis is a specialized, self-contained E2E suite located in its own subdirectory. Unlike the other tests, it uses a real **Continuwuity** (Matrix) homeserver running in Docker.\n\n### Purpose\nIt validates the complex cryptographic bootstrap logic in `MatrixAdapter`:\n1. **Key Generation**: Ensures cross-signing keys are published with unpadded base64 key IDs (required for compatibility with `matrix-rust-sdk`).\n2. **Idempotency**: Verifies that bootstrap is skipped on subsequent startups if keys already exist in the `PgCryptoStore`.\n3. **Recovery Path**: Confirms that providing a `MATRIX_RECOVERY_KEY` allows the adapter to verify existing keys rather than generating new ones.\n\n### Usage\nThe Matrix E2E test requires Docker and the `mautrix` Python package. It is executed via:\n```bash\ndocker compose -f tests/e2e/matrix_xsign_bootstrap/docker-compose.yml up -d\npython tests/e2e/matrix_xsign_bootstrap/test_bootstrap.py\n```\n\n## Key Test Patterns\n\n### Handling Async Settle Times\nBecause the gateway processes messages in background tasks, tests must allow the event loop to cycle. The `send_and_capture` helper implements a `0.3s` sleep. If a test fails intermittently, check if the background task completed within this window.\n\n### Mocking the Agent Layer\nBy default, `make_runner` mocks `_handle_message_with_agent` to return a static string. This isolates the gateway logic from the LLM provider logic. To test agent-specific routing, override this mock in the specific test case:\n```python\nrunner._handle_message_with_agent = AsyncMock(return_value=\"Custom Agent Response\")\n```","tests-environments":"# tests — environments\n\n# Terminal-Bench 2 Environment Security Tests\n\nThe `test_terminalbench2_env_security.py` module provides a specialized test suite focused on the security of archive extraction within the Terminal-Bench 2 environment. It specifically validates that the environment's internal extraction logic is resilient against common archive-based attacks such as path traversal and symlink exploitation.\n\n## Overview\n\nThe primary target of these tests is the `_extract_base64_tar` function within the `environments.benchmarks.terminalbench_2.terminalbench2_env` module. Because the environment module has extensive dependencies on internal libraries (like `atroposlib`), this test suite employs a sophisticated stubbing mechanism to isolate the extraction logic for unit testing.\n\n## Isolation and Stubbing Strategy\n\nTo test the environment in isolation, the module uses `_load_terminalbench_module` to dynamically construct a mock environment.\n\n1. **`_stub_module(name, **attrs)`**: A helper that creates a `types.ModuleType` object and populates it with provided attributes.\n2. **Dependency Mocking**: The suite mocks the following namespaces before importing the target module:\n * `atroposlib` (and its sub-packages `envs.base`, `envs.server_handling`)\n * `environments.agent_loop`\n * `environments.hermes_base_env`\n * `tools.terminal_tool`\n3. **Monkeypatching**: These stubs are injected into `sys.modules` using pytest's `monkeypatch`. This allows the test to call `importlib.import_module` on the Terminal-Bench 2 environment without triggering real side effects or requiring the full production stack.\n\n## Test Utilities\n\n### Archive Generation\nThe `_build_tar_b64(entries)` function is a utility that programmatically generates base64-encoded Gzip-compressed tarballs. It supports creating:\n* **Directories**: `kind: \"dir\"`\n* **Regular Files**: `kind: \"file\"` with custom string data.\n* **Symlinks**: `kind: \"symlink\"` with a specified target path.\n\nThis utility allows the test suite to craft malicious payloads (e.g., files with `..` in the path) to verify the environment's validation logic.\n\n## Security Scenarios Tested\n\nThe module validates three critical behaviors of the `_extract_base64_tar` function:\n\n### 1. Safe Extraction\n**Function**: `test_extract_base64_tar_allows_safe_files`\nVerifies that standard, well-formed archives containing directories and files are extracted correctly to the target destination without errors.\n\n### 2. Path Traversal Prevention\n**Function**: `test_extract_base64_tar_rejects_path_traversal`\nEnsures that the environment detects and rejects archive members containing path traversal sequences (e.g., `../escape.txt`). \n* **Expected Behavior**: The environment must raise a `ValueError` matching \"Unsafe archive member path\".\n* **Security Goal**: Prevent an attacker from overwriting files outside the designated temporary extraction directory.\n\n### 3. Symlink Restriction\n**Function**: `test_extract_base64_tar_rejects_symlinks`\nEnsures that the environment rejects archives containing symbolic links.\n* **Expected Behavior**: The environment must raise a `ValueError` matching \"Unsupported archive member type\".\n* **Security Goal**: Prevent symlink attacks where an archive creates a link to a sensitive system file (like `/etc/passwd`) which might later be read or written to by the agent.\n\n## Execution Flow\n\n```mermaid\ngraph TD\n T[Test Case] --> LB[load_terminalbench_module]\n LB --> S[Stub Dependencies in sys.modules]\n S --> I[importlib.import_module]\n T --> B[build_tar_b64]\n B --> P[Payload Generation]\n T --> E[_extract_base64_tar]\n E --> V{Validation Logic}\n V -- Unsafe Path --> R[Raise ValueError]\n V -- Symlink --> R\n V -- Safe --> EX[Extract to Disk]\n```\n\n## Usage for Contributors\n\nWhen modifying the extraction logic in `terminalbench2_env.py`, ensure these tests pass to maintain the security baseline. If adding support for new archive types or extraction features, add corresponding test cases to `_build_tar_b64` and create new security validation tests here.","tests-fakes":"# tests — fakes\n\n# Tests — Fakes\n\nThe `tests.fakes` module provides a mock implementation of the Home Assistant API. Its primary component, `FakeHAServer`, is an in-process HTTP and WebSocket server built on `aiohttp.web`. It allows integration tests to exercise the `hermes-agent` against a realistic API surface without requiring a live Home Assistant instance.\n\n## FakeHAServer\n\nThe `FakeHAServer` class simulates the core Home Assistant REST and WebSocket endpoints. It maintains an internal state of entities and records incoming requests for test assertions.\n\n### Lifecycle Management\n\nThe server is designed to be used as an asynchronous context manager, which handles the setup and teardown of the underlying `aiohttp.test_utils.TestServer`.\n\n```python\nasync with FakeHAServer(token=\"test-token\") as server:\n url = server.url # http://127.0.0.1:<random_port>\n # Run tests against server.url\n```\n\nAlternatively, you can manually call `await server.start()` and `await server.stop()`.\n\n### Supported Endpoints\n\n| Protocol | Endpoint | Description |\n| :--- | :--- | :--- |\n| **REST** | `GET /api/states` | Returns the full list of `ENTITY_STATES`. |\n| **REST** | `GET /api/states/{entity_id}` | Returns state for a specific entity or 404. |\n| **REST** | `POST /api/services/{domain}/{service}` | Records a service call and updates internal state. |\n| **REST** | `POST /api/services/persistent_notification/create` | Specifically handles notification creation. |\n| **WS** | `/api/websocket` | Handles auth handshake and event subscriptions. |\n\n### WebSocket Protocol Flow\n\nThe WebSocket implementation follows the standard Home Assistant handshake. Once a subscription is established, the server enters a loop, pushing any events added to the internal queue.\n\n```mermaid\nsequenceDiagram\n participant C as Client (Agent)\n participant S as FakeHAServer\n S->>C: {\"type\": \"auth_required\"}\n C->>S: {\"type\": \"auth\", \"access_token\": \"...\"}\n alt Valid Token\n S->>C: {\"type\": \"auth_ok\"}\n C->>S: {\"type\": \"subscribe_events\", \"id\": 1}\n S->>C: {\"id\": 1, \"type\": \"result\", \"success\": true}\n Note over S,C: Server begins pushing events from _event_queue\n else Invalid Token\n S->>C: {\"type\": \"auth_invalid\"}\n end\n```\n\n### State and Observability\n\nThe server provides several attributes to inspect its state and the interactions it has received:\n\n* **`received_service_calls`**: A list of dictionaries containing the `domain`, `service`, and `data` of every service call POSTed to the server.\n* **`received_notifications`**: A list of payloads sent to the `persistent_notification/create` endpoint.\n* **`ENTITY_STATES`**: A static list of sample entities (lights, sensors, switches, climate) used as the initial state.\n\n### Controlling Behavior\n\nTests can manipulate the server's behavior dynamically:\n\n1. **Pushing Events**: Use `await server.push_event(event_data)` to simulate a state change in Home Assistant. This event is forwarded to all active WebSocket subscribers.\n2. **Simulating Failures**:\n * Set `server.reject_auth = True` to force WebSocket authentication failures.\n * Set `server.force_500 = True` to make all REST endpoints return a 500 Internal Server Error.\n3. **State Side Effects**: The `_handle_call_service` method contains logic to update `ENTITY_STATES` when specific services are called (e.g., `turn_on`, `turn_off`, `set_temperature`). For example, calling `set_temperature` on a climate entity will also update the linked `sensor.temperature` state to simulate a realistic environment response.\n\n### Authentication\n\nThe server enforces Bearer token authentication for REST requests via the `_check_rest_auth` helper. The expected token is defined during initialization. If the `Authorization` header is missing or incorrect, the server returns a `401 Unauthorized` response.","tests-gateway":"# tests — gateway\n\n# Tests — Gateway\n\nThe `tests/gateway` module provides the testing infrastructure, mocks, and integration suites for the gateway layer. This includes the `GatewayRunner`, session management, agent caching, and various platform adapters (Telegram, Discord, Feishu, API Server, etc.).\n\n## Core Infrastructure & Safety Guards\n\n### Plugin Adapter Loader\nEvery platform plugin (located in `plugins/platforms/<name>/`) contains its own `adapter.py`. To prevent `ImportError` and `sys.modules` collisions when running tests in parallel (e.g., via `pytest-xdist`), the module provides `load_plugin_adapter`.\n\n* **Function**: `load_plugin_adapter(plugin_name: str)`\n* **Mechanism**: Imports the adapter from an explicit file path and registers it under a unique name (`plugin_adapter_<plugin_name>`). This avoids the \"polluted `sys.path`\" anti-pattern where multiple plugins compete for the top-level `adapter` module name.\n\n### Anti-Pattern Guard\nThe `conftest.py` implements a mandatory AST-based scan during the `pytest_configure` phase. It rejects any test file that attempts to:\n1. Manually insert `plugins/platforms` paths into `sys.path`.\n2. Perform a bare `import adapter` or `from adapter import ...`.\n\nIf the guard detects these patterns, it raises a `pytest.UsageError` with instructions to use the `load_plugin_adapter` helper.\n\n## Global Mocks\n\nThe gateway relies on several heavy external libraries. To ensure tests remain fast and environment-independent, `conftest.py` installs idempotent mocks into `sys.modules` before test collection.\n\n* **Telegram Mock**: `_ensure_telegram_mock()` provides a `MagicMock` for `telegram`, `telegram.ext`, and `telegram.constants`. It includes real exception classes (e.g., `NetworkError`, `RetryAfter`) to ensure `except` blocks in production code function correctly.\n* **Discord Mock**: `_ensure_discord_mock()` provides a comprehensive mock for `discord.py`, including fake implementations of `ui.View`, `ui.Button`, and `app_commands`. This allows testing of complex interaction flows (like model pickers) without the actual library.\n\n## Agent Cache Testing\n\nThe `test_agent_cache.py` suite verifies the lifecycle of `AIAgent` instances within the `GatewayRunner`.\n\n### Cache-Busting Logic\nThe runner generates a signature for cached agents. The tests verify that the cache is correctly invalidated (busted) when specific configuration keys change:\n* `model.context_length`\n* `compression.enabled` / `compression.threshold`\n* `tools.registry_generation` (triggered by MCP reloads)\n\n### Safety & Eviction\nThe cache implements an LRU (Least Recently Used) policy and an idle-TTL sweep.\n* **Active Safety**: The `_enforce_agent_cache_cap` and `_sweep_idle_cached_agents` functions are tested to ensure they **skip** agents currently mid-turn (present in `_running_agents`). This prevents `agent.close()` from tearing down clients or sandboxes while a request is in flight.\n* **Soft vs. Hard Cleanup**: Tests distinguish between `release_clients()` (soft cleanup for cache eviction, preserving terminal/browser state) and `close()` (hard cleanup for session expiry).\n\n## Platform-Specific Helpers\n\n### Feishu Helpers\n`feishu_helpers.py` provides factory functions for Feishu-specific testing:\n* `make_sender` / `make_message`: Generates `SimpleNamespace` objects mimicking Feishu's nested ID structures.\n* `make_adapter_skeleton`: Manually constructs a `FeishuAdapter` with specific policies (allowlists, bot permissions) for unit testing admission logic.\n\n### Restart & Drain Helpers\n`restart_test_helpers.py` facilitates testing the gateway's graceful shutdown and restart logic.\n* **`RestartTestAdapter`**: A stub adapter that tracks sent messages and simulates connection states.\n* **`make_restart_runner`**: A factory that assembles a `GatewayRunner` with mocked hooks, session stores, and a controlled environment to test the `request_restart` flow and message draining.\n\n## API Server Integration Tests\n\nThe `test_api_server.py` suite covers the OpenAI-compatible gateway endpoint.\n\n### Key Components Tested:\n* **Idempotency**: `_IdempotencyCache` ensures that concurrent requests with the same key and fingerprint only trigger one agent execution.\n* **SSE Streaming**: Verifies that `stream=true` correctly handles:\n * Keepalive comments (`: keepalive`) during long tool executions.\n * Filtering of internal `None` sentinels used for UI box management.\n * **Tool Progress**: Verifies that tool lifecycle events are emitted as custom SSE events (`event: hermes.tool.progress`) rather than leaking into the `content` delta.\n* **Response Store**: Tests the LRU `ResponseStore` used for retrieving previous completions and chaining responses.\n\n## Failure Classification\n\n`test_7100_transient_failure_transcript.py` validates the logic used to decide if a failed agent turn should be persisted to the session transcript.\n\n| Failure Type | Classification | Transcript Action |\n| :--- | :--- | :--- |\n| Context Window Exceeded | Context Overflow | **Skip** (Prevents infinite loops) |\n| Rate Limit (429) | Transient | **Persist** (Agent remembers turn on retry) |\n| Read Timeout / 500 | Transient | **Persist** |\n| 400 (Short Session) | Client Error | **Persist** |\n\n```mermaid\ngraph TD\n A[Agent Result] --> B{Failed?}\n B -- No --> C[Persist Transcript]\n B -- Yes --> D{Is Context Overflow?}\n D -- Yes --> E[Skip Transcript]\n D -- No --> C\n \n subgraph \"Overflow Detection\"\n D1[compression_exhausted]\n D2[Token Limit Strings]\n D3[400 Error + Long History]\n end\n```","tests-hermes-cli":"# tests — hermes_cli\n\n# Hermes CLI Test Suite\n\nThe `tests/hermes_cli` module provides comprehensive test coverage for the Hermes command-line interface, focusing on authentication flows, provider integration, model management, and CLI-specific utilities. It ensures that the interaction between the user's environment, the `hermes_cli` logic, and external AI providers remains robust.\n\n## Core Testing Areas\n\n### 1. Provider Registry and Resolution\nThe suite extensively validates the `PROVIDER_REGISTRY` and the logic used to determine which AI provider to use based on environment variables or explicit flags.\n\n* **Provider Mapping:** Tests in `test_api_key_providers.py` verify that providers like `zai` (Zhipu), `kimi-coding` (Moonshot), `stepfun`, `minimax`, and `arcee` are correctly registered with their respective base URLs and environment variable keys.\n* **Alias Resolution:** Ensures that user-friendly aliases (e.g., `vercel` for `ai-gateway`, `moonshot` for `kimi-coding`) resolve to the correct internal provider ID via `resolve_provider()`.\n* **Auto-Detection:** Validates that `resolve_provider(\"auto\")` correctly prioritizes keys (e.g., `OPENROUTER_API_KEY` taking priority over `GLM_API_KEY`).\n* **Credential Resolution:** Tests `resolve_api_key_provider_credentials()` to ensure keys and base URLs are correctly extracted from the environment, including fallback logic for local servers like LM Studio.\n\n### 2. Authentication Flows\nA significant portion of the module is dedicated to complex OAuth and API key persistence flows.\n\n#### Anthropic OAuth & Stale Tokens\n`test_anthropic_model_flow_stale_oauth.py` and `test_anthropic_oauth_flow.py` pin the behavior for Anthropic's unique authentication requirements:\n* **Stale Token Detection:** Detects when an `ANTHROPIC_TOKEN` exists but is an expired OAuth token without valid Claude Code credentials, forcing a re-authentication prompt.\n* **Credential Linking:** Verifies that successful OAuth flows correctly link Claude Code credentials and clear conflicting environment variables.\n\n#### OpenAI Codex (ChatGPT)\n`test_auth_codex_provider.py` covers the specialized OAuth flow for Codex:\n* **Token Storage:** Validates reading/writing tokens to `~/.hermes/auth.json`.\n* **Refresh Logic:** Tests `refresh_codex_oauth_pure` against specific OpenAI error shapes (e.g., `refresh_token_reused`) to ensure the CLI provides actionable re-login guidance.\n\n#### Credential Pool\n`test_auth_commands.py` tests the `hermes auth add` command, ensuring that manually entered keys or OAuth results are correctly persisted into the `credential_pool` within the Hermes auth store.\n\n### 3. Model Management and Metadata\nThese tests ensure that model-specific information is accurate and provider-aware.\n\n* **AI Gateway Integration:** `test_ai_gateway_models.py` validates the translation of Vercel AI Gateway's pricing schema (`input`/`output`) into the internal `prompt`/`completion` format. It also tests the filtering of \"recommended\" and \"free\" models.\n* **Context Window Resolution:** `test_apply_model_switch_result_context.py` is a regression suite ensuring that the `/model` picker displays provider-specific context limits (e.g., 272K for Codex) rather than generic vendor limits (1M for GPT-4).\n* **Model Normalization:** `test_arcee_provider.py` and others verify that provider prefixes are correctly stripped or added during model selection (e.g., `arcee/trinity-mini` -> `trinity-mini`).\n\n### 4. CLI UX and Argument Parsing\n* **Flag Propagation:** `test_argparse_flag_propagation.py` ensures that flags like `--yolo` or `--worktree` are not lost when placed before subcommands. It verifies the use of `argparse.SUPPRESS` in subparsers to prevent default values from overwriting parent parser values.\n* **Context Completions:** `test_at_context_completion_filter.py` validates that the TUI/CLI completions for `@file:` and `@folder:` correctly filter the filesystem (e.g., `@folder:` should not suggest `.env` files).\n\n## Execution Flow: Provider Resolution\n\nThe following diagram illustrates how the test suite validates the resolution of a provider from a user request to runtime credentials.\n\n```mermaid\ngraph TD\n A[User Request / 'auto'] --> B{resolve_provider}\n B --> C[Check Env Vars]\n B --> D[Check Aliases]\n C --> E[Provider ID]\n D --> E\n E --> F{resolve_runtime_provider}\n F --> G[API Key Auth]\n F --> H[OAuth / Auth Store]\n F --> I[External Process]\n G --> J[Runtime Credentials]\n H --> J\n I --> J\n```\n\n## Utility Tests\nThe module also includes tests for low-level utilities used by the CLI:\n* **Atomic Writes:** `test_atomic_json_write.py` and `test_atomic_yaml_write.py` ensure that configuration and auth files are written using a temporary-file-and-rename pattern to prevent corruption during crashes or concurrent writes.\n\n## Contributor Notes\n* **Mocks:** The suite heavily uses `unittest.mock.patch` and `monkeypatch` to simulate network responses and filesystem states.\n* **Hermes Home:** Most tests use a `tmp_path` and set the `HERMES_HOME` environment variable to isolate configuration and auth state from the developer's actual machine.\n* **Adding Providers:** When adding a new provider, add a corresponding `test_<provider>_provider.py` and update the registry tests in `test_api_key_providers.py`.","tests-hermes-state":"# tests — hermes_state\n\n# Testing Session Redirection (hermes_state)\n\nThe `tests/hermes_state/test_resolve_resume_session_id.py` module provides regression testing for the session resolution logic within `SessionDB`. It specifically targets behaviors related to **Context Compression**, where a single logical conversation is split across multiple database session records.\n\n## Context: The Compression Problem (#15000)\n\nIn Hermes, when a conversation exceeds the context window, the system performs \"compression.\" This process:\n1. Ends the current session.\n2. Forks a new child session.\n3. Links the child to the parent via `parent_session_id`.\n\nBecause the SQLite flush cursor is reset during this fork, the parent session's `message_count` in the `sessions` table often drops to zero, while the new child session receives the subsequent messages. Previously, running `hermes --resume <parent_id>` would load the empty parent row and display a blank chat.\n\nThe `SessionDB.resolve_resume_session_id()` method was introduced to solve this by walking the descendant chain to find the actual content.\n\n## Redirection Logic\n\nThe tests verify that the resolution logic follows these rules:\n1. **Content Priority**: If the requested session has messages, return its ID immediately.\n2. **Chain Traversal**: If the requested session is empty, look for children. Follow the chain until a session with messages is found.\n3. **Deterministic Branching**: If a session has multiple children (a fork), the resolver must pick the descendant with the most recent `started_at` timestamp.\n4. **Safety Fallbacks**: If no descendants have messages, or if the ID does not exist, return the original ID to avoid breaking standard CLI expectations.\n\n```mermaid\ngraph TD\n A[Request ID: 'head'] --> B{Has Messages?}\n B -- Yes --> C[Return 'head']\n B -- No --> D{Has Children?}\n D -- No --> C\n D -- Yes --> E[Pick Latest Child: 'mid1']\n E --> F{Has Messages?}\n F -- No --> G[...]\n G --> H[Return 'bulk']\n```\n\n## Test Implementation Details\n\n### Fixtures and Helpers\n* **`db` fixture**: Initializes a transient `SessionDB` using a `tmp_path` to ensure test isolation.\n* **`_make_chain(db, ids_with_parent)`**: A utility that creates a lineage of sessions. It manually updates the `started_at` column in the SQLite database to ensure that session ordering is deterministic and not dependent on rapid-fire execution speeds.\n\n### Key Test Scenarios\n\n| Test Case | Purpose |\n|:---|:---|\n| `test_redirects_from_empty_head_to_descendant_with_messages` | Validates the primary fix for #15000: jumping from a root parent through multiple empty intermediates to the session containing the \"bulk\" of the messages. |\n| `test_walks_from_middle_of_chain` | Ensures that if a user resumes using an ID from the middle of a compressed chain, they are still redirected forward to the active content. |\n| `test_prefers_most_recent_child_when_fork_exists` | Tests the tie-breaking logic. If a session was forked into two different paths, the resolver follows the most recent temporal path. |\n| `test_returns_self_when_no_descendant_has_messages` | Ensures the resolver doesn't return `None` or an error if a user resumes a genuinely empty conversation chain. |\n\n## Database Interaction\nThese tests interact directly with the `sessions` table schema:\n* **`id`**: The primary session identifier.\n* **`parent_session_id`**: The foreign key used to reconstruct the conversation lineage.\n* **`started_at`**: Used to determine the \"latest\" path in the event of a fork.\n* **`messages` table**: The resolver checks for the existence of rows in this table linked to the session ID to determine if a session is \"empty.\"","tests-honcho-plugin":"# tests — honcho_plugin\n\n# Honcho Plugin Test Suite\n\nThe `tests/honcho_plugin` module provides comprehensive test coverage for the Honcho memory integration. It validates configuration parsing, session lifecycle management, asynchronous persistence strategies, and the tool-calling interface used by the Hermes agent.\n\n## Core Test Areas\n\n### 1. Configuration & Client Setup\nTests in `test_client.py` and `test_cli.py` verify how `HonchoClientConfig` assembles settings from environment variables, global configuration files, and host-specific overrides.\n\n* **Precedence Logic:** Validates that host-specific blocks (e.g., `hosts.hermes`) override root-level settings for fields like `workspace`, `aiPeer`, and `contextTokens`.\n* **Environment Fallbacks:** Ensures `HONCHO_API_KEY` and `HONCHO_BASE_URL` are correctly prioritized when file-based config is missing or partial.\n* **Connection Settings:** Tests the resolution of `baseUrl` and `timeout` (including aliases like `requestTimeout`), ensuring the `honcho` SDK receives the correct parameters.\n* **CLI Status:** `test_cli.py` mocks connection failures to ensure `cmd_status` accurately reports \"FAILED\" vs \"OK\" based on API reachability.\n\n### 2. Session Management & Identity\n`test_session.py` and `test_pin_peer_name.py` focus on how Hermes identifies conversations and users within the Honcho ecosystem.\n\n* **Session Naming:** Tests `resolve_session_name` across different strategies (`per-directory`, `per-repo`, `per-session`). It includes regression tests for the **100-character limit** on Honcho session IDs, verifying that long IDs (common in Matrix or Slack) are deterministically truncated and hashed.\n* **Peer Pinning (`pinPeerName`):** Validates the logic for unifying memory across platforms. If `pin_peer_name` is true, the system uses the configured `peer_name` instead of platform-native IDs (like Telegram UIDs), allowing a single user to share memory across different chat gateways.\n* **Sanitization:** Ensures session and peer IDs are stripped of invalid characters (colons, spaces, etc.) before being sent to the Honcho API via `_sanitize_id`.\n\n### 3. Asynchronous Persistence\n`test_async_memory.py` covers the non-blocking write system, which prevents API latency from stalling the agent's response loop.\n\n* **Write Frequencies:** Validates routing logic for `write_frequency` settings:\n * `turn`: Immediate synchronous flush.\n * `async`: Enqueue to background thread.\n * `session`: No flush until explicit shutdown/flush.\n * `int` (e.g., `3`): Flush every N turns.\n* **Writer Thread Lifecycle:** Tests the `_async_thread` startup, the use of `_ASYNC_SHUTDOWN` sentinels, and ensuring `flush_all()` drains the queue before exit.\n* **Retry Mechanism:** `TestAsyncWriterRetry` verifies that the background worker retries failed network calls (e.g., `ConnectionError`) exactly once before dropping the message to prevent infinite loops.\n\n### 4. Memory Provider & Tools\n`test_empty_profile_hint.py` and `test_session.py` exercise the `HonchoMemoryProvider` and its interaction with the agent's tool-calling system.\n\n* **Tool Dispatch:** Validates parameters and outputs for:\n * `honcho_profile`: Returns peer cards or helpful hints if the profile is empty.\n * `honcho_conclude`: Handles creation and deletion of memory facts, enforcing that exactly one of `conclusion` or `delete_id` is provided.\n * `honcho_search` / `honcho_reasoning`: Verifies context retrieval and dialectic multi-pass reasoning.\n* **Context Truncation:** Tests `_truncate_to_budget`, ensuring that injected memory context stays within the `context_tokens` limit by truncating at word boundaries.\n* **Message Chunking:** Tests `_chunk_message` logic, which splits oversized messages into smaller segments with `[continued]` prefixes to satisfy Honcho API constraints.\n\n## Execution Flow: Async Save\n\n```mermaid\ngraph TD\n A[HonchoMemoryProvider.sync_turn] --> B[HonchoSessionManager.save]\n B --> C{write_frequency?}\n C -- \"turn\" --> D[Immediate _flush_session]\n C -- \"async\" --> E[Put in _async_queue]\n E --> F[Async Writer Thread]\n F --> G[_flush_session]\n G -- \"Failure\" --> H[Retry once after sleep]\n```\n\n## Key Components Tested\n\n| Class/Function | Responsibility Tested |\n| :--- | :--- |\n| `HonchoSession` | In-memory message buffer, history formatting, and timestamp tracking. |\n| `HonchoSessionManager` | Peer/Session caching, ID sanitization, and routing saves to the async worker. |\n| `HonchoClientConfig` | Complex JSON/Env merging and session name resolution logic. |\n| `HonchoMemoryProvider` | Tool schema validation, context injection, and dialectic reasoning orchestration. |\n| `_chunk_message` | Splitting large text blocks at paragraph/sentence boundaries. |\n| `migrate_memory_files` | Uploading local `MEMORY.md` or `SOUL.md` files to Honcho peers. |\n\n## Utility Helpers\nThe suite uses several internal helpers to simplify setup:\n* `_make_session`: Creates a `HonchoSession` with default test IDs.\n* `_make_manager`: Initializes a manager with a mocked `Honcho` client.\n* `_make_provider`: Sets up a full provider with mocked config and session state for tool testing.\n* `_settle_prewarm`: A synchronization helper that waits for background pre-warm threads to finish before assertions run.","tests-integration":"# tests — integration\n\n# Integration Tests\n\nThe `tests/integration` module contains end-to-end tests designed to verify the interaction between the system's core logic and external services, platforms, and hardware-abstracted tools. Unlike unit tests, these modules often perform real network I/O, interact with external sandboxes, or simulate complex stateful protocols like Discord's voice encryption.\n\nAll tests in this module are marked with `@pytest.mark.integration`.\n\n## Module Architecture\n\nThe integration suite is organized by the functional area it exercises:\n\n```mermaid\ngraph TD\n subgraph \"Integration Tests\"\n A[Batch Processing] --> B[test_batch_runner.py]\n A --> C[test_checkpoint_resumption.py]\n D[Terminal Backends] --> E[test_modal_terminal.py]\n D --> F[test_daytona_terminal.py]\n G[Platform Adapters] --> H[test_ha_integration.py]\n G --> I[test_voice_channel_flow.py]\n J[Web Tools] --> K[test_web_tools.py]\n end\n B -.-> Runner[BatchRunner]\n E -.-> Term[terminal_tool]\n H -.-> HA[HomeAssistantAdapter]\n I -.-> Voice[VoiceReceiver]\n```\n\n---\n\n## Batch Processing & Resumption\n\nThese tests ensure the reliability of long-running batch jobs.\n\n### `test_batch_runner.py`\nVerifies the standard execution flow of the `BatchRunner`. It creates a temporary JSONL dataset, executes a mock-configured run, and validates that:\n* `checkpoint.json` is created.\n* `statistics.json` contains accurate prompt counts and durations.\n* Output batch files are correctly partitioned.\n\n### `test_checkpoint_resumption.py`\nA specialized test for the `BatchRunner`'s fault tolerance. It simulates process interruptions to verify:\n* **Incremental Saving:** Uses a monitoring thread to check if `checkpoint.json` updates during the run rather than just at the end.\n* **Resume Logic:** Validates that when `run(resume=True)` is called, the runner skips already-completed prompts and maintains data integrity.\n\n---\n\n## Terminal Backends\n\nThese tests verify the `terminal_tool` across different remote execution environments. They require specific environment variables (e.g., `MODAL_TOKEN_ID`, `DAYTONA_API_KEY`).\n\n### `test_modal_terminal.py` & `test_daytona_terminal.py`\nBoth scripts follow a similar validation pattern for their respective backends:\n1. **Requirements Check:** Validates API keys and local configuration (e.g., `~/.modal.toml`).\n2. **Command Execution:** Runs basic shell commands and Python scripts to verify the runtime.\n3. **Persistence:** Confirms that files written in one `terminal_tool` call persist in subsequent calls within the same `task_id`.\n4. **Isolation:** Ensures that different `task_id` values result in completely isolated environments.\n\n---\n\n## Platform Integrations\n\n### `test_ha_integration.py` (Home Assistant)\nThis module tests the `HomeAssistantAdapter` and its associated tools using a `FakeHAServer` (a local aiohttp-based mock of the HA API).\n* **WebSocket Flow:** Tests the full handshake: `auth_required` -> `auth` -> `auth_ok` -> `subscribe_events`.\n* **Event Forwarding:** Verifies that state changes pushed by the server are correctly filtered by `watch_domains` and forwarded to the gateway.\n* **REST Tools:** Exercises `_async_call_service`, `_async_get_state`, and `_async_list_entities` against real TCP connections.\n\n### `test_voice_channel_flow.py` (Discord Voice)\nA high-fidelity simulation of the Discord voice pipeline. It does not connect to Discord but uses real `PyNaCl` encryption and `Opus` codecs to test the `VoiceReceiver` class.\n* **Packet Processing:** Generates real RTP packets with NaCl AEAD encryption to test `_on_packet` decryption.\n* **RTP Handling:** Validates RFC 3550 compliance by testing the stripping of RTP padding and header extensions.\n* **Silence Detection:** Simulates a stream of audio followed by a pause to verify that `check_silence()` correctly identifies and returns completed utterances.\n* **DAVE Passthrough:** Tests the interaction with Discord's \"DAVE\" end-to-end encryption protocol.\n\n---\n\n## Web Tools\n\n### `test_web_tools.py`\nValidates the `web_search_tool`, `web_extract_tool`, and `web_crawl_tool` using either the Firecrawl or Parallel backends.\n* **Search Validation:** Checks that search results contain required fields (`url`, `title`, `description`).\n* **Extraction:** Tests both raw Markdown extraction and LLM-augmented extraction (if an auxiliary model is configured).\n* **Crawling:** Verifies that the crawler follows instructions and returns multiple pages from a target domain.\n\n---\n\n## Running Integration Tests\n\nIntegration tests are skipped by default in some environments due to their reliance on external API keys. To run them:\n\n```bash\n# Run all integration tests\npytest -m integration\n\n# Run a specific integration test with verbose output\nTERMINAL_ENV=modal pytest tests/integration/test_modal_terminal.py -v\n```\n\n### Required Environment Variables\n| Variable | Used By |\n| :--- | :--- |\n| `MODAL_TOKEN_ID` / `MODAL_TOKEN_SECRET` | `test_modal_terminal.py` |\n| `DAYTONA_API_KEY` | `test_daytona_terminal.py` |\n| `FIRECRAWL_API_KEY` or `PARALLEL_API_KEY` | `test_web_tools.py` |\n| `OPENROUTER_API_KEY` | `test_web_tools.py` (LLM features) |","tests-openviking-plugin":"# tests — openviking_plugin\n\n# OpenViking Plugin Tests\n\nThe `tests/openviking_plugin/test_openviking.py` module provides a comprehensive test suite for the `OpenVikingMemoryProvider`. It focuses on validating URI normalization, content retrieval logic (including fallback mechanisms), and the transformation of API responses into standardized internal formats.\n\n## Mocking Strategy\n\nThe tests utilize a `FakeVikingClient` to simulate the OpenViking API. This mock client:\n- Stores a dictionary of responses keyed by a tuple of `(path, sorted_params)`.\n- Tracks all calls made to the `get` method in a `calls` list for assertion.\n- Simulates network or server errors by raising exceptions stored in the response map.\n\n## Core Test Areas\n\n### 1. URI Normalization\nThe provider uses \"pseudo-files\" to represent directory summaries. The tests verify that `_normalize_summary_uri` correctly strips these suffixes to target the actual directory resource.\n\n| Input URI | Normalized Output |\n| :--- | :--- |\n| `viking://user/hermes/.overview.md` | `viking://user/hermes` |\n| `viking://resources/.abstract.md` | `viking://resources` |\n| `viking://path/to/file.md` | `viking://path/to/file.md` |\n\n### 2. Content Retrieval (`_tool_read`)\nThe `_tool_read` method logic is complex because it must decide between the `overview` endpoint (for directories) and the `read` endpoint (for files). The tests validate three distinct execution paths:\n\n#### Path A: Pseudo-Summary URI\nIf the URI ends in a pseudo-file (like `.overview.md`), the provider skips metadata checks and calls the `/api/v1/content/overview` endpoint directly.\n\n#### Path B: Standard URI with `fs/stat` Probe\nFor standard URIs, the provider calls `/api/v1/fs/stat` to determine if the target is a directory or a file:\n- **If Directory:** Calls `/api/v1/content/overview`.\n- **If File:** Calls `/api/v1/content/read`.\n\n#### Path C: Fallback Mechanism\nIf the `fs/stat` probe fails or returns an indeterminate result, the provider attempts to call the overview endpoint. If that fails, it falls back to a full content read as a last resort.\n\n```mermaid\ngraph TD\n A[Read Request] --> B{Is Pseudo-URI?}\n B -- Yes --> C[API: content/overview]\n B -- No --> D[API: fs/stat]\n D -- isDir: true --> C\n D -- isDir: false --> E[API: content/read]\n D -- Error --> F[Try content/overview]\n F -- Error --> E\n```\n\n### 3. Directory Browsing (`_tool_browse`)\nThe tests ensure that the `_tool_browse` method correctly normalizes inconsistent API response shapes from the `/api/v1/fs/ls` endpoint.\n\nThe provider maps various upstream fields to a consistent internal schema:\n- **Path Mapping:** Converts `rel_path` to `name` if `name` is missing.\n- **Type Mapping:** Converts boolean `isDir` to string `type` (`dir` or `file`).\n- **Defaulting:** Ensures the `abstract` field exists, defaulting to an empty string if not provided by the API.\n\n## Key Test Cases\n\n| Test Name | Purpose |\n| :--- | :--- |\n| `test_overview_read_normalizes_uri` | Validates that reading an `.overview.md` file correctly targets the parent directory's summary. |\n| `test_overview_file_uri_routes_straight_to_content_read` | Confirms that if `fs/stat` identifies a file, the \"overview\" request is fulfilled by a full file read. |\n| `test_overview_file_uri_falls_back_via_exception` | Validates the resilience of the provider when multiple API endpoints fail sequentially. |\n| `test_list_browse_unwraps_and_normalizes` | Ensures the directory listing logic can handle mixed response formats (e.g., some entries using `isDir` and others using `type`). |\n\n## Usage for Contributors\nWhen modifying the `OpenVikingMemoryProvider`, ensure that:\n1. New API response fields are added to the normalization logic in `test_list_browse_unwraps_and_normalizes`.\n2. Any changes to the routing logic (how the provider chooses between `overview` and `read`) are reflected in the `TestOpenVikingRead` class.\n3. The `FakeVikingClient` is updated if the provider begins using new HTTP methods (e.g., `POST` or `PUT`).","tests-plugins":"# tests — plugins\n\n# Tests — Plugins Module\n\nThe `tests/plugins` module provides a comprehensive suite of unit and integration tests for the Hermes Agent plugin ecosystem. It ensures that external integrations—specifically image generation and long-term memory providers—adhere to the expected interfaces, handle configuration correctly, and manage resources (like threads and event loops) without leaking.\n\n## Architecture Overview\n\nThe test suite mirrors the plugin directory structure, focusing on the two primary plugin categories: `image_gen` and `memory`.\n\n```mermaid\ngraph TD\n T[Test Suite] --> IG[Image Gen Tests]\n T --> M[Memory Provider Tests]\n T --> U[Utility/Dashboard Tests]\n \n IG --> OpenAI[OpenAI / Codex]\n IG --> XAI[xAI / Grok]\n \n M --> HS[Hindsight]\n M --> M0[Mem0 v2]\n M --> SM[Supermemory]\n```\n\n## Image Generation Provider Tests\n\nThese tests verify that image providers correctly map user prompts and aspect ratios to provider-specific API calls.\n\n### OpenAI & OpenAI-Codex\nThe suite distinguishes between the standard OpenAI REST API and the \"Codex\" (ChatGPT-OAuth) path.\n* **Model Tiers:** Validates the three-tier system (`low`, `medium`, `high`) and ensures they map to the correct `quality` parameters while targeting the underlying `gpt-image-2` model.\n* **Codex Stream Handling:** `test_openai_codex_provider.py` specifically tests the tool-based stream path. It mocks `response.output_item.done` and `partial_image` events to ensure images are captured even if the stream is interrupted.\n* **Aspect Ratio Mapping:** Verifies that \"landscape\", \"portrait\", and \"square\" correctly translate to pixel dimensions (e.g., `1536x1024`).\n\n### xAI (Grok)\n* **Authentication:** Ensures the provider is unavailable if `XAI_API_KEY` is missing.\n* **Response Handling:** Tests both Base64 JSON responses and direct URL returns.\n\n## Memory Provider Tests\n\nMemory plugins are the most complex to test due to their asynchronous nature and lifecycle requirements.\n\n### Hindsight Provider\nThe Hindsight tests (`test_hindsight_provider.py`) are the reference implementation for testing complex memory lifecycles:\n* **Shared Event Loop Lifecycle:** Crucial tests ensure that calling `shutdown()` on one provider instance does not stop the module-global event loop, which would orphan `aiohttp` sessions for other concurrent agents.\n* **Sync Turn Logic:** Validates that conversation turns are batched and sent to the \"Bank\" based on the `retain_every_n_turns` configuration.\n* **Bank ID Templates:** Tests the dynamic resolution of bank IDs using placeholders like `{profile}`, `{platform}`, and `{user}`, including sanitization logic that converts emails or special characters into safe segments.\n* **Prefetching:** Verifies that background threads correctly truncate long queries and populate the `_prefetch_result` before the LLM requests it.\n\n### Mem0 (v2) Compatibility\nFocuses on the migration from Mem0 v1 to v2:\n* **Filter Migration:** Ensures that `user_id` and `agent_id` are passed within a `filters={}` dictionary rather than as bare keyword arguments.\n* **Response Unwrapping:** Validates that the provider correctly extracts data from the v2 `{\"results\": [...]}` wrapper while maintaining backward compatibility for bare lists.\n\n### Supermemory Provider\n* **Multi-Container Logic:** Tests the \"whitelisting\" of container tags. If `enable_custom_container_tags` is active, the test ensures the tool schema dynamically includes `container_tag` as a parameter.\n* **Text Cleaning:** Verifies that `<supermemory-context>` tags injected during prefetch are stripped before the text is re-captured into long-term memory to prevent \"hallucination loops.\"\n\n### OpenViking Provider\n* **Cross-Bucket Ranking:** Specifically tests the logic that merges and sorts results from `memories`, `resources`, and `skills` buckets based on raw scores.\n\n## Utility and Dashboard Tests\n\n### Achievements Plugin\nThe `test_achievements_plugin.py` focuses on integration performance:\n* **Full History Scanning:** Verifies the removal of the 200-session scan limit, ensuring the plugin can walk the entire SQLite database.\n* **Non-Blocking Initialization:** Ensures that the first-ever scan runs in a background thread so the dashboard UI remains responsive.\n\n## Common Testing Patterns\n\n### Mocking External Clients\nMost tests use a `FakeClient` or `MagicMock` to intercept API calls. For providers using `aiohttp` or asynchronous libraries (like Hindsight), the tests utilize a shared event loop pattern to simulate real-world async execution within a synchronous `pytest` environment.\n\n### Environment Isolation\nTests frequently use the `_tmp_hermes_home` fixture to redirect `HERMES_HOME` to a temporary directory. This prevents tests from reading the developer's actual `config.yaml` or writing to the real `cache/` directory.\n\n### Hyphenated Module Imports\nBecause some plugin directories use hyphens (e.g., `openai-codex`), which are invalid in standard Python import statements, the tests use `importlib.import_module` to load the plugin code:\n```python\ncodex_plugin = importlib.import_module(\"plugins.image_gen.openai-codex\")\n```","tests-run-agent":"# tests — run_agent\n\n# tests — run_agent\n\nThe `tests/run_agent/` directory contains the test suite for the core agent execution logic, primarily targeting `run_agent.py` and `environments/agent_loop.py`. These tests verify the agent's lifecycle, including multi-turn conversations, tool execution, error recovery, context window management, and session persistence.\n\n## Test Infrastructure and Fast-Pathing\n\nTo ensure the test suite remains performant, `conftest.py` implements a global fast-path for retry logic.\n\n* **`_fast_retry_backoff`**: An autouse fixture that monkeypatches `run_agent.jittered_backoff` to return `0.0`. This collapses the production `while time.time() < sleep_end` loops, allowing tests to exercise retry paths without waiting for real-world backoff delays.\n* **Selective Mocking**: `time.sleep` is deliberately *not* mocked globally, as specific tests (e.g., thread coordination or interrupt propagation) rely on real timing or assert specific sleep durations.\n\n## Core Testing Areas\n\n### 1. Context Management and Compression\nTests in `test_413_compression.py` and `test_1630_context_overflow_loop.py` verify how the agent handles LLM context window limits.\n\n* **Error Heuristics**: The agent identifies context overflows not just by HTTP 413 status codes, but also by parsing HTTP 400 error messages for phrases like \"maximum context length\" or \"too many tokens.\"\n* **Large Session Heuristic**: If a generic 400 error occurs and the session is large (>40% of context window or >80 messages), the agent treats it as a probable context overflow and triggers compression.\n* **Compression Flow**:\n 1. Detect 413/400 context error.\n 2. Invoke `_compress_context`.\n 3. Reset `_last_flushed_db_idx` to 0.\n 4. Retry the API call with the compressed history.\n* **Persistence Guard**: To prevent infinite loops where a failed session keeps growing, the gateway is tested to ensure it skips message persistence if the agent fails early due to context exhaustion.\n\n### 2. Agent Guardrails\n`test_agent_guardrails.py` validates static methods on `AIAgent` designed to sanitize LLM outputs before they reach the tool execution or persistence layers.\n\n* **`_sanitize_api_messages`**: Repairs orphaned tool pairs. It removes tool results that have no matching call and injects stub results for tool calls that the LLM failed to provide results for.\n* **`_cap_delegate_task_calls`**: Enforces concurrency limits on sub-agent creation by truncating `delegate_task` calls exceeding `MAX_CONCURRENT_CHILDREN`.\n* **`_deduplicate_tool_calls`**: Identifies and removes identical tool calls (same tool, same arguments) within a single turn to prevent redundant execution.\n\n### 3. Session Persistence and Deduplication\n`test_860_dedup.py` ensures that the SQLite session transcript remains clean across multiple flushes.\n\n* **Incremental Flushing**: `_flush_messages_to_session_db` uses the `_last_flushed_db_idx` pointer to ensure only new messages are written to the database, even if `_persist_session` is called multiple times in a single turn.\n* **JSONL vs. SQLite**: Tests verify that `append_to_transcript(skip_db=True)` correctly writes to the JSONL log while bypassing the SQLite database, a pattern used when the agent has already handled its own persistence.\n\n### 4. HermesAgentLoop (Multi-turn Engine)\n`test_agent_loop.py` and `test_agent_loop_tool_calling.py` test the `HermesAgentLoop` class, which manages the iterative \"Think-Act-Observe\" cycle.\n\n* **Mock Server Infrastructure**: Uses a `MockServer` to simulate `chat_completion` responses, allowing for deterministic testing of turn counts, tool call handling, and reasoning extraction.\n* **Reasoning Extraction**: Verifies that `_extract_reasoning_from_message` correctly pulls thinking blocks from various provider formats (e.g., `reasoning_content`, `reasoning_details`, or `<think>` tags).\n* **Tool Blocking**: Ensures that specific tools (like `memory` or `session_search`) are blocked or return errors when running in restricted environments (e.g., RL training loops).\n\n### 5. Provider-Specific Error Handling\n`test_anthropic_error_handling.py` covers the specific retry logic for the Anthropic API mode.\n\n* **Retryable Errors**: 429 (Rate Limit), 529 (Overloaded), and 500 (Server Error) trigger the backoff loop.\n* **Non-Retryable Errors**: 400 (Bad Request) fails immediately to prevent wasting tokens.\n* **Credential Refresh**: 401 (Unauthorized) triggers a call to `_try_refresh_anthropic_client_credentials` and a single retry.\n\n## Execution Flow: Context Overflow Recovery\n\nThe following diagram illustrates the logic tested in the compression and retry modules:\n\n```mermaid\ngraph TD\n A[Start API Call] --> B{API Error?}\n B -- No --> C[Process Response]\n B -- Yes --> D{Error Type?}\n D -- 429/500/529 --> E[Jittered Backoff & Retry]\n D -- 413 / Context 400 --> F[Invoke _compress_context]\n D -- Generic 400 --> G{Large Session?}\n G -- Yes --> F\n G -- No --> H[Abort: Client Error]\n F --> I[Reset _last_flushed_db_idx]\n I --> A\n```\n\n## Key Components for Contributors\n\n* **`MockServer`**: Located in `test_agent_loop.py`, this is the preferred way to test agent logic without hitting real APIs. It allows you to queue a sequence of `MockChatCompletion` objects.\n* **`_make_agent`**: Most test files contain a helper to instantiate a minimal `AIAgent` with mocked dependencies (OpenAI client, tool definitions, etc.).\n* **Integration Tests**: `test_agent_loop_vllm.py` provides a template for testing against a local vLLM instance, which is critical for verifying token ID and logprob generation used in Reinforcement Learning (RL) workflows.","tests-skills":"# tests — skills\n\n# Skills Testing Module\n\nThe **tests — skills** module provides comprehensive regression and unit testing for the core productivity and utility skills within the Hermes ecosystem. These tests ensure the reliability of external integrations (Google Workspace, Twilio), data persistence (Flashcards), and system-wide migration tools.\n\n## Core Test Suites\n\n### 1. Google Workspace Integration\nTests for Google Workspace are split between OAuth setup and API execution.\n\n#### OAuth Setup (`test_google_oauth_setup.py`)\nThis suite validates the headless/manual authorization code flow used to grant Hermes access to Gmail, Calendar, Drive, and other Workspace APIs.\n- **PKCE Material Persistence**: Ensures that `code_verifier` and `state` are correctly saved to `google_oauth_pending.json` during the initial URL generation and retrieved during the code exchange.\n- **Token Exchange**: Validates that the `exchange_auth_code` function correctly handles both raw codes and redirect URLs, extracts scopes, and persists the final token to `google_token.json`.\n- **Scope Validation**: Tests the \"v2.0 migration\" logic where partial scopes are accepted with a warning rather than failing the entire exchange.\n\n#### API Bridge (`test_google_workspace_api.py`)\nTests the `gws_bridge.py` and `google_api.py` scripts which act as a CLI wrapper for Google services.\n- **Token Management**: Verifies that expired tokens trigger an automatic refresh via `urllib.request` and that the new token is persisted with the `authorized_user` type.\n- **Subprocess Injection**: Confirms that `gws_bridge.py` correctly injects the `GOOGLE_WORKSPACE_CLI_TOKEN` into the environment before calling the `gws` binary.\n- **Calendar Operations**: Validates that date ranges and calendar IDs are correctly transformed into JSON parameters for the CLI.\n\n### 2. Memento Flashcards (`test_memento_cards.py`, `test_youtube_quiz.py`)\nThis suite covers the spaced-repetition system and its associated content generation tools.\n\n#### Card Management\n- **CRUD Operations**: Validates adding, listing, and deleting cards or entire collections.\n- **Spaced Repetition Logic**: Tests the `rate` command's effect on card scheduling:\n - `hard`: Resets ease streak, adds 1 day.\n - `good`: Adds 3 days.\n - `easy`: Increments ease streak, adds 7 days.\n - **Auto-Retirement**: Confirms cards are marked as `retired` after 3 consecutive `easy` ratings or a manual `retire` command.\n- **Data Integrity**: Ensures atomic writes to `cards.json` and handles recovery from corrupted JSON files.\n\n#### YouTube Quiz Generation\n- **Transcript Fetching**: Tests `youtube_quiz.py` integration with `youtube-transcript-api`, including error handling for unavailable videos or missing dependencies.\n- **Text Normalization**: Validates the `_normalize_segments` function which collapses whitespace and joins transcript fragments into a clean string for LLM processing.\n\n### 3. OpenClaw Migration (`test_openclaw_migration.py`, `test_openclaw_migration_hardening.py`)\nTests the `openclaw_to_hermes.py` script, which migrates user data, memories, and configurations from legacy OpenClaw installations.\n\n#### Migration Logic\n- **Rebranding**: Validates `rebrand_text`, which performs case-sensitive replacement of legacy terms (e.g., `OpenClaw` -> `Hermes`, `~/.openclaw` -> `~/.hermes`).\n- **Memory Merging**: Tests the extraction of Markdown entries and the merging of daily notes into the long-term `MEMORY.md` file, respecting character limits.\n- **Conflict Resolution**: Validates `skill_conflict_mode` settings (`rename`, `overwrite`, `skip`) when importing skills that already exist in the target directory.\n\n#### Hardening & Security\n- **Secret Redaction**: Tests `redact_migration_value`, which recursively scrubs API keys (OpenRouter, Anthropic, Slack, etc.) from migration reports using pattern matching.\n- **Execution Sequencing**: Ensures that if a conflict occurs while writing `config.yaml`, subsequent configuration mutations are blocked to prevent partial or corrupt state.\n- **JSON Output**: Validates the `--json` flag for structured reporting in CI/CD pipelines.\n\n### 4. Telephony Skill (`test_telephony_skill.py`)\nCovers the `telephony.py` script used for Twilio and Vapi integrations.\n- **Environment Management**: Tests `_upsert_env_file` to ensure Twilio SIDs and tokens are correctly written to the `.env` file without overwriting unrelated variables.\n- **Inbox Checkpointing**: Validates that `_twilio_inbox` correctly identifies new messages by comparing SIDs against the `last_inbound_message_sid` stored in `telephony_state.json`.\n- **Provider Diagnostics**: Tests the `diagnose()` function, which generates a decision tree of available telephony providers based on current configuration.\n\n## Testing Patterns & Infrastructure\n\n### Mocking Strategy\nThe module relies heavily on `pytest` fixtures and `monkeypatch` to simulate external environments:\n- **Filesystem Isolation**: Uses `tmp_path` to redirect all file operations (tokens, cards, configs) to temporary directories.\n- **Module Mocking**: Dynamically creates `types.ModuleType` objects to simulate missing dependencies like `google_auth_oauthlib` or `hermes_constants` in CI environments.\n- **Subprocess Mocking**: Patches `subprocess.run` to capture command-line arguments and environment variables without executing real binaries.\n\n### Data Flow: Google OAuth Test Pattern\n```mermaid\ngraph TD\n A[pytest: setup_module] --> B[Create FakeFlow/FakeCredentials]\n B --> C[Mock sys.modules]\n C --> D[Execute get_auth_url]\n D --> E[Verify PENDING_AUTH_PATH JSON]\n E --> F[Execute exchange_auth_code]\n F --> G[Verify TOKEN_PATH JSON]\n G --> H[Cleanup PENDING_AUTH_PATH]\n```\n\n### Key Helper Functions\n- `_run(capsys, argv)`: Used in Memento tests to simulate CLI execution and capture JSON output from `stdout`.\n- `load_module()`: A utility used in migration and telephony tests to import scripts from relative paths outside the standard Python path.\n- `_make_minimal_migrator()`: Factory function for creating `Migrator` instances with controlled dry-run settings.","tests-stress":"# tests — stress\n\n# Stress and Battle-Test Suite\n\nThe `tests/stress` module contains long-running, adversarial tests designed to exercise the Kanban kernel under heavy load and edge-case conditions. Unlike the standard unit tests, these suites often spawn real subprocesses, simulate high concurrency, and perform randomized property-based fuzzing.\n\nDue to their execution time (30s+ per file) and resource requirements, these tests are **not run by the default test script**.\n\n## Execution\n\nStress tests are opted into via a `pytest` flag or by running the scripts directly as Python modules.\n\n```bash\n# Run all stress tests via pytest\n./venv/bin/python -m pytest tests/stress/ --run-stress -v -s\n\n# Run individual suites directly\n./venv/bin/python tests/stress/test_concurrency.py\n./venv/bin/python tests/stress/test_property_fuzzing.py\n./venv/bin/python tests/stress/test_benchmarks.py\n```\n\n## Concurrency and Race Conditions\n\nThe concurrency suite validates the kernel's locking mechanisms and SQLite WAL (Write-Ahead Logging) stability.\n\n* **`test_concurrency.py`**: Simulates 5 workers racing to claim 100 tasks. It asserts that no task is double-claimed, every completion has a matching claim, and no SQLite locking errors escape the internal retry logic.\n* **`test_concurrency_mixed.py`**: A more complex simulation involving 10 workers and a background reclaimer. Workers randomly perform `claim`, `complete`, `block`, `unblock`, and `archive` operations.\n* **`test_concurrency_reclaim_race.py`**: Specifically targets the race between a worker's `complete_task` and the dispatcher's `release_stale_claims`. It sets a Task TTL shorter than the work duration to force the reclaimer to yank tasks mid-work, verifying that the worker's late completion is correctly refused via CAS (Compare-And-Swap) on the task status.\n\n## Property-Based Fuzzing\n\n`test_property_fuzzing.py` executes randomized operation sequences (create, claim, complete, block, etc.) and validates the entire database state against a set of core invariants after every step.\n\n### System Invariants\n| ID | Invariant Description |\n|:---|:---|\n| **I1** | If `current_run_id` is set, the run must exist and its `ended_at` must be NULL. |\n| **I2** | Every open run (NULL `ended_at`) must be pointed to by a task's `current_run_id`. |\n| **I3** | Task status must be one of the seven valid states (triage, todo, ready, etc.). |\n| **I4** | `claim_lock` must be NULL unless the task status is `running`. |\n| **I5** | For all runs, `started_at` must be less than or equal to `ended_at`. |\n| **I6** | If a run has an `outcome`, it must have an `ended_at` timestamp. |\n| **I8** | `task_events.run_id` must reference a valid `task_runs.id` or be NULL. |\n| **I9** | If all parents of a task are `done`, the child cannot remain in `todo` status. |\n\n## End-to-End Subprocess Lifecycle\n\n`test_subprocess_e2e.py` validates the integration between the `kanban_db` kernel and the OS process model.\n\n1. **Real Spawning**: Uses a `spawn_fn` that calls `subprocess.Popen` to launch `_fake_worker.py`.\n2. **CLI Integration**: The worker process communicates back to the kernel using the actual `hermes kanban heartbeat` and `complete` CLI commands.\n3. **Crash Detection**: Validates `detect_crashed_workers` by spawning a process, killing it with `SIGKILL`, and verifying the kernel detects the dead PID and moves the task back to `ready` with a `crashed` run outcome.\n4. **Log Capture**: Verifies that worker `stdout/stderr` is correctly redirected to the `HERMES_HOME/kanban/logs/` directory.\n\n```mermaid\ngraph TD\n D[Dispatcher] -->|dispatch_once| K[Kanban Kernel]\n K -->|spawn_fn| W[Subprocess Worker]\n W -->|CLI: heartbeat| K\n W -->|CLI: complete| K\n D -->|detect_crashed_workers| P[OS Process Table]\n P -.->|Check PID| D\n```\n\n## Atypical Scenarios\n\n`test_atypical_scenarios.py` contains 28+ isolated scenarios testing the \"dark corners\" of the system:\n* **Data Extremes**: 1MB task bodies, 50-level deep metadata JSON, and Unicode/Emoji/RTL string handling.\n* **Graph Pathologies**: Detection and rejection of dependency cycles (A → B → A) and self-parenting.\n* **Environment**: `HERMES_HOME` paths containing spaces, symlinks, or non-ASCII characters.\n* **Security**: Empirical verification that SQL injection payloads in titles or assignees are neutralized by parameterized queries.\n* **Idempotency**: Races where two processes attempt to `create_task` with the same `idempotency_key` simultaneously.\n\n## Performance Benchmarking\n\n`test_benchmarks.py` measures kernel latency at scales of 100, 1,000, and 10,000 tasks. It records metrics for:\n* `dispatch_once` latency.\n* `recompute_ready` performance on wide fan-out graphs.\n* `build_worker_context` overhead for tasks with many parents or large comment histories.\n* `board_stats` and `list_tasks` query timings.\n\nResults are output as a summary table and saved to `/tmp/kanban_bench_results.json` for regression tracking.","tests-tests":"# tests — tests\n\n# Hermes Agent Test Suite\n\nThe `tests` module provides a hermetic, deterministic environment for validating the Hermes Agent. It is designed to ensure that tests run identically in local development environments and CI by strictly isolating the agent's state, configuration, and credentials.\n\n## Hermetic Test Invariants\n\nThe test suite enforces several invariants via `tests/conftest.py` to prevent \"works on my machine\" bugs and credential leakage. These are applied automatically to every test via the `_hermetic_environment` fixture.\n\n1. **Credential Isolation**: All environment variables matching credential patterns (e.g., `*_API_KEY`, `*_TOKEN`, `AWS_ACCESS_KEY_ID`) are unset before every test. This prevents local developer keys from leaking into tests that assert provider auto-detection.\n2. **Isolated HERMES_HOME**: `HERMES_HOME` is redirected to a per-test temporary directory. This ensures that tests cannot see or modify the user's real `~/.hermes/` configuration, sessions, or memories.\n3. **Deterministic Runtime**: The environment is pinned to `TZ=UTC`, `LANG=C.UTF-8`, and `PYTHONHASHSEED=0` to ensure date and locale-sensitive tests are stable.\n4. **Behavioral Reset**: Specific `HERMES_*` behavioral flags (like `HERMES_YOLO_MODE` or `HERMES_MANAGED`) are cleared to ensure tests start from a default state.\n5. **AWS IMDS Disabling**: AWS metadata service lookups are disabled and timed out quickly to prevent 2-second hangs during provider detection in non-EC2 environments.\n\n## State Management and Isolation\n\nBecause `pytest-xdist` workers are long-lived, Python module singletons and `ContextVars` can leak state between tests. The `_reset_module_state` fixture explicitly clears mutable state in the following areas:\n\n* **`tools.approval`**: Clears session approvals, YOLO mode flags, and pending queues.\n* **`gateway.session_context`**: Resets `ContextVars` representing the active gateway session (Platform, Chat ID, User ID, etc.).\n* **`tools.terminal_tool`**: Clears cached environments and working directories to prevent path resolution pollution.\n* **`tools.file_tools`**: Resets the read history tracker used for loop detection.\n* **`tools.registry`**: Invalidates the `check_fn` cache to ensure tool availability is re-evaluated per test.\n\n### Global Test Timeout\nTo prevent hanging the entire suite due to subprocess deadlocks or blocking I/O, a global 30-second timeout is enforced on every test using `SIGALRM` (on Unix systems).\n\n## Key Test Modules\n\n### Core Utility Tests\n* **`test_atomic_replace_symlinks.py`**: Validates that `utils.atomic_replace` preserves symlinks. This is critical for managed deployments where `config.yaml` is symlinked to a git-tracked profile.\n* **`test_base_url_hostname.py`**: Tests the logic for extracting hostnames and matching providers. It specifically guards against substring collision attacks (e.g., ensuring `evil.test/openrouter.ai` is not identified as OpenRouter).\n* **`test_hermes_constants.py`**: Validates environment detection, including Docker/Podman container detection and `HERMES_HOME` path resolution.\n\n### Agent and Model Logic\n* **`test_ctx_halving_fix.py`**: Tests the fix for \"max_tokens too large\" errors. It ensures the agent uses `_ephemeral_max_output_tokens` to cap a single response rather than incorrectly halving the entire context window.\n* **`test_batch_runner_checkpoint.py`**: Validates the atomicity and resume logic of the `BatchRunner`, ensuring no duplicate prompt indices are written to checkpoints.\n* **`test_get_tool_definitions_cache_isolation.py`**: Ensures that the tool registry cache returns fresh list copies. This prevents long-lived Gateway processes from poisoning the global tool list when injecting session-specific tools (like memory).\n\n### CLI and Integration\n* **`test_cli_file_drop.py`**: Tests the regex and logic for detecting absolute file paths pasted into the CLI, distinguishing them from slash commands.\n* **`test_cli_skin_integration.py`**: Validates that the `HermesCLI` correctly applies colors and symbols from the `skin_engine`.\n* **`test_hermes_logging.py`**: Ensures that `setup_logging` correctly initializes `agent.log`, `errors.log`, and `gateway.log` with proper rotation and filtering.\n\n## Specialized Test Runners\n\n### `tests/run_interrupt_test.py`\nThis is a standalone script rather than a standard pytest module. It performs a live integration test of the `AIAgent` interruption mechanism. It spawns a real agent thread, triggers a `delegate_tool` call, and verifies that calling `parent.interrupt()` successfully propagates the interrupt signal to child agents and halts execution within a 2-second window.\n\n## Execution Flow: Test Setup\n\n```mermaid\ngraph TD\n A[pytest Start] --> B{_hermetic_environment}\n B --> C[Unset Credential Env Vars]\n B --> D[Redirect HERMES_HOME to tmp_path]\n B --> E[Pin TZ/LANG/Hashseed]\n E --> F{_reset_module_state}\n F --> G[Clear tools.approval]\n F --> H[Reset Gateway ContextVars]\n F --> I[Clear Tool Registry Caches]\n I --> J[Execute Test Body]\n J --> K[Enforce 30s Timeout]\n```\n\n## Contributing Tests\n\nWhen adding new tests:\n1. **Use `get_hermes_home()`**: Never use `Path.home() / \".hermes\"`. The test suite redirects the former but not the latter.\n2. **Check for State Leakage**: If your module uses a global dictionary or `ContextVar`, add a reset entry to `_reset_module_state` in `conftest.py`.\n3. **Avoid Real API Calls**: The environment is stripped of keys by design. Use `unittest.mock` or `pytest-recording` if network interaction is required.\n4. **Async Tests**: Use `@pytest.mark.asyncio`. For sync tests that internally use `asyncio.get_event_loop()`, the `_ensure_current_event_loop` fixture provides a safe loop environment.","tests-tools":"# tests — tools\n\n# Tests — Tools Module\n\nThe `tests/tools` module provides comprehensive validation for the core utility functions, safety guardrails, and environment abstractions used by the Hermes agent. This test suite ensures that the agent's interactions with the host system—ranging from file reads and shell execution to browser automation—remain safe, performant, and accurate.\n\n## Core Components Under Test\n\n### 1. Safety & Command Approval System\nThe most critical part of the module is the validation of `tools/approval.py`. These tests ensure that dangerous operations are intercepted before execution.\n\n* **Pattern Detection**: `test_approval.py` validates regex-based detection for:\n * **Destructive Filesystem Ops**: `rm -rf`, `chmod` recursion, and `find -delete`.\n * **Shell Obfuscation**: Detects bypasses using multiline commands (`\\n`), null bytes (`\\x00`), and ANSI escape sequences embedded within command strings.\n * **Remote Execution**: Intercepts `curl | sh` patterns and process substitution (e.g., `bash <(curl ...)`).\n * **Sensitive Writes**: Monitors `tee` or redirections to system files like `/etc/passwd`, `~/.ssh/authorized_keys`, or `.env` files.\n * **Self-Termination**: Prevents the agent from killing its own gateway or parent processes.\n* **Normalization Bypasses**: Tests verify that commands are NFKC normalized before checking, catching \"fullwidth\" Unicode variants (e.g., `rm` instead of `rm`).\n* **Heartbeat Mechanism**: `test_approval_heartbeat.py` ensures that while the agent is blocked waiting for user approval, it continues to fire activity heartbeats to the gateway to prevent premature session timeouts.\n* **Plugin Hooks**: Validates that `pre_approval_request` and `post_approval_response` hooks fire correctly across both CLI and Gateway surfaces, allowing external notification systems to trigger.\n\n### 2. Environment Execution Model\n`test_base_environment.py` validates the `BaseEnvironment` class, which is the foundation for all shell-based tools.\n\n* **Command Wrapping**: Tests the `_wrap_command` logic which injects state-tracking code into every execution. This includes:\n * Automatic `cd` to the target directory.\n * Environment variable snapshotting.\n * Exit code propagation.\n* **CWD Tracking**: Validates the `_cwd_marker` contract. The environment appends a unique session-based marker to output to reliably track the Current Working Directory even if the user's command changes it.\n* **Stdin Handling**: Tests `_embed_stdin_heredoc`, ensuring that multi-line input is safely passed to commands using unique UUID delimiters to prevent collision with the payload.\n\n### 3. Browser Automation (Camofox & CDP)\nThe suite covers both the high-level Camofox backend and low-level Chrome DevTools Protocol (CDP) interactions.\n\n* **Camofox Persistence**: `test_browser_camofox_persistence.py` ensures that when `managed_persistence` is enabled, the agent uses a stable `userId` derived from the Hermes profile. This allows persistent logins and cookies across different tasks within the same profile.\n* **CDP Tooling**: `test_browser_cdp_tool.py` uses an in-process mock WebSocket server to validate the binary protocol handling, target attachment, and session routing without requiring a live browser instance.\n* **Vision Integration**: Validates that `camofox_vision` correctly passes screenshots to the LLM with configured temperature and timeout settings.\n\n### 4. Resource Accretion Management\nLong-running sessions (CLI or Gateway) previously suffered from unbounded memory growth in internal trackers. `test_accretion_caps.py` pins the pruning logic for:\n\n* **File Read Tracker**: Caps `read_history`, `dedup` dictionaries, and `read_timestamps` in `file_tools`.\n* **Process Registry**: Ensures `_completion_consumed` sets are pruned when sessions expire or exceed `MAX_PROCESSES`, preventing memory leaks in high-churn environments.\n\n### 5. ANSI Sanitization\n`test_ansi_strip.py` provides exhaustive coverage for `strip_ansi`. This is vital for \"cleaning\" terminal output before it is sent to the LLM. It tests:\n* **SGR Sequences**: Colors, bold, and reset codes.\n* **CSI/OSC Sequences**: Cursor movement, window titles, and bracketed paste modes.\n* **Fidelity**: Ensures that legitimate code (like Python array indexing `arr[0]`) is not accidentally stripped.\n\n## Execution Flow: Command Approval\n\nThe following diagram illustrates the logic validated by the approval tests when a tool attempts to run a command:\n\n```mermaid\ngraph TD\n A[Tool Calls check_all_command_guards] --> B{Is YOLO mode?}\n B -- Yes --> C[Approve Automatically]\n B -- No --> D[Normalize & Strip ANSI/Nulls]\n D --> E{Matches Dangerous Pattern?}\n E -- No --> C\n E -- Yes --> F{Is Session Approved?}\n F -- Yes --> C\n F -- No --> G[Invoke pre_approval_request Hook]\n G --> H[Prompt User / Notify Gateway]\n H --> I{User Choice}\n I -- Deny --> J[Return Failure]\n I -- Approve --> K[Invoke post_approval_response Hook]\n K --> C\n```\n\n## Key Function References\n\n| Function | Test File | Purpose |\n| :--- | :--- | :--- |\n| `detect_dangerous_command` | `test_approval.py` | Primary regex engine for security scanning. |\n| `_wrap_command` | `test_base_environment.py` | Shell script generation for environment state. |\n| `strip_ansi` | `test_ansi_strip.py` | ECMA-48 compliant string cleaner. |\n| `_cap_read_tracker_data` | `test_accretion_caps.py` | LRU-style pruning for file metadata. |\n| `get_camofox_identity` | `test_browser_camofox_state.py` | Deterministic ID generation for browser profiles. |\n| `browser_cdp` | `test_browser_cdp_tool.py` | Low-level protocol dispatcher. |\n\n## Contributing to Tests\nWhen adding new tools or modifying existing ones:\n1. **Security**: If the tool executes shell commands, add a test case in `test_approval.py` to ensure it cannot be used for common bypasses.\n2. **Memory**: If the tool maintains state across calls, verify it is covered by an accretion cap in `test_accretion_caps.py`.\n3. **Environment**: If modifying how commands are run, ensure `test_base_environment.py` still correctly extracts the CWD and exit codes.","tests-tui-gateway":"# tests — tui_gateway\n\n# Tests — TUI Gateway\n\nThe `tests/tui_gateway` module provides a comprehensive test suite for the JSON-RPC 2.0 gateway that bridges the Hermes CLI core with its Terminal User Interface (TUI). These tests ensure that the communication protocol is robust, that agent initialization handles complex configuration states, and that background processes correctly report status to the frontend.\n\n## Core Test Areas\n\n### 1. JSON-RPC Protocol & Transport (`test_protocol.py`)\nThis sub-module validates the plumbing of the `tui_gateway.server`. It ensures that the server adheres to the JSON-RPC 2.0 specification and handles I/O failures gracefully.\n\n* **Envelope Integrity**: Tests `_ok` and `_err` helpers to ensure responses contain the correct `jsonrpc`, `id`, and `result`/`error` keys.\n* **I/O Robustness**: Validates `write_json` behavior under various failure modes:\n * **Peer Gone**: Returns `False` on `BrokenPipeError` or specific `ValueError` (\"I/O on closed file\") to allow the dispatcher to exit cleanly.\n * **Encoding Errors**: Re-raises `UnicodeEncodeError` to ensure configuration bugs are logged rather than swallowed.\n * **Flush Control**: Verifies that `HERMES_TUI_GATEWAY_NO_FLUSH` correctly disables stream flushing, which is used in specific performance-sensitive environments.\n* **Request Dispatching**: Tests the routing of methods. It specifically validates the **Thread Pool Dispatcher** logic:\n * **Short Handlers**: Executed synchronously to minimize latency.\n * **Long Handlers**: Methods like `slash.exec` and `session.compress` are offloaded to a worker pool so they do not block the main RPC loop, allowing the TUI to remain responsive (e.g., responding to `fast.ping` while a command is running).\n\n### 2. Agent Lifecycle & Provider Resolution (`test_make_agent_provider.py`)\nThese tests focus on `_make_agent`, the factory function responsible for instantiating `AIAgent` objects within the TUI context.\n\n* **Runtime Provider Resolution**: Ensures that bare model slugs (e.g., `claude-3-opus`) are correctly resolved into full provider configurations (API keys, base URLs, and modes) via `hermes_cli.runtime_provider.resolve_runtime_provider`. This prevents HTTP 404 errors caused by missing provider metadata.\n* **Personality Logic**: Validates that \"personalities\" defined in config only become active once saved to the `system_prompt`, matching the behavior of the classic CLI.\n* **Config Health Checks**: Tests `_probe_config_health` to ensure the gateway detects \"null\" YAML sections (e.g., an empty `agent:` key) which would otherwise cause downstream attribute errors.\n\n### 3. Rendering Bridge (`test_render.py`)\nThe TUI relies on a rendering bridge to convert agent output into formatted strings. These tests verify the fallback behavior of `tui_gateway.render`.\n\n* **Rich Integration**: Tests `render_message` and `render_diff`.\n* **Graceful Degradation**: Ensures that if the `agent.rich_output` module is missing or if a specific formatting call raises a `TypeError` or `RuntimeError`, the system falls back to raw text or returns `None` rather than crashing the gateway.\n\n### 4. Background Callbacks (`test_review_summary_callback.py`)\nHermes agents perform background \"self-improvement\" reviews. In the TUI, these cannot use standard print statements.\n\n* **Review Summaries**: Validates that `_init_session` correctly attaches a `background_review_callback` to the agent.\n* **Event Emission**: Ensures that when a background review completes (e.g., patching a skill), the gateway emits a `review.summary` event to the TUI frontend.\n\n## Execution Flow: Request Dispatching\n\nThe following diagram illustrates how the gateway handles incoming JSON-RPC requests, distinguishing between synchronous and asynchronous (pool-based) execution.\n\n```mermaid\ngraph TD\n A[Stdin Reader] --> B{Method Type?}\n B -- \"Short (e.g. ping)\" --> C[Execute Inline]\n B -- \"Long (e.g. slash.exec)\" --> D[Offload to Worker Pool]\n C --> E[Write to Stdout]\n D --> F[Execute Task]\n F --> E\n E --> G[TUI Frontend]\n```\n\n## Key Components & Mocking Patterns\n\n### Session Management\nTests frequently mock the session database (`_get_db`) and session initialization (`_init_session`). A common pattern is verifying that `session.resume` correctly hydrates message history, filtering out internal roles like `narrator` while preserving `user`, `assistant`, and `tool` messages.\n\n### Blocking Round-trips\nThe `test_block_and_respond` test demonstrates how the gateway handles requests that require user input (e.g., a tool asking for confirmation). It uses `threading.Event` to simulate the gateway blocking a worker thread while waiting for a response from the TUI frontend via the `_answers` map.\n\n### Command Interception\nTests for `command.dispatch` and `slash.exec` ensure that:\n1. **Skill Commands**: Intercepted and rejected if they should be handled by the TUI's primary command dispatcher.\n2. **Retry Logic**: Correctly truncates session history and identifies the last user message to facilitate the `/retry` command.\n3. **Plugin Support**: Correctly awaits and returns output from asynchronous plugin handlers.","tests-website":"# tests — website\n\n# Website Skill Documentation Tests\n\nThe `tests/website` module provides regression testing for the documentation generation pipeline. Its primary focus is ensuring that the `website/scripts/generate-skill-docs.py` script correctly processes skill definitions into Docusaurus-compatible Markdown without triggering CI linting failures.\n\n## Purpose: ASCII Guard Integration\n\nThe documentation site uses `ascii-guard` to lint for unexpected non-standard characters. However, many skill definitions (`SKILL.md`) use Unicode box-drawing characters to create architectural diagrams. \n\nTo prevent these diagrams from failing the `docs-site-checks` CI workflow, the generator must wrap code blocks containing ASCII art in `<!-- ascii-guard-ignore -->` markers. This module validates that the generator identifies these blocks accurately and applies the wrappers correctly.\n\n## Key Component: `mdx_escape_body`\n\nThe tests primarily target the `mdx_escape_body` function within the generator script. This function is responsible for scanning the Markdown body of a skill and applying defensive wrappers where necessary.\n\n### Test Scenarios\n\n| Test Case | Logic Validated |\n| :--- | :--- |\n| `test_code_block_without_box_chars_is_not_wrapped` | Ensures standard code blocks (bash, python) remain untouched to avoid unnecessary noise in the output. |\n| `test_code_block_with_box_chars_gets_wrapped` | Verifies that blocks containing characters like `┌`, `─`, or `│` are wrapped in ignore markers. |\n| `test_multiple_code_blocks_only_box_ones_wrapped` | Confirms the logic is granular; in a file with both plain code and ASCII art, only the art is wrapped. |\n| `test_tilde_fenced_box_is_wrapped` | Ensures support for both backtick (`` ` ``) and tilde (`~`) code fences. |\n| `test_already_wrapped_source_double_wraps_harmlessly` | Validates that if a developer manually added ignore markers, the generator's automated markers do not break the document. |\n\n## Character Coverage\n\nThe module includes a smoke test, `test_box_drawing_detection_covers_common_chars`, which verifies that the internal `_BOX_DRAWING_CHARS` set in the generator includes the full range of characters used across existing skill diagrams (e.g., `segment-anything`, `research-paper-writing`).\n\nThis includes:\n- Standard box lines: `┌┐└┘─│├┤┬┴┼`\n- Double lines: `═║╔╗╚╝`\n- Rounded corners: `╰╮╯╰`\n- Arrows/Pointers: `▶◀▲▼`\n\n## Technical Implementation: Loading the Generator\n\nBecause `generate-skill-docs.py` is a script with a hyphenated filename located outside the standard Python package structure, it cannot be imported using a standard `import` statement. \n\nThe test suite uses the `gen_module` fixture to load the script dynamically using `importlib.util`:\n\n```python\ndef gen_module():\n spec = importlib.util.spec_from_file_location(\"generate_skill_docs\", GENERATOR)\n module = importlib.util.module_from_spec(spec)\n spec.loader.exec_module(module)\n return module\n```\n\n## Execution Flow\n\nThe following diagram illustrates how the tested logic fits into the documentation CI pipeline:\n\n```mermaid\ngraph TD\n A[SKILL.md with ASCII Art] --> B[generate-skill-docs.py]\n B --> C{mdx_escape_body}\n C -->|Contains Box Chars| D[Wrap in ascii-guard-ignore]\n C -->|Plain Text| E[Leave Untouched]\n D --> F[Docusaurus .mdx Output]\n E --> F\n F --> G[ascii-guard lint]\n G --> H[CI Pass]\n```\n\n## Running Tests\n\nTo run these tests specifically, execute pytest from the repository root:\n\n```bash\npytest tests/website/test_generate_skill_docs.py\n```","tests":"# tests\n\n# Hermes Agent Test Suite\n\nThe `tests` module provides a hermetic, deterministic environment for validating the Hermes Agent across its entire stack. It ensures that the agent's core logic, platform integrations, and safety guardrails function identically in local development and CI by strictly isolating state and credentials.\n\n## Testing Architecture\n\nThe suite is structured to mirror the agent's lifecycle, from raw input handling to LLM inference and tool execution.\n\n```mermaid\ngraph TD\n subgraph \"Input & Transport\"\n CLI[tests/cli] --> GW\n ACP[tests/acp] --> GW\n TUI[tests/tui_gateway] --> GW\n GW[tests/gateway]\n end\n\n subgraph \"Core Execution\"\n GW --> E2E[tests/e2e]\n E2E --> RA[tests/run_agent]\n RA --> AG[tests/agent]\n AG --> ST[tests/hermes_state]\n end\n\n subgraph \"Capabilities & Safety\"\n RA --> TL[tests/tools]\n RA --> SK[tests/skills]\n RA --> PL[tests/plugins]\n TL --> ENV[tests/environments]\n end\n\n subgraph \"External Mocks\"\n PL --> FK[tests/fakes]\n PL --> HP[tests/honcho_plugin]\n PL --> OP[tests/openviking_plugin]\n end\n```\n\n## Core Testing Pillars\n\n### 1. Hermetic Environment & Safety\nThe foundation of the suite is the `_hermetic_environment` fixture in `conftest.py`. It prevents credential leakage by unsetting sensitive environment variables and provides a deterministic execution context.\n* **[Tools](tools.md)**: Validates the `approval.py` system, ensuring dangerous filesystem and shell operations are intercepted.\n* **[Environments](environments.md)**: Focuses on security isolation, specifically testing against path traversal and archive exploitation.\n\n### 2. Agent Execution & State\nThese modules test the \"brain\" of the system, focusing on how the agent thinks and remembers.\n* **[Agent](agent.md)**: Validates LLM provider adapters (e.g., Anthropic) and message format conversion.\n* **[Run Agent](run_agent.md)**: Tests the core execution loop, including multi-turn logic and tool-call retries.\n* **[Hermes State](hermes_state.md)**: Manages session persistence and handles \"Context Compression\" where conversations are split across database records.\n\n### 3. Communication & Gateways\nHermes interacts with the world through various protocols, each with its own validation suite.\n* **[Gateway](gateway.md)**: The central hub for platform adapters (Telegram, Discord, etc.) and session management.\n* **[ACP & ACP Adapter](acp.md)**: Tests the JSON-RPC bridge used by external clients like the Zed editor, utilizing `FakeAgent` and `CaptureConn` for isolation.\n* **[CLI](cli.md) & [TUI Gateway](tui_gateway.md)**: Validates the terminal interface, slash command prefix matching, and the JSON-RPC 2.0 protocol that powers the TUI.\n\n### 4. Integrations & Skills\nThe agent's extended capabilities are tested via specialized mocks and integration suites.\n* **[Skills](skills.md)**: Regression tests for Google Workspace (OAuth flows), Twilio, and productivity tools.\n* **[Plugins](plugins.md)**: Ensures image generation and memory providers (like [Honcho](honcho_plugin.md) and [OpenViking](openviking_plugin.md)) adhere to internal interfaces.\n* **[Fakes](fakes.md)**: Provides `FakeHAServer`, an in-process Home Assistant mock for testing IoT integrations without live hardware.\n\n### 5. Specialized Suites\n* **[E2E](e2e.md)**: Exercises the full asynchronous pipeline from event injection to response dispatch.\n* **[Integration](integration.md)**: Tests requiring real network I/O or complex stateful protocols.\n* **[Stress](stress.md)**: Adversarial, high-concurrency tests and fuzzing (opt-in only).\n* **[Cron](cron.md)**: Validates background task scheduling and duration parsing.\n* **[Website](website.md)**: Ensures documentation generation remains compatible with CI linting and ASCII-art guards.","tools-browser-providers":"# tools — browser_providers\n\n# Browser Providers\n\nThe `tools.browser_providers` module provides a unified abstraction layer for interacting with various cloud-hosted browser services (e.g., Browser Use, Browserbase, Firecrawl). It allows the higher-level `browser_tool` to manage remote browser sessions without needing to handle vendor-specific API differences.\n\n## Architecture\n\nThe module follows a provider pattern using an Abstract Base Class (ABC). Each cloud vendor is implemented as a subclass of `CloudBrowserProvider`.\n\n```mermaid\nclassDiagram\n class CloudBrowserProvider {\n <<abstract>>\n +provider_name() str\n +is_configured() bool\n +create_session(task_id) dict\n +close_session(session_id) bool\n +emergency_cleanup(session_id)\n }\n class BrowserUseProvider {\n +create_session()\n }\n class BrowserbaseProvider {\n +create_session()\n }\n class FirecrawlProvider {\n +create_session()\n }\n CloudBrowserProvider <|-- BrowserUseProvider\n CloudBrowserProvider <|-- BrowserbaseProvider\n CloudBrowserProvider <|-- FirecrawlProvider\n```\n\n## Core Interface: `CloudBrowserProvider`\n\nDefined in `base.py`, this class enforces the lifecycle methods required for any cloud browser backend:\n\n- **`is_configured()`**: Performs a cheap check (usually environment variable presence) to determine if the provider is available for use.\n- **`create_session(task_id)`**: Provisions a new remote browser. It returns a dictionary containing:\n - `cdp_url`: The WebSocket URL used to connect a Playwright/Puppeteer driver.\n - `bb_session_id`: The provider's internal session ID (used for termination).\n - `session_name`: A human-readable identifier for logging.\n- **`close_session(session_id)`**: Gracefully terminates the session.\n- **`emergency_cleanup(session_id)`**: A best-effort termination called during process exit or crashes.\n\n## Supported Providers\n\n### Browser Use (`BrowserUseProvider`)\nThe primary provider for managed environments. It supports two modes of operation:\n1. **Direct API**: Uses `BROWSER_USE_API_KEY`.\n2. **Managed Gateway**: Uses `tools.managed_tool_gateway` to resolve credentials and routing via the Nous infrastructure.\n\n**Key Features:**\n- **Idempotency**: Uses `X-Idempotency-Key` during session creation in managed mode to prevent duplicate billing/sessions on retries.\n- **Configurable Proxies**: Defaults to `us` country codes for managed sessions.\n\n### Browserbase (`BrowserbaseProvider`)\nA robust provider requiring `BROWSERBASE_API_KEY` and `BROWSERBASE_PROJECT_ID`.\n\n**Key Features:**\n- **Feature Fallbacks**: If a session creation fails with HTTP 402 (Payment Required), the provider automatically retries by stripping advanced features like `keepAlive` or `proxies`.\n- **Advanced Stealth**: Supports toggling `advancedStealth` and custom session timeouts via environment variables (`BROWSERBASE_SESSION_TIMEOUT`).\n\n### Firecrawl (`FirecrawlProvider`)\nA lightweight provider focused on web scraping and crawling contexts.\n\n**Key Features:**\n- **TTL Management**: Uses `FIRECRAWL_BROWSER_TTL` (default 300s) to ensure sessions do not persist indefinitely if the client disconnects.\n- **Simple REST Interface**: Uses standard Bearer token authentication via `FIRECRAWL_API_KEY`.\n\n## Session Lifecycle Flow\n\n1. **Discovery**: `browser_tool` checks `is_configured()` for the provider selected in the user's configuration.\n2. **Provisioning**: `create_session` is called. The provider performs a POST request to the vendor API and returns the `cdp_url`.\n3. **Connection**: The agent connects to the `cdp_url` to perform browser actions.\n4. **Teardown**: Upon task completion, `close_session` is called. If the process receives a termination signal, `emergency_cleanup` is triggered via `atexit` handlers in the calling module.\n\n## Configuration\n\nProviders are configured primarily through environment variables:\n\n| Provider | Required Variables | Optional Variables |\n| :--- | :--- | :--- |\n| **Browser Use** | `BROWSER_USE_API_KEY` | `BROWSER_USE_PROXY_COUNTRY` |\n| **Browserbase** | `BROWSERBASE_API_KEY`, `BROWSERBASE_PROJECT_ID` | `BROWSERBASE_PROXIES`, `BROWSERBASE_KEEP_ALIVE` |\n| **Firecrawl** | `FIRECRAWL_API_KEY` | `FIRECRAWL_API_URL`, `FIRECRAWL_BROWSER_TTL` |\n\n## Implementation Details\n\n### Legacy Key Names\nThe `create_session` return dictionary uses the key `bb_session_id` to store the provider's session ID. This is a legacy naming convention (originally referring to Browserbase) maintained for backward compatibility with the `browser_tool.py` logic.\n\n### Error Handling\nImplementations are expected to catch network exceptions during `close_session` and `emergency_cleanup`, logging a warning rather than raising. This ensures that a failure to close a browser session does not crash the main agent loop.","tools-environments":"# tools — environments\n\n# tools — environments\n\nThe `tools.environments` module provides a unified interface for executing shell commands across diverse backends. It abstracts the complexities of local processes, containers, and cloud sandboxes into a consistent API used by the Hermes terminal tool.\n\n## Core Architecture: Spawn-per-Call\n\nHermes uses a **spawn-per-call** model rather than maintaining a long-lived interactive shell process. Every command execution spawns a fresh `bash -c` instance. To provide the illusion of a persistent session (where environment variables and the working directory persist), the module employs a **Session Snapshot** mechanism.\n\n### Session Snapshots\n1. **Initialization**: When an environment is created, `init_session()` runs a bootstrap script in a login shell (`bash -l`).\n2. **Capture**: It captures the environment state (exported variables, functions, aliases) into a snapshot file (e.g., `/tmp/hermes-snap-[id].sh`).\n3. **Restoration**: Every subsequent call to `execute()` wraps the user's command. The wrapper sources the snapshot file, `cd`s to the last known directory, runs the command, and then re-dumps the environment state back into the snapshot.\n\n```mermaid\ngraph TD\n A[execute command] --> B{Snapshot Ready?}\n B -- Yes --> C[Source snapshot file]\n B -- No --> D[Run as bash -l]\n C --> E[cd to CWD]\n D --> E\n E --> F[eval user command]\n F --> G[Capture env to snapshot]\n G --> H[Emit CWD marker]\n H --> I[Return output]\n```\n\n## BaseEnvironment\n\nThe `BaseEnvironment` abstract base class (ABC) implements the core execution logic, including command wrapping, output draining, and interrupt handling.\n\n### Key Methods\n- `execute(command, cwd, timeout, stdin_data)`: The primary entry point. It prepares the command (handling `sudo` transformations), wraps it in the snapshot logic, and manages the process lifecycle.\n- `_run_bash(...)`: Abstract method implemented by backends to spawn the actual process.\n- `_wait_for_process(proc, timeout)`: A robust polling loop that:\n - Drains `stdout` non-blockingly using `select()`.\n - Monitors for interrupts via `is_interrupted()`.\n - Fires an activity callback every 10s to prevent gateway inactivity timeouts.\n - Handles \"grandchild pipe leaks\" by stopping the drain shortly after the main bash process exits.\n\n### Process Abstraction\nBackends return a `ProcessHandle`. While `subprocess.Popen` satisfies this natively for local/Docker execution, SDK-based backends (Modal, Daytona) use `_ThreadedProcessHandle`. This adapter wraps blocking SDK calls in a background thread to provide the `poll()`, `kill()`, and `wait()` interface required by the base class.\n\n## File Synchronization\n\nRemote backends (SSH, Modal, Daytona) that do not have direct access to the host filesystem use the `FileSyncManager`.\n\n- **Tracking**: It tracks local files (credentials, skills, cache) using a combination of `mtime` and file size.\n- **Transactional Sync**: Files are uploaded in batches. The internal state is only updated if the entire batch succeeds, ensuring consistency.\n- **Sync-Back**: On environment cleanup, `sync_back()` can pull remote changes back to the host. It uses SHA-256 hashes to detect remote modifications and applies a \"last-write-wins\" strategy in case of conflicts.\n- **Optimization**: Backends like `DaytonaEnvironment` implement `_daytona_bulk_upload` to batch multiple files into a single HTTP POST, significantly reducing overhead.\n\n## Backend Implementations\n\n### LocalEnvironment\nRuns commands directly on the host.\n- **Security**: Uses `_sanitize_subprocess_env` to strip Hermes-internal secrets and API keys from the environment before execution.\n- **Isolation**: Redirects `HOME` to a profile-specific directory (via `get_subprocess_home`) to isolate tool configurations (git, npm, etc.).\n- **Process Groups**: On POSIX, it uses `os.setsid` to run commands in their own process group, allowing `_kill_process` to reliably terminate entire process trees.\n\n### DockerEnvironment\nProvides hardened container isolation.\n- **Security**: Drops all capabilities (`--cap-drop ALL`) and adds back only the minimum required (`DAC_OVERRIDE`, `CHOWN`, `FOWNER`). It enforces `no-new-privileges` and sets a `pids-limit`.\n- **Persistence**: Supports optional filesystem persistence via bind mounts to `TERMINAL_SANDBOX_DIR`.\n- **Resource Limits**: Configurable CPU, memory, and disk quotas (disk quotas require `overlay2` on XFS).\n\n### Cloud Backends (Modal & Daytona)\n- **ManagedModalEnvironment**: Connects to a remote tool gateway to manage sandboxes, avoiding the need for local Modal credentials.\n- **ModalEnvironment**: Uses the native Modal SDK. It supports image restoration from snapshots to speed up cold starts.\n- **DaytonaEnvironment**: Utilizes the Daytona SDK for persistent cloud workspaces.\n\n## Working Directory Tracking\n\nBecause the shell exits after every command, the working directory must be tracked manually.\n- **Remote**: The command wrapper emits a unique marker: `__HERMES_CWD_{session_id}__[path]__HERMES_CWD_{session_id}__`. `_extract_cwd_from_output` parses this from the stdout stream and updates `self.cwd`.\n- **Local**: The wrapper writes the CWD to a temporary file, which `LocalEnvironment._update_cwd` reads directly to avoid stdout pollution.\n\n## Interrupt Handling\n\nThe module is designed to be highly responsive to user interrupts.\n- `_wait_for_process` checks `is_interrupted()` on every poll iteration (default 200ms).\n- If an interrupt is detected, it calls `_kill_process`.\n- For `LocalEnvironment`, this sends `SIGTERM` (and eventually `SIGKILL`) to the entire process group.\n- For SDK backends, this triggers the `cancel_fn` (e.g., `sandbox.stop()` or `sandbox.terminate()`).","tools-neutts-samples":"# tools — neutts_samples\n\n# Module: tools/neutts_samples\n\nThe `tools/neutts_samples` module is a static resource directory containing sample text files used for testing, benchmarking, and demonstrating the capabilities of the Neuphonic Text-to-Speech (TTS) integration.\n\nThese samples are primarily utilized as standardized inputs for the TTS engine to evaluate voice quality, latency, and feature support (such as voice cloning and conversational agents).\n\n## Sample Content: jo.txt\n\nThe core file currently within this module is `jo.txt`. It contains a conversational testimonial designed to test the naturalness and prosody of the synthesized output.\n\n**Content:**\n> \"So I just tried Neuphonic and I’m genuinely impressed. It's super responsive, it sounds clean, supports voice cloning, and the agent feature is fun to play with too. Highly recommend it for podcasts, conversations, or even just messing around with voiceovers.\"\n\n### Key Testing Characteristics\nThe text in `jo.txt` is structured to validate specific TTS features:\n* **Responsiveness:** The conversational tone allows developers to measure the \"time to first byte\" (TTFB) in interactive scenarios.\n* **Clarity and Cleanliness:** The vocabulary is chosen to test the engine's ability to produce high-fidelity audio without artifacts.\n* **Feature Mention:** The text explicitly references \"voice cloning\" and \"agent features,\" making it a suitable script for marketing demos or feature-specific regression tests.\n\n## Integration and Usage\n\nWhile this module contains no executable code or logic, it serves as a data source for other components in the `tools` or `tts` namespaces. \n\n### Typical Workflow\nDevelopers typically ingest these samples into a testing harness or a CLI tool to generate audio output.\n\n```mermaid\ngraph LR\n Sample[tools/neutts_samples/jo.txt] --> Loader[File Loader]\n Loader --> TTS_Engine[Neuphonic API/Engine]\n TTS_Engine --> Audio[WAV/MP3 Output]\n```\n\n### How to Use\nTo use these samples in a test suite, reference the file path relative to the project root:\n\n```python\n# Example pattern for utilizing the sample\nwith open('tools/neutts_samples/jo.txt', 'r') as f:\n sample_text = f.read()\n # Pass sample_text to the Neuphonic synthesis function\n```\n\n## Contribution Guidelines\nWhen adding new samples to this directory:\n1. Use the `.txt` extension.\n2. Ensure the text covers specific phonetic ranges or emotional tones not present in existing samples.\n3. Keep samples concise to minimize API costs during automated testing.","tools-tools":"# tools — tools\n\n# Tools Module\n\nThe `tools` module serves as the primary interface between the Hermes agent and the host environment. It encompasses command execution safety, browser automation backends, and output sanitization. The package is designed for minimal side effects during initialization to prevent circular dependencies with `hermes_cli.config`.\n\n## Command Safety and Approval System\n\nThe `tools.approval` module is the central authority for preventing the execution of destructive commands. It implements a multi-layered defense strategy.\n\n### 1. Hardline Blocklist\nThe `HARDLINE_PATTERNS` list contains catastrophic commands that are blocked unconditionally. These cannot be bypassed by `--yolo` mode or user approval.\n- **Targets:** Root filesystem deletion (`rm -rf /`), disk formatting (`mkfs`), raw block device overwrites (`dd of=/dev/sda`), and system power commands (`shutdown`, `reboot`).\n- **Detection:** `detect_hardline_command(command)` uses normalized regex matching to identify these patterns at the start of shell command positions.\n\n### 2. Dangerous Command Detection\nThe `DANGEROUS_PATTERNS` list identifies risky but potentially valid operations (e.g., `git reset --hard`, `chmod 777`, or `kill -9`).\n- **Normalization:** `_normalize_command_for_detection` strips ANSI codes, null bytes, and normalizes Unicode to prevent obfuscation bypasses.\n- **Smart Approval:** If `approvals.mode` is set to `smart`, the system invokes `_smart_approve`. This uses an auxiliary LLM to assess if a flagged command is a false positive (e.g., a benign `python -c` script) before prompting the user.\n\n### 3. Approval Orchestration\n`check_all_command_guards` is the primary entry point for terminal tools. It coordinates:\n- **Tirith Integration:** Incorporates security findings from `tools.tirith_security`.\n- **Session State:** Tracks approvals per `session_key` using `ContextVars` to ensure thread safety during concurrent agent turns.\n- **Gateway Bridging:** For headless environments, `register_gateway_notify` allows the agent to block on a `threading.Event` while waiting for a user to approve a command via the Gateway UI.\n\n```mermaid\ngraph TD\n A[Terminal Tool] --> B{check_all_command_guards}\n B --> C[Hardline Check]\n C -- Match --> D[Block Unconditionally]\n C -- No Match --> E[Dangerous Pattern Check]\n E -- Match --> F{Approval Mode?}\n F -- smart --> G[Auxiliary LLM Review]\n F -- manual --> H[User Prompt/Gateway]\n G -- Approve --> I[Execute]\n G -- Escalate --> H\n H -- Approved --> I\n E -- No Match --> I\n```\n\n## Output Sanitization\n\nThe `tools.ansi_strip` module provides `strip_ansi(text)`. This is a high-performance utility used by `terminal_tool` and `code_execution_tool` to remove ECMA-48 escape sequences from subprocess output. \n\n**Purpose:** It prevents the model from seeing terminal formatting codes (colors, cursor movements). If these codes enter the model's context, the model often erroneously copies them into subsequent file writes, corrupting source code.\n\n## Browser Infrastructure\n\nHermes supports multiple browser backends and a stateful supervision layer.\n\n### CDP Supervisor\nThe `tools.browser_supervisor` module runs a background `CDPSupervisor` per task. It maintains a persistent WebSocket connection to a Chrome DevTools Protocol (CDP) endpoint.\n- **Dialog Handling:** Intercepts JavaScript `alert`, `confirm`, and `prompt` calls. It can auto-dismiss based on policy or hold them for agent response via `browser_dialog_tool`.\n- **Frame Tracking:** Maintains a real-time `frame_tree`, identifying Out-of-Process Iframes (OOPIFs) and mapping them to CDP session IDs.\n- **Injection:** Uses `Page.addScriptToEvaluateOnNewDocument` to inject a bridge that routes synchronous JS dialogs through a controlled XHR interceptor.\n\n### Browser Backends\n1. **Camofox (`tools.browser_camofox`):** A REST-based backend for the Camoufox anti-detection browser. It handles navigation, snapshots, and vision-based analysis without requiring a direct CDP connection.\n2. **CDP Passthrough (`tools.browser_cdp_tool`):** Provides the `browser_cdp` tool, allowing the agent to send raw CDP commands. It supports routing commands to specific frames via `frame_id` by multiplexing through the supervisor's session.\n\n## File System Utilities\n\n### Binary Detection\n`tools.binary_extensions` defines `has_binary_extension(path)`. This is used by file-searching and reading tools to avoid ingesting non-text data (images, archives, executables) into the LLM context, which would waste tokens and cause hallucination.\n\n### Requirement Checks\n`tools.check_file_requirements()` validates the environment for file operations. It primarily ensures terminal backend availability via `tools.terminal_tool.check_terminal_requirements()`.\n\n## Execution Flow: Command Approval\n\nWhen an agent attempts to run a command like `rm -rf ./node_modules`:\n\n1. **Terminal Tool** calls `check_all_command_guards(command, env_type)`.\n2. **Normalization:** `strip_ansi` and Unicode normalization are applied.\n3. **Hardline Check:** `detect_hardline_command` returns `False`.\n4. **Dangerous Check:** `detect_dangerous_command` matches the `recursive delete` pattern.\n5. **Session Lookup:** `is_approved` checks if this pattern was already allowed for the current `HERMES_SESSION_KEY`.\n6. **Prompting:** If not approved, `prompt_dangerous_approval` (CLI) or the gateway notification callback is triggered.\n7. **Persistence:** If the user selects \"Always\", `save_permanent_allowlist` updates the `command_allowlist` in `config.yaml`.","tools":"# tools\n\n# Tools Module\n\nThe `tools` module provides the execution engine for the Hermes agent, bridging high-level reasoning with low-level system, web, and multimodal interactions. It manages the lifecycle of tool execution, from discovery and safety validation to environment-specific deployment.\n\n## Core Architecture\n\nThe module is organized into three functional layers: **Execution**, **Safety & Policy**, and **Specialized Capabilities**.\n\n```mermaid\ngraph TD\n Agent[Hermes Agent] --> Registry[tools.registry]\n Registry --> Terminal[tools.terminal_tool]\n Registry --> Web[tools.web_tools]\n \n subgraph Execution\n Terminal --> Env[tools.environments]\n Web --> Providers[tools.browser_providers]\n end\n \n subgraph Safety\n Terminal --> Approval[tools.approval]\n Web --> Policy[tools.website_policy]\n end\n \n Env --> Host[Host/Container/Cloud]\n Providers --> Cloud[Cloud Browser Services]\n```\n\n## Functional Areas\n\n### System Execution & Safety\nThe interaction with shell environments is handled by a combination of [environments](environments.md) and [terminal_tool](terminal_tool.md). \n* **Persistence:** While [environments](environments.md) uses a \"spawn-per-call\" model, it maintains session state (working directories and variables) via snapshots.\n* **Gatekeeping:** Before any command reaches the environment, [approval](approval.md) enforces a hardline blocklist of destructive patterns, while `terminal_tool` manages sudo credentials and command transformation.\n\n### Web Automation & Research\nThe [web_tools](web_tools.md) sub-module provides high-level functions for searching, crawling, and extracting data.\n* **Backend Abstraction:** It utilizes [browser_providers](browser_providers.md) to interface with various cloud-hosted browser services (like Browserbase or Firecrawl) through a unified API.\n* **Compliance:** Every request is filtered through [website_policy](website_policy.md) and URL safety checks to ensure the agent adheres to access rules and avoids restricted domains.\n\n### Multimodal & Media\nHermes interacts with the physical and digital world through specialized media tools:\n* **Voice & Audio:** [voice_mode](voice_mode.md) handles real-time audio capture and playback, utilizing [neutts_samples](neutts_samples.md) for testing and benchmarking speech synthesis quality.\n* **Vision:** [vision_tools](vision_tools.md) allows the agent to process and describe visual inputs, integrated with the core interrupt system to allow for long-running analysis.\n\n### Infrastructure & Registry\nThe [registry](registry.md) serves as the central source of truth for tool discovery. It manages toolset aliases and snapshots the state of available tools, allowing the agent to resolve which capabilities are active in a given environment. This registry is frequently accessed during the `rollout_and_score_eval` workflows to validate tool distributions.\n\n## Key Sub-modules\n\n| Module | Responsibility |\n| :--- | :--- |\n| [approval](approval.md) | Hardline command blocklists and safety enforcement. |\n| [browser_providers](browser_providers.md) | Unified interface for cloud-hosted browser vendors. |\n| [environments](environments.md) | Shell execution backends (Local, Docker, Modal). |\n| [neutts_samples](neutts_samples.md) | Static resources for TTS benchmarking and testing. |\n| [registry](registry.md) | Tool discovery, aliasing, and state snapshotting. |\n| [web_tools](web_tools.md) | High-level web search, crawling, and content extraction. |\n| [website_policy](website_policy.md) | Domain-level access control and blocklist management. |\n| [voice_mode](voice_mode.md) | Audio stream management and STT/TTS integration. |","tui-gateway":"# tui_gateway\n\n# tui_gateway\n\nThe `tui_gateway` module serves as the JSON-RPC bridge between the Hermes TUI (Terminal User Interface) and the underlying AI agent logic. It runs as a standalone subprocess, communicating with the TUI over standard I/O (stdin/stdout) to manage sessions, execute prompts, and stream events.\n\n## Architecture Overview\n\nThe gateway is designed to be highly responsive, offloading long-running tasks to a thread pool while maintaining a synchronous command loop for state management.\n\n```mermaid\ngraph TD\n TUI[Hermes TUI] -- JSON-RPC over Stdin --> Entry[entry.py: main loop]\n Entry -- dispatch --> Pool{Thread Pool}\n Entry -- dispatch --> Inline[Inline Handlers]\n Pool -- AIAgent.run --> Agent[AIAgent]\n Agent -- Events --> Transport[transport.py]\n Transport -- JSON-RPC over Stdout --> TUI\n Transport -- WebSocket --> Sidecar[Dashboard Sidecar]\n```\n\n## Core Components\n\n### 1. Entry Point (`entry.py`)\nThe `main()` function in `entry.py` initializes the gateway environment:\n- **Signal Handling**: Configures `SIGPIPE` to be ignored (preventing crashes when background threads write to a closed pipe) and `SIGTERM`/`SIGHUP` to trigger an orderly shutdown via `_log_signal`.\n- **Sidecar Setup**: If `HERMES_TUI_SIDECAR_URL` is present, it wraps the standard I/O transport in a `TeeTransport` to mirror events to a WebSocket publisher.\n- **Command Loop**: Reads newline-framed JSON from `sys.stdin`, parses it, and passes it to the dispatcher.\n\n### 2. RPC Dispatcher (`server.py`)\nThe `dispatch()` function routes inbound requests based on their expected execution time:\n- **Inline Handlers**: Fast operations (e.g., `session.list`, `terminal.resize`) run directly on the main thread.\n- **Long Handlers**: Operations defined in `_LONG_HANDLERS` (e.g., `prompt.submit`, `session.resume`, `slash.exec`) are dispatched to a `ThreadPoolExecutor` (`_pool`). This prevents the stdin pipe from backing up while waiting for LLM responses or shell commands.\n\n### 3. Session Management\nSessions are tracked in the `_sessions` dictionary. Each session encapsulates:\n- An `AIAgent` instance.\n- A `history_lock` for thread-safe transcript mutations.\n- A `_SlashWorker` subprocess for executing `/` commands.\n- Transport-specific bindings to ensure events reach the correct client.\n\n**Lazy Agent Building**: To keep the TUI responsive, `session.create` returns a session ID immediately. The actual `AIAgent` construction (which involves tool discovery and model metadata loading) is deferred to a background thread via `_start_agent_build`.\n\n### 4. Transport Layer (`transport.py`)\nThe gateway uses a pluggable transport system to emit JSON-RPC frames:\n- `StdioTransport`: The default, writing to the real `sys.stdout`.\n- `WsPublisherTransport`: A best-effort WebSocket client used for the dashboard sidebar.\n- `TeeTransport`: Duplicates writes across multiple transports.\n\nThe `write_json()` function automatically resolves the correct transport using `contextvars` or session-specific metadata.\n\n## JSON-RPC Methods\n\nThe module exposes several categories of methods via the `@method` decorator:\n\n| Category | Key Methods | Description |\n| :--- | :--- | :--- |\n| **Session** | `session.create`, `session.resume`, `session.undo` | Manages the lifecycle and history of agent conversations. |\n| **Prompt** | `prompt.submit`, `session.steer` | Sends user input to the agent and handles streaming responses. |\n| **State** | `session.list`, `session.title`, `session.usage` | Interacts with `hermes_state` (SQLite) to persist and retrieve metadata. |\n| **Observability** | `spawn_tree.list`, `spawn_tree.load` | Manages snapshots of sub-agent execution trees. |\n| **Control** | `session.interrupt`, `subagent.interrupt` | Signals the agent or sub-agents to stop execution. |\n\n## Error Handling and Forensics\n\nBecause the gateway's `stdout` is reserved for JSON-RPC traffic, standard Python `print()` calls and unhandled exceptions could corrupt the protocol. \n\n- **Stdout Redirection**: `sys.stdout` is redirected to `sys.stderr` at startup.\n- **Panic Hooks**: `_panic_hook` and `_thread_panic_hook` intercept unhandled exceptions, writing full stack traces to `~/.hermes/logs/tui_gateway_crash.log` and emitting a summary to `stderr`.\n- **Shutdown Grace**: On termination signals, the gateway attempts an orderly shutdown (atexit handlers) but will force an `os._exit(0)` after a configurable grace period (default 1s) to prevent deadlocks in the worker pool.\n\n## Event Emission\n\nThe gateway emits asynchronous events to the TUI using the `method: \"event\"` JSON-RPC pattern. Key events include:\n- `message.delta`: Incremental LLM response text.\n- `tool.start` / `tool.complete`: Tool execution lifecycle.\n- `status.update`: UI status bar text updates.\n- `approval.request`: Requests for user permission (e.g., for shell execution).\n- `reasoning.delta`: Thinking/reasoning tokens from supported models.\n\n## Rendering Bridge (`render.py`)\n\nThe gateway provides a bridge to `agent.rich_output` via `render_message` and `render_diff`. If the `agent` package is available, it uses Python-side logic to format Markdown and diffs before sending them to the TUI; otherwise, the TUI falls back to its internal React-based rendering.","ui-tui-packages":"# ui-tui — packages\n\n# @hermes/ink\n\n`@hermes/ink` is a high-performance React reconciler specifically tuned for building complex Terminal User Interfaces (TUIs). It extends the core concepts of Ink with advanced terminal features including bidirectional text support, sophisticated mouse interaction (multi-click, drag-selection), and environment-aware color rendering.\n\n## Architecture Overview\n\nThe module functions as a bridge between React's component model and the terminal's character-grid buffer.\n\n```mermaid\ngraph TD\n React[React Components] --> Rec[Reconciler]\n Rec --> DOM[Virtual DOM Tree]\n DOM --> Layout[Yoga Layout]\n Layout --> Screen[Screen Buffer]\n Screen --> Diff[Diffing Engine]\n Diff --> Term[Terminal Output]\n App[App Component] -- Manages --> Stdin[Stdin / Input Parsing]\n```\n\n## Core Components\n\n### App\nThe `App` class (in `src/ink/components/App.tsx`) is the root of the Ink instance. It manages the lifecycle of the TUI session, including:\n- **Raw Mode Management:** Toggles `stdin.setRawMode` and tracks a `rawModeEnabledCount` to ensure terminal settings are restored only when all components release them.\n- **Input Pipeline:** Orchestrates the flow from `handleReadable` through `parseMultipleKeypresses` to `processKeysInBatch`.\n- **Terminal Probing:** Uses `TerminalQuerier` to send `XTVERSION` queries to identify the host terminal (e.g., xterm.js vs. iTerm2).\n\n### AlternateScreen\nThe `AlternateScreen` component switches the terminal to the DEC 1049 buffer.\n- **Viewport Constraint:** Automatically constrains its height to the terminal's row count.\n- **Mouse Tracking:** Enables SGR mouse tracking (wheel, click, drag) while mounted.\n- **Cleanup:** Ensures the main screen is restored and the cursor is homed upon unmounting or process exit.\n\n### Ansi\nA specialized component for rendering pre-formatted ANSI strings (e.g., output from syntax highlighters).\n- **Parsing:** Uses a `Parser` from `termio.js` to convert ANSI escape codes into a tree of `Text` and `Link` components.\n- **Optimization:** Memoized to prevent expensive re-parsing when the parent re-renders but the content remains static.\n\n## Input Handling & Events\n\nThe module implements a sophisticated event system that goes beyond simple keypresses.\n\n### Keypress Parsing\nInput is processed via `parseMultipleKeypresses`, which handles:\n- **Bracketed Paste:** Buffers input between `EBP` (Enable Bracketed Paste) sequences to prevent rapid text entry from being interpreted as individual commands.\n- **Extended Keys:** Supports Kitty keyboard protocol and xterm `modifyOtherKeys` to distinguish combinations like `Ctrl+Shift+A` from `Ctrl+A`.\n- **Escape Sequence Watchdog:** Uses `incompleteEscapeTimer` to flush partial sequences (like a lone `ESC` key) after a 50ms timeout.\n\n### Mouse & Selection\nThe `handleMouseEvent` function manages complex terminal interactions:\n- **Multi-click Detection:** Tracks timing and distance between clicks to trigger word-select (double-click) or line-select (triple-click).\n- **Drag Selection:** Implements character, word, and line-based selection modes.\n- **Hyperlink Support:** Resolves OSC 8 hyperlinks at the click coordinates. Browser opening is deferred by `MULTI_CLICK_TIMEOUT_MS` to allow double-clicks to select text without triggering a URL open.\n\n## Terminal Compatibility & Color\n\n`@hermes/ink` includes specific logic to normalize behavior across different terminal emulators.\n\n### Color Normalization (`colorize.ts`)\n- **xterm.js Boost:** Automatically upgrades `chalk.level` to 3 (Truecolor) if `TERM_PROGRAM` is `vscode`, as many xterm.js environments support 24-bit color but fail to set `COLORTERM`.\n- **tmux Clamping:** Clamps output to level 2 (256-color) when running inside `tmux` unless the user has explicitly configured truecolor passthrough, preventing background color rendering issues.\n- **Apple Terminal Downgrade:** Implements a custom `richEightBitColorNumber` algorithm to provide better 256-color downgrades for legacy Apple Terminal versions.\n\n### Bidirectional Text (`bidi.ts`)\nSince many Windows terminals (conhost, older Windows Terminal versions) do not implement the Unicode Bidi Algorithm, the `reorderBidi` function:\n1. Detects if the environment requires software bidi (Windows, WSL, or VS Code).\n2. Identifies RTL character ranges (Hebrew, Arabic, etc.).\n3. Reorders `ClusteredChar` arrays from logical to visual order before rendering.\n\n## Performance & Memory Management\n\nTo maintain high frame rates in complex UIs, the module utilizes several module-level caches:\n- **Width Cache:** Stores results of `stringWidth` calculations.\n- **Wrap Cache:** Stores text wrapping results.\n- **Slice Cache:** Caches ANSI-aware string slicing.\n\n### Cache Eviction\nThe `evictInkCaches` function (in `src/ink/cache-eviction.ts`) allows the host application to clear these caches under memory pressure. It supports `all` or `half` eviction levels, using an LRU-style strategy to drop content-keyed entries.\n\n## Hooks API\n\n- `useInput(inputHandler)`: Subscribes to keyboard events.\n- `useSelection()`: Accesses the current terminal text selection state.\n- `useTerminalFocus()`: Returns a boolean indicating if the terminal window is currently focused (via DECSET 1004).\n- `useDeclaredCursor()`: Allows a component to declare where the native terminal cursor should be parked (essential for IME support and screen readers).\n- `useExternalProcess()`: Suspends the Ink renderer to allow a child process (like `vim` or `less`) to take over the terminal.","ui-tui-scripts":"# ui-tui — scripts\n\n# ui-tui Scripts\n\nThe `scripts` directory contains utility scripts for performance analysis and benchmarking of the TUI components. The primary tool is `profile-tui.mjs`, which provides a controlled environment to measure rendering performance, memory consumption, and output volume of the React-based terminal interface.\n\n## profile-tui.mjs\n\nThis script benchmarks the `AppLayout` component by simulating a high-pressure environment: a large message history and a rapid stream of incoming text. It uses the Node.js `inspector` module to capture CPU profiles and heap statistics.\n\n### Core Components\n\n#### The `Sink` Class\nTo avoid the overhead and side effects of actual terminal rendering, the script implements a `Sink` class. This acts as a mock `stdout`/`stderr` that:\n- Tracks the total number of bytes written.\n- Tracks the total number of write operations.\n- Simulates a TTY environment with configurable dimensions (`COLS`, `ROWS`).\n- Discards the actual string data to keep the benchmark focused on the rendering logic rather than terminal I/O.\n\n#### `baseProps(streamingText)`\nThis helper function constructs a comprehensive props object for `AppLayout`. It populates the TUI with:\n- **History**: A large array of mock messages (default 500) to test virtualization.\n- **Virtual History**: Pre-calculated offsets and spacers to simulate the state of the `VirtualList`.\n- **Progress**: State representing active reasoning, tool usage, and streaming text.\n- **Status**: Mock session data including CWD and turn timers.\n\n### Execution Flow\n\nThe script follows a strict lifecycle to ensure clean measurements:\n\n```mermaid\ngraph TD\n A[Reset Global Stores] --> B[Initialize Sink & Mock Stdin]\n B --> C[Enable Node Profiler & HeapProfiler]\n C --> D[Initial Render via @hermes/ink]\n D --> E[Loop: Iterative Rerender]\n E --> F[Simulate Streaming Text Growth]\n F --> G[Stop Profiler & Collect GC]\n G --> H[Output JSON Metrics]\n```\n\n1. **State Reset**: Calls `resetUiState()`, `resetTurnState()`, and `resetOverlayState()` to ensure no leakage from previous runs.\n2. **Profiler Start**: Connects to a `node:inspector` session and starts the CPU profiler.\n3. **The Iteration Loop**: The script performs a configurable number of iterations (default 40). In each iteration:\n * A slice of a large text block is passed as the `reasoning` prop.\n * `inst.rerender()` is called to trigger the React reconciliation and Ink rendering cycle.\n * `setImmediate` is used to allow the event loop to process the render.\n4. **Metrics Collection**: Captures `process.memoryUsage()` before and after the loop, and again after an explicit `HeapProfiler.collectGarbage` call.\n\n### Configuration\n\nThe script is configured via environment variables:\n\n| Variable | Default | Description |\n| :--- | :--- | :--- |\n| `HISTORY` | `500` | Number of messages in the transcript history. |\n| `MOUNTED` | `120` | Number of messages currently \"mounted\" in the virtual window. |\n| `ITERS` | `40` | Number of rerender iterations to perform. |\n| `LINES` | `1200` | Total lines of streaming text to simulate. |\n| `COLS` | `120` | Mock terminal width. |\n| `ROWS` | `42` | Mock terminal height. |\n\n### Output\n\nUpon completion, the script prints a JSON object to `stdout` containing:\n- `elapsedMs`: Total time taken for the iteration loop.\n- `stdoutBytes`: Total volume of data generated by the renderer.\n- `stdoutWrites`: Number of distinct write calls made to the terminal.\n- `startMem` / `endMem` / `afterGc`: Memory snapshots (rss, heapTotal, heapUsed, external).\n- `profileNodes`: The number of nodes in the CPU profile (a proxy for call tree complexity).\n\n### Usage\n\nRun the script directly using `node`:\n\n```bash\nHISTORY=1000 ITERS=100 ./scripts/profile-tui.mjs\n```\n\nThis is typically used during development to detect performance regressions in the rendering pipeline or to validate that virtualization logic in `AppLayout` is effectively limiting the work performed by `@hermes/ink`.","ui-tui-src":"# ui-tui — src\n\n# ui-tui — src\n\nThe `ui-tui` module serves as the core application logic for the Terminal User Interface (TUI). It manages the bridge between the React-based rendering layer (using Ink) and the backend Gateway service. It handles state synchronization, complex interaction patterns like tool-calling and subagent delegation, and the execution of slash commands.\n\n## Architecture Overview\n\nThe module follows a reactive architecture where the Gateway emits events that are processed by a central handler, updating various `nanostores`. These stores then drive the React UI components.\n\n```mermaid\ngraph TD\n GW[GatewayClient] -->|Events| GEH[GatewayEventHandler]\n GEH --> TC[TurnController]\n GEH --> Stores[Nanostores: UI, Turn, Overlay]\n TC --> Stores\n UI[React Components] -->|Actions| SH[SlashHandler]\n SH -->|RPC| GW\n Stores --> UI\n```\n\n## Core Components\n\n### App Entry (`app.tsx`)\nThe `App` component is the root of the TUI. It initializes the application context using `useMainApp` and wraps the layout in a `GatewayProvider`. It injects the `GatewayClient` into the logic layer, enabling RPC communication.\n\n### Turn Controller (`turnController.ts`)\nThe `TurnController` is a singleton class that manages the lifecycle of a single \"turn\" (the period from a user's input to the final assistant response). It is responsible for:\n- **Streaming Management**: Buffering `message.delta` events and flushing them into segments to prevent UI flickering.\n- **Reasoning/Thinking**: Handling reasoning deltas and managing the \"thinking\" state visibility.\n- **Tool Execution**: Tracking active tools, recording progress, and handling inline diffs.\n- **Interruptions**: Managing the state when a user interrupts a running agent, ensuring the transcript remains consistent.\n- **Persistence**: Archiving completed spawn trees to the `spawnHistoryStore`.\n\n### Gateway Event Handler (`createGatewayEventHandler.ts`)\nThis factory creates the primary listener for all events originating from the Gateway. It maps low-level protocol events to high-level application actions:\n- **Session Lifecycle**: Handles `gateway.ready`, `session.info`, and session resumption.\n- **Subagent Tracking**: Processes `subagent.start`, `subagent.progress`, and `subagent.complete` to maintain the delegation tree.\n- **User Prompts**: Handles `clarify.request`, `approval.request`, and `secret.request` by triggering UI overlays.\n- **Voice Integration**: Manages VAD (Voice Activity Detection) states and transcripts for voice-mode interaction.\n\n### Slash Command System\nSlash commands are handled by `createSlashHandler.ts`, which coordinates between local command implementations and remote gateway execution.\n\n- **Registry**: `slash/registry.ts` aggregates commands from core, debug, ops, session, and setup categories.\n- **Resolution**: It first checks the local registry for matches or aliases. If not found locally, it dispatches the command to the Gateway via `slash.exec` or `command.dispatch`.\n- **Context**: Commands receive a `SlashRunCtx` providing access to the transcript, gateway RPCs, and UI state.\n\n## State Management\n\nThe module uses `nanostores` for lightweight, reactive state management outside of the React tree:\n\n| Store | Purpose |\n| :--- | :--- |\n| `$uiState` | Global UI configuration (theme, busy status, compact mode, mouse tracking). |\n| `$turnStore` | Transient state for the active turn (current tools, streaming text, activity logs). |\n| `$overlayState` | Controls visibility and data for modal-like prompts (approvals, model picker, pager). |\n| `$delegationState` | Tracks subagent caps, concurrency limits, and pause status. |\n| `$spawnHistory` | Stores snapshots of completed subagent trees for the `/replay` command. |\n\n## Key Execution Flows\n\n### Message Streaming\n1. `message.delta` arrives via the Gateway.\n2. `turnController.recordMessageDelta` updates the internal buffer.\n3. A batching timer (defined by `STREAM_BATCH_MS`) triggers `flushStreamingSegment`.\n4. The `turnStore` is updated, causing the React `AppLayout` to re-render the streaming text.\n\n### Tool Completion with Inline Diffs\n1. `tool.complete` arrives with an `inline_diff` payload.\n2. `turnController.recordInlineDiffToolComplete` is called.\n3. It flushes any preceding text segments and pushes a specialized `diff` segment into the message history.\n4. This ensures the diff is anchored at the correct temporal point in the conversation.\n\n### Session Resumption\n1. On `gateway.ready`, the handler checks for `STARTUP_RESUME_ID`.\n2. If `tui_auto_resume_recent` is enabled in config, it calls the `session.most_recent` RPC.\n3. It triggers `resumeById`, which fetches the historical transcript and populates the UI.\n\n## External Process Handoff\nThe `setupHandoff.ts` utility manages transitions where the TUI must suspend itself to run an external CLI process (e.g., `hermes setup`). It uses `@hermes/ink`'s `withInkSuspended` to release terminal control and resumes the TUI session once the external process exits.","ui-tui-ui-tui":"# ui-tui — ui-tui\n\n# Hermes TUI (ui-tui)\n\nThe `ui-tui` module provides a React-based terminal user interface for Hermes, powered by [Ink](https://github.com/vadimdemedes/ink). It follows a client-server architecture where the TypeScript frontend manages the screen and user input, while a Python-based gateway handles session state, tool execution, and model interactions.\n\n## Architecture\n\nThe TUI operates as a Node.js process that spawns a Python subprocess (`tui_gateway.entry`) as its backend. Communication occurs via newline-delimited JSON-RPC over `stdin` and `stdout`.\n\n```mermaid\ngraph TD\n A[entry.tsx] --> B[GatewayClient]\n A --> C[App Component]\n B -- JSON-RPC / stdio --> D[Python Gateway]\n C --> E[useComposerState]\n C --> F[useTurnState]\n C --> G[Markdown Renderer]\n```\n\n### Gateway Communication\n- **`GatewayClient`**: Manages the lifecycle of the Python gateway process. It handles interpreter resolution, process spawning, and the JSON-RPC bridge.\n- **Transport**: `stdout` is reserved for JSON-RPC responses and events. `stderr` is captured into an in-memory log ring and surfaced via `gateway.stderr` events to prevent UI corruption.\n- **Event Handling**: `createGatewayEventHandler.ts` maps incoming gateway events (like `message.delta` or `tool.start`) to React state updates.\n\n## Core State Management\n\nThe application state is centralized in `src/app.tsx` and managed through specialized hooks and stores:\n\n- **`useComposerState`**: Manages the input buffer, multiline editing, and the message queue. It handles the logic for \"drafting\" messages while the agent is busy.\n- **`useTurnState`**: Tracks the lifecycle of an agent \"turn,\" including streaming status, tool progress, and reasoning blocks.\n- **`uiStore` & `overlayStore`**: Nanostores used for global UI flags (e.g., status bar visibility) and managing modal-like overlays (e.g., session pickers).\n- **`gatewayContext`**: Provides the `GatewayClient` instance to the component tree via React Context.\n\n## Input & Interaction Model\n\nThe TUI implements a custom input handler in `components/textInput.tsx` and `useInputHandlers.ts` to support advanced terminal interactions.\n\n### Input Modes\n1. **Chat Input**: The default mode for sending messages and slash commands.\n2. **Multiline Mode**: Triggered by `Shift+Enter` or `Alt+Enter`, allowing for complex prompt engineering within the TUI.\n3. **Prompt Overlays**: Blocking states triggered by the gateway (e.g., `approval.request`, `sudo.request`). These suspend the main chat input until resolved.\n4. **External Editor**: `Cmd/Ctrl+G` suspends the TUI and opens the current buffer in the user's `$EDITOR`.\n\n### Command Dispatch\nInput starting with `/` is processed by `createSlashHandler.ts`.\n- **Local Commands**: Commands like `/clear`, `/copy`, and `/exit` are handled directly by the TUI.\n- **Remote Commands**: Unknown slash commands are forwarded to the gateway via `slash.exec` or `command.dispatch`, allowing Python-based plugins to extend the TUI.\n\n## Rendering Engine\n\nThe TUI uses a hybrid rendering approach to balance performance and rich formatting:\n\n- **Transcript**: Uses Ink's `Static` component to render historical messages. This ensures that as the conversation grows, the TUI remains performant by not re-rendering the entire history.\n- **Markdown**: `components/markdown.tsx` transforms a subset of Markdown into Ink components. It supports fenced code blocks (with syntax highlighting), tables, and diffs.\n- **ANSI Support**: If the gateway sends pre-rendered ANSI strings, `messageLine.tsx` renders them directly to preserve formatting from external tools.\n- **Activity Lane**: `thinking.tsx` provides a live view of tool execution, reasoning tokens, and spinners without cluttering the main transcript.\n\n## Prompt Flows\n\nThe gateway can pause execution to request structured input. These are handled as stateful branches in `App.tsx`:\n\n| Request Type | Component | Purpose |\n| :--- | :--- | :--- |\n| `approval.request` | `Prompts` | Security confirmation for tool execution (Once/Always/Deny). |\n| `clarify.request` | `Prompts` | Disambiguation questions with multiple-choice or free-text. |\n| `sudo.request` | `MaskedPrompt` | Secure password entry for elevated permissions. |\n| `session.list` | `SessionPicker` | Interactive list for resuming previous sessions. |\n\n## Development\n\n### Setup\nThe TUI requires `node_modules` to be populated. If running from the repository root:\n```bash\ncd ui-tui\nnpm install\nnpm run build\n```\n\n### Key Files\n- `src/entry.tsx`: The TTY gate and React entry point.\n- `src/app.tsx`: The root component composing the layout and logic.\n- `src/theme.ts`: Merges the default palette with \"skin\" data provided by the gateway.\n- `packages/hermes-ink`: A local fork of Ink used to provide specific terminal behaviors required by Hermes.","ui-tui":"# ui-tui\n\n# Hermes TUI (ui-tui)\n\nThe `ui-tui` module implements a high-performance Terminal User Interface for Hermes. It utilizes a client-server architecture where a Node.js frontend, built with React and a custom terminal reconciler, communicates with a Python-based gateway to manage model interactions and tool execution.\n\n## Architecture Overview\n\nThe TUI is structured into three primary layers: the application logic, the rendering engine, and the performance utility suite.\n\n```mermaid\ngraph TD\n subgraph \"Backend (Python)\"\n PG[Python Gateway]\n end\n\n subgraph \"Frontend (Node.js / React)\"\n GC[GatewayClient] <-->|JSON-RPC| PG\n GEH[GatewayEventHandler] --> NS[Nanostores]\n TC[TurnController] --> NS\n \n subgraph \"Rendering Engine (@hermes/ink)\"\n Rec[Reconciler] --> Yoga[Layout Engine]\n Yoga --> Buffer[Screen Buffer]\n end\n\n NS --> UI[React Components]\n UI --> Rec\n end\n\n subgraph \"Tooling\"\n Bench[profile-tui.mjs] -.-> UI\n end\n```\n\n## Sub-modules\n\n### [Core Application (src)](src.md)\nThe `src` directory contains the central business logic. It manages the lifecycle of a \"turn\" (a single interaction with the model) via the `TurnController`. \n- **State Management:** Uses `nanostores` to synchronize state between the backend and the UI.\n- **Gateway Communication:** The `GatewayClient` handles the bidirectional JSON-RPC stream over `stdio` to the Python backend.\n- **Event Handling:** Processes incoming events (streaming text, tool calls, reasoning phases) and updates the UI state reactively.\n\n### [Rendering Engine (@hermes/ink)](packages.md)\nLocated in `packages/ink`, this is a specialized React reconciler optimized for terminal environments. It extends the standard Ink library to support:\n- **Advanced Interactions:** Multi-click mouse support and drag-selection.\n- **Layout & Buffer:** Uses the Yoga layout engine to map React components to a character-grid buffer.\n- **Performance:** Implements a diffing engine that minimizes terminal write operations by only updating changed cells.\n\n### [Utility & Benchmarking (scripts)](scripts.md)\nThe `scripts` directory provides tools for maintaining TUI performance.\n- **Profiling:** `profile-tui.mjs` benchmarks the `AppLayout` under high-pressure scenarios (e.g., rapid text streaming).\n- **Mocking:** Includes a `Sink` class that simulates terminal output, allowing for CPU and memory profiling without the overhead of actual TTY rendering.\n\n## Key Workflows\n\n1. **The Interaction Loop:** When the Python Gateway emits a message delta, the `GatewayClient` parses the JSON-RPC notification. The `GatewayEventHandler` then triggers the `TurnController` to update the `turnStore`. React components, observing these stores, re-render via the `@hermes/ink` reconciler.\n2. **Tool Execution:** When a tool call is detected, the `TurnController` manages the transition from message streaming to tool execution state, updating the UI to show progress indicators or subagent delegation status.\n3. **Performance Validation:** Developers use the `scripts` suite to ensure that complex UI updates—such as markdown rendering or inline diffs—do not exceed memory or CPU budgets during long-running sessions.","web-src":"# web — src\n\n# Hermes Dashboard (web/src)\n\nThe `web/src` module is the React-based frontend for the Hermes Agent. It provides a comprehensive management dashboard for sessions, analytics, model configuration, and a persistent terminal-based chat interface.\n\n## Core Architecture\n\n### Routing and Persistence\nThe application uses `react-router-dom` for navigation, but employs a hybrid rendering strategy to maintain state for the terminal-based chat.\n\n* **Standard Routes:** Pages like Analytics, Logs, and Config are rendered within a standard `<Routes>` switch.\n* **Persistent Chat:** When `isDashboardEmbeddedChatEnabled()` is true, the `ChatPage` is rendered outside the main `<Routes>` block. This ensures that the PTY child, WebSocket connections, and xterm.js instances survive when a user navigates to other tabs. A `display: none` toggle is used to hide the terminal without unmounting it.\n* **ChatRouteSink:** A placeholder component used in the router to claim the `/chat` path, preventing the `*` redirect while the persistent host handles the actual rendering.\n\n### Plugin Integration\nThe dashboard is highly extensible via a manifest-driven plugin system.\n* **Navigation Injection:** `partitionSidebarNav` merges built-in routes with plugin-defined tabs, supporting positioning hints like `before:path` or `after:path`.\n* **UI Slots:** The `PluginSlot` component provides named injection points (e.g., `backdrop`, `header-banner`, `pre-main`) where plugins can render custom components.\n* **Route Overrides:** Plugins can override built-in routes (like `/chat`) by specifying an `override` path in their manifest.\n\n## Communication Layer\n\nThe dashboard communicates with the Hermes backend through two primary channels:\n\n1. **REST API (`lib/api.ts`):** Used for stateless operations such as fetching logs, updating configuration, managing cron jobs, and retrieving model information.\n2. **Gateway Client (`lib/gatewayClient.ts`):** A JSON-RPC over WebSocket client used for stateful, real-time interactions.\n\n### Chat Synchronization\nThe `ChatSidebar` component demonstrates a dual-socket pattern:\n* **JSON-RPC Sidecar:** Uses `GatewayClient` to drive the dashboard's in-process gateway (e.g., switching models via `slash.exec`).\n* **Event Subscriber:** Connects to `/api/events?channel=...` to passively receive tool execution updates (`tool.start`, `tool.progress`, `tool.complete`) fanned out from the PTY child.\n\n```mermaid\ngraph TD\n App --> Routes\n App --> ChatPage\n ChatPage --> ChatSidebar\n ChatSidebar --> GatewayClient[JSON-RPC WS]\n ChatSidebar --> EventSub[Event Subscriber WS]\n GatewayClient --> Backend\n EventSub --> Backend\n```\n\n## Key Components\n\n### Model Selection (`ModelPickerDialog.tsx`)\nA two-stage modal for selecting providers and models. It operates in two modes:\n* **Chat Mode:** Emits a slash command (e.g., `/model gpt-4o`) to the active session via JSON-RPC.\n* **Standalone Mode:** Used in configuration pages to update global settings via REST API.\n\n### Dynamic Forms (`AutoField.tsx`)\nGenerates UI inputs dynamically based on a schema. It supports:\n* **Booleans:** Rendered as `Switch`.\n* **Selects:** Rendered as `Select` with predefined options.\n* **Lists:** Handles comma-separated string inputs.\n* **Objects:** Recursively renders nested fields for complex configurations.\n\n### Markdown Rendering (`Markdown.tsx`)\nA lightweight, performance-optimized Markdown renderer tailored for LLM outputs.\n* **Streaming Support:** Includes a `streaming` prop that renders a blinking caret at the end of the last block.\n* **Pattern Matching:** Specifically handles fenced code blocks, headers, and inline formatting (bold, italic, links) without the overhead of a full CommonMark parser.\n\n### OAuth Management (`OAuthProvidersCard.tsx`)\nHandles authentication flows for external platforms.\n* **PKCE Flow:** Opens a browser window for authorization and accepts a manual code entry.\n* **Device Code Flow:** Displays a user code and polls the backend until the user approves the login on the external site.\n\n## Theming and Visuals\n\n### Backdrop System (`Backdrop.tsx`)\nImplements a complex visual stack to match the Hermes design language:\n1. **Base Layer:** `background-base` with `difference` blend mode.\n2. **Filler Layer:** Inverted JPEG textures at low opacity.\n3. **Warm Glow:** A radial vignette anchored to the top-left.\n4. **Noise Grain:** An SVG-based fractal noise layer, gated by `useGpuTier` to disable animations on low-power hardware or for users with `prefers-reduced-motion`.\n\n### Theme Switcher (`ThemeSwitcher.tsx`)\nAllows users to toggle between built-in and user-defined themes. It provides a 3-stop swatch preview (Background, Midground, Warm Glow) for each theme. Themes are applied by updating CSS custom properties on the root element, allowing for instant repainting without a page reload.\n\n## Execution Flows\n\n### System Actions\nThe `SidebarSystemActions` component triggers high-level gateway operations:\n1. User clicks \"Restart Gateway\".\n2. `useSystemActions` hook invokes the backend action.\n3. The UI enters a \"Busy\" state, showing a spinner in the sidebar.\n4. The app navigates to `/sessions` to monitor the gateway's recovery.\n\n### Slash Command Autocomplete\nThe `SlashPopover` provides real-time suggestions in the chat composer:\n1. Input starts with `/`.\n2. `complete.slash` request is debounced and sent via `GatewayClient`.\n3. Results are rendered in a popover above the input.\n4. Keyboard events (Arrow keys, Tab) are intercepted by the popover via `useImperativeHandle`.","web-web":"# web — web\n\n# Hermes Agent Web UI\n\nThe `web` module is a React-based dashboard providing a graphical interface for managing Hermes Agent configurations, API keys, and monitoring active sessions. It is built as a Single Page Application (SPA) that integrates tightly with the Hermes Python backend.\n\n## Tech Stack\n\n- **Framework**: React 19 with TypeScript\n- **Build Tool**: Vite\n- **Styling**: Tailwind CSS v4\n- **UI Components**: Custom primitives inspired by shadcn/ui and `@nous-research/ui`\n- **State & Routing**: `react-router-dom`\n\n## Architecture & Integration\n\nThe dashboard operates in two modes: **Development** (with HMR) and **Production** (served as static assets by FastAPI).\n\n```mermaid\ngraph TD\n subgraph \"Browser\"\n UI[React UI]\n API[api.ts Client]\n end\n subgraph \"Vite Dev Server (Port 5173)\"\n Proxy[Vite Proxy]\n TokenPlugin[hermesDevToken Plugin]\n end\n subgraph \"Python Backend (Port 9119)\"\n FastAPI[FastAPI Server]\n Static[web_dist Static Files]\n end\n\n UI --> API\n API --> Proxy\n Proxy --> FastAPI\n TokenPlugin -- Scrapes Token --> FastAPI\n```\n\n### API Communication\nAll backend interactions are centralized in `src/lib/api.ts`. This module provides typed fetch wrappers for the FastAPI endpoints. In development, Vite proxies requests starting with `/api` to the backend server (defaulting to `http://127.0.0.1:9119`).\n\n### Session Authentication\nThe Hermes backend uses a one-shot session token for security. \n- **Production**: The Python server injects `window.__HERMES_SESSION_TOKEN__` directly into the `index.html` before serving it.\n- **Development**: The `hermesDevToken` plugin in `vite.config.ts` fetches the backend's `index.html`, extracts the token via regex (`TOKEN_RE`), and injects it into the Vite-served HTML. This ensures that developers can make authenticated API calls during local development without manual token management.\n\n## Directory Structure\n\n- `src/components/ui/`: Reusable UI primitives (Buttons, Cards, Inputs).\n- `src/lib/api.ts`: The core API client.\n- `src/lib/utils.ts`: Contains the `cn()` helper for merging Tailwind classes using `clsx` and `tailwind-merge`.\n- `src/pages/`:\n - `StatusPage`: Displays agent health and active/recent session telemetry.\n - `ConfigPage`: A dynamic configuration editor that renders forms based on the JSON schema provided by the backend.\n - `EnvPage`: Interface for managing environment variables and API keys.\n\n## Development Workflow\n\n### Setup\nBefore starting the UI, the backend must be running to provide the API and the session token:\n\n```bash\n# Terminal 1: Backend\npython -m hermes_cli.main web --no-open\n\n# Terminal 2: Frontend\ncd web/\nnpm install\nnpm run dev\n```\n\n### Asset Syncing\nThe project relies on external design system assets. The `sync-assets` script (triggered via `predev` and `prebuild`) copies fonts and assets from `@nous-research/ui` into the `public/` directory.\n\n### Dependency Deduplication\nThe `vite.config.ts` includes a `dedupe` configuration for packages like `react`, `three`, and `gsap`. This is critical when using symlinked libraries (like a local design language repo) to prevent multiple instances of React or WebGL contexts, which would otherwise cause hook errors or rendering conflicts.\n\n## Build and Deployment\n\nRunning `npm run build` executes the following:\n1. `tsc -b`: Type-checks the project.\n2. `vite build`: Bundles assets into `../hermes_cli/web_dist/`.\n\nThe Python package is configured to include the `web_dist` directory as package data. When a user runs `hermes dashboard`, the FastAPI server mounts this directory to serve the SPA.","web":"# web\n\n# Web Module\n\nThe `web` module provides the graphical interface for the Hermes Agent ecosystem. It is a React-based Single Page Application (SPA) designed to manage agent configurations, monitor real-time sessions, and provide a persistent terminal-based chat interface.\n\n## Architecture Overview\n\nThe module is structured to balance standard web navigation with the high-availability requirements of LLM interactions and terminal emulators.\n\n* **[web](web.md)**: Defines the build system (Vite), styling framework (Tailwind CSS v4), and the integration strategy with the FastAPI backend. It manages the transition between development (HMR) and production (static asset serving).\n* **[src](src.md)**: Contains the application logic, including a hybrid rendering engine that separates transient UI (Analytics, Logs) from persistent stateful components (Chat, WebSockets).\n\n### Component Interaction\n\nThe dashboard utilizes a centralized gateway client to synchronize state between the browser and the Python backend.\n\n```mermaid\ngraph LR\n subgraph \"web/src (Frontend)\"\n App[App Shell]\n Router[React Router]\n Chat[Persistent Chat]\n Gateway[Gateway Client]\n end\n\n subgraph \"Backend\"\n API[FastAPI]\n WS[WebSocket/PTY]\n end\n\n App --> Router\n App --> Chat\n Router --> Pages[Analytics / Config / Logs]\n Chat <--> WS\n Pages <--> Gateway\n Gateway <--> API\n```\n\n## Key Workflows\n\n### Persistent Communication\nUnlike standard SPA routes that unmount on navigation, the `web` module employs a hybrid strategy for the **ChatPage**. When embedded chat is enabled, the terminal instance and its associated WebSocket connections are rendered outside the main routing switch. This ensures that active agent sessions and xterm.js instances remain alive while the user navigates between **Analytics**, **Models**, and **Skills** pages.\n\n### Plugin & Theme Integration\n functionality is extended through a dynamic plugin registry. The `usePlugins` hook resolves components at runtime, allowing the dashboard to incorporate new tools and views without core logic changes. This is complemented by a `ThemeProvider` that injects CSS variables and font stylesheets to maintain visual consistency across custom and core components.\n\n### Session & Model Management\nThe interface provides specialized views for managing the agent's lifecycle:\n* **Sessions & Logs**: Real-time monitoring of agent thoughts and tool calls via `SessionsPage`.\n* **Configuration**: Centralized management of LLM providers, API keys, and model parameters through `ModelsPage` and `ProfilesPage`.\n* **Skill Orchestration**: A dedicated `SkillsPage` for toggling agent capabilities and viewing tool categories.","website-docs":"# website — docs\n\n# Hermes Agent Developer Documentation\n\nThis module contains the technical specifications, internal architecture, and extensibility guides for the Hermes Agent ecosystem. It serves as the primary reference for developers contributing to the core engine, building platform adapters, or implementing new tools and skills.\n\n## System Architecture\n\nHermes is designed as a platform-agnostic orchestration engine. The core logic resides in the `AIAgent` class, which is wrapped by various entry points (CLI, Gateway, ACP).\n\n### High-Level Component Map\n\n```mermaid\ngraph TD\n Entry[CLI / Gateway / ACP] --> Agent[AIAgent - run_agent.py]\n Agent --> Prompt[Prompt Builder]\n Agent --> Context[Context Engine]\n Agent --> Tools[Tool Registry]\n Agent --> Providers[Runtime Provider Resolver]\n Tools --> Backends[Terminal / Browser / File / MCP]\n Agent --> Storage[Session DB - SQLite]\n```\n\n### Core Subsystems\n* **Agent Loop (`run_agent.py`)**: The central orchestration engine handling conversation state, tool dispatch, and provider failover.\n* **Tool Registry (`tools/registry.py`)**: A discovery-based system where tools self-register. It manages schemas and execution for 60+ built-in tools.\n* **Gateway (`gateway/run.py`)**: A multi-platform messaging server supporting 20+ adapters (Telegram, Discord, Slack, etc.).\n* **ACP Adapter (`acp_adapter/`)**: An implementation of the Agent Control Protocol, allowing IDEs (VS Code, Zed) to communicate with Hermes via JSON-RPC over stdio.\n\n---\n\n## Agent Loop Internals\n\nThe `AIAgent` class in `run_agent.py` manages the lifecycle of a conversation turn.\n\n### Execution Flow: `run_conversation()`\n1. **Prompt Assembly**: `prompt_builder.py` constructs the system prompt from personality (`SOUL.md`), memory, and active skills.\n2. **Context Check**: If the conversation exceeds the compression threshold (default 50%), `ContextCompressor` triggers a summarization pass.\n3. **API Mode Selection**: The agent resolves the provider to one of three modes:\n * `chat_completions`: Standard OpenAI-compatible flow.\n * `codex_responses`: OpenAI Codex/Responses format.\n * `anthropic_messages`: Native Anthropic Messages API via `anthropic_adapter.py`.\n4. **Interruptible Call**: The LLM request is wrapped in `_interruptible_api_call` to allow user cancellation mid-stream.\n5. **Tool Dispatch**: If the model returns `tool_calls`, `model_tools.handle_function_call()` routes them to the registry or intercepts agent-level tools (`todo`, `memory`, `delegate_task`).\n\n### API Role Alternation\nThe loop enforces strict OpenAI-style role sequences: `User -> Assistant -> Tool -> Assistant`. It prevents consecutive messages of the same role to ensure compatibility across strict providers.\n\n---\n\n## Extensibility\n\n### 1. Adding Tools\nTools are Python functions registered with the `registry`.\n* **Location**: `tools/your_tool.py`\n* **Requirement**: Must return a JSON string.\n* **Registration**:\n ```python\n registry.register(\n name=\"my_tool\",\n schema=MY_SCHEMA,\n handler=my_handler_func,\n check_fn=check_requirements\n )\n ```\n* **Integration**: Add the tool name to `_HERMES_CORE_TOOLS` in `toolsets.py`.\n\n### 2. Creating Skills\nSkills are instruction-based capabilities defined in `SKILL.md` files.\n* **Format**: Markdown with YAML frontmatter.\n* **Features**: Supports platform gating (`platforms: [macos]`), tool dependencies (`requires_tools`), and environment variable passthrough.\n* **Dynamic Context**: Supports template variables like `${HERMES_SKILL_DIR}` and inline shell snippets `` !`cmd` ``.\n\n### 3. Platform Adapters\nAdapters connect Hermes to messaging services.\n* **Base Class**: `BasePlatformAdapter` in `gateway/platforms/base.py`.\n* **Methods**: Must implement `connect()`, `disconnect()`, and `send()`.\n* **Plugin Path**: New platforms can be added without core changes by placing an `adapter.py` and `PLUGIN.yaml` in `~/.hermes/plugins/`.\n\n---\n\n## Context Management\n\nHermes uses a dual-layer approach to manage large context windows.\n\n### Context Compression\nTriggered when prompt tokens reach a threshold (default 50%).\n1. **Pruning**: Old, verbose tool results are cleared.\n2. **Summarization**: Middle conversation turns are sent to an auxiliary LLM to generate a structured summary (Goal, Progress, Decisions, Next Steps).\n3. **Tail Protection**: The most recent `N` messages (default 20) are preserved intact.\n\n### Prompt Caching\nFor Anthropic providers, `prompt_caching.py` implements a \"system_and_3\" strategy, placing `cache_control` breakpoints at the system prompt and the last three messages to minimize latency and cost in multi-turn sessions.\n\n---\n\n## ACP (Agent Control Protocol)\n\nThe ACP adapter (`acp_adapter/server.py`) transforms the synchronous `AIAgent` into an asynchronous JSON-RPC server.\n* **Transport**: Stdio (Stdout for RPC, Stderr for logs).\n* **Session Management**: `SessionManager` tracks live sessions, supporting `fork`, `resume`, and `cancel` operations.\n* **Event Bridge**: `events.py` uses `asyncio.run_coroutine_threadsafe` to pipe sync agent callbacks (thinking, tool progress) into async ACP notifications.\n\n---\n\n## Browser Supervision\n\nThe `CDPSupervisor` (`tools/browser_supervisor.py`) manages persistent Chrome DevTools Protocol connections.\n* **Dialog Handling**: Intercepts `alert`, `confirm`, and `prompt` calls. It can pause execution until the agent calls `browser_dialog`.\n* **Iframe Interaction**: Tracks the frame tree and enables `Runtime.evaluate` calls inside cross-origin (OOPIF) iframes by routing through specific CDP session IDs.\n* **Backend Support**: Optimized for Local Chrome and Browserbase; provides a bridge for environments where native CDP is restricted.\n\n---\n\n## Development Standards\n\n### Environment Setup\n* **Python**: 3.11+ managed via `uv`.\n* **Home Directory**: All state is stored in `~/.hermes/` (or a profile-specific subdirectory).\n* **Testing**: Pytest suite located in `tests/`. Use `-n0` for tests involving shared resources like the Session DB.\n\n### Security\n* **Dangerous Commands**: `tools/approval.py` contains regex patterns for destructive shell commands that trigger mandatory user approval.\n* **Sandboxing**: `execute_code` and `terminal` tools support backends like Docker, Modal, and SSH to isolate execution from the host.","website-scripts":"# website — scripts\n\n# Website Scripts Module\n\nThe `website/scripts` module contains the automation logic required to synchronize the Hermes Agent documentation and skill metadata with the Docusaurus-based website. These scripts transform raw repository content (Markdown files, YAML metadata, and cached indexes) into structured data and web-ready documentation pages.\n\n## The Prebuild Pipeline\n\nThe primary entry point for this module is `prebuild.mjs`. This script is executed automatically during `npm run start` or `npm run build` to ensure the website's data is up-to-date.\n\n```mermaid\ngraph TD\n A[prebuild.mjs] --> B[extract-skills.py]\n A --> C[generate-llms-txt.py]\n D[SKILL.md files] --> B\n D --> E[generate-skill-docs.py]\n F[website/docs/] --> C\n B --> G[skills.json]\n E --> H[Skill Pages & Catalogs]\n C --> I[llms.txt & llms-full.txt]\n```\n\n### prebuild.mjs\nA Node.js wrapper that orchestrates the Python scripts. It includes fallback logic: if `python3` or `pyyaml` is missing on the local machine, it writes an empty `skills.json` to allow the Docusaurus build to proceed without failing, though the Skills Hub will be empty.\n\n## Skill Metadata Extraction\n\n### extract-skills.py\nThis script aggregates skill metadata from multiple sources into a single JSON file used by the website's \"Skills Hub.\"\n\n* **Sources:**\n * **Local Skills:** Scans `skills/` and `optional-skills/` for `SKILL.md` files.\n * **Cached Indexes:** Processes JSON files in `skills/index-cache/` (e.g., community skills from Anthropic, OpenAI, or LobeHub).\n* **Processing Logic:**\n * **Category Mapping:** Uses `CATEGORY_LABELS` to normalize directory names into human-readable labels.\n * **Category Guessing:** For external skills without explicit categories, `_guess_category` uses a tag-to-category mapping.\n * **Consolidation:** Categories with fewer than 4 skills are moved to \"Other\" via `_consolidate_small_categories` to prevent UI clutter.\n* **Output:** Generates `website/src/data/skills.json`.\n\n## Automated Skill Documentation\n\n### generate-skill-docs.py\nThis script converts the raw `SKILL.md` files found in the repository into Docusaurus-compatible Markdown pages. This ensures that every skill has a dedicated, searchable page in the documentation.\n\n* **MDX Safety:** Since Docusaurus uses MDX, raw Markdown can break the build if it contains unescaped `{` or `<` characters. The `mdx_escape_body` and `escape_text` functions sanitize the content while preserving valid HTML tags (like `<img>` or `<br>`) and fenced code blocks.\n* **ASCII Guard:** If a skill's documentation contains box-drawing characters (common in ASCII diagrams), `_wrap_ascii_art_code_blocks` wraps the block in `<!-- ascii-guard-ignore -->` to bypass documentation linting rules.\n* **Link Rewriting:** `rewrite_relative_links` converts relative file paths (e.g., `./templates/config.json`) into absolute GitHub URLs, as these supporting files are not copied to the website.\n* **Catalog Generation:**\n * Updates `website/docs/reference/skills-catalog.md` (Bundled skills).\n * Updates `website/docs/reference/optional-skills-catalog.md` (Installable skills).\n* **Sidebar Management:** `write_sidebar` programmatically modifies `website/sidebars.ts` to include the generated catalogs without overwhelming the navigation with hundreds of individual skill links.\n\n## Documentation for LLMs\n\n### generate-llms-txt.py\nGenerates agent-friendly versions of the documentation, following the `llms.txt` proposal.\n\n* **llms.txt:** A curated, high-level index of the documentation. It uses the `SECTIONS` constant to define a narrative flow (Getting Started -> Using Hermes -> Core Features, etc.) rather than a raw filesystem crawl.\n* **llms-full.txt:** A massive concatenation of all documentation files. \n * **Ordering:** Prioritizes the curated `SECTIONS` first to ensure the most important context appears within the token window of most LLMs.\n * **Source Attribution:** Injects `<!-- source: path/to/file.md -->` comments before each section to help agents identify the origin of the information.\n* **Pathing:** Outputs to `website/static/`. Note that Docusaurus serves the `static/` directory at the `/docs/` base path, making these available at `/docs/llms.txt`.\n\n## Key Functions and Patterns\n\n| Function | Script | Purpose |\n|:---|:---|:---|\n| `read_frontmatter` | `generate-llms-txt.py` | Extracts YAML metadata and body text from Markdown files. |\n| `derive_skill_meta` | `generate-skill-docs.py` | Determines category and slug based on the `skills/` directory structure. |\n| `render_skill_page` | `generate-skill-docs.py` | Templates the final Docusaurus Markdown, including metadata tables. |\n| `_guess_category` | `extract-skills.py` | Assigns categories to external skills based on keyword matching in tags. |\n| `runPython` | `prebuild.mjs` | Safely executes Python scripts and handles `ENOENT` errors. |","website-src":"# website — src\n\n# Website Source Module\n\nThe `website/src` module contains the frontend components, pages, and global styling for the Hermes Agent documentation and marketing site. Built on Docusaurus, it implements a custom \"terminal aesthetic\" using a dark amber-on-black color palette and provides interactive dashboards for exploring the Hermes ecosystem.\n\n## Global Styling and Theme\n\nThe site's visual identity is defined in `src/css/custom.css`. It overrides Docusaurus defaults to match the Hermes Agent branding.\n\n### Terminal Aesthetic\n- **Color Palette**: Uses a primary amber/gold color (`#FFD700` in dark mode, `#8B6508` in light mode).\n- **Typography**: Utilizes `Inter` for UI text and `JetBrains Mono` for code and technical data.\n- **Backgrounds**: Implements a subtle radial-gradient dot grid on `.main-wrapper` to simulate a retro-tech feel.\n- **Component Overrides**: Customizes Docusaurus admonitions, tables, and navigation menus with gold-tinted borders and translucent backgrounds.\n\n## Skills Hub (`SkillsDashboard`)\n\nLocated at `src/pages/skills/index.tsx`, this component provides a searchable catalog of agent capabilities. It consumes data from `src/data/skills.json`.\n\n### Data Architecture\nThe dashboard manages a collection of `Skill` objects:\n```typescript\ninterface Skill {\n name: string;\n description: string;\n category: string;\n categoryLabel: string;\n source: string; // e.g., 'built-in', 'optional', 'LobeHub'\n tags: string[];\n platforms: string[];\n author: string;\n version: string;\n}\n```\n\n### Key Features\n- **Multi-faceted Filtering**: Users can filter by registry source (via `sourceFilter`) and functional category (via `categoryFilter`).\n- **Search with Highlighting**: The `highlightMatch` function performs case-insensitive substring matching across names and descriptions, wrapping matches in `<mark>` tags.\n- **Interactive Cards**: The `SkillCard` component supports an expanded state to show metadata (author, version, tags) and a CLI installation hint (`hermes skills install <name>`).\n- **Performance**: Filtering and category count aggregations are wrapped in `useMemo` to prevent expensive recalculations on every keystroke.\n\n### Execution Flow\n```mermaid\ngraph TD\n JSON[skills.json] --> Dashboard[SkillsDashboard]\n Dashboard --> Filter[useMemo: Filtered List]\n Filter --> Grid[Render SkillCard Grid]\n Grid --> Interaction[Toggle Expand / Filter by Tag]\n```\n\n## User Stories Collage\n\nLocated at `src/components/UserStoriesCollage/index.tsx`, this component displays community use cases in a masonry-style grid.\n\n### Masonry Layout\nUnlike standard grids, this component uses CSS `column-count` (defined in `styles.module.css`) to create a \"true collage\" feel where tiles of different heights (defined by `size: 'sm' | 'md' | 'lg'`) stack efficiently.\n\n### Dynamic Styling\nThe component uses a mapping object `CATEGORIES` to assign specific accent colors and gradients to tiles based on their metadata. These are passed to the DOM via CSS variables:\n```tsx\nstyle={{\n '--tile-accent': cat.strip,\n '--tile-accent-solid': cat.solid,\n '--tile-accent-soft': cat.soft,\n} as React.CSSProperties}\n```\n\n### Source Mapping\nThe `sourceColor` helper function assigns brand-specific colors to badges based on the origin of the story (e.g., X/Twitter, Hacker News, Reddit, GitHub).\n\n## Component Patterns\n\n### Filter Buttons\nBoth the Skills Hub and User Stories use a consistent \"Pill\" filter pattern. Buttons display the count of items available in that category, calculated via `useMemo` loops over the raw data sets.\n\n### Responsive Design\n- **Mobile Sidebar**: The Skills Hub implements a `sidebarToggle` and a `backdrop` for mobile users, as the standard desktop sidebar is hidden via media queries at widths below 900px.\n- **Grid Scaling**: The User Stories grid scales from 4 columns on desktop down to 1 column on mobile devices using standard CSS breakpoints.\n\n### Search UX\nThe Skills Hub implements a global keyboard listener for the `/` key to focus the search input and `Escape` to clear focus or collapse expanded cards, mimicking IDE and documentation search patterns.","website-static":"# website — static\n\n# Website Static Assets\n\nThe `website/static` module contains non-executable assets served by the Hermes Agent web platform. The primary component is the Model Catalog, which acts as the central manifest for supported Large Language Models (LLMs) across different providers.\n\n## Model Catalog (`/api/model-catalog.json`)\n\nThe `model-catalog.json` file is a versioned manifest used by the frontend to populate model selection interfaces and apply provider-specific metadata. It decouples the UI's model list from the application's hardcoded logic, allowing for updates to supported models without requiring a full redeploy of the core services.\n\n### Schema Structure\n\n| Field | Type | Description |\n| :--- | :--- | :--- |\n| `version` | Integer | Schema version for compatibility tracking. |\n| `updated_at` | ISO8601 | Timestamp of the last manual or automated update. |\n| `metadata` | Object | Source information and links to reference documentation. |\n| `providers` | Object | A map of provider keys (e.g., `openrouter`, `nous`) containing model lists. |\n\n### Provider Configurations\n\nEach provider entry contains a `metadata` block and a `models` array.\n\n#### OpenRouter\nThe OpenRouter implementation uses the `description` field in the model list to drive UI elements:\n* **Badges**: Values like `\"recommended\"` or `\"free\"` are used by the frontend picker to render visual badges next to model names.\n* **Filtering**: While this manifest provides a curated list, the application logic typically intersects this list with the live OpenRouter `/api/v1/models` endpoint to filter for tool-calling support and current availability.\n\n#### Nous Portal\nThe Nous Portal configuration represents models available via the internal Nous infrastructure.\n* **Tier Gating**: Unlike OpenRouter, the \"free\" or \"pro\" status of Nous models is not determined by this static file. The application uses the `partition_nous_models_by_tier` function to determine access levels dynamically based on live Portal pricing data.\n\n### Data Flow\n\n```mermaid\ngraph TD\n Catalog[model-catalog.json] --> UI[Model Picker UI]\n Catalog --> Filter[Provider Filter Logic]\n Filter -->|Intersects| LiveAPI[OpenRouter/Portal API]\n UI -->|Displays| Badges[UI Badges: free/recommended]\n```\n\n## Usage in Development\n\n### Adding a New Model\nTo add a model to the catalog, append a new object to the relevant provider's `models` array:\n\n```json\n{\n \"id\": \"provider/model-name\",\n \"description\": \"recommended\"\n}\n```\n\n### Integration Notes\n* **Model IDs**: Ensure the `id` matches the exact string expected by the provider's completion endpoint.\n* **Descriptions**: The `description` field is currently optimized for OpenRouter. For the Nous provider, the field is optional as tiering is handled by the `partition_nous_models_by_tier` logic in the backend/client integration layer.\n* **Caching**: As a static asset under `/api/`, this file is subject to standard web caching headers. Ensure version increments if structural changes are made to the schema.","website-website":"# website — website\n\n# Hermes Agent Documentation Website\n\nThe `website` module contains the source code and configuration for the [Hermes Agent documentation](https://hermes-agent.nousresearch.com/docs/). It is built using **Docusaurus 3**, a modern static website generator, and is configured to provide a comprehensive guide for users, integrators, and developers.\n\n## Architecture Overview\n\nThe website is structured as a documentation-only Docusaurus site (the blog feature is disabled). It serves content from the root path `/docs/`.\n\n```mermaid\ngraph TD\n A[Markdown Sources] --> B[Docusaurus Engine]\n C[sidebars.ts] --> B\n D[docusaurus.config.ts] --> B\n E[scripts/prebuild.mjs] -- Generates Content --> A\n B --> F[Static HTML/JS/CSS]\n F --> G[GitHub Pages / Web Hosting]\n```\n\n## Key Components\n\n### Configuration (`docusaurus.config.ts`)\nThis is the central configuration file. Key settings include:\n- **Search**: Uses `@easyops-cn/docusaurus-search-local`. It is configured to ignore auto-generated skill pages (under `user-guide/skills/bundled/` and `user-guide/skills/optional/`) to ensure search results prioritize human-written guides.\n- **Markdown**: Supports Mermaid diagrams and uses `onBrokenLinks: 'warn'` to manage internal cross-references.\n- **Theme**: Uses the Docusaurus classic preset with a custom dark-mode-first color scheme.\n- **Syntax Highlighting**: Powered by Prism with support for `bash`, `yaml`, `json`, `python`, and `toml`.\n\n### Navigation (`sidebars.ts`)\nThe sidebar defines the logical flow of the documentation. It is organized into several high-level categories:\n- **Getting Started**: Installation and initial setup.\n- **Using Hermes**: Core CLI/TUI usage and configuration.\n- **Features**: Deep dives into tools, skills, memory, and automation.\n- **Messaging Platforms**: Integration guides for Telegram, Discord, Slack, etc.\n- **Developer Guide**: Architecture, internals, and contribution guidelines.\n- **Reference**: CLI commands, environment variables, and tool catalogs.\n\n### Pre-build Processing\nThe module utilizes a `scripts/prebuild.mjs` script (executed via `npm run prebuild` or `npm run prestart`). This script is responsible for preparing dynamic content or catalogs before the Docusaurus engine generates the static files.\n\n## Development Workflow\n\n### Installation\nInstall dependencies using Yarn:\n```bash\nyarn\n```\n\n### Local Development\nStart the development server with hot-reloading:\n```bash\nyarn start\n```\nThe site will typically be available at `http://localhost:3000/docs/`.\n\n### Build and Deployment\nTo generate the static production build:\n```bash\nyarn build\n```\nThe output is located in the `build/` directory.\n\nTo deploy to GitHub Pages:\n```bash\n# Using SSH\nUSE_SSH=true yarn deploy\n\n# Using HTTPS\nGIT_USER=<username> yarn deploy\n```\n\n## Content Standards\n\n### Diagram Linting\nThe project uses `ascii-guard` to ensure documentation quality. \n- **Constraint**: Do not use ASCII box diagrams in Markdown files.\n- **Requirement**: Use Mermaid code blocks (````mermaid`) or standard Markdown lists/tables.\n- **Validation**: Run `yarn lint:diagrams` to check for violations.\n\n### Search Indexing\nThe search plugin is configured with `indexBlog: false` and `docsRouteBasePath: '/'`. If adding new auto-generated content sections that might clutter search results, update the `ignoreFiles` regex array in `docusaurus.config.ts`.\n\n### Styling\nCustom styles are managed in `src/css/custom.css`. The site respects the user's system color scheme but defaults to `dark` mode.","website":"# website\n\n# Website Module\n\nThe `website` module is a Docusaurus 3-based platform that serves as the central documentation hub for the Hermes Agent ecosystem. It integrates static technical guides, automated skill documentation, and interactive catalogs into a unified \"terminal-themed\" web interface.\n\n## Module Integration\n\nThe website functions through a pipeline that transforms raw repository data into a structured documentation site:\n\n1. **Content Generation**: The [scripts](scripts.md) module runs a prebuild pipeline (via `prebuild.mjs`) that extracts metadata from the core repository. It processes `SKILL.md` files and YAML metadata to generate dynamic documentation pages and the `skills.json` index.\n2. **Static Documentation**: The [docs](docs.md) module provides the manual technical specifications, architecture maps, and developer guides that form the core of the site's knowledge base.\n3. **Frontend & Styling**: The [src](src.md) module defines the visual identity, using custom CSS to implement a high-contrast amber-on-black terminal aesthetic. It includes React components for interactive elements like skill cards and dashboards.\n4. **Data Manifests**: The [static](static.md) module hosts the `model-catalog.json`, which the frontend consumes to display supported LLMs and provider metadata without requiring code changes to the core engine.\n\n## Documentation Pipeline\n\nThe following diagram illustrates how the sub-modules interact to produce the final static site:\n\n```mermaid\ngraph LR\n subgraph \"Data Layer\"\n A[SKILL.md / YAML]\n B[model-catalog.json]\n end\n\n subgraph \"Processing (scripts)\"\n C[prebuild.mjs]\n D[generate-skill-docs.py]\n E[extract-skills.py]\n end\n\n subgraph \"Presentation (src & docs)\"\n F[Markdown Docs]\n G[React Components]\n H[Terminal Theme]\n end\n\n A --> D\n A --> E\n C --> D\n C --> E\n E --> G\n B --> G\n F --> I[Docusaurus Build]\n G --> I\n H --> I\n D --> I\n I --> J[Static Website]\n```\n\n## Key Components\n\n- **[docs](docs.md)**: Technical reference for the `AIAgent` core, platform adapters, and system architecture.\n- **[scripts](scripts.md)**: Automation tools including `generate-skill-docs.py` and `generate-llms-txt.py` for LLM-friendly documentation.\n- **[src](src.md)**: Custom frontend logic, global styles (`custom.css`), and the \"Inter\" and \"JetBrains Mono\" typographic configuration.\n- **[static](static.md)**: The Model Catalog manifest and other non-executable assets served at the site root."};
var TREE = [{"name":"Root","slug":"root","files":[],"children":[{"name":"Root — AGENTS.md","slug":"root-agents-md","files":["AGENTS.md"]},{"name":"Root — Dockerfile","slug":"root-dockerfile","files":["Dockerfile"]},{"name":"Root — GEMINI.md","slug":"root-gemini-md","files":["GEMINI.md"]},{"name":"Root — MANIFEST.in","slug":"root-manifest-in","files":["MANIFEST.in"]},{"name":"Root — README.md","slug":"root-readme-md","files":["README.md"]},{"name":"Root — RELEASE_v0.10.0.md","slug":"root-release-v0-10-0-md","files":["RELEASE_v0.10.0.md"]},{"name":"Root — RELEASE_v0.11.0.md","slug":"root-release-v0-11-0-md","files":["RELEASE_v0.11.0.md"]},{"name":"Root — RELEASE_v0.12.0.md","slug":"root-release-v0-12-0-md","files":["RELEASE_v0.12.0.md"]},{"name":"Root — RELEASE_v0.2.0.md","slug":"root-release-v0-2-0-md","files":["RELEASE_v0.2.0.md"]},{"name":"Root — RELEASE_v0.3.0.md","slug":"root-release-v0-3-0-md","files":["RELEASE_v0.3.0.md"]},{"name":"Root — RELEASE_v0.4.0.md","slug":"root-release-v0-4-0-md","files":["RELEASE_v0.4.0.md"]},{"name":"Root — RELEASE_v0.5.0.md","slug":"root-release-v0-5-0-md","files":["RELEASE_v0.5.0.md"]},{"name":"Root — RELEASE_v0.6.0.md","slug":"root-release-v0-6-0-md","files":["RELEASE_v0.6.0.md"]},{"name":"Root — RELEASE_v0.7.0.md","slug":"root-release-v0-7-0-md","files":["RELEASE_v0.7.0.md"]},{"name":"Root — RELEASE_v0.8.0.md","slug":"root-release-v0-8-0-md","files":["RELEASE_v0.8.0.md"]},{"name":"Root — RELEASE_v0.9.0.md","slug":"root-release-v0-9-0-md","files":["RELEASE_v0.9.0.md"]},{"name":"Root — batch_runner.py","slug":"root-batch-runner-py","files":["batch_runner.py"]},{"name":"Root — cli-config.yaml.example","slug":"root-cli-config-yaml-example","files":["cli-config.yaml.example"]},{"name":"Root — constraints-termux.txt","slug":"root-constraints-termux-txt","files":["constraints-termux.txt"]},{"name":"Root — coolify-docker-compose.yaml","slug":"root-coolify-docker-compose-yaml","files":["coolify-docker-compose.yaml"]},{"name":"Root — docker-compose.yml","slug":"root-docker-compose-yml","files":["docker-compose.yml"]},{"name":"Root — flake.nix","slug":"root-flake-nix","files":["flake.nix"]},{"name":"Root — hermes","slug":"root-hermes","files":["hermes"]},{"name":"Root — hermes-already-has-routines.md","slug":"root-hermes-already-has-routines-md","files":["hermes-already-has-routines.md"]},{"name":"Root — hermes_constants.py","slug":"root-hermes-constants-py","files":["hermes_constants.py"]},{"name":"Root — hermes_logging.py","slug":"root-hermes-logging-py","files":["hermes_logging.py"]},{"name":"Root — hermes_state.py","slug":"root-hermes-state-py","files":["hermes_state.py"]},{"name":"Root — hermes_time.py","slug":"root-hermes-time-py","files":["hermes_time.py"]},{"name":"Root — mcp_serve.py","slug":"root-mcp-serve-py","files":["mcp_serve.py"]},{"name":"Root — mini_swe_runner.py","slug":"root-mini-swe-runner-py","files":["mini_swe_runner.py"]},{"name":"Root — model_tools.py","slug":"root-model-tools-py","files":["model_tools.py"]},{"name":"Root — package.json","slug":"root-package-json","files":["package.json"]},{"name":"Root — pyproject.toml","slug":"root-pyproject-toml","files":["pyproject.toml"]},{"name":"Root — rl_cli.py","slug":"root-rl-cli-py","files":["rl_cli.py"]},{"name":"Root — setup-hermes.sh","slug":"root-setup-hermes-sh","files":["setup-hermes.sh"]},{"name":"Root — toolset_distributions.py","slug":"root-toolset-distributions-py","files":["toolset_distributions.py"]},{"name":"Root — toolsets.py","slug":"root-toolsets-py","files":["toolsets.py"]},{"name":"Root — trajectory_compressor.py","slug":"root-trajectory-compressor-py","files":["trajectory_compressor.py"]},{"name":"Root — utils.py","slug":"root-utils-py","files":["utils.py"]}]},{"name":"acp_adapter","slug":"acp-adapter","files":["acp_adapter/__init__.py","acp_adapter/__main__.py","acp_adapter/auth.py","acp_adapter/entry.py","acp_adapter/events.py","acp_adapter/permissions.py","acp_adapter/server.py","acp_adapter/session.py","acp_adapter/tools.py"]},{"name":"acp_registry","slug":"acp-registry","files":["acp_registry/agent.json"]},{"name":"agent","slug":"agent","files":[],"children":[{"name":"agent — agent","slug":"agent-agent","files":["agent/__init__.py","agent/account_usage.py","agent/anthropic_adapter.py","agent/auxiliary_client.py","agent/bedrock_adapter.py","agent/codex_responses_adapter.py","agent/context_compressor.py","agent/context_engine.py","agent/context_references.py","agent/copilot_acp_client.py","agent/credential_pool.py","agent/credential_sources.py","agent/curator.py","agent/curator_backup.py","agent/display.py","agent/error_classifier.py","agent/file_safety.py","agent/gemini_cloudcode_adapter.py","agent/gemini_native_adapter.py","agent/gemini_schema.py","agent/google_code_assist.py","agent/google_oauth.py","agent/image_gen_provider.py","agent/image_gen_registry.py","agent/image_routing.py","agent/insights.py","agent/lmstudio_reasoning.py","agent/manual_compression_feedback.py","agent/memory_manager.py","agent/memory_provider.py","agent/model_metadata.py","agent/models_dev.py","agent/moonshot_schema.py","agent/nous_rate_guard.py","agent/onboarding.py","agent/prompt_builder.py","agent/prompt_caching.py","agent/rate_limit_tracker.py","agent/redact.py","agent/retry_utils.py","agent/shell_hooks.py","agent/skill_commands.py","agent/skill_preprocessing.py","agent/skill_utils.py","agent/subdirectory_hints.py","agent/title_generator.py","agent/tool_guardrails.py","agent/trajectory.py","agent/usage_pricing.py"]},{"name":"agent — transports","slug":"agent-transports","files":["agent/transports/__init__.py","agent/transports/anthropic.py","agent/transports/base.py","agent/transports/bedrock.py","agent/transports/chat_completions.py","agent/transports/codex.py","agent/transports/types.py"]}]},{"name":"cron","slug":"cron","files":["cron/__init__.py","cron/jobs.py","cron/scheduler.py"]},{"name":"datagen-config-examples","slug":"datagen-config-examples","files":["datagen-config-examples/example_browser_tasks.jsonl","datagen-config-examples/run_browser_tasks.sh","datagen-config-examples/trajectory_compression.yaml","datagen-config-examples/web_research.yaml"]},{"name":"docker","slug":"docker","files":["docker/SOUL.md","docker/entrypoint.sh"]},{"name":"environments","slug":"environments","files":[],"children":[{"name":"environments — environments","slug":"environments-environments","files":["environments/README.md","environments/__init__.py","environments/agent_loop.py","environments/agentic_opd_env.py","environments/hermes_base_env.py","environments/patches.py","environments/tool_context.py","environments/web_research_env.py"]},{"name":"environments — benchmarks","slug":"environments-benchmarks","files":["environments/benchmarks/__init__.py","environments/benchmarks/tblite/README.md","environments/benchmarks/tblite/__init__.py","environments/benchmarks/tblite/default.yaml","environments/benchmarks/tblite/local.yaml","environments/benchmarks/tblite/local_vllm.yaml","environments/benchmarks/tblite/run_eval.sh","environments/benchmarks/tblite/tblite_env.py","environments/benchmarks/terminalbench_2/__init__.py","environments/benchmarks/terminalbench_2/default.yaml","environments/benchmarks/terminalbench_2/run_eval.sh","environments/benchmarks/terminalbench_2/terminalbench2_env.py","environments/benchmarks/yc_bench/README.md","environments/benchmarks/yc_bench/__init__.py","environments/benchmarks/yc_bench/default.yaml","environments/benchmarks/yc_bench/run_eval.sh","environments/benchmarks/yc_bench/yc_bench_env.py"]},{"name":"environments — hermes_swe_env","slug":"environments-hermes-swe-env","files":["environments/hermes_swe_env/__init__.py","environments/hermes_swe_env/default.yaml","environments/hermes_swe_env/hermes_swe_env.py"]},{"name":"environments — terminal_test_env","slug":"environments-terminal-test-env","files":["environments/terminal_test_env/__init__.py","environments/terminal_test_env/default.yaml","environments/terminal_test_env/terminal_test_env.py"]},{"name":"environments — tool_call_parsers","slug":"environments-tool-call-parsers","files":["environments/tool_call_parsers/__init__.py","environments/tool_call_parsers/deepseek_v3_1_parser.py","environments/tool_call_parsers/deepseek_v3_parser.py","environments/tool_call_parsers/glm45_parser.py","environments/tool_call_parsers/glm47_parser.py","environments/tool_call_parsers/hermes_parser.py","environments/tool_call_parsers/kimi_k2_parser.py","environments/tool_call_parsers/llama_parser.py","environments/tool_call_parsers/longcat_parser.py","environments/tool_call_parsers/mistral_parser.py","environments/tool_call_parsers/qwen3_coder_parser.py","environments/tool_call_parsers/qwen_parser.py"]}]},{"name":"gateway","slug":"gateway","files":[],"children":[{"name":"gateway — gateway","slug":"gateway-gateway","files":["gateway/__init__.py","gateway/channel_directory.py","gateway/config.py","gateway/delivery.py","gateway/display_config.py","gateway/hooks.py","gateway/mirror.py","gateway/pairing.py","gateway/platform_registry.py","gateway/restart.py","gateway/runtime_footer.py","gateway/session.py","gateway/session_context.py","gateway/status.py","gateway/sticker_cache.py","gateway/stream_consumer.py","gateway/whatsapp_identity.py"]},{"name":"gateway — builtin_hooks","slug":"gateway-builtin-hooks","files":["gateway/builtin_hooks/__init__.py"]},{"name":"gateway — platforms","slug":"gateway-platforms","files":["gateway/platforms/ADDING_A_PLATFORM.md","gateway/platforms/__init__.py","gateway/platforms/_http_client_limits.py","gateway/platforms/api_server.py","gateway/platforms/base.py","gateway/platforms/bluebubbles.py","gateway/platforms/dingtalk.py","gateway/platforms/discord.py","gateway/platforms/email.py","gateway/platforms/feishu.py","gateway/platforms/feishu_comment.py","gateway/platforms/feishu_comment_rules.py","gateway/platforms/helpers.py","gateway/platforms/homeassistant.py","gateway/platforms/matrix.py","gateway/platforms/mattermost.py","gateway/platforms/qqbot/__init__.py","gateway/platforms/qqbot/adapter.py","gateway/platforms/qqbot/constants.py","gateway/platforms/qqbot/crypto.py","gateway/platforms/qqbot/onboard.py","gateway/platforms/qqbot/utils.py","gateway/platforms/signal.py","gateway/platforms/signal_rate_limit.py","gateway/platforms/slack.py","gateway/platforms/sms.py","gateway/platforms/telegram.py","gateway/platforms/telegram_network.py","gateway/platforms/webhook.py","gateway/platforms/wecom.py","gateway/platforms/wecom_callback.py","gateway/platforms/wecom_crypto.py","gateway/platforms/weixin.py","gateway/platforms/whatsapp.py","gateway/platforms/yuanbao.py","gateway/platforms/yuanbao_media.py","gateway/platforms/yuanbao_proto.py","gateway/platforms/yuanbao_sticker.py"]}]},{"name":"graphify-out","slug":"graphify-out","files":["graphify-out/cost.json","graphify-out/manifest.json"]},{"name":"hermes_cli","slug":"hermes-cli","files":["hermes_cli/__init__.py","hermes_cli/_parser.py","hermes_cli/auth.py","hermes_cli/auth_commands.py","hermes_cli/azure_detect.py","hermes_cli/backup.py","hermes_cli/banner.py","hermes_cli/browser_connect.py","hermes_cli/callbacks.py","hermes_cli/claw.py","hermes_cli/cli_output.py","hermes_cli/clipboard.py","hermes_cli/codex_models.py","hermes_cli/colors.py","hermes_cli/commands.py","hermes_cli/completion.py","hermes_cli/config.py","hermes_cli/copilot_auth.py","hermes_cli/cron.py","hermes_cli/curator.py","hermes_cli/curses_ui.py","hermes_cli/debug.py","hermes_cli/default_soul.py","hermes_cli/dingtalk_auth.py","hermes_cli/doctor.py","hermes_cli/dump.py","hermes_cli/env_loader.py","hermes_cli/fallback_cmd.py","hermes_cli/gateway.py","hermes_cli/goals.py","hermes_cli/hooks.py","hermes_cli/kanban.py","hermes_cli/kanban_db.py","hermes_cli/logs.py","hermes_cli/main.py","hermes_cli/mcp_config.py","hermes_cli/memory_setup.py","hermes_cli/model_catalog.py","hermes_cli/model_normalize.py","hermes_cli/model_switch.py","hermes_cli/models.py","hermes_cli/nous_subscription.py","hermes_cli/oneshot.py","hermes_cli/pairing.py","hermes_cli/platforms.py","hermes_cli/plugins.py","hermes_cli/plugins_cmd.py","hermes_cli/profiles.py","hermes_cli/providers.py","hermes_cli/pty_bridge.py","hermes_cli/relaunch.py","hermes_cli/runtime_provider.py","hermes_cli/setup.py","hermes_cli/skills_config.py","hermes_cli/skills_hub.py","hermes_cli/skin_engine.py","hermes_cli/slack_cli.py","hermes_cli/status.py","hermes_cli/timeouts.py","hermes_cli/tips.py","hermes_cli/tools_config.py","hermes_cli/uninstall.py","hermes_cli/vercel_auth.py","hermes_cli/voice.py","hermes_cli/web_server.py","hermes_cli/webhook.py"]},{"name":"nix","slug":"nix","files":["nix/checks.nix","nix/configMergeScript.nix","nix/devShell.nix","nix/hermes-agent.nix","nix/lib.nix","nix/nixosModules.nix","nix/overlays.nix","nix/packages.nix","nix/python.nix","nix/tui.nix","nix/web.nix"]},{"name":"optional-skills","slug":"optional-skills","files":[],"children":[{"name":"optional-skills — optional-skills","slug":"optional-skills-optional-skills","files":["optional-skills/DESCRIPTION.md"]},{"name":"optional-skills — autonomous-ai-agents","slug":"optional-skills-autonomous-ai-agents","files":["optional-skills/autonomous-ai-agents/DESCRIPTION.md","optional-skills/autonomous-ai-agents/blackbox/SKILL.md","optional-skills/autonomous-ai-agents/honcho/SKILL.md"]},{"name":"optional-skills — blockchain","slug":"optional-skills-blockchain","files":["optional-skills/blockchain/base/SKILL.md","optional-skills/blockchain/base/scripts/base_client.py","optional-skills/blockchain/solana/SKILL.md","optional-skills/blockchain/solana/scripts/solana_client.py"]},{"name":"optional-skills — communication","slug":"optional-skills-communication","files":["optional-skills/communication/DESCRIPTION.md","optional-skills/communication/one-three-one-rule/SKILL.md"]},{"name":"optional-skills — creative","slug":"optional-skills-creative","files":["optional-skills/creative/blender-mcp/SKILL.md","optional-skills/creative/concept-diagrams/SKILL.md","optional-skills/creative/concept-diagrams/references/dashboard-patterns.md","optional-skills/creative/concept-diagrams/references/infrastructure-patterns.md","optional-skills/creative/concept-diagrams/references/physical-shape-cookbook.md","optional-skills/creative/concept-diagrams/templates/template.html","optional-skills/creative/meme-generation/EXAMPLES.md","optional-skills/creative/meme-generation/SKILL.md","optional-skills/creative/meme-generation/scripts/generate_meme.py","optional-skills/creative/meme-generation/scripts/templates.json"]},{"name":"optional-skills — devops","slug":"optional-skills-devops","files":["optional-skills/devops/cli/SKILL.md","optional-skills/devops/cli/references/app-discovery.md","optional-skills/devops/cli/references/authentication.md","optional-skills/devops/cli/references/cli-reference.md","optional-skills/devops/cli/references/running-apps.md","optional-skills/devops/docker-management/SKILL.md"]},{"name":"optional-skills — dogfood","slug":"optional-skills-dogfood","files":["optional-skills/dogfood/DESCRIPTION.md","optional-skills/dogfood/adversarial-ux-test/SKILL.md"]},{"name":"optional-skills — email","slug":"optional-skills-email","files":["optional-skills/email/agentmail/SKILL.md"]},{"name":"optional-skills — health","slug":"optional-skills-health","files":["optional-skills/health/DESCRIPTION.md","optional-skills/health/fitness-nutrition/SKILL.md","optional-skills/health/fitness-nutrition/references/FORMULAS.md","optional-skills/health/fitness-nutrition/scripts/body_calc.py","optional-skills/health/fitness-nutrition/scripts/nutrition_search.py","optional-skills/health/neuroskill-bci/SKILL.md","optional-skills/health/neuroskill-bci/references/api.md","optional-skills/health/neuroskill-bci/references/metrics.md","optional-skills/health/neuroskill-bci/references/protocols.md"]},{"name":"optional-skills — mcp","slug":"optional-skills-mcp","files":["optional-skills/mcp/DESCRIPTION.md","optional-skills/mcp/fastmcp/SKILL.md","optional-skills/mcp/fastmcp/references/fastmcp-cli.md","optional-skills/mcp/fastmcp/scripts/scaffold_fastmcp.py","optional-skills/mcp/fastmcp/templates/api_wrapper.py","optional-skills/mcp/fastmcp/templates/database_server.py","optional-skills/mcp/fastmcp/templates/file_processor.py","optional-skills/mcp/mcporter/SKILL.md"]},{"name":"optional-skills — migration","slug":"optional-skills-migration","files":["optional-skills/migration/DESCRIPTION.md","optional-skills/migration/openclaw-migration/SKILL.md","optional-skills/migration/openclaw-migration/scripts/openclaw_to_hermes.py"]},{"name":"optional-skills — mlops","slug":"optional-skills-mlops","files":["optional-skills/mlops/accelerate/SKILL.md","optional-skills/mlops/accelerate/references/custom-plugins.md","optional-skills/mlops/accelerate/references/megatron-integration.md","optional-skills/mlops/accelerate/references/performance.md","optional-skills/mlops/chroma/SKILL.md","optional-skills/mlops/chroma/references/integration.md","optional-skills/mlops/clip/SKILL.md","optional-skills/mlops/clip/references/applications.md","optional-skills/mlops/faiss/SKILL.md","optional-skills/mlops/faiss/references/index_types.md","optional-skills/mlops/flash-attention/SKILL.md","optional-skills/mlops/flash-attention/references/benchmarks.md","optional-skills/mlops/flash-attention/references/transformers-integration.md","optional-skills/mlops/guidance/SKILL.md","optional-skills/mlops/guidance/references/backends.md","optional-skills/mlops/guidance/references/constraints.md","optional-skills/mlops/guidance/references/examples.md","optional-skills/mlops/hermes-atropos-environments/SKILL.md","optional-skills/mlops/hermes-atropos-environments/references/agentresult-fields.md","optional-skills/mlops/hermes-atropos-environments/references/atropos-base-env.md","optional-skills/mlops/hermes-atropos-environments/references/usage-patterns.md","optional-skills/mlops/huggingface-tokenizers/SKILL.md","optional-skills/mlops/huggingface-tokenizers/references/algorithms.md","optional-skills/mlops/huggingface-tokenizers/references/integration.md","optional-skills/mlops/huggingface-tokenizers/references/pipeline.md","optional-skills/mlops/huggingface-tokenizers/references/training.md","optional-skills/mlops/instructor/SKILL.md","optional-skills/mlops/instructor/references/examples.md","optional-skills/mlops/instructor/references/providers.md","optional-skills/mlops/instructor/references/validation.md","optional-skills/mlops/lambda-labs/SKILL.md","optional-skills/mlops/lambda-labs/references/advanced-usage.md","optional-skills/mlops/lambda-labs/references/troubleshooting.md","optional-skills/mlops/llava/SKILL.md","optional-skills/mlops/llava/references/training.md","optional-skills/mlops/modal/SKILL.md","optional-skills/mlops/modal/references/advanced-usage.md","optional-skills/mlops/modal/references/troubleshooting.md","optional-skills/mlops/nemo-curator/SKILL.md","optional-skills/mlops/nemo-curator/references/deduplication.md","optional-skills/mlops/nemo-curator/references/filtering.md","optional-skills/mlops/peft/SKILL.md","optional-skills/mlops/peft/references/advanced-usage.md","optional-skills/mlops/peft/references/troubleshooting.md","optional-skills/mlops/pinecone/SKILL.md","optional-skills/mlops/pinecone/references/deployment.md","optional-skills/mlops/pytorch-fsdp/SKILL.md","optional-skills/mlops/pytorch-fsdp/references/index.md","optional-skills/mlops/pytorch-fsdp/references/other.md","optional-skills/mlops/pytorch-lightning/SKILL.md","optional-skills/mlops/pytorch-lightning/references/callbacks.md","optional-skills/mlops/pytorch-lightning/references/distributed.md","optional-skills/mlops/pytorch-lightning/references/hyperparameter-tuning.md","optional-skills/mlops/qdrant/SKILL.md","optional-skills/mlops/qdrant/references/advanced-usage.md","optional-skills/mlops/qdrant/references/troubleshooting.md","optional-skills/mlops/saelens/SKILL.md","optional-skills/mlops/saelens/references/README.md","optional-skills/mlops/saelens/references/api.md","optional-skills/mlops/saelens/references/tutorials.md","optional-skills/mlops/simpo/SKILL.md","optional-skills/mlops/simpo/references/datasets.md","optional-skills/mlops/simpo/references/hyperparameters.md","optional-skills/mlops/simpo/references/loss-functions.md","optional-skills/mlops/slime/SKILL.md","optional-skills/mlops/slime/references/api-reference.md","optional-skills/mlops/slime/references/troubleshooting.md","optional-skills/mlops/stable-diffusion/SKILL.md","optional-skills/mlops/stable-diffusion/references/advanced-usage.md","optional-skills/mlops/stable-diffusion/references/troubleshooting.md","optional-skills/mlops/tensorrt-llm/SKILL.md","optional-skills/mlops/tensorrt-llm/references/multi-gpu.md","optional-skills/mlops/tensorrt-llm/references/optimization.md","optional-skills/mlops/tensorrt-llm/references/serving.md","optional-skills/mlops/torchtitan/SKILL.md","optional-skills/mlops/torchtitan/references/checkpoint.md","optional-skills/mlops/torchtitan/references/custom-models.md","optional-skills/mlops/torchtitan/references/float8.md","optional-skills/mlops/torchtitan/references/fsdp.md","optional-skills/mlops/whisper/SKILL.md","optional-skills/mlops/whisper/references/languages.md"]},{"name":"optional-skills — productivity","slug":"optional-skills-productivity","files":["optional-skills/productivity/canvas/SKILL.md","optional-skills/productivity/canvas/scripts/canvas_api.py","optional-skills/productivity/here-now/SKILL.md","optional-skills/productivity/here-now/scripts/drive.sh","optional-skills/productivity/here-now/scripts/publish.sh","optional-skills/productivity/memento-flashcards/SKILL.md","optional-skills/productivity/memento-flashcards/scripts/memento_cards.py","optional-skills/productivity/memento-flashcards/scripts/youtube_quiz.py","optional-skills/productivity/shopify/SKILL.md","optional-skills/productivity/siyuan/SKILL.md","optional-skills/productivity/telephony/SKILL.md","optional-skills/productivity/telephony/scripts/telephony.py"]},{"name":"optional-skills — research","slug":"optional-skills-research","files":["optional-skills/research/bioinformatics/SKILL.md","optional-skills/research/domain-intel/SKILL.md","optional-skills/research/domain-intel/scripts/domain_intel.py","optional-skills/research/drug-discovery/SKILL.md","optional-skills/research/drug-discovery/references/ADMET_REFERENCE.md","optional-skills/research/drug-discovery/scripts/chembl_target.py","optional-skills/research/drug-discovery/scripts/ro5_screen.py","optional-skills/research/duckduckgo-search/SKILL.md","optional-skills/research/duckduckgo-search/scripts/duckduckgo.sh","optional-skills/research/gitnexus-explorer/SKILL.md","optional-skills/research/gitnexus-explorer/scripts/proxy.mjs","optional-skills/research/parallel-cli/SKILL.md","optional-skills/research/qmd/SKILL.md","optional-skills/research/scrapling/SKILL.md"]},{"name":"optional-skills — security","slug":"optional-skills-security","files":["optional-skills/security/1password/SKILL.md","optional-skills/security/1password/references/cli-examples.md","optional-skills/security/1password/references/get-started.md","optional-skills/security/DESCRIPTION.md","optional-skills/security/oss-forensics/SKILL.md","optional-skills/security/oss-forensics/references/evidence-types.md","optional-skills/security/oss-forensics/references/github-archive-guide.md","optional-skills/security/oss-forensics/references/investigation-templates.md","optional-skills/security/oss-forensics/references/recovery-techniques.md","optional-skills/security/oss-forensics/scripts/evidence-store.py","optional-skills/security/oss-forensics/templates/forensic-report.md","optional-skills/security/oss-forensics/templates/malicious-package-report.md","optional-skills/security/sherlock/SKILL.md"]},{"name":"optional-skills — web-development","slug":"optional-skills-web-development","files":["optional-skills/web-development/DESCRIPTION.md","optional-skills/web-development/page-agent/SKILL.md"]}]},{"name":"packaging","slug":"packaging","files":["packaging/homebrew/README.md","packaging/homebrew/hermes-agent.rb"]},{"name":"plans","slug":"plans","files":["plans/gemini-oauth-provider.md"]},{"name":"plugins","slug":"plugins","files":[],"children":[{"name":"plugins — plugins","slug":"plugins-plugins","files":["plugins/__init__.py"]},{"name":"plugins — context_engine","slug":"plugins-context-engine","files":["plugins/context_engine/__init__.py"]},{"name":"plugins — disk-cleanup","slug":"plugins-disk-cleanup","files":["plugins/disk-cleanup/README.md","plugins/disk-cleanup/__init__.py","plugins/disk-cleanup/disk_cleanup.py","plugins/disk-cleanup/plugin.yaml"]},{"name":"plugins — example-dashboard","slug":"plugins-example-dashboard","files":["plugins/example-dashboard/dashboard/manifest.json","plugins/example-dashboard/dashboard/plugin_api.py"]},{"name":"plugins — google_meet","slug":"plugins-google-meet","files":["plugins/google_meet/README.md","plugins/google_meet/SKILL.md","plugins/google_meet/__init__.py","plugins/google_meet/audio_bridge.py","plugins/google_meet/cli.py","plugins/google_meet/meet_bot.py","plugins/google_meet/node/__init__.py","plugins/google_meet/node/cli.py","plugins/google_meet/node/client.py","plugins/google_meet/node/protocol.py","plugins/google_meet/node/registry.py","plugins/google_meet/node/server.py","plugins/google_meet/plugin.yaml","plugins/google_meet/process_manager.py","plugins/google_meet/realtime/__init__.py","plugins/google_meet/realtime/openai_client.py","plugins/google_meet/tools.py"]},{"name":"plugins — hermes-achievements","slug":"plugins-hermes-achievements","files":["plugins/hermes-achievements/README.md","plugins/hermes-achievements/dashboard/manifest.json","plugins/hermes-achievements/dashboard/plugin_api.py","plugins/hermes-achievements/docs/achievements-performance-implementation-plan.md","plugins/hermes-achievements/docs/achievements-performance-implementation-spec.md","plugins/hermes-achievements/docs/achievements-performance-spec.md","plugins/hermes-achievements/tests/test_achievement_engine.py"]},{"name":"plugins — image_gen","slug":"plugins-image-gen","files":["plugins/image_gen/openai-codex/__init__.py","plugins/image_gen/openai-codex/plugin.yaml","plugins/image_gen/openai/__init__.py","plugins/image_gen/openai/plugin.yaml","plugins/image_gen/xai/__init__.py","plugins/image_gen/xai/plugin.yaml"]},{"name":"plugins — kanban","slug":"plugins-kanban","files":["plugins/kanban/dashboard/manifest.json","plugins/kanban/dashboard/plugin_api.py","plugins/kanban/systemd/hermes-kanban-dispatcher.service"]},{"name":"plugins — memory","slug":"plugins-memory","files":["plugins/memory/__init__.py","plugins/memory/byterover/README.md","plugins/memory/byterover/__init__.py","plugins/memory/byterover/plugin.yaml","plugins/memory/hindsight/README.md","plugins/memory/hindsight/__init__.py","plugins/memory/hindsight/plugin.yaml","plugins/memory/holographic/README.md","plugins/memory/holographic/__init__.py","plugins/memory/holographic/holographic.py","plugins/memory/holographic/plugin.yaml","plugins/memory/holographic/retrieval.py","plugins/memory/holographic/store.py","plugins/memory/honcho/README.md","plugins/memory/honcho/__init__.py","plugins/memory/honcho/cli.py","plugins/memory/honcho/client.py","plugins/memory/honcho/plugin.yaml","plugins/memory/honcho/session.py","plugins/memory/mem0/README.md","plugins/memory/mem0/__init__.py","plugins/memory/mem0/plugin.yaml","plugins/memory/openviking/README.md","plugins/memory/openviking/__init__.py","plugins/memory/openviking/plugin.yaml","plugins/memory/retaindb/README.md","plugins/memory/retaindb/__init__.py","plugins/memory/retaindb/plugin.yaml","plugins/memory/supermemory/README.md","plugins/memory/supermemory/__init__.py","plugins/memory/supermemory/plugin.yaml"]},{"name":"plugins — observability","slug":"plugins-observability","files":["plugins/observability/langfuse/README.md","plugins/observability/langfuse/__init__.py","plugins/observability/langfuse/plugin.yaml"]},{"name":"plugins — platforms","slug":"plugins-platforms","files":["plugins/platforms/irc/__init__.py","plugins/platforms/irc/adapter.py","plugins/platforms/irc/plugin.yaml","plugins/platforms/teams/__init__.py","plugins/platforms/teams/adapter.py","plugins/platforms/teams/plugin.yaml"]},{"name":"plugins — spotify","slug":"plugins-spotify","files":["plugins/spotify/__init__.py","plugins/spotify/client.py","plugins/spotify/plugin.yaml","plugins/spotify/tools.py"]},{"name":"plugins — strike-freedom-cockpit","slug":"plugins-strike-freedom-cockpit","files":["plugins/strike-freedom-cockpit/README.md","plugins/strike-freedom-cockpit/dashboard/manifest.json","plugins/strike-freedom-cockpit/theme/strike-freedom.yaml"]}]},{"name":"scripts","slug":"scripts","files":[],"children":[{"name":"scripts — scripts","slug":"scripts-scripts","files":["scripts/build_model_catalog.py","scripts/build_skills_index.py","scripts/contributor_audit.py","scripts/discord-voice-doctor.py","scripts/hermes-gateway","scripts/install.cmd","scripts/install.ps1","scripts/install.sh","scripts/kill_modal.sh","scripts/profile-tui.py","scripts/release.py","scripts/run_tests.sh","scripts/sample_and_compress.py"]},{"name":"scripts — lib","slug":"scripts-lib","files":["scripts/lib/node-bootstrap.sh"]},{"name":"scripts — whatsapp-bridge","slug":"scripts-whatsapp-bridge","files":["scripts/whatsapp-bridge/allowlist.js","scripts/whatsapp-bridge/allowlist.test.mjs","scripts/whatsapp-bridge/bridge.js","scripts/whatsapp-bridge/package.json"]}]},{"name":"skills","slug":"skills","files":[],"children":[{"name":"skills — apple","slug":"skills-apple","files":["skills/apple/DESCRIPTION.md","skills/apple/apple-notes/SKILL.md","skills/apple/apple-reminders/SKILL.md","skills/apple/findmy/SKILL.md","skills/apple/imessage/SKILL.md"]},{"name":"skills — autonomous-ai-agents","slug":"skills-autonomous-ai-agents","files":["skills/autonomous-ai-agents/DESCRIPTION.md","skills/autonomous-ai-agents/claude-code/SKILL.md","skills/autonomous-ai-agents/codex/SKILL.md","skills/autonomous-ai-agents/hermes-agent/SKILL.md","skills/autonomous-ai-agents/opencode/SKILL.md"]},{"name":"skills — creative","slug":"skills-creative","files":["skills/creative/DESCRIPTION.md","skills/creative/architecture-diagram/SKILL.md","skills/creative/architecture-diagram/templates/template.html","skills/creative/ascii-art/SKILL.md","skills/creative/ascii-video/README.md","skills/creative/ascii-video/SKILL.md","skills/creative/ascii-video/references/architecture.md","skills/creative/ascii-video/references/composition.md","skills/creative/ascii-video/references/effects.md","skills/creative/ascii-video/references/inputs.md","skills/creative/ascii-video/references/optimization.md","skills/creative/ascii-video/references/scenes.md","skills/creative/ascii-video/references/shaders.md","skills/creative/ascii-video/references/troubleshooting.md","skills/creative/baoyu-comic/PORT_NOTES.md","skills/creative/baoyu-comic/SKILL.md","skills/creative/baoyu-comic/references/analysis-framework.md","skills/creative/baoyu-comic/references/art-styles/chalk.md","skills/creative/baoyu-comic/references/art-styles/ink-brush.md","skills/creative/baoyu-comic/references/art-styles/ligne-claire.md","skills/creative/baoyu-comic/references/art-styles/manga.md","skills/creative/baoyu-comic/references/art-styles/minimalist.md","skills/creative/baoyu-comic/references/art-styles/realistic.md","skills/creative/baoyu-comic/references/auto-selection.md","skills/creative/baoyu-comic/references/base-prompt.md","skills/creative/baoyu-comic/references/character-template.md","skills/creative/baoyu-comic/references/layouts/cinematic.md","skills/creative/baoyu-comic/references/layouts/dense.md","skills/creative/baoyu-comic/references/layouts/four-panel.md","skills/creative/baoyu-comic/references/layouts/mixed.md","skills/creative/baoyu-comic/references/layouts/splash.md","skills/creative/baoyu-comic/references/layouts/standard.md","skills/creative/baoyu-comic/references/layouts/webtoon.md","skills/creative/baoyu-comic/references/ohmsha-guide.md","skills/creative/baoyu-comic/references/partial-workflows.md","skills/creative/baoyu-comic/references/presets/concept-story.md","skills/creative/baoyu-comic/references/presets/four-panel.md","skills/creative/baoyu-comic/references/presets/ohmsha.md","skills/creative/baoyu-comic/references/presets/shoujo.md","skills/creative/baoyu-comic/references/presets/wuxia.md","skills/creative/baoyu-comic/references/storyboard-template.md","skills/creative/baoyu-comic/references/tones/action.md","skills/creative/baoyu-comic/references/tones/dramatic.md","skills/creative/baoyu-comic/references/tones/energetic.md","skills/creative/baoyu-comic/references/tones/neutral.md","skills/creative/baoyu-comic/references/tones/romantic.md","skills/creative/baoyu-comic/references/tones/vintage.md","skills/creative/baoyu-comic/references/tones/warm.md","skills/creative/baoyu-comic/references/workflow.md","skills/creative/baoyu-infographic/PORT_NOTES.md","skills/creative/baoyu-infographic/SKILL.md","skills/creative/baoyu-infographic/references/analysis-framework.md","skills/creative/baoyu-infographic/references/base-prompt.md","skills/creative/baoyu-infographic/references/layouts/bento-grid.md","skills/creative/baoyu-infographic/references/layouts/binary-comparison.md","skills/creative/baoyu-infographic/references/layouts/bridge.md","skills/creative/baoyu-infographic/references/layouts/circular-flow.md","skills/creative/baoyu-infographic/references/layouts/comic-strip.md","skills/creative/baoyu-infographic/references/layouts/comparison-matrix.md","skills/creative/baoyu-infographic/references/layouts/dashboard.md","skills/creative/baoyu-infographic/references/layouts/dense-modules.md","skills/creative/baoyu-infographic/references/layouts/funnel.md","skills/creative/baoyu-infographic/references/layouts/hierarchical-layers.md","skills/creative/baoyu-infographic/references/layouts/hub-spoke.md","skills/creative/baoyu-infographic/references/layouts/iceberg.md","skills/creative/baoyu-infographic/references/layouts/isometric-map.md","skills/creative/baoyu-infographic/references/layouts/jigsaw.md","skills/creative/baoyu-infographic/references/layouts/linear-progression.md","skills/creative/baoyu-infographic/references/layouts/periodic-table.md","skills/creative/baoyu-infographic/references/layouts/story-mountain.md","skills/creative/baoyu-infographic/references/layouts/structural-breakdown.md","skills/creative/baoyu-infographic/references/layouts/tree-branching.md","skills/creative/baoyu-infographic/references/layouts/venn-diagram.md","skills/creative/baoyu-infographic/references/layouts/winding-roadmap.md","skills/creative/baoyu-infographic/references/structured-content-template.md","skills/creative/baoyu-infographic/references/styles/aged-academia.md","skills/creative/baoyu-infographic/references/styles/bold-graphic.md","skills/creative/baoyu-infographic/references/styles/chalkboard.md","skills/creative/baoyu-infographic/references/styles/claymation.md","skills/creative/baoyu-infographic/references/styles/corporate-memphis.md","skills/creative/baoyu-infographic/references/styles/craft-handmade.md","skills/creative/baoyu-infographic/references/styles/cyberpunk-neon.md","skills/creative/baoyu-infographic/references/styles/hand-drawn-edu.md","skills/creative/baoyu-infographic/references/styles/ikea-manual.md","skills/creative/baoyu-infographic/references/styles/kawaii.md","skills/creative/baoyu-infographic/references/styles/knolling.md","skills/creative/baoyu-infographic/references/styles/lego-brick.md","skills/creative/baoyu-infographic/references/styles/morandi-journal.md","skills/creative/baoyu-infographic/references/styles/origami.md","skills/creative/baoyu-infographic/references/styles/pixel-art.md","skills/creative/baoyu-infographic/references/styles/pop-laboratory.md","skills/creative/baoyu-infographic/references/styles/retro-pop-grid.md","skills/creative/baoyu-infographic/references/styles/storybook-watercolor.md","skills/creative/baoyu-infographic/references/styles/subway-map.md","skills/creative/baoyu-infographic/references/styles/technical-schematic.md","skills/creative/baoyu-infographic/references/styles/ui-wireframe.md","skills/creative/claude-design/SKILL.md","skills/creative/comfyui/SKILL.md","skills/creative/comfyui/references/official-cli.md","skills/creative/comfyui/references/rest-api.md","skills/creative/comfyui/references/workflow-format.md","skills/creative/comfyui/scripts/_common.py","skills/creative/comfyui/scripts/auto_fix_deps.py","skills/creative/comfyui/scripts/check_deps.py","skills/creative/comfyui/scripts/comfyui_setup.sh","skills/creative/comfyui/scripts/extract_schema.py","skills/creative/comfyui/scripts/fetch_logs.py","skills/creative/comfyui/scripts/hardware_check.py","skills/creative/comfyui/scripts/health_check.py","skills/creative/comfyui/scripts/run_batch.py","skills/creative/comfyui/scripts/run_workflow.py","skills/creative/comfyui/scripts/ws_monitor.py","skills/creative/comfyui/tests/README.md","skills/creative/comfyui/tests/conftest.py","skills/creative/comfyui/tests/pytest.ini","skills/creative/comfyui/tests/test_check_deps.py","skills/creative/comfyui/tests/test_cloud_integration.py","skills/creative/comfyui/tests/test_common.py","skills/creative/comfyui/tests/test_extract_schema.py","skills/creative/comfyui/tests/test_run_workflow.py","skills/creative/comfyui/workflows/README.md","skills/creative/comfyui/workflows/animatediff_video.json","skills/creative/comfyui/workflows/flux_dev_txt2img.json","skills/creative/comfyui/workflows/sd15_txt2img.json","skills/creative/comfyui/workflows/sdxl_img2img.json","skills/creative/comfyui/workflows/sdxl_inpaint.json","skills/creative/comfyui/workflows/sdxl_txt2img.json","skills/creative/comfyui/workflows/upscale_4x.json","skills/creative/comfyui/workflows/wan_video_t2v.json","skills/creative/creative-ideation/SKILL.md","skills/creative/creative-ideation/references/full-prompt-library.md","skills/creative/design-md/SKILL.md","skills/creative/design-md/templates/starter.md","skills/creative/excalidraw/SKILL.md","skills/creative/excalidraw/references/colors.md","skills/creative/excalidraw/references/dark-mode.md","skills/creative/excalidraw/references/examples.md","skills/creative/excalidraw/scripts/upload.py","skills/creative/humanizer/SKILL.md","skills/creative/manim-video/README.md","skills/creative/manim-video/SKILL.md","skills/creative/manim-video/references/animation-design-thinking.md","skills/creative/manim-video/references/animations.md","skills/creative/manim-video/references/camera-and-3d.md","skills/creative/manim-video/references/decorations.md","skills/creative/manim-video/references/equations.md","skills/creative/manim-video/references/graphs-and-data.md","skills/creative/manim-video/references/mobjects.md","skills/creative/manim-video/references/paper-explainer.md","skills/creative/manim-video/references/production-quality.md","skills/creative/manim-video/references/rendering.md","skills/creative/manim-video/references/scene-planning.md","skills/creative/manim-video/references/troubleshooting.md","skills/creative/manim-video/references/updaters-and-trackers.md","skills/creative/manim-video/references/visual-design.md","skills/creative/manim-video/scripts/setup.sh","skills/creative/p5js/README.md","skills/creative/p5js/SKILL.md","skills/creative/p5js/references/animation.md","skills/creative/p5js/references/color-systems.md","skills/creative/p5js/references/core-api.md","skills/creative/p5js/references/interaction.md","skills/creative/p5js/references/shapes-and-geometry.md","skills/creative/p5js/references/troubleshooting.md","skills/creative/p5js/references/typography.md","skills/creative/p5js/references/visual-effects.md","skills/creative/p5js/references/webgl-and-3d.md","skills/creative/p5js/scripts/render.sh","skills/creative/p5js/scripts/serve.sh","skills/creative/p5js/scripts/setup.sh","skills/creative/p5js/templates/viewer.html","skills/creative/pixel-art/ATTRIBUTION.md","skills/creative/pixel-art/SKILL.md","skills/creative/pixel-art/references/palettes.md","skills/creative/pixel-art/scripts/__init__.py","skills/creative/pixel-art/scripts/palettes.py","skills/creative/pixel-art/scripts/pixel_art.py","skills/creative/pixel-art/scripts/pixel_art_video.py","skills/creative/popular-web-designs/SKILL.md","skills/creative/popular-web-designs/templates/airbnb.md","skills/creative/popular-web-designs/templates/airtable.md","skills/creative/popular-web-designs/templates/apple.md","skills/creative/popular-web-designs/templates/bmw.md","skills/creative/popular-web-designs/templates/cal.md","skills/creative/popular-web-designs/templates/claude.md","skills/creative/popular-web-designs/templates/clay.md","skills/creative/popular-web-designs/templates/clickhouse.md","skills/creative/popular-web-designs/templates/cohere.md","skills/creative/popular-web-designs/templates/coinbase.md","skills/creative/popular-web-designs/templates/composio.md","skills/creative/popular-web-designs/templates/cursor.md","skills/creative/popular-web-designs/templates/elevenlabs.md","skills/creative/popular-web-designs/templates/expo.md","skills/creative/popular-web-designs/templates/figma.md","skills/creative/popular-web-designs/templates/framer.md","skills/creative/popular-web-designs/templates/hashicorp.md","skills/creative/popular-web-designs/templates/ibm.md","skills/creative/popular-web-designs/templates/intercom.md","skills/creative/popular-web-designs/templates/kraken.md","skills/creative/popular-web-designs/templates/linear.app.md","skills/creative/popular-web-designs/templates/lovable.md","skills/creative/popular-web-designs/templates/minimax.md","skills/creative/popular-web-designs/templates/mintlify.md","skills/creative/popular-web-designs/templates/miro.md","skills/creative/popular-web-designs/templates/mistral.ai.md","skills/creative/popular-web-designs/templates/mongodb.md","skills/creative/popular-web-designs/templates/notion.md","skills/creative/popular-web-designs/templates/nvidia.md","skills/creative/popular-web-designs/templates/ollama.md","skills/creative/popular-web-designs/templates/opencode.ai.md","skills/creative/popular-web-designs/templates/pinterest.md","skills/creative/popular-web-designs/templates/posthog.md","skills/creative/popular-web-designs/templates/raycast.md","skills/creative/popular-web-designs/templates/replicate.md","skills/creative/popular-web-designs/templates/resend.md","skills/creative/popular-web-designs/templates/revolut.md","skills/creative/popular-web-designs/templates/runwayml.md","skills/creative/popular-web-designs/templates/sanity.md","skills/creative/popular-web-designs/templates/sentry.md","skills/creative/popular-web-designs/templates/spacex.md","skills/creative/popular-web-designs/templates/spotify.md","skills/creative/popular-web-designs/templates/stripe.md","skills/creative/popular-web-designs/templates/supabase.md","skills/creative/popular-web-designs/templates/superhuman.md","skills/creative/popular-web-designs/templates/together.ai.md","skills/creative/popular-web-designs/templates/uber.md","skills/creative/popular-web-designs/templates/vercel.md","skills/creative/popular-web-designs/templates/voltagent.md","skills/creative/popular-web-designs/templates/warp.md","skills/creative/popular-web-designs/templates/webflow.md","skills/creative/popular-web-designs/templates/wise.md","skills/creative/popular-web-designs/templates/x.ai.md","skills/creative/popular-web-designs/templates/zapier.md","skills/creative/pretext/SKILL.md","skills/creative/pretext/references/patterns.md","skills/creative/pretext/templates/donut-orbit.html","skills/creative/pretext/templates/hello-orb-flow.html","skills/creative/sketch/SKILL.md","skills/creative/songwriting-and-ai-music/SKILL.md","skills/creative/touchdesigner-mcp/SKILL.md","skills/creative/touchdesigner-mcp/references/3d-scene.md","skills/creative/touchdesigner-mcp/references/animation.md","skills/creative/touchdesigner-mcp/references/audio-reactive.md","skills/creative/touchdesigner-mcp/references/dat-scripting.md","skills/creative/touchdesigner-mcp/references/external-data.md","skills/creative/touchdesigner-mcp/references/geometry-comp.md","skills/creative/touchdesigner-mcp/references/glsl.md","skills/creative/touchdesigner-mcp/references/layout-compositor.md","skills/creative/touchdesigner-mcp/references/mcp-tools.md","skills/creative/touchdesigner-mcp/references/midi-osc.md","skills/creative/touchdesigner-mcp/references/network-patterns.md","skills/creative/touchdesigner-mcp/references/operator-tips.md","skills/creative/touchdesigner-mcp/references/operators.md","skills/creative/touchdesigner-mcp/references/panel-ui.md","skills/creative/touchdesigner-mcp/references/particles.md","skills/creative/touchdesigner-mcp/references/pitfalls.md","skills/creative/touchdesigner-mcp/references/postfx.md","skills/creative/touchdesigner-mcp/references/projection-mapping.md","skills/creative/touchdesigner-mcp/references/python-api.md","skills/creative/touchdesigner-mcp/references/replicator.md","skills/creative/touchdesigner-mcp/references/troubleshooting.md","skills/creative/touchdesigner-mcp/scripts/setup.sh"]},{"name":"skills — data-science","slug":"skills-data-science","files":["skills/data-science/DESCRIPTION.md","skills/data-science/jupyter-live-kernel/SKILL.md"]},{"name":"skills — devops","slug":"skills-devops","files":["skills/devops/kanban-orchestrator/SKILL.md","skills/devops/kanban-worker/SKILL.md","skills/devops/webhook-subscriptions/SKILL.md"]},{"name":"skills — diagramming","slug":"skills-diagramming","files":["skills/diagramming/DESCRIPTION.md"]},{"name":"skills — dogfood","slug":"skills-dogfood","files":["skills/dogfood/SKILL.md","skills/dogfood/references/issue-taxonomy.md","skills/dogfood/templates/dogfood-report-template.md"]},{"name":"skills — domain","slug":"skills-domain","files":["skills/domain/DESCRIPTION.md"]},{"name":"skills — email","slug":"skills-email","files":["skills/email/DESCRIPTION.md","skills/email/himalaya/SKILL.md","skills/email/himalaya/references/configuration.md","skills/email/himalaya/references/message-composition.md"]},{"name":"skills — gaming","slug":"skills-gaming","files":["skills/gaming/DESCRIPTION.md","skills/gaming/minecraft-modpack-server/SKILL.md","skills/gaming/pokemon-player/SKILL.md"]},{"name":"skills — gifs","slug":"skills-gifs","files":["skills/gifs/DESCRIPTION.md"]},{"name":"skills — github","slug":"skills-github","files":["skills/github/DESCRIPTION.md","skills/github/codebase-inspection/SKILL.md","skills/github/github-auth/SKILL.md","skills/github/github-auth/scripts/gh-env.sh","skills/github/github-code-review/SKILL.md","skills/github/github-code-review/references/review-output-template.md","skills/github/github-issues/SKILL.md","skills/github/github-issues/templates/bug-report.md","skills/github/github-issues/templates/feature-request.md","skills/github/github-pr-workflow/SKILL.md","skills/github/github-pr-workflow/references/ci-troubleshooting.md","skills/github/github-pr-workflow/references/conventional-commits.md","skills/github/github-pr-workflow/templates/pr-body-bugfix.md","skills/github/github-pr-workflow/templates/pr-body-feature.md","skills/github/github-repo-management/SKILL.md","skills/github/github-repo-management/references/github-api-cheatsheet.md"]},{"name":"skills — index-cache","slug":"skills-index-cache","files":["skills/index-cache/anthropics_skills_skills_.json","skills/index-cache/claude_marketplace_anthropics_skills.json","skills/index-cache/lobehub_index.json","skills/index-cache/openai_skills_skills_.json"]},{"name":"skills — inference-sh","slug":"skills-inference-sh","files":["skills/inference-sh/DESCRIPTION.md"]},{"name":"skills — mcp","slug":"skills-mcp","files":["skills/mcp/DESCRIPTION.md","skills/mcp/native-mcp/SKILL.md"]},{"name":"skills — media","slug":"skills-media","files":["skills/media/DESCRIPTION.md","skills/media/gif-search/SKILL.md","skills/media/heartmula/SKILL.md","skills/media/songsee/SKILL.md","skills/media/spotify/SKILL.md","skills/media/youtube-content/SKILL.md","skills/media/youtube-content/references/output-formats.md","skills/media/youtube-content/scripts/fetch_transcript.py"]},{"name":"skills — mlops","slug":"skills-mlops","files":["skills/mlops/DESCRIPTION.md","skills/mlops/evaluation/DESCRIPTION.md","skills/mlops/evaluation/lm-evaluation-harness/SKILL.md","skills/mlops/evaluation/lm-evaluation-harness/references/api-evaluation.md","skills/mlops/evaluation/lm-evaluation-harness/references/benchmark-guide.md","skills/mlops/evaluation/lm-evaluation-harness/references/custom-tasks.md","skills/mlops/evaluation/lm-evaluation-harness/references/distributed-eval.md","skills/mlops/evaluation/weights-and-biases/SKILL.md","skills/mlops/evaluation/weights-and-biases/references/artifacts.md","skills/mlops/evaluation/weights-and-biases/references/integrations.md","skills/mlops/evaluation/weights-and-biases/references/sweeps.md","skills/mlops/huggingface-hub/SKILL.md","skills/mlops/inference/DESCRIPTION.md","skills/mlops/inference/llama-cpp/SKILL.md","skills/mlops/inference/llama-cpp/references/advanced-usage.md","skills/mlops/inference/llama-cpp/references/hub-discovery.md","skills/mlops/inference/llama-cpp/references/optimization.md","skills/mlops/inference/llama-cpp/references/quantization.md","skills/mlops/inference/llama-cpp/references/server.md","skills/mlops/inference/llama-cpp/references/troubleshooting.md","skills/mlops/inference/obliteratus/SKILL.md","skills/mlops/inference/obliteratus/references/analysis-modules.md","skills/mlops/inference/obliteratus/references/methods-guide.md","skills/mlops/inference/obliteratus/templates/abliteration-config.yaml","skills/mlops/inference/obliteratus/templates/analysis-study.yaml","skills/mlops/inference/obliteratus/templates/batch-abliteration.yaml","skills/mlops/inference/outlines/SKILL.md","skills/mlops/inference/outlines/references/backends.md","skills/mlops/inference/outlines/references/examples.md","skills/mlops/inference/outlines/references/json_generation.md","skills/mlops/inference/vllm/SKILL.md","skills/mlops/inference/vllm/references/optimization.md","skills/mlops/inference/vllm/references/quantization.md","skills/mlops/inference/vllm/references/server-deployment.md","skills/mlops/inference/vllm/references/troubleshooting.md","skills/mlops/models/DESCRIPTION.md","skills/mlops/models/audiocraft/SKILL.md","skills/mlops/models/audiocraft/references/advanced-usage.md","skills/mlops/models/audiocraft/references/troubleshooting.md","skills/mlops/models/segment-anything/SKILL.md","skills/mlops/models/segment-anything/references/advanced-usage.md","skills/mlops/models/segment-anything/references/troubleshooting.md","skills/mlops/research/DESCRIPTION.md","skills/mlops/research/dspy/SKILL.md","skills/mlops/research/dspy/references/examples.md","skills/mlops/research/dspy/references/modules.md","skills/mlops/research/dspy/references/optimizers.md","skills/mlops/training/DESCRIPTION.md","skills/mlops/training/axolotl/SKILL.md","skills/mlops/training/axolotl/references/api.md","skills/mlops/training/axolotl/references/dataset-formats.md","skills/mlops/training/axolotl/references/index.md","skills/mlops/training/axolotl/references/other.md","skills/mlops/training/trl-fine-tuning/SKILL.md","skills/mlops/training/trl-fine-tuning/references/dpo-variants.md","skills/mlops/training/trl-fine-tuning/references/grpo-training.md","skills/mlops/training/trl-fine-tuning/references/online-rl.md","skills/mlops/training/trl-fine-tuning/references/reward-modeling.md","skills/mlops/training/trl-fine-tuning/references/sft-training.md","skills/mlops/training/trl-fine-tuning/templates/basic_grpo_training.py","skills/mlops/training/unsloth/SKILL.md","skills/mlops/training/unsloth/references/index.md","skills/mlops/training/unsloth/references/llms.md","skills/mlops/vector-databases/DESCRIPTION.md"]},{"name":"skills — note-taking","slug":"skills-note-taking","files":["skills/note-taking/DESCRIPTION.md","skills/note-taking/obsidian/SKILL.md"]},{"name":"skills — productivity","slug":"skills-productivity","files":["skills/productivity/DESCRIPTION.md","skills/productivity/airtable/SKILL.md","skills/productivity/google-workspace/SKILL.md","skills/productivity/google-workspace/references/gmail-search-syntax.md","skills/productivity/google-workspace/scripts/_hermes_home.py","skills/productivity/google-workspace/scripts/google_api.py","skills/productivity/google-workspace/scripts/gws_bridge.py","skills/productivity/google-workspace/scripts/setup.py","skills/productivity/linear/SKILL.md","skills/productivity/maps/SKILL.md","skills/productivity/maps/scripts/maps_client.py","skills/productivity/nano-pdf/SKILL.md","skills/productivity/notion/SKILL.md","skills/productivity/notion/references/block-types.md","skills/productivity/ocr-and-documents/DESCRIPTION.md","skills/productivity/ocr-and-documents/SKILL.md","skills/productivity/ocr-and-documents/scripts/extract_marker.py","skills/productivity/ocr-and-documents/scripts/extract_pymupdf.py","skills/productivity/powerpoint/SKILL.md","skills/productivity/powerpoint/editing.md","skills/productivity/powerpoint/pptxgenjs.md","skills/productivity/powerpoint/scripts/__init__.py","skills/productivity/powerpoint/scripts/add_slide.py","skills/productivity/powerpoint/scripts/clean.py","skills/productivity/powerpoint/scripts/office/helpers/__init__.py","skills/productivity/powerpoint/scripts/office/helpers/merge_runs.py","skills/productivity/powerpoint/scripts/office/helpers/simplify_redlines.py","skills/productivity/powerpoint/scripts/office/pack.py","skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd","skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd","skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd","skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd","skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd","skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd","skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd","skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd","skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd","skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd","skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd","skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd","skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd","skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd","skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd","skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd","skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd","skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd","skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd","skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd","skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd","skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd","skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd","skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd","skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd","skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd","skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd","skills/productivity/powerpoint/scripts/office/schemas/ecma/fourth-edition/opc-contentTypes.xsd","skills/productivity/powerpoint/scripts/office/schemas/ecma/fourth-edition/opc-coreProperties.xsd","skills/productivity/powerpoint/scripts/office/schemas/ecma/fourth-edition/opc-digSig.xsd","skills/productivity/powerpoint/scripts/office/schemas/ecma/fourth-edition/opc-relationships.xsd","skills/productivity/powerpoint/scripts/office/schemas/mce/mc.xsd","skills/productivity/powerpoint/scripts/office/schemas/microsoft/wml-2010.xsd","skills/productivity/powerpoint/scripts/office/schemas/microsoft/wml-2012.xsd","skills/productivity/powerpoint/scripts/office/schemas/microsoft/wml-2018.xsd","skills/productivity/powerpoint/scripts/office/schemas/microsoft/wml-cex-2018.xsd","skills/productivity/powerpoint/scripts/office/schemas/microsoft/wml-cid-2016.xsd","skills/productivity/powerpoint/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd","skills/productivity/powerpoint/scripts/office/schemas/microsoft/wml-symex-2015.xsd"]},{"name":"skills — red-teaming","slug":"skills-red-teaming","files":["skills/red-teaming/godmode/SKILL.md","skills/red-teaming/godmode/references/jailbreak-templates.md","skills/red-teaming/godmode/references/refusal-detection.md","skills/red-teaming/godmode/scripts/auto_jailbreak.py","skills/red-teaming/godmode/scripts/godmode_race.py","skills/red-teaming/godmode/scripts/load_godmode.py","skills/red-teaming/godmode/scripts/parseltongue.py","skills/red-teaming/godmode/templates/prefill-subtle.json","skills/red-teaming/godmode/templates/prefill.json"]},{"name":"skills — research","slug":"skills-research","files":["skills/research/DESCRIPTION.md","skills/research/arxiv/SKILL.md","skills/research/arxiv/scripts/search_arxiv.py","skills/research/blogwatcher/SKILL.md","skills/research/llm-wiki/SKILL.md","skills/research/polymarket/SKILL.md","skills/research/polymarket/references/api-endpoints.md","skills/research/polymarket/scripts/polymarket.py","skills/research/research-paper-writing/SKILL.md","skills/research/research-paper-writing/references/autoreason-methodology.md","skills/research/research-paper-writing/references/checklists.md","skills/research/research-paper-writing/references/citation-workflow.md","skills/research/research-paper-writing/references/experiment-patterns.md","skills/research/research-paper-writing/references/human-evaluation.md","skills/research/research-paper-writing/references/paper-types.md","skills/research/research-paper-writing/references/reviewer-guidelines.md","skills/research/research-paper-writing/references/sources.md","skills/research/research-paper-writing/references/writing-guide.md","skills/research/research-paper-writing/templates/README.md","skills/research/research-paper-writing/templates/aaai2026/README.md","skills/research/research-paper-writing/templates/aaai2026/aaai2026-unified-supp.tex","skills/research/research-paper-writing/templates/aaai2026/aaai2026-unified-template.tex","skills/research/research-paper-writing/templates/aaai2026/aaai2026.bib","skills/research/research-paper-writing/templates/aaai2026/aaai2026.bst","skills/research/research-paper-writing/templates/aaai2026/aaai2026.sty","skills/research/research-paper-writing/templates/acl/README.md","skills/research/research-paper-writing/templates/acl/acl.sty","skills/research/research-paper-writing/templates/acl/acl_latex.tex","skills/research/research-paper-writing/templates/acl/acl_lualatex.tex","skills/research/research-paper-writing/templates/acl/acl_natbib.bst","skills/research/research-paper-writing/templates/acl/anthology.bib.txt","skills/research/research-paper-writing/templates/acl/custom.bib","skills/research/research-paper-writing/templates/acl/formatting.md","skills/research/research-paper-writing/templates/colm2025/README.md","skills/research/research-paper-writing/templates/colm2025/colm2025_conference.bib","skills/research/research-paper-writing/templates/colm2025/colm2025_conference.bst","skills/research/research-paper-writing/templates/colm2025/colm2025_conference.sty","skills/research/research-paper-writing/templates/colm2025/colm2025_conference.tex","skills/research/research-paper-writing/templates/colm2025/fancyhdr.sty","skills/research/research-paper-writing/templates/colm2025/math_commands.tex","skills/research/research-paper-writing/templates/colm2025/natbib.sty","skills/research/research-paper-writing/templates/iclr2026/fancyhdr.sty","skills/research/research-paper-writing/templates/iclr2026/iclr2026_conference.bib","skills/research/research-paper-writing/templates/iclr2026/iclr2026_conference.bst","skills/research/research-paper-writing/templates/iclr2026/iclr2026_conference.sty","skills/research/research-paper-writing/templates/iclr2026/iclr2026_conference.tex","skills/research/research-paper-writing/templates/iclr2026/math_commands.tex","skills/research/research-paper-writing/templates/iclr2026/natbib.sty","skills/research/research-paper-writing/templates/icml2026/algorithm.sty","skills/research/research-paper-writing/templates/icml2026/algorithmic.sty","skills/research/research-paper-writing/templates/icml2026/example_paper.bib","skills/research/research-paper-writing/templates/icml2026/example_paper.tex","skills/research/research-paper-writing/templates/icml2026/fancyhdr.sty","skills/research/research-paper-writing/templates/icml2026/icml2026.bst","skills/research/research-paper-writing/templates/icml2026/icml2026.sty","skills/research/research-paper-writing/templates/neurips2025/Makefile","skills/research/research-paper-writing/templates/neurips2025/extra_pkgs.tex","skills/research/research-paper-writing/templates/neurips2025/main.tex","skills/research/research-paper-writing/templates/neurips2025/neurips.sty"]},{"name":"skills — smart-home","slug":"skills-smart-home","files":["skills/smart-home/DESCRIPTION.md","skills/smart-home/openhue/SKILL.md"]},{"name":"skills — social-media","slug":"skills-social-media","files":["skills/social-media/DESCRIPTION.md","skills/social-media/xurl/SKILL.md"]},{"name":"skills — software-development","slug":"skills-software-development","files":["skills/software-development/debugging-hermes-tui-commands/SKILL.md","skills/software-development/hermes-agent-skill-authoring/SKILL.md","skills/software-development/node-inspect-debugger/SKILL.md","skills/software-development/plan/SKILL.md","skills/software-development/python-debugpy/SKILL.md","skills/software-development/requesting-code-review/SKILL.md","skills/software-development/spike/SKILL.md","skills/software-development/subagent-driven-development/SKILL.md","skills/software-development/subagent-driven-development/references/context-budget-discipline.md","skills/software-development/subagent-driven-development/references/gates-taxonomy.md","skills/software-development/systematic-debugging/SKILL.md","skills/software-development/test-driven-development/SKILL.md","skills/software-development/writing-plans/SKILL.md"]},{"name":"skills — yuanbao","slug":"skills-yuanbao","files":["skills/yuanbao/SKILL.md"]}]},{"name":"tests","slug":"tests","files":[],"children":[{"name":"tests — tests","slug":"tests-tests","files":["tests/__init__.py","tests/conftest.py","tests/run_interrupt_test.py","tests/test_account_usage.py","tests/test_atomic_replace_symlinks.py","tests/test_base_url_hostname.py","tests/test_batch_runner_checkpoint.py","tests/test_cli_file_drop.py","tests/test_cli_manual_compress.py","tests/test_cli_skin_integration.py","tests/test_ctx_halving_fix.py","tests/test_empty_model_fallback.py","tests/test_evidence_store.py","tests/test_get_tool_definitions_cache_isolation.py","tests/test_hermes_constants.py","tests/test_hermes_home_profile_warning.py","tests/test_hermes_logging.py","tests/test_hermes_state.py","tests/test_honcho_client_config.py","tests/test_install_sh_setup_wizard_tty_probe.py","tests/test_ipv4_preference.py","tests/test_mcp_serve.py","tests/test_mini_swe_runner.py","tests/test_minimax_model_validation.py","tests/test_minimax_oauth.py","tests/test_minisweagent_path.py","tests/test_model_picker_scroll.py","tests/test_model_tools.py","tests/test_model_tools_async_bridge.py","tests/test_ollama_num_ctx.py","tests/test_packaging_metadata.py","tests/test_plugin_skills.py","tests/test_project_metadata.py","tests/test_retry_utils.py","tests/test_sql_injection.py","tests/test_subprocess_home_isolation.py","tests/test_timezone.py","tests/test_toolset_distributions.py","tests/test_toolsets.py","tests/test_trajectory_compressor.py","tests/test_trajectory_compressor_async.py","tests/test_transform_tool_result_hook.py","tests/test_tui_gateway_server.py","tests/test_utils_truthy_values.py","tests/test_yuanbao_integration.py","tests/test_yuanbao_markdown.py","tests/test_yuanbao_pipeline.py","tests/test_yuanbao_proto.py"]},{"name":"tests — acp","slug":"tests-acp","files":["tests/acp/__init__.py","tests/acp/test_approval_isolation.py","tests/acp/test_auth.py","tests/acp/test_entry.py","tests/acp/test_events.py","tests/acp/test_mcp_e2e.py","tests/acp/test_permissions.py","tests/acp/test_ping_suppression.py","tests/acp/test_server.py","tests/acp/test_session.py","tests/acp/test_tools.py"]},{"name":"tests — acp_adapter","slug":"tests-acp-adapter","files":["tests/acp_adapter/test_acp_commands.py","tests/acp_adapter/test_acp_images.py"]},{"name":"tests — agent","slug":"tests-agent","files":["tests/agent/__init__.py","tests/agent/test_anthropic_adapter.py","tests/agent/test_anthropic_keychain.py","tests/agent/test_auxiliary_client.py","tests/agent/test_auxiliary_client_anthropic_custom.py","tests/agent/test_auxiliary_config_bridge.py","tests/agent/test_auxiliary_main_first.py","tests/agent/test_auxiliary_named_custom_providers.py","tests/agent/test_auxiliary_transport_autodetect.py","tests/agent/test_bedrock_1m_context.py","tests/agent/test_bedrock_adapter.py","tests/agent/test_bedrock_integration.py","tests/agent/test_codex_cloudflare_headers.py","tests/agent/test_compress_focus.py","tests/agent/test_compressor_image_tokens.py","tests/agent/test_context_compressor.py","tests/agent/test_context_engine.py","tests/agent/test_context_references.py","tests/agent/test_copilot_acp_client.py","tests/agent/test_credential_pool.py","tests/agent/test_credential_pool_routing.py","tests/agent/test_crossloop_client_cache.py","tests/agent/test_curator.py","tests/agent/test_curator_activity.py","tests/agent/test_curator_backup.py","tests/agent/test_curator_classification.py","tests/agent/test_curator_reports.py","tests/agent/test_deepseek_anthropic_thinking.py","tests/agent/test_direct_provider_url_detection.py","tests/agent/test_display.py","tests/agent/test_display_emoji.py","tests/agent/test_error_classifier.py","tests/agent/test_external_skills.py","tests/agent/test_gemini_cloudcode.py","tests/agent/test_gemini_free_tier_gate.py","tests/agent/test_gemini_native_adapter.py","tests/agent/test_gemini_schema.py","tests/agent/test_image_gen_registry.py","tests/agent/test_image_routing.py","tests/agent/test_insights.py","tests/agent/test_kimi_coding_anthropic_thinking.py","tests/agent/test_local_stream_timeout.py","tests/agent/test_memory_provider.py","tests/agent/test_memory_session_switch.py","tests/agent/test_memory_user_id.py","tests/agent/test_minimax_auxiliary_url.py","tests/agent/test_minimax_provider.py","tests/agent/test_model_metadata.py","tests/agent/test_model_metadata_local_ctx.py","tests/agent/test_model_metadata_ssl.py","tests/agent/test_models_dev.py","tests/agent/test_moonshot_schema.py","tests/agent/test_nous_rate_guard.py","tests/agent/test_onboarding.py","tests/agent/test_prompt_builder.py","tests/agent/test_prompt_caching.py","tests/agent/test_proxy_and_url_validation.py","tests/agent/test_rate_limit_tracker.py","tests/agent/test_redact.py","tests/agent/test_shell_hooks.py","tests/agent/test_shell_hooks_consent.py","tests/agent/test_skill_commands.py","tests/agent/test_skill_commands_reload.py","tests/agent/test_skill_utils.py","tests/agent/test_streaming_context_scrubber.py","tests/agent/test_subagent_progress.py","tests/agent/test_subagent_stop_hook.py","tests/agent/test_subdirectory_hints.py","tests/agent/test_title_generator.py","tests/agent/test_tool_guardrails.py","tests/agent/test_unsupported_parameter_retry.py","tests/agent/test_unsupported_temperature_retry.py","tests/agent/test_usage_pricing.py","tests/agent/test_vision_resolved_args.py","tests/agent/transports/__init__.py","tests/agent/transports/test_bedrock_transport.py","tests/agent/transports/test_chat_completions.py","tests/agent/transports/test_codex_transport.py","tests/agent/transports/test_transport.py","tests/agent/transports/test_types.py"]},{"name":"tests — cli","slug":"tests-cli","files":["tests/cli/__init__.py","tests/cli/test_branch_command.py","tests/cli/test_busy_input_mode_command.py","tests/cli/test_cli_approval_ui.py","tests/cli/test_cli_background_tui_refresh.py","tests/cli/test_cli_bracketed_paste_sanitizer.py","tests/cli/test_cli_browser_connect.py","tests/cli/test_cli_context_warning.py","tests/cli/test_cli_copy_command.py","tests/cli/test_cli_extension_hooks.py","tests/cli/test_cli_external_editor.py","tests/cli/test_cli_file_drop.py","tests/cli/test_cli_force_redraw.py","tests/cli/test_cli_image_command.py","tests/cli/test_cli_init.py","tests/cli/test_cli_interrupt_subagent.py","tests/cli/test_cli_loading_indicator.py","tests/cli/test_cli_markdown_rendering.py","tests/cli/test_cli_mcp_config_watch.py","tests/cli/test_cli_new_session.py","tests/cli/test_cli_prefix_matching.py","tests/cli/test_cli_preloaded_skills.py","tests/cli/test_cli_provider_resolution.py","tests/cli/test_cli_reload_skills.py","tests/cli/test_cli_retry.py","tests/cli/test_cli_save_config_value.py","tests/cli/test_cli_secret_capture.py","tests/cli/test_cli_shutdown_memory_messages.py","tests/cli/test_cli_skin_integration.py","tests/cli/test_cli_status_bar.py","tests/cli/test_cli_status_command.py","tests/cli/test_cli_steer_busy_path.py","tests/cli/test_cli_terminal_response_sanitizer.py","tests/cli/test_cli_tools_command.py","tests/cli/test_cli_user_message_preview.py","tests/cli/test_compress_focus.py","tests/cli/test_cprint_bg_thread.py","tests/cli/test_cwd_env_respect.py","tests/cli/test_fast_command.py","tests/cli/test_gquota_command.py","tests/cli/test_manual_compress.py","tests/cli/test_personality_none.py","tests/cli/test_quick_commands.py","tests/cli/test_reasoning_command.py","tests/cli/test_resume_display.py","tests/cli/test_save_conversation_location.py","tests/cli/test_session_boundary_hooks.py","tests/cli/test_stream_delta_think_tag.py","tests/cli/test_surrogate_sanitization.py","tests/cli/test_tool_progress_scrollback.py","tests/cli/test_worktree.py","tests/cli/test_worktree_security.py"]},{"name":"tests — cron","slug":"tests-cron","files":["tests/cron/__init__.py","tests/cron/test_codex_execution_paths.py","tests/cron/test_compute_next_run_last_run_at.py","tests/cron/test_cron_context_from.py","tests/cron/test_cron_inactivity_timeout.py","tests/cron/test_cron_script.py","tests/cron/test_cron_workdir.py","tests/cron/test_file_permissions.py","tests/cron/test_jobs.py","tests/cron/test_rewrite_skill_refs.py","tests/cron/test_scheduler.py"]},{"name":"tests — e2e","slug":"tests-e2e","files":["tests/e2e/__init__.py","tests/e2e/conftest.py","tests/e2e/matrix_xsign_bootstrap/README.md","tests/e2e/matrix_xsign_bootstrap/docker-compose.yml","tests/e2e/matrix_xsign_bootstrap/test_bootstrap.py","tests/e2e/test_discord_adapter.py","tests/e2e/test_platform_commands.py"]},{"name":"tests — environments","slug":"tests-environments","files":["tests/environments/benchmarks/test_terminalbench2_env_security.py"]},{"name":"tests — fakes","slug":"tests-fakes","files":["tests/fakes/__init__.py","tests/fakes/fake_ha_server.py"]},{"name":"tests — gateway","slug":"tests-gateway","files":["tests/gateway/__init__.py","tests/gateway/_plugin_adapter_loader.py","tests/gateway/conftest.py","tests/gateway/feishu_helpers.py","tests/gateway/restart_test_helpers.py","tests/gateway/test_7100_transient_failure_transcript.py","tests/gateway/test_agent_cache.py","tests/gateway/test_allowlist_startup_check.py","tests/gateway/test_api_server.py","tests/gateway/test_api_server_bind_guard.py","tests/gateway/test_api_server_jobs.py","tests/gateway/test_api_server_multimodal.py","tests/gateway/test_api_server_normalize.py","tests/gateway/test_api_server_runs.py","tests/gateway/test_api_server_toolset.py","tests/gateway/test_approve_deny_commands.py","tests/gateway/test_auth_fallback.py","tests/gateway/test_auto_continue.py","tests/gateway/test_background_command.py","tests/gateway/test_background_process_notifications.py","tests/gateway/test_base_topic_sessions.py","tests/gateway/test_bluebubbles.py","tests/gateway/test_busy_session_ack.py","tests/gateway/test_busy_session_auth_bypass.py","tests/gateway/test_cancel_background_drain.py","tests/gateway/test_channel_directory.py","tests/gateway/test_clean_shutdown_marker.py","tests/gateway/test_command_bypass_active_session.py","tests/gateway/test_complete_path_at_filter.py","tests/gateway/test_compress_command.py","tests/gateway/test_compress_focus.py","tests/gateway/test_compress_plugin_engine.py","tests/gateway/test_config.py","tests/gateway/test_config_cwd_bridge.py","tests/gateway/test_config_env_bridge_authority.py","tests/gateway/test_debug_command.py","tests/gateway/test_delivery.py","tests/gateway/test_dingtalk.py","tests/gateway/test_discord_allowed_channels.py","tests/gateway/test_discord_allowed_mentions.py","tests/gateway/test_discord_attachment_download.py","tests/gateway/test_discord_bot_auth_bypass.py","tests/gateway/test_discord_bot_filter.py","tests/gateway/test_discord_channel_controls.py","tests/gateway/test_discord_channel_prompts.py","tests/gateway/test_discord_channel_skills.py","tests/gateway/test_discord_connect.py","tests/gateway/test_discord_document_handling.py","tests/gateway/test_discord_free_response.py","tests/gateway/test_discord_imports.py","tests/gateway/test_discord_media_metadata.py","tests/gateway/test_discord_model_picker.py","tests/gateway/test_discord_opus.py","tests/gateway/test_discord_race_polish.py","tests/gateway/test_discord_reactions.py","tests/gateway/test_discord_reply_mode.py","tests/gateway/test_discord_send.py","tests/gateway/test_discord_slash_commands.py","tests/gateway/test_discord_system_messages.py","tests/gateway/test_discord_thread_persistence.py","tests/gateway/test_display_config.py","tests/gateway/test_dm_topics.py","tests/gateway/test_document_cache.py","tests/gateway/test_duplicate_reply_suppression.py","tests/gateway/test_email.py","tests/gateway/test_ephemeral_reply.py","tests/gateway/test_extract_local_files.py","tests/gateway/test_fallback_eviction.py","tests/gateway/test_fast_command.py","tests/gateway/test_feishu.py","tests/gateway/test_feishu_approval_buttons.py","tests/gateway/test_feishu_bot_admission.py","tests/gateway/test_feishu_bot_auth_bypass.py","tests/gateway/test_feishu_comment.py","tests/gateway/test_feishu_comment_rules.py","tests/gateway/test_feishu_onboard.py","tests/gateway/test_fresh_reset_skill_injection.py","tests/gateway/test_gateway_inactivity_timeout.py","tests/gateway/test_gateway_shutdown.py","tests/gateway/test_home_target_env_var.py","tests/gateway/test_homeassistant.py","tests/gateway/test_hooks.py","tests/gateway/test_insights_unicode_flags.py","tests/gateway/test_internal_event_bypass_pairing.py","tests/gateway/test_interrupt_key_match.py","tests/gateway/test_irc_adapter.py","tests/gateway/test_keep_typing_timeout.py","tests/gateway/test_matrix.py","tests/gateway/test_matrix_exec_approval.py","tests/gateway/test_matrix_mention.py","tests/gateway/test_matrix_voice.py","tests/gateway/test_mattermost.py","tests/gateway/test_media_download_retry.py","tests/gateway/test_media_extraction.py","tests/gateway/test_message_deduplicator.py","tests/gateway/test_mirror.py","tests/gateway/test_model_command_custom_providers.py","tests/gateway/test_model_switch_persistence.py","tests/gateway/test_native_image_buffer_isolation.py","tests/gateway/test_notice_delivery.py","tests/gateway/test_pairing.py","tests/gateway/test_pending_drain_no_recursion.py","tests/gateway/test_pending_drain_race.py","tests/gateway/test_pending_event_none.py","tests/gateway/test_pii_redaction.py","tests/gateway/test_platform_base.py","tests/gateway/test_platform_connected_checkers.py","tests/gateway/test_platform_http_client_limits.py","tests/gateway/test_platform_reconnect.py","tests/gateway/test_platform_registry.py","tests/gateway/test_plugin_platform_interface.py","tests/gateway/test_pre_gateway_dispatch.py","tests/gateway/test_proxy_mode.py","tests/gateway/test_qqbot.py","tests/gateway/test_queue_consumption.py","tests/gateway/test_reasoning_command.py","tests/gateway/test_reload_skills_command.py","tests/gateway/test_reload_skills_discord_resync.py","tests/gateway/test_reply_to_injection.py","tests/gateway/test_restart_drain.py","tests/gateway/test_restart_notification.py","tests/gateway/test_restart_redelivery_dedup.py","tests/gateway/test_restart_resume_pending.py","tests/gateway/test_resume_command.py","tests/gateway/test_retry_replacement.py","tests/gateway/test_retry_response.py","tests/gateway/test_run_progress_interrupt.py","tests/gateway/test_run_progress_topics.py","tests/gateway/test_runner_fatal_adapter.py","tests/gateway/test_runner_startup_failures.py","tests/gateway/test_running_agent_session_toggles.py","tests/gateway/test_runtime_footer.py","tests/gateway/test_safe_adapter_disconnect.py","tests/gateway/test_send_image_file.py","tests/gateway/test_send_multiple_images.py","tests/gateway/test_send_retry.py","tests/gateway/test_session.py","tests/gateway/test_session_boundary_hooks.py","tests/gateway/test_session_boundary_security_state.py","tests/gateway/test_session_dm_thread_seeding.py","tests/gateway/test_session_env.py","tests/gateway/test_session_hygiene.py","tests/gateway/test_session_info.py","tests/gateway/test_session_list_allowed_sources.py","tests/gateway/test_session_model_override_routing.py","tests/gateway/test_session_model_reset.py","tests/gateway/test_session_race_guard.py","tests/gateway/test_session_reset_notify.py","tests/gateway/test_session_split_brain_11016.py","tests/gateway/test_session_state_cleanup.py","tests/gateway/test_session_store_prune.py","tests/gateway/test_setup_feishu.py","tests/gateway/test_shared_group_sender_prefix.py","tests/gateway/test_shutdown_cache_cleanup.py","tests/gateway/test_shutdown_memory_provider_messages.py","tests/gateway/test_signal.py","tests/gateway/test_signal_format.py","tests/gateway/test_signal_rate_limit.py","tests/gateway/test_slack.py","tests/gateway/test_slack_approval_buttons.py","tests/gateway/test_slack_channel_skills.py","tests/gateway/test_slack_mention.py","tests/gateway/test_sms.py","tests/gateway/test_sse_agent_cancel.py","tests/gateway/test_ssl_certs.py","tests/gateway/test_stale_code_self_check.py","tests/gateway/test_status.py","tests/gateway/test_status_command.py","tests/gateway/test_steer_command.py","tests/gateway/test_step_callback_compat.py","tests/gateway/test_sticker_cache.py","tests/gateway/test_stream_consumer.py","tests/gateway/test_stream_consumer_fresh_final.py","tests/gateway/test_stt_config.py","tests/gateway/test_stuck_loop.py","tests/gateway/test_teams.py","tests/gateway/test_telegram_approval_buttons.py","tests/gateway/test_telegram_caption_merge.py","tests/gateway/test_telegram_conflict.py","tests/gateway/test_telegram_documents.py","tests/gateway/test_telegram_format.py","tests/gateway/test_telegram_group_gating.py","tests/gateway/test_telegram_mention_boundaries.py","tests/gateway/test_telegram_network.py","tests/gateway/test_telegram_network_reconnect.py","tests/gateway/test_telegram_photo_interrupts.py","tests/gateway/test_telegram_reactions.py","tests/gateway/test_telegram_reply_mode.py","tests/gateway/test_telegram_text_batching.py","tests/gateway/test_telegram_thread_fallback.py","tests/gateway/test_telegram_webhook_secret.py","tests/gateway/test_text_batching.py","tests/gateway/test_title_command.py","tests/gateway/test_transcript_offset.py","tests/gateway/test_tts_media_routing.py","tests/gateway/test_unauthorized_dm_behavior.py","tests/gateway/test_unavailable_skill_hint.py","tests/gateway/test_unknown_command.py","tests/gateway/test_update_command.py","tests/gateway/test_update_streaming.py","tests/gateway/test_usage_command.py","tests/gateway/test_verbose_command.py","tests/gateway/test_vision_memory_leak.py","tests/gateway/test_voice_command.py","tests/gateway/test_voice_mode_platform_isolation.py","tests/gateway/test_weak_credential_guard.py","tests/gateway/test_webhook_adapter.py","tests/gateway/test_webhook_deliver_only.py","tests/gateway/test_webhook_dynamic_routes.py","tests/gateway/test_webhook_integration.py","tests/gateway/test_webhook_signature_rate_limit.py","tests/gateway/test_wecom.py","tests/gateway/test_wecom_callback.py","tests/gateway/test_weixin.py","tests/gateway/test_whatsapp_connect.py","tests/gateway/test_whatsapp_formatting.py","tests/gateway/test_whatsapp_group_gating.py","tests/gateway/test_whatsapp_reply_prefix.py","tests/gateway/test_ws_auth_retry.py","tests/gateway/test_yolo_command.py"]},{"name":"tests — hermes_cli","slug":"tests-hermes-cli","files":["tests/hermes_cli/__init__.py","tests/hermes_cli/test_ai_gateway_models.py","tests/hermes_cli/test_anthropic_model_flow_stale_oauth.py","tests/hermes_cli/test_anthropic_oauth_flow.py","tests/hermes_cli/test_anthropic_provider_persistence.py","tests/hermes_cli/test_api_key_providers.py","tests/hermes_cli/test_apply_model_switch_result_context.py","tests/hermes_cli/test_arcee_provider.py","tests/hermes_cli/test_argparse_flag_propagation.py","tests/hermes_cli/test_at_context_completion_filter.py","tests/hermes_cli/test_atomic_json_write.py","tests/hermes_cli/test_atomic_yaml_write.py","tests/hermes_cli/test_auth_codex_provider.py","tests/hermes_cli/test_auth_commands.py","tests/hermes_cli/test_auth_nous_provider.py","tests/hermes_cli/test_auth_provider_gate.py","tests/hermes_cli/test_auth_qwen_provider.py","tests/hermes_cli/test_auth_ssl_macos.py","tests/hermes_cli/test_aux_config.py","tests/hermes_cli/test_azure_detect.py","tests/hermes_cli/test_backup.py","tests/hermes_cli/test_banner.py","tests/hermes_cli/test_banner_git_state.py","tests/hermes_cli/test_banner_skills.py","tests/hermes_cli/test_bedrock_model_picker.py","tests/hermes_cli/test_chat_skills_flag.py","tests/hermes_cli/test_claw.py","tests/hermes_cli/test_clear_stale_base_url.py","tests/hermes_cli/test_cmd_update.py","tests/hermes_cli/test_coalesce_session_args.py","tests/hermes_cli/test_codex_cli_model_picker.py","tests/hermes_cli/test_codex_models.py","tests/hermes_cli/test_commands.py","tests/hermes_cli/test_completion.py","tests/hermes_cli/test_config.py","tests/hermes_cli/test_config_drift.py","tests/hermes_cli/test_config_env_expansion.py","tests/hermes_cli/test_config_env_refs.py","tests/hermes_cli/test_config_validation.py","tests/hermes_cli/test_container_aware_cli.py","tests/hermes_cli/test_copilot_auth.py","tests/hermes_cli/test_copilot_catalog_oauth_fallback.py","tests/hermes_cli/test_copilot_context.py","tests/hermes_cli/test_copilot_in_model_list.py","tests/hermes_cli/test_copilot_token_exchange.py","tests/hermes_cli/test_cron.py","tests/hermes_cli/test_curator_status.py","tests/hermes_cli/test_custom_provider_context_length.py","tests/hermes_cli/test_custom_provider_model_switch.py","tests/hermes_cli/test_dashboard_browser_safe_imports.py","tests/hermes_cli/test_dashboard_lifecycle_flags.py","tests/hermes_cli/test_dashboard_profiles_nav_label.py","tests/hermes_cli/test_debug.py","tests/hermes_cli/test_deprecated_cwd_warning.py","tests/hermes_cli/test_detect_api_mode_for_url.py","tests/hermes_cli/test_determine_api_mode_hostname.py","tests/hermes_cli/test_dingtalk_auth.py","tests/hermes_cli/test_discord_skill_clamp_warning.py","tests/hermes_cli/test_doctor.py","tests/hermes_cli/test_doctor_command_install.py","tests/hermes_cli/test_env_loader.py","tests/hermes_cli/test_env_sanitize_on_load.py","tests/hermes_cli/test_fallback_cmd.py","tests/hermes_cli/test_gateway.py","tests/hermes_cli/test_gateway_linger.py","tests/hermes_cli/test_gateway_runtime_health.py","tests/hermes_cli/test_gateway_service.py","tests/hermes_cli/test_gateway_wsl.py","tests/hermes_cli/test_gemini_free_tier_setup_block.py","tests/hermes_cli/test_gemini_provider.py","tests/hermes_cli/test_gmi_provider.py","tests/hermes_cli/test_goals.py","tests/hermes_cli/test_hooks_cli.py","tests/hermes_cli/test_ignore_user_config_flags.py","tests/hermes_cli/test_image_gen_picker.py","tests/hermes_cli/test_kanban_cli.py","tests/hermes_cli/test_kanban_core_functionality.py","tests/hermes_cli/test_kanban_db.py","tests/hermes_cli/test_launcher.py","tests/hermes_cli/test_logs.py","tests/hermes_cli/test_managed_installs.py","tests/hermes_cli/test_mcp_config.py","tests/hermes_cli/test_mcp_reload_confirm_gate.py","tests/hermes_cli/test_mcp_tools_config.py","tests/hermes_cli/test_memory_reset.py","tests/hermes_cli/test_model_catalog.py","tests/hermes_cli/test_model_normalize.py","tests/hermes_cli/test_model_picker_viewport.py","tests/hermes_cli/test_model_provider_persistence.py","tests/hermes_cli/test_model_switch_context_display.py","tests/hermes_cli/test_model_switch_copilot_api_mode.py","tests/hermes_cli/test_model_switch_custom_providers.py","tests/hermes_cli/test_model_switch_opencode_anthropic.py","tests/hermes_cli/test_model_switch_variant_tags.py","tests/hermes_cli/test_model_validation.py","tests/hermes_cli/test_models.py","tests/hermes_cli/test_models_dev_preferred_merge.py","tests/hermes_cli/test_non_ascii_credential.py","tests/hermes_cli/test_nous_hermes_non_agentic.py","tests/hermes_cli/test_nous_subscription.py","tests/hermes_cli/test_ollama_cloud_auth.py","tests/hermes_cli/test_ollama_cloud_provider.py","tests/hermes_cli/test_opencode_go_in_model_list.py","tests/hermes_cli/test_opencode_go_validation_fallback.py","tests/hermes_cli/test_overlay_slug_resolution.py","tests/hermes_cli/test_path_completion.py","tests/hermes_cli/test_placeholder_usage.py","tests/hermes_cli/test_plugin_cli_registration.py","tests/hermes_cli/test_plugin_scanner_recursion.py","tests/hermes_cli/test_plugins.py","tests/hermes_cli/test_plugins_cmd.py","tests/hermes_cli/test_profile_export_credentials.py","tests/hermes_cli/test_profiles.py","tests/hermes_cli/test_provider_config_validation.py","tests/hermes_cli/test_pty_bridge.py","tests/hermes_cli/test_reasoning_effort_menu.py","tests/hermes_cli/test_redact_config_bridge.py","tests/hermes_cli/test_regression_16767.py","tests/hermes_cli/test_relaunch.py","tests/hermes_cli/test_resolve_last_session.py","tests/hermes_cli/test_runtime_provider_resolution.py","tests/hermes_cli/test_session_browse.py","tests/hermes_cli/test_sessions_delete.py","tests/hermes_cli/test_set_config_value.py","tests/hermes_cli/test_setup.py","tests/hermes_cli/test_setup_agent_settings.py","tests/hermes_cli/test_setup_hermes_script.py","tests/hermes_cli/test_setup_irc.py","tests/hermes_cli/test_setup_matrix_e2ee.py","tests/hermes_cli/test_setup_model_provider.py","tests/hermes_cli/test_setup_noninteractive.py","tests/hermes_cli/test_setup_ollama_cloud_force_refresh.py","tests/hermes_cli/test_setup_openclaw_migration.py","tests/hermes_cli/test_setup_prompt_menus.py","tests/hermes_cli/test_setup_reconfigure.py","tests/hermes_cli/test_skills_config.py","tests/hermes_cli/test_skills_hub.py","tests/hermes_cli/test_skills_install_flags.py","tests/hermes_cli/test_skills_skip_confirm.py","tests/hermes_cli/test_skills_subparser.py","tests/hermes_cli/test_skin_engine.py","tests/hermes_cli/test_spotify_auth.py","tests/hermes_cli/test_status.py","tests/hermes_cli/test_status_model_provider.py","tests/hermes_cli/test_subparser_routing_fallback.py","tests/hermes_cli/test_subprocess_timeouts.py","tests/hermes_cli/test_suppress_eio_on_interrupt.py","tests/hermes_cli/test_tencent_tokenhub_provider.py","tests/hermes_cli/test_terminal_menu_fallbacks.py","tests/hermes_cli/test_timeouts.py","tests/hermes_cli/test_tips.py","tests/hermes_cli/test_tool_token_estimation.py","tests/hermes_cli/test_tools_config.py","tests/hermes_cli/test_tools_disable_enable.py","tests/hermes_cli/test_tui_npm_install.py","tests/hermes_cli/test_tui_resume_flow.py","tests/hermes_cli/test_update_autostash.py","tests/hermes_cli/test_update_check.py","tests/hermes_cli/test_update_config_clears_custom_fields.py","tests/hermes_cli/test_update_gateway_restart.py","tests/hermes_cli/test_update_hangup_protection.py","tests/hermes_cli/test_update_stale_dashboard.py","tests/hermes_cli/test_update_yes_flag.py","tests/hermes_cli/test_user_providers_model_switch.py","tests/hermes_cli/test_voice_wrapper.py","tests/hermes_cli/test_web_server.py","tests/hermes_cli/test_web_server_host_header.py","tests/hermes_cli/test_web_ui_build.py","tests/hermes_cli/test_webhook_cli.py","tests/hermes_cli/test_xiaomi_provider.py"]},{"name":"tests — hermes_state","slug":"tests-hermes-state","files":["tests/hermes_state/test_resolve_resume_session_id.py"]},{"name":"tests — honcho_plugin","slug":"tests-honcho-plugin","files":["tests/honcho_plugin/__init__.py","tests/honcho_plugin/test_async_memory.py","tests/honcho_plugin/test_cli.py","tests/honcho_plugin/test_client.py","tests/honcho_plugin/test_empty_profile_hint.py","tests/honcho_plugin/test_pin_peer_name.py","tests/honcho_plugin/test_session.py"]},{"name":"tests — integration","slug":"tests-integration","files":["tests/integration/__init__.py","tests/integration/test_batch_runner.py","tests/integration/test_checkpoint_resumption.py","tests/integration/test_daytona_terminal.py","tests/integration/test_ha_integration.py","tests/integration/test_modal_terminal.py","tests/integration/test_voice_channel_flow.py","tests/integration/test_web_tools.py"]},{"name":"tests — openviking_plugin","slug":"tests-openviking-plugin","files":["tests/openviking_plugin/test_openviking.py"]},{"name":"tests — plugins","slug":"tests-plugins","files":["tests/plugins/__init__.py","tests/plugins/image_gen/__init__.py","tests/plugins/image_gen/test_openai_codex_provider.py","tests/plugins/image_gen/test_openai_provider.py","tests/plugins/image_gen/test_xai_provider.py","tests/plugins/memory/__init__.py","tests/plugins/memory/test_hindsight_provider.py","tests/plugins/memory/test_mem0_v2.py","tests/plugins/memory/test_openviking_provider.py","tests/plugins/memory/test_supermemory_provider.py","tests/plugins/test_achievements_plugin.py","tests/plugins/test_disk_cleanup_plugin.py","tests/plugins/test_google_meet_audio.py","tests/plugins/test_google_meet_node.py","tests/plugins/test_google_meet_plugin.py","tests/plugins/test_google_meet_realtime.py","tests/plugins/test_kanban_dashboard_plugin.py","tests/plugins/test_langfuse_plugin.py","tests/plugins/test_retaindb_plugin.py"]},{"name":"tests — run_agent","slug":"tests-run-agent","files":["tests/run_agent/__init__.py","tests/run_agent/conftest.py","tests/run_agent/test_1630_context_overflow_loop.py","tests/run_agent/test_413_compression.py","tests/run_agent/test_860_dedup.py","tests/run_agent/test_agent_guardrails.py","tests/run_agent/test_agent_loop.py","tests/run_agent/test_agent_loop_tool_calling.py","tests/run_agent/test_agent_loop_vllm.py","tests/run_agent/test_anthropic_error_handling.py","tests/run_agent/test_anthropic_prompt_cache_policy.py","tests/run_agent/test_anthropic_third_party_oauth_guard.py","tests/run_agent/test_anthropic_truncation_continuation.py","tests/run_agent/test_api_max_retries_config.py","tests/run_agent/test_async_httpx_del_neuter.py","tests/run_agent/test_background_review.py","tests/run_agent/test_background_review_summary.py","tests/run_agent/test_background_review_toolset_restriction.py","tests/run_agent/test_compress_focus_plugin_fallback.py","tests/run_agent/test_compression_boundary.py","tests/run_agent/test_compression_boundary_hook.py","tests/run_agent/test_compression_feasibility.py","tests/run_agent/test_compression_persistence.py","tests/run_agent/test_compression_trigger_excludes_reasoning.py","tests/run_agent/test_compressor_fallback_update.py","tests/run_agent/test_concurrent_interrupt.py","tests/run_agent/test_context_token_tracking.py","tests/run_agent/test_copilot_native_vision_headers.py","tests/run_agent/test_create_openai_client_kwargs_isolation.py","tests/run_agent/test_create_openai_client_proxy_env.py","tests/run_agent/test_create_openai_client_reuse.py","tests/run_agent/test_deepseek_reasoning_content_echo.py","tests/run_agent/test_deepseek_v4_thinking_live.py","tests/run_agent/test_dict_tool_call_args.py","tests/run_agent/test_exit_cleanup_interrupt.py","tests/run_agent/test_fallback_model.py","tests/run_agent/test_image_shrink_recovery.py","tests/run_agent/test_init_fallback_on_exhausted_pool.py","tests/run_agent/test_interactive_interrupt.py","tests/run_agent/test_interrupt_propagation.py","tests/run_agent/test_invalid_context_length_warning.py","tests/run_agent/test_jsondecodeerror_retryable.py","tests/run_agent/test_long_context_tier_429.py","tests/run_agent/test_memory_provider_init.py","tests/run_agent/test_memory_sync_interrupted.py","tests/run_agent/test_openai_client_lifecycle.py","tests/run_agent/test_percentage_clamp.py","tests/run_agent/test_plugin_context_engine_init.py","tests/run_agent/test_primary_runtime_restore.py","tests/run_agent/test_provider_attribution_headers.py","tests/run_agent/test_provider_fallback.py","tests/run_agent/test_provider_parity.py","tests/run_agent/test_real_interrupt_subagent.py","tests/run_agent/test_redirect_stdout_issue.py","tests/run_agent/test_repair_tool_call_arguments.py","tests/run_agent/test_repair_tool_call_name.py","tests/run_agent/test_review_prompt_class_first.py","tests/run_agent/test_run_agent.py","tests/run_agent/test_run_agent_codex_responses.py","tests/run_agent/test_run_agent_multimodal_prologue.py","tests/run_agent/test_sequential_chats_live.py","tests/run_agent/test_session_meta_filtering.py","tests/run_agent/test_session_reset_fix.py","tests/run_agent/test_steer.py","tests/run_agent/test_stream_interrupt_retry.py","tests/run_agent/test_streaming.py","tests/run_agent/test_streaming_tool_call_repair.py","tests/run_agent/test_strict_api_validation.py","tests/run_agent/test_strip_reasoning_tags_cli.py","tests/run_agent/test_switch_model_context.py","tests/run_agent/test_switch_model_fallback_prune.py","tests/run_agent/test_thinking_only_sanitizer.py","tests/run_agent/test_token_persistence_non_cli.py","tests/run_agent/test_tool_arg_coercion.py","tests/run_agent/test_tool_call_args_sanitizer.py","tests/run_agent/test_tool_call_guardrail_runtime.py","tests/run_agent/test_tool_executor_contextvar_propagation.py","tests/run_agent/test_unicode_ascii_codec.py","tests/run_agent/test_vision_aware_preprocessing.py"]},{"name":"tests — skills","slug":"tests-skills","files":["tests/skills/test_google_oauth_setup.py","tests/skills/test_google_workspace_api.py","tests/skills/test_memento_cards.py","tests/skills/test_openclaw_migration.py","tests/skills/test_openclaw_migration_hardening.py","tests/skills/test_telephony_skill.py","tests/skills/test_youtube_quiz.py"]},{"name":"tests — stress","slug":"tests-stress","files":["tests/stress/README.md","tests/stress/_fake_worker.py","tests/stress/conftest.py","tests/stress/test_atypical_scenarios.py","tests/stress/test_benchmarks.py","tests/stress/test_concurrency.py","tests/stress/test_concurrency_mixed.py","tests/stress/test_concurrency_reclaim_race.py","tests/stress/test_property_fuzzing.py","tests/stress/test_subprocess_e2e.py"]},{"name":"tests — tools","slug":"tests-tools","files":["tests/tools/__init__.py","tests/tools/test_accretion_caps.py","tests/tools/test_ansi_strip.py","tests/tools/test_approval.py","tests/tools/test_approval_heartbeat.py","tests/tools/test_approval_plugin_hooks.py","tests/tools/test_base_environment.py","tests/tools/test_browser_camofox.py","tests/tools/test_browser_camofox_persistence.py","tests/tools/test_browser_camofox_state.py","tests/tools/test_browser_cdp_override.py","tests/tools/test_browser_cdp_tool.py","tests/tools/test_browser_chromium_check.py","tests/tools/test_browser_cleanup.py","tests/tools/test_browser_cloud_fallback.py","tests/tools/test_browser_console.py","tests/tools/test_browser_content_none_guard.py","tests/tools/test_browser_hardening.py","tests/tools/test_browser_homebrew_paths.py","tests/tools/test_browser_hybrid_routing.py","tests/tools/test_browser_orphan_reaper.py","tests/tools/test_browser_secret_exfil.py","tests/tools/test_browser_ssrf_local.py","tests/tools/test_browser_supervisor.py","tests/tools/test_browser_supervisor_healthcheck.py","tests/tools/test_budget_config.py","tests/tools/test_checkpoint_manager.py","tests/tools/test_clarify_tool.py","tests/tools/test_clipboard.py","tests/tools/test_code_execution.py","tests/tools/test_code_execution_modes.py","tests/tools/test_command_guards.py","tests/tools/test_config_null_guard.py","tests/tools/test_credential_files.py","tests/tools/test_credential_pool_env_fallback.py","tests/tools/test_cron_approval_mode.py","tests/tools/test_cron_prompt_injection.py","tests/tools/test_cronjob_tools.py","tests/tools/test_daytona_environment.py","tests/tools/test_debug_helpers.py","tests/tools/test_delegate.py","tests/tools/test_delegate_subagent_timeout_diagnostic.py","tests/tools/test_delegate_toolset_scope.py","tests/tools/test_discord_tool.py","tests/tools/test_docker_environment.py","tests/tools/test_docker_find.py","tests/tools/test_dockerfile_pid1_reaping.py","tests/tools/test_env_passthrough.py","tests/tools/test_feishu_tools.py","tests/tools/test_file_operations.py","tests/tools/test_file_operations_edge_cases.py","tests/tools/test_file_ops_cwd_tracking.py","tests/tools/test_file_read_guards.py","tests/tools/test_file_staleness.py","tests/tools/test_file_state_registry.py","tests/tools/test_file_sync.py","tests/tools/test_file_sync_back.py","tests/tools/test_file_sync_perf.py","tests/tools/test_file_tools.py","tests/tools/test_file_tools_container_config.py","tests/tools/test_file_tools_live.py","tests/tools/test_file_write_safety.py","tests/tools/test_force_dangerous_override.py","tests/tools/test_fuzzy_match.py","tests/tools/test_hardline_blocklist.py","tests/tools/test_hidden_dir_filter.py","tests/tools/test_homeassistant_tool.py","tests/tools/test_image_generation.py","tests/tools/test_image_generation_env.py","tests/tools/test_image_generation_plugin_dispatch.py","tests/tools/test_init_session_cwd_respect.py","tests/tools/test_interrupt.py","tests/tools/test_kanban_tools.py","tests/tools/test_llm_content_none_guard.py","tests/tools/test_local_background_child_hang.py","tests/tools/test_local_env_blocklist.py","tests/tools/test_local_interrupt_cleanup.py","tests/tools/test_local_shell_init.py","tests/tools/test_local_tempdir.py","tests/tools/test_managed_browserbase_and_modal.py","tests/tools/test_managed_media_gateways.py","tests/tools/test_managed_modal_environment.py","tests/tools/test_managed_server_tool_support.py","tests/tools/test_managed_tool_gateway.py","tests/tools/test_mcp_circuit_breaker.py","tests/tools/test_mcp_dynamic_discovery.py","tests/tools/test_mcp_oauth.py","tests/tools/test_mcp_oauth_bidirectional.py","tests/tools/test_mcp_oauth_cold_load_expiry.py","tests/tools/test_mcp_oauth_integration.py","tests/tools/test_mcp_oauth_manager.py","tests/tools/test_mcp_probe.py","tests/tools/test_mcp_reconnect_signal.py","tests/tools/test_mcp_stability.py","tests/tools/test_mcp_structured_content.py","tests/tools/test_mcp_tool.py","tests/tools/test_mcp_tool_401_handling.py","tests/tools/test_mcp_tool_issue_948.py","tests/tools/test_mcp_tool_session_expired.py","tests/tools/test_memory_tool.py","tests/tools/test_memory_tool_import_fallback.py","tests/tools/test_mixture_of_agents_tool.py","tests/tools/test_modal_bulk_upload.py","tests/tools/test_modal_sandbox_fixes.py","tests/tools/test_modal_snapshot_isolation.py","tests/tools/test_notify_on_complete.py","tests/tools/test_osv_check.py","tests/tools/test_parse_env_var.py","tests/tools/test_patch_parser.py","tests/tools/test_process_registry.py","tests/tools/test_read_loop_detection.py","tests/tools/test_registry.py","tests/tools/test_resolve_path.py","tests/tools/test_rl_training_tool.py","tests/tools/test_schema_sanitizer.py","tests/tools/test_search_hidden_dirs.py","tests/tools/test_send_message_missing_platforms.py","tests/tools/test_send_message_tool.py","tests/tools/test_session_search.py","tests/tools/test_shared_container_task_id.py","tests/tools/test_signal_media.py","tests/tools/test_singularity_preflight.py","tests/tools/test_skill_env_passthrough.py","tests/tools/test_skill_improvements.py","tests/tools/test_skill_manager_tool.py","tests/tools/test_skill_size_limits.py","tests/tools/test_skill_usage.py","tests/tools/test_skill_view_path_check.py","tests/tools/test_skill_view_traversal.py","tests/tools/test_skills_guard.py","tests/tools/test_skills_hub.py","tests/tools/test_skills_hub_clawhub.py","tests/tools/test_skills_sync.py","tests/tools/test_skills_tool.py","tests/tools/test_slash_confirm.py","tests/tools/test_spotify_client.py","tests/tools/test_ssh_bulk_upload.py","tests/tools/test_ssh_environment.py","tests/tools/test_symlink_prefix_confusion.py","tests/tools/test_sync_back_backends.py","tests/tools/test_terminal_compound_background.py","tests/tools/test_terminal_config_env_sync.py","tests/tools/test_terminal_exit_semantics.py","tests/tools/test_terminal_foreground_timeout_cap.py","tests/tools/test_terminal_none_command_guard.py","tests/tools/test_terminal_output_transform_hook.py","tests/tools/test_terminal_requirements.py","tests/tools/test_terminal_timeout_output.py","tests/tools/test_terminal_tool.py","tests/tools/test_terminal_tool_pty_fallback.py","tests/tools/test_terminal_tool_requirements.py","tests/tools/test_threaded_process_handle.py","tests/tools/test_tirith_security.py","tests/tools/test_todo_tool.py","tests/tools/test_tool_backend_helpers.py","tests/tools/test_tool_call_parsers.py","tests/tools/test_tool_output_limits.py","tests/tools/test_tool_result_storage.py","tests/tools/test_transcription.py","tests/tools/test_transcription_dotenv_fallback.py","tests/tools/test_transcription_tools.py","tests/tools/test_tts_command_providers.py","tests/tools/test_tts_dotenv_fallback.py","tests/tools/test_tts_gemini.py","tests/tools/test_tts_kittentts.py","tests/tools/test_tts_max_text_length.py","tests/tools/test_tts_mistral.py","tests/tools/test_tts_piper.py","tests/tools/test_tts_speed.py","tests/tools/test_url_safety.py","tests/tools/test_vercel_sandbox_environment.py","tests/tools/test_vision_tools.py","tests/tools/test_voice_cli_integration.py","tests/tools/test_voice_mode.py","tests/tools/test_watch_patterns.py","tests/tools/test_web_tools_config.py","tests/tools/test_web_tools_tavily.py","tests/tools/test_website_policy.py","tests/tools/test_windows_compat.py","tests/tools/test_write_deny.py","tests/tools/test_yolo_mode.py","tests/tools/test_zombie_process_cleanup.py"]},{"name":"tests — tui_gateway","slug":"tests-tui-gateway","files":["tests/tui_gateway/__init__.py","tests/tui_gateway/test_make_agent_provider.py","tests/tui_gateway/test_protocol.py","tests/tui_gateway/test_render.py","tests/tui_gateway/test_review_summary_callback.py"]},{"name":"tests — website","slug":"tests-website","files":["tests/website/__init__.py","tests/website/test_generate_skill_docs.py"]}]},{"name":"tools","slug":"tools","files":[],"children":[{"name":"tools — tools","slug":"tools-tools","files":["tools/__init__.py","tools/ansi_strip.py","tools/approval.py","tools/binary_extensions.py","tools/browser_camofox.py","tools/browser_camofox_state.py","tools/browser_cdp_tool.py","tools/browser_dialog_tool.py","tools/browser_supervisor.py","tools/browser_tool.py","tools/budget_config.py","tools/checkpoint_manager.py","tools/clarify_tool.py","tools/code_execution_tool.py","tools/credential_files.py","tools/cronjob_tools.py","tools/debug_helpers.py","tools/delegate_tool.py","tools/discord_tool.py","tools/env_passthrough.py","tools/feishu_doc_tool.py","tools/feishu_drive_tool.py","tools/file_operations.py","tools/file_state.py","tools/file_tools.py","tools/fuzzy_match.py","tools/homeassistant_tool.py","tools/image_generation_tool.py","tools/interrupt.py","tools/kanban_tools.py","tools/managed_tool_gateway.py","tools/mcp_oauth.py","tools/mcp_oauth_manager.py","tools/mcp_tool.py","tools/memory_tool.py","tools/mixture_of_agents_tool.py","tools/neutts_synth.py","tools/openrouter_client.py","tools/osv_check.py","tools/patch_parser.py","tools/path_security.py","tools/process_registry.py","tools/registry.py","tools/rl_training_tool.py","tools/schema_sanitizer.py","tools/send_message_tool.py","tools/session_search_tool.py","tools/skill_manager_tool.py","tools/skill_usage.py","tools/skills_guard.py","tools/skills_hub.py","tools/skills_sync.py","tools/skills_tool.py","tools/slash_confirm.py","tools/terminal_tool.py","tools/tirith_security.py","tools/todo_tool.py","tools/tool_backend_helpers.py","tools/tool_output_limits.py","tools/tool_result_storage.py","tools/transcription_tools.py","tools/tts_tool.py","tools/url_safety.py","tools/vision_tools.py","tools/voice_mode.py","tools/web_tools.py","tools/website_policy.py","tools/xai_http.py","tools/yuanbao_tools.py"]},{"name":"tools — browser_providers","slug":"tools-browser-providers","files":["tools/browser_providers/__init__.py","tools/browser_providers/base.py","tools/browser_providers/browser_use.py","tools/browser_providers/browserbase.py","tools/browser_providers/firecrawl.py"]},{"name":"tools — environments","slug":"tools-environments","files":["tools/environments/__init__.py","tools/environments/base.py","tools/environments/daytona.py","tools/environments/docker.py","tools/environments/file_sync.py","tools/environments/local.py","tools/environments/managed_modal.py","tools/environments/modal.py","tools/environments/modal_utils.py","tools/environments/singularity.py","tools/environments/ssh.py","tools/environments/vercel_sandbox.py"]},{"name":"tools — neutts_samples","slug":"tools-neutts-samples","files":["tools/neutts_samples/jo.txt"]}]},{"name":"tui_gateway","slug":"tui-gateway","files":["tui_gateway/__init__.py","tui_gateway/entry.py","tui_gateway/event_publisher.py","tui_gateway/render.py","tui_gateway/server.py","tui_gateway/slash_worker.py","tui_gateway/transport.py","tui_gateway/ws.py"]},{"name":"ui-tui","slug":"ui-tui","files":[],"children":[{"name":"ui-tui — ui-tui","slug":"ui-tui-ui-tui","files":["ui-tui/README.md","ui-tui/babel.compiler.config.cjs","ui-tui/eslint.config.mjs","ui-tui/package.json","ui-tui/tsconfig.build.json","ui-tui/tsconfig.json","ui-tui/vitest.config.ts"]},{"name":"ui-tui — packages","slug":"ui-tui-packages","files":["ui-tui/packages/hermes-ink/index.js","ui-tui/packages/hermes-ink/package.json","ui-tui/packages/hermes-ink/src/bootstrap/state.ts","ui-tui/packages/hermes-ink/src/entry-exports.ts","ui-tui/packages/hermes-ink/src/hooks/use-stderr.ts","ui-tui/packages/hermes-ink/src/hooks/use-stdout.ts","ui-tui/packages/hermes-ink/src/ink/Ansi.tsx","ui-tui/packages/hermes-ink/src/ink/bidi.ts","ui-tui/packages/hermes-ink/src/ink/cache-eviction.ts","ui-tui/packages/hermes-ink/src/ink/clearTerminal.ts","ui-tui/packages/hermes-ink/src/ink/colorize.test.ts","ui-tui/packages/hermes-ink/src/ink/colorize.ts","ui-tui/packages/hermes-ink/src/ink/components/AlternateScreen.tsx","ui-tui/packages/hermes-ink/src/ink/components/App.tsx","ui-tui/packages/hermes-ink/src/ink/components/AppContext.ts","ui-tui/packages/hermes-ink/src/ink/components/Box.tsx","ui-tui/packages/hermes-ink/src/ink/components/Button.tsx","ui-tui/packages/hermes-ink/src/ink/components/ClockContext.tsx","ui-tui/packages/hermes-ink/src/ink/components/CursorDeclarationContext.ts","ui-tui/packages/hermes-ink/src/ink/components/ErrorOverview.tsx","ui-tui/packages/hermes-ink/src/ink/components/Link.tsx","ui-tui/packages/hermes-ink/src/ink/components/Newline.tsx","ui-tui/packages/hermes-ink/src/ink/components/NoSelect.tsx","ui-tui/packages/hermes-ink/src/ink/components/RawAnsi.tsx","ui-tui/packages/hermes-ink/src/ink/components/ScrollBox.tsx","ui-tui/packages/hermes-ink/src/ink/components/Spacer.tsx","ui-tui/packages/hermes-ink/src/ink/components/StdinContext.ts","ui-tui/packages/hermes-ink/src/ink/components/TerminalFocusContext.tsx","ui-tui/packages/hermes-ink/src/ink/components/TerminalSizeContext.tsx","ui-tui/packages/hermes-ink/src/ink/components/Text.test.ts","ui-tui/packages/hermes-ink/src/ink/components/Text.tsx","ui-tui/packages/hermes-ink/src/ink/constants.ts","ui-tui/packages/hermes-ink/src/ink/cursor.ts","ui-tui/packages/hermes-ink/src/ink/devtools.ts","ui-tui/packages/hermes-ink/src/ink/dom.ts","ui-tui/packages/hermes-ink/src/ink/events/click-event.ts","ui-tui/packages/hermes-ink/src/ink/events/cmd-shortcuts.test.ts","ui-tui/packages/hermes-ink/src/ink/events/dispatcher.ts","ui-tui/packages/hermes-ink/src/ink/events/emitter.ts","ui-tui/packages/hermes-ink/src/ink/events/event-handlers.ts","ui-tui/packages/hermes-ink/src/ink/events/event.ts","ui-tui/packages/hermes-ink/src/ink/events/focus-event.ts","ui-tui/packages/hermes-ink/src/ink/events/input-event.ts","ui-tui/packages/hermes-ink/src/ink/events/keyboard-event.ts","ui-tui/packages/hermes-ink/src/ink/events/mouse-event.ts","ui-tui/packages/hermes-ink/src/ink/events/paste-event.ts","ui-tui/packages/hermes-ink/src/ink/events/resize-event.ts","ui-tui/packages/hermes-ink/src/ink/events/terminal-event.ts","ui-tui/packages/hermes-ink/src/ink/events/terminal-focus-event.ts","ui-tui/packages/hermes-ink/src/ink/focus.ts","ui-tui/packages/hermes-ink/src/ink/frame.ts","ui-tui/packages/hermes-ink/src/ink/get-max-width.ts","ui-tui/packages/hermes-ink/src/ink/hit-test.ts","ui-tui/packages/hermes-ink/src/ink/hooks/use-animation-frame.ts","ui-tui/packages/hermes-ink/src/ink/hooks/use-app.ts","ui-tui/packages/hermes-ink/src/ink/hooks/use-declared-cursor.ts","ui-tui/packages/hermes-ink/src/ink/hooks/use-external-process.ts","ui-tui/packages/hermes-ink/src/ink/hooks/use-input.ts","ui-tui/packages/hermes-ink/src/ink/hooks/use-interval.ts","ui-tui/packages/hermes-ink/src/ink/hooks/use-search-highlight.ts","ui-tui/packages/hermes-ink/src/ink/hooks/use-selection.ts","ui-tui/packages/hermes-ink/src/ink/hooks/use-stdin.ts","ui-tui/packages/hermes-ink/src/ink/hooks/use-tab-status.ts","ui-tui/packages/hermes-ink/src/ink/hooks/use-terminal-focus.ts","ui-tui/packages/hermes-ink/src/ink/hooks/use-terminal-title.ts","ui-tui/packages/hermes-ink/src/ink/hooks/use-terminal-viewport.ts","ui-tui/packages/hermes-ink/src/ink/ink.tsx","ui-tui/packages/hermes-ink/src/ink/instances.ts","ui-tui/packages/hermes-ink/src/ink/layout/engine.ts","ui-tui/packages/hermes-ink/src/ink/layout/geometry.ts","ui-tui/packages/hermes-ink/src/ink/layout/node.ts","ui-tui/packages/hermes-ink/src/ink/layout/yoga.ts","ui-tui/packages/hermes-ink/src/ink/line-width-cache.ts","ui-tui/packages/hermes-ink/src/ink/log-update.test.ts","ui-tui/packages/hermes-ink/src/ink/log-update.ts","ui-tui/packages/hermes-ink/src/ink/lru.ts","ui-tui/packages/hermes-ink/src/ink/measure-element.ts","ui-tui/packages/hermes-ink/src/ink/measure-text.ts","ui-tui/packages/hermes-ink/src/ink/node-cache.ts","ui-tui/packages/hermes-ink/src/ink/optimizer.ts","ui-tui/packages/hermes-ink/src/ink/output.ts","ui-tui/packages/hermes-ink/src/ink/parse-keypress.test.ts","ui-tui/packages/hermes-ink/src/ink/parse-keypress.ts","ui-tui/packages/hermes-ink/src/ink/reconciler.ts","ui-tui/packages/hermes-ink/src/ink/render-border.ts","ui-tui/packages/hermes-ink/src/ink/render-node-to-output.ts","ui-tui/packages/hermes-ink/src/ink/render-to-screen.ts","ui-tui/packages/hermes-ink/src/ink/renderer.ts","ui-tui/packages/hermes-ink/src/ink/root.ts","ui-tui/packages/hermes-ink/src/ink/screen.ts","ui-tui/packages/hermes-ink/src/ink/searchHighlight.ts","ui-tui/packages/hermes-ink/src/ink/selection.test.ts","ui-tui/packages/hermes-ink/src/ink/selection.ts","ui-tui/packages/hermes-ink/src/ink/squash-text-nodes.ts","ui-tui/packages/hermes-ink/src/ink/stringWidth.ts","ui-tui/packages/hermes-ink/src/ink/styles.ts","ui-tui/packages/hermes-ink/src/ink/supports-hyperlinks.ts","ui-tui/packages/hermes-ink/src/ink/tabstops.ts","ui-tui/packages/hermes-ink/src/ink/terminal-focus-state.ts","ui-tui/packages/hermes-ink/src/ink/terminal-querier.ts","ui-tui/packages/hermes-ink/src/ink/terminal.ts","ui-tui/packages/hermes-ink/src/ink/termio.ts","ui-tui/packages/hermes-ink/src/ink/termio/ansi.ts","ui-tui/packages/hermes-ink/src/ink/termio/csi.ts","ui-tui/packages/hermes-ink/src/ink/termio/dec.ts","ui-tui/packages/hermes-ink/src/ink/termio/esc.ts","ui-tui/packages/hermes-ink/src/ink/termio/osc.test.ts","ui-tui/packages/hermes-ink/src/ink/termio/osc.ts","ui-tui/packages/hermes-ink/src/ink/termio/parser.ts","ui-tui/packages/hermes-ink/src/ink/termio/sgr.ts","ui-tui/packages/hermes-ink/src/ink/termio/tokenize.ts","ui-tui/packages/hermes-ink/src/ink/termio/types.ts","ui-tui/packages/hermes-ink/src/ink/useTerminalNotification.ts","ui-tui/packages/hermes-ink/src/ink/warn.ts","ui-tui/packages/hermes-ink/src/ink/widest-line.ts","ui-tui/packages/hermes-ink/src/ink/wrap-text.ts","ui-tui/packages/hermes-ink/src/ink/wrapAnsi.ts","ui-tui/packages/hermes-ink/src/native-ts/yoga-layout/enums.ts","ui-tui/packages/hermes-ink/src/native-ts/yoga-layout/index.ts","ui-tui/packages/hermes-ink/src/utils/debug.ts","ui-tui/packages/hermes-ink/src/utils/earlyInput.ts","ui-tui/packages/hermes-ink/src/utils/env.ts","ui-tui/packages/hermes-ink/src/utils/envUtils.ts","ui-tui/packages/hermes-ink/src/utils/execFileNoThrow.ts","ui-tui/packages/hermes-ink/src/utils/fullscreen.ts","ui-tui/packages/hermes-ink/src/utils/intl.ts","ui-tui/packages/hermes-ink/src/utils/log.ts","ui-tui/packages/hermes-ink/src/utils/semver.ts","ui-tui/packages/hermes-ink/src/utils/sliceAnsi.ts","ui-tui/packages/hermes-ink/text-input.js"]},{"name":"ui-tui — scripts","slug":"ui-tui-scripts","files":["ui-tui/scripts/profile-tui.mjs"]},{"name":"ui-tui — src","slug":"ui-tui-src","files":["ui-tui/src/app.tsx","ui-tui/src/app/createGatewayEventHandler.ts","ui-tui/src/app/createSlashHandler.ts","ui-tui/src/app/delegationStore.ts","ui-tui/src/app/gatewayContext.tsx","ui-tui/src/app/inputSelectionStore.ts","ui-tui/src/app/interfaces.ts","ui-tui/src/app/overlayStore.ts","ui-tui/src/app/scroll.ts","ui-tui/src/app/setupHandoff.ts","ui-tui/src/app/slash/commands/core.ts","ui-tui/src/app/slash/commands/debug.ts","ui-tui/src/app/slash/commands/ops.ts","ui-tui/src/app/slash/commands/session.ts","ui-tui/src/app/slash/commands/setup.ts","ui-tui/src/app/slash/registry.ts","ui-tui/src/app/slash/types.ts","ui-tui/src/app/spawnHistoryStore.ts","ui-tui/src/app/turnController.ts","ui-tui/src/app/turnStore.ts","ui-tui/src/app/uiStore.ts","ui-tui/src/app/useComposerState.ts","ui-tui/src/app/useConfigSync.ts","ui-tui/src/app/useInputHandlers.ts","ui-tui/src/app/useLongRunToolCharms.ts","ui-tui/src/app/useMainApp.ts","ui-tui/src/app/useSessionLifecycle.ts","ui-tui/src/app/useSubmission.ts","ui-tui/src/banner.ts","ui-tui/src/components/agentsOverlay.tsx","ui-tui/src/components/appChrome.tsx","ui-tui/src/components/appLayout.tsx","ui-tui/src/components/appOverlays.tsx","ui-tui/src/components/branding.tsx","ui-tui/src/components/fpsOverlay.tsx","ui-tui/src/components/helpHint.tsx","ui-tui/src/components/markdown.tsx","ui-tui/src/components/maskedPrompt.tsx","ui-tui/src/components/messageLine.tsx","ui-tui/src/components/modelPicker.tsx","ui-tui/src/components/overlayControls.tsx","ui-tui/src/components/prompts.tsx","ui-tui/src/components/queuedMessages.tsx","ui-tui/src/components/sessionPicker.tsx","ui-tui/src/components/skillsHub.tsx","ui-tui/src/components/streamingAssistant.tsx","ui-tui/src/components/streamingMarkdown.tsx","ui-tui/src/components/textInput.tsx","ui-tui/src/components/themed.tsx","ui-tui/src/components/thinking.tsx","ui-tui/src/components/todoPanel.tsx","ui-tui/src/config/env.ts","ui-tui/src/config/limits.ts","ui-tui/src/config/timing.ts","ui-tui/src/content/charms.ts","ui-tui/src/content/faces.ts","ui-tui/src/content/fortunes.ts","ui-tui/src/content/hotkeys.ts","ui-tui/src/content/placeholders.ts","ui-tui/src/content/setup.ts","ui-tui/src/content/verbs.ts","ui-tui/src/domain/details.ts","ui-tui/src/domain/messages.ts","ui-tui/src/domain/paths.ts","ui-tui/src/domain/providers.ts","ui-tui/src/domain/roles.ts","ui-tui/src/domain/slash.ts","ui-tui/src/domain/usage.ts","ui-tui/src/domain/viewport.ts","ui-tui/src/entry.tsx","ui-tui/src/gatewayClient.ts","ui-tui/src/gatewayTypes.ts","ui-tui/src/hooks/useCompletion.ts","ui-tui/src/hooks/useGitBranch.ts","ui-tui/src/hooks/useInputHistory.ts","ui-tui/src/hooks/useQueue.ts","ui-tui/src/hooks/useVirtualHistory.ts","ui-tui/src/lib/circularBuffer.ts","ui-tui/src/lib/clipboard.ts","ui-tui/src/lib/editor.test.ts","ui-tui/src/lib/editor.ts","ui-tui/src/lib/emoji.ts","ui-tui/src/lib/externalCli.ts","ui-tui/src/lib/forceTruecolor.ts","ui-tui/src/lib/fpsStore.ts","ui-tui/src/lib/gracefulExit.ts","ui-tui/src/lib/history.ts","ui-tui/src/lib/inputMetrics.ts","ui-tui/src/lib/liveProgress.test.ts","ui-tui/src/lib/liveProgress.ts","ui-tui/src/lib/mathUnicode.ts","ui-tui/src/lib/memory.ts","ui-tui/src/lib/memoryMonitor.ts","ui-tui/src/lib/messages.test.ts","ui-tui/src/lib/messages.ts","ui-tui/src/lib/osc52.ts","ui-tui/src/lib/perfPane.tsx","ui-tui/src/lib/platform.ts","ui-tui/src/lib/reasoning.ts","ui-tui/src/lib/rpc.ts","ui-tui/src/lib/subagentTree.ts","ui-tui/src/lib/syntax.ts","ui-tui/src/lib/terminalModes.ts","ui-tui/src/lib/terminalParity.ts","ui-tui/src/lib/terminalSetup.ts","ui-tui/src/lib/text.test.ts","ui-tui/src/lib/text.ts","ui-tui/src/lib/todo.test.ts","ui-tui/src/lib/todo.ts","ui-tui/src/lib/viewportStore.ts","ui-tui/src/lib/virtualHeights.ts","ui-tui/src/lib/wheelAccel.ts","ui-tui/src/protocol/interpolation.ts","ui-tui/src/protocol/paste.ts","ui-tui/src/theme.ts","ui-tui/src/types.ts"]}]},{"name":"web","slug":"web","files":[],"children":[{"name":"web — web","slug":"web-web","files":["web/README.md","web/eslint.config.js","web/index.html","web/package.json","web/tsconfig.app.json","web/tsconfig.json","web/tsconfig.node.json","web/vite.config.ts"]},{"name":"web — src","slug":"web-src","files":["web/src/App.tsx","web/src/components/AutoField.tsx","web/src/components/Backdrop.tsx","web/src/components/ChatSidebar.tsx","web/src/components/DeleteConfirmDialog.tsx","web/src/components/LanguageSwitcher.tsx","web/src/components/Markdown.tsx","web/src/components/ModelInfoCard.tsx","web/src/components/ModelPickerDialog.tsx","web/src/components/NouiTypography.tsx","web/src/components/OAuthLoginModal.tsx","web/src/components/OAuthProvidersCard.tsx","web/src/components/PlatformsCard.tsx","web/src/components/SidebarFooter.tsx","web/src/components/SidebarStatusStrip.tsx","web/src/components/SlashPopover.tsx","web/src/components/ThemeSwitcher.tsx","web/src/components/Toast.tsx","web/src/components/ToolCall.tsx","web/src/components/ui/card.tsx","web/src/components/ui/confirm-dialog.tsx","web/src/components/ui/input.tsx","web/src/components/ui/label.tsx","web/src/components/ui/separator.tsx","web/src/contexts/PageHeaderProvider.tsx","web/src/contexts/SystemActions.tsx","web/src/contexts/page-header-context.ts","web/src/contexts/system-actions-context.ts","web/src/contexts/usePageHeader.ts","web/src/contexts/useSystemActions.ts","web/src/hooks/useConfirmDelete.ts","web/src/hooks/useSidebarStatus.ts","web/src/hooks/useToast.ts","web/src/i18n/context.tsx","web/src/i18n/en.ts","web/src/i18n/index.ts","web/src/i18n/types.ts","web/src/i18n/zh.ts","web/src/index.css","web/src/lib/api.ts","web/src/lib/dashboard-flags.ts","web/src/lib/format.ts","web/src/lib/gatewayClient.ts","web/src/lib/nested.ts","web/src/lib/resolve-page-title.ts","web/src/lib/slashExec.ts","web/src/lib/utils.ts","web/src/main.tsx","web/src/pages/AnalyticsPage.tsx","web/src/pages/ChatPage.tsx","web/src/pages/ConfigPage.tsx","web/src/pages/CronPage.tsx","web/src/pages/DocsPage.tsx","web/src/pages/EnvPage.tsx","web/src/pages/LogsPage.tsx","web/src/pages/ModelsPage.tsx","web/src/pages/PluginsPage.tsx","web/src/pages/ProfilesPage.tsx","web/src/pages/SessionsPage.tsx","web/src/pages/SkillsPage.tsx","web/src/plugins/PluginPage.tsx","web/src/plugins/index.ts","web/src/plugins/registry.ts","web/src/plugins/slots.ts","web/src/plugins/types.ts","web/src/plugins/usePlugins.ts","web/src/themes/context.tsx","web/src/themes/index.ts","web/src/themes/presets.ts","web/src/themes/types.ts"]}]},{"name":"website","slug":"website","files":[],"children":[{"name":"website — website","slug":"website-website","files":["website/README.md","website/docusaurus.config.ts","website/package.json","website/sidebars.ts","website/tsconfig.json"]},{"name":"website — docs","slug":"website-docs","files":["website/docs/developer-guide/_category_.json","website/docs/developer-guide/acp-internals.md","website/docs/developer-guide/adding-platform-adapters.md","website/docs/developer-guide/adding-providers.md","website/docs/developer-guide/adding-tools.md","website/docs/developer-guide/agent-loop.md","website/docs/developer-guide/architecture.md","website/docs/developer-guide/browser-supervisor.md","website/docs/developer-guide/context-compression-and-caching.md","website/docs/developer-guide/context-engine-plugin.md","website/docs/developer-guide/contributing.md","website/docs/developer-guide/creating-skills.md","website/docs/developer-guide/cron-internals.md","website/docs/developer-guide/environments.md","website/docs/developer-guide/extending-the-cli.md","website/docs/developer-guide/gateway-internals.md","website/docs/developer-guide/memory-provider-plugin.md","website/docs/developer-guide/prompt-assembly.md","website/docs/developer-guide/provider-runtime.md","website/docs/developer-guide/session-storage.md","website/docs/developer-guide/tools-runtime.md","website/docs/developer-guide/trajectory-format.md","website/docs/getting-started/_category_.json","website/docs/getting-started/installation.md","website/docs/getting-started/learning-path.md","website/docs/getting-started/nix-setup.md","website/docs/getting-started/quickstart.md","website/docs/getting-started/termux.md","website/docs/getting-started/updating.md","website/docs/guides/_category_.json","website/docs/guides/automate-with-cron.md","website/docs/guides/automation-templates.md","website/docs/guides/aws-bedrock.md","website/docs/guides/azure-foundry.md","website/docs/guides/build-a-hermes-plugin.md","website/docs/guides/cron-troubleshooting.md","website/docs/guides/daily-briefing-bot.md","website/docs/guides/delegation-patterns.md","website/docs/guides/github-pr-review-agent.md","website/docs/guides/local-llm-on-mac.md","website/docs/guides/migrate-from-openclaw.md","website/docs/guides/minimax-oauth.md","website/docs/guides/python-library.md","website/docs/guides/team-telegram-assistant.md","website/docs/guides/tips.md","website/docs/guides/use-mcp-with-hermes.md","website/docs/guides/use-soul-with-hermes.md","website/docs/guides/use-voice-mode-with-hermes.md","website/docs/guides/webhook-github-pr-review.md","website/docs/guides/work-with-skills.md","website/docs/index.md","website/docs/integrations/index.md","website/docs/integrations/providers.md","website/docs/reference/_category_.json","website/docs/reference/cli-commands.md","website/docs/reference/environment-variables.md","website/docs/reference/faq.md","website/docs/reference/mcp-config-reference.md","website/docs/reference/model-catalog.md","website/docs/reference/optional-skills-catalog.md","website/docs/reference/profile-commands.md","website/docs/reference/skills-catalog.md","website/docs/reference/slash-commands.md","website/docs/reference/tools-reference.md","website/docs/reference/toolsets-reference.md","website/docs/user-guide/_category_.json","website/docs/user-guide/checkpoints-and-rollback.md","website/docs/user-guide/cli.md","website/docs/user-guide/configuration.md","website/docs/user-guide/configuring-models.md","website/docs/user-guide/docker.md","website/docs/user-guide/features/_category_.json","website/docs/user-guide/features/acp.md","website/docs/user-guide/features/api-server.md","website/docs/user-guide/features/batch-processing.md","website/docs/user-guide/features/browser.md","website/docs/user-guide/features/built-in-plugins.md","website/docs/user-guide/features/code-execution.md","website/docs/user-guide/features/context-files.md","website/docs/user-guide/features/context-references.md","website/docs/user-guide/features/credential-pools.md","website/docs/user-guide/features/cron.md","website/docs/user-guide/features/curator.md","website/docs/user-guide/features/delegation.md","website/docs/user-guide/features/extending-the-dashboard.md","website/docs/user-guide/features/fallback-providers.md","website/docs/user-guide/features/goals.md","website/docs/user-guide/features/honcho.md","website/docs/user-guide/features/hooks.md","website/docs/user-guide/features/image-generation.md","website/docs/user-guide/features/kanban-tutorial.md","website/docs/user-guide/features/kanban.md","website/docs/user-guide/features/mcp.md","website/docs/user-guide/features/memory-providers.md","website/docs/user-guide/features/memory.md","website/docs/user-guide/features/overview.md","website/docs/user-guide/features/personality.md","website/docs/user-guide/features/plugins.md","website/docs/user-guide/features/provider-routing.md","website/docs/user-guide/features/rl-training.md","website/docs/user-guide/features/skills.md","website/docs/user-guide/features/skins.md","website/docs/user-guide/features/spotify.md","website/docs/user-guide/features/tool-gateway.md","website/docs/user-guide/features/tools.md","website/docs/user-guide/features/tts.md","website/docs/user-guide/features/vision.md","website/docs/user-guide/features/voice-mode.md","website/docs/user-guide/features/web-dashboard.md","website/docs/user-guide/git-worktrees.md","website/docs/user-guide/messaging/_category_.json","website/docs/user-guide/messaging/bluebubbles.md","website/docs/user-guide/messaging/dingtalk.md","website/docs/user-guide/messaging/discord.md","website/docs/user-guide/messaging/email.md","website/docs/user-guide/messaging/feishu.md","website/docs/user-guide/messaging/homeassistant.md","website/docs/user-guide/messaging/index.md","website/docs/user-guide/messaging/matrix.md","website/docs/user-guide/messaging/mattermost.md","website/docs/user-guide/messaging/open-webui.md","website/docs/user-guide/messaging/qqbot.md","website/docs/user-guide/messaging/signal.md","website/docs/user-guide/messaging/slack.md","website/docs/user-guide/messaging/sms.md","website/docs/user-guide/messaging/teams.md","website/docs/user-guide/messaging/telegram.md","website/docs/user-guide/messaging/webhooks.md","website/docs/user-guide/messaging/wecom-callback.md","website/docs/user-guide/messaging/wecom.md","website/docs/user-guide/messaging/weixin.md","website/docs/user-guide/messaging/whatsapp.md","website/docs/user-guide/messaging/yuanbao.md","website/docs/user-guide/profiles.md","website/docs/user-guide/security.md","website/docs/user-guide/sessions.md","website/docs/user-guide/skills/bundled/apple/apple-apple-notes.md","website/docs/user-guide/skills/bundled/apple/apple-apple-reminders.md","website/docs/user-guide/skills/bundled/apple/apple-findmy.md","website/docs/user-guide/skills/bundled/apple/apple-imessage.md","website/docs/user-guide/skills/bundled/autonomous-ai-agents/autonomous-ai-agents-claude-code.md","website/docs/user-guide/skills/bundled/autonomous-ai-agents/autonomous-ai-agents-codex.md","website/docs/user-guide/skills/bundled/autonomous-ai-agents/autonomous-ai-agents-hermes-agent.md","website/docs/user-guide/skills/bundled/autonomous-ai-agents/autonomous-ai-agents-opencode.md","website/docs/user-guide/skills/bundled/creative/creative-architecture-diagram.md","website/docs/user-guide/skills/bundled/creative/creative-ascii-art.md","website/docs/user-guide/skills/bundled/creative/creative-ascii-video.md","website/docs/user-guide/skills/bundled/creative/creative-baoyu-comic.md","website/docs/user-guide/skills/bundled/creative/creative-baoyu-infographic.md","website/docs/user-guide/skills/bundled/creative/creative-claude-design.md","website/docs/user-guide/skills/bundled/creative/creative-comfyui.md","website/docs/user-guide/skills/bundled/creative/creative-creative-ideation.md","website/docs/user-guide/skills/bundled/creative/creative-design-md.md","website/docs/user-guide/skills/bundled/creative/creative-excalidraw.md","website/docs/user-guide/skills/bundled/creative/creative-humanizer.md","website/docs/user-guide/skills/bundled/creative/creative-manim-video.md","website/docs/user-guide/skills/bundled/creative/creative-p5js.md","website/docs/user-guide/skills/bundled/creative/creative-pixel-art.md","website/docs/user-guide/skills/bundled/creative/creative-popular-web-designs.md","website/docs/user-guide/skills/bundled/creative/creative-pretext.md","website/docs/user-guide/skills/bundled/creative/creative-sketch.md","website/docs/user-guide/skills/bundled/creative/creative-songwriting-and-ai-music.md","website/docs/user-guide/skills/bundled/creative/creative-touchdesigner-mcp.md","website/docs/user-guide/skills/bundled/data-science/data-science-jupyter-live-kernel.md","website/docs/user-guide/skills/bundled/devops/devops-kanban-orchestrator.md","website/docs/user-guide/skills/bundled/devops/devops-kanban-worker.md","website/docs/user-guide/skills/bundled/devops/devops-webhook-subscriptions.md","website/docs/user-guide/skills/bundled/dogfood/dogfood-dogfood.md","website/docs/user-guide/skills/bundled/email/email-himalaya.md","website/docs/user-guide/skills/bundled/gaming/gaming-minecraft-modpack-server.md","website/docs/user-guide/skills/bundled/gaming/gaming-pokemon-player.md","website/docs/user-guide/skills/bundled/github/github-codebase-inspection.md","website/docs/user-guide/skills/bundled/github/github-github-auth.md","website/docs/user-guide/skills/bundled/github/github-github-code-review.md","website/docs/user-guide/skills/bundled/github/github-github-issues.md","website/docs/user-guide/skills/bundled/github/github-github-pr-workflow.md","website/docs/user-guide/skills/bundled/github/github-github-repo-management.md","website/docs/user-guide/skills/bundled/mcp/mcp-native-mcp.md","website/docs/user-guide/skills/bundled/media/media-gif-search.md","website/docs/user-guide/skills/bundled/media/media-heartmula.md","website/docs/user-guide/skills/bundled/media/media-songsee.md","website/docs/user-guide/skills/bundled/media/media-spotify.md","website/docs/user-guide/skills/bundled/media/media-youtube-content.md","website/docs/user-guide/skills/bundled/mlops/mlops-evaluation-lm-evaluation-harness.md","website/docs/user-guide/skills/bundled/mlops/mlops-evaluation-weights-and-biases.md","website/docs/user-guide/skills/bundled/mlops/mlops-huggingface-hub.md","website/docs/user-guide/skills/bundled/mlops/mlops-inference-llama-cpp.md","website/docs/user-guide/skills/bundled/mlops/mlops-inference-obliteratus.md","website/docs/user-guide/skills/bundled/mlops/mlops-inference-outlines.md","website/docs/user-guide/skills/bundled/mlops/mlops-inference-vllm.md","website/docs/user-guid
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment