Hermes Agent - Complete Project Guide (A-Z)
Purpose of this document: A single, comprehensive reference that explains everything about the Hermes Agent project — its architecture, source code, features, release history, and design patterns — so that any AI or developer can fully understand the system.
Table of Contents
- Project Overview
- Key Features Summary
- Installation & Getting Started
- Project Structure
- Core Architecture
- CLI System
- Tool System
- Agent Internals
- Messaging Gateway
- Cron Scheduling
- Skills System
- Plugin System
- Memory System
- ACP Server (IDE Integration)
- API Server
- MCP Server Mode
- RL Training Environments
- Profiles (Multi-Instance)
- Security Model
- Provider & Model System
- Streaming & Reasoning
- Release History
- File Dependency Chain
- Key Design Patterns
- Configuration Reference
- Known Pitfalls
1. Project Overview
Hermes Agent is a self-improving AI agent built by Nous Research. It is an open-source (MIT licensed), Python-based project that provides:
- A full interactive terminal UI (CLI) for conversing with LLMs
- A messaging gateway supporting 16+ platforms (Telegram, Discord, Slack, WhatsApp, Signal, Matrix, Email, etc.)
- A closed learning loop — the agent creates skills from experience, improves them during use, nudges itself to persist knowledge, searches past conversations, and builds a deepening model of who you are
- 40+ built-in tools — terminal execution, file manipulation, web search, browser automation, code execution, image generation, TTS/STT, and more
- Any LLM provider — OpenRouter (200+ models), Nous Portal (400+ models), OpenAI, Anthropic, Hugging Face, GitHub Copilot, z.ai/GLM, Kimi/Moonshot, MiniMax, Alibaba/DashScope, custom endpoints
- Six terminal backends — local, Docker, SSH, Modal (serverless), Daytona (serverless), Singularity (HPC)
- Scheduled automations via built-in cron scheduler
- IDE integration via ACP (Agent Communication Protocol) for VS Code, Zed, JetBrains
- MCP integration — both client (connect to any MCP server) and server (expose Hermes to MCP clients)
- RL training via Atropos environments for training the next generation of tool-calling models
Tech Stack:
- Python 3.11+ (core agent, tools, gateway, cron)
- Node.js (browser automation via agent-browser)
- SQLite with WAL mode and FTS5 (session storage, full-text search)
- OpenAI-compatible API (primary inference interface)
- Anthropic SDK (native Anthropic support)
- Rich + prompt_toolkit (CLI rendering)
Repository: github.com/NousResearch/hermes-agent
Version: 0.7.0 (as of April 2026)
License: MIT
2. Key Features Summary
| Feature |
Description |
| Terminal UI |
Full TUI with multiline editing, slash-command autocomplete, conversation history, interrupt-and-redirect, streaming tool output |
| Multi-Platform Messaging |
Telegram, Discord, Slack, WhatsApp, Signal, Matrix, Email, Home Assistant, DingTalk, Feishu/Lark, WeCom, Mattermost, SMS, Webhook — all from a single gateway process |
| Learning Loop |
Agent-curated memory with periodic nudges, autonomous skill creation, skills self-improve during use, FTS5 session search with LLM summarization, Honcho dialectic user modeling |
| Scheduled Tasks |
Built-in cron scheduler with delivery to any platform (daily reports, nightly backups, weekly audits) |
| Subagent Delegation |
Spawn isolated subagents for parallel workstreams with restricted toolsets |
| Execute Code |
Python scripts that call tools via RPC, collapsing multi-step pipelines into zero-context-cost turns |
| Terminal Backends |
Local, Docker, SSH, Modal, Daytona, Singularity — run on a $5 VPS or a GPU cluster |
| Skills |
70+ bundled skills across 28 categories, Skills Hub for community discovery, agentskills.io compatibility |
| Plugins |
Drop-in Python plugins with lifecycle hooks (pre_llm_call, post_llm_call, on_session_start, on_session_end) |
| MCP |
Client (connect to MCP servers for extended tools) and Server (expose conversations to MCP clients) |
| IDE Integration |
VS Code, Zed, JetBrains via ACP server with session management and tool streaming |
| API Server |
OpenAI-compatible /v1/chat/completions endpoint for headless integrations |
| Profiles |
Multi-instance support — each profile gets isolated config, memory, sessions, skills, gateway |
| Security |
Command approval system, secret redaction, SSRF protection, PII redaction, injection detection, credential directory protection |
| RL Training |
Atropos environments for batch trajectory generation and agent policy optimization |
3. Installation & Getting Started
# One-line install (Linux, macOS, WSL2)
curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash
# After install
source ~/.bashrc # or: source ~/.zshrc
hermes # start chatting
# Key commands
hermes model # Choose LLM provider and model
hermes tools # Configure which tools are enabled
hermes config set # Set individual config values
hermes gateway # Start the messaging gateway
hermes setup # Run the full setup wizard
hermes update # Update to latest version
hermes doctor # Diagnose any issues
For development:
git clone https://github.com/NousResearch/hermes-agent.git
cd hermes-agent
curl -LsSf https://astral.sh/uv/install.sh | sh
uv venv venv --python 3.11
source venv/bin/activate
uv pip install -e ".[all,dev]"
python -m pytest tests/ -q # ~3000 tests
4. Project Structure
hermes-agent/
├── run_agent.py # AIAgent class — core conversation loop
├── model_tools.py # Tool orchestration, _discover_tools(), handle_function_call()
├── toolsets.py # Toolset definitions, _HERMES_CORE_TOOLS list
├── toolset_distributions.py # Toolset sampling distributions for RL
├── cli.py # HermesCLI class — interactive CLI orchestrator
├── hermes_state.py # SessionDB — SQLite session store (FTS5 search)
├── hermes_constants.py # Shared constants, get_hermes_home()
├── hermes_time.py # Timezone handling
├── utils.py # Shared utility functions
├── batch_runner.py # Parallel batch processing
├── trajectory_compressor.py # Trajectory compression for RL training
├── mcp_serve.py # MCP server mode entry point
├── mini_swe_runner.py # Minimal SWE benchmark runner
├── rl_cli.py # RL CLI commands
│
├── agent/ # Agent internals
│ ├── prompt_builder.py # System prompt assembly
│ ├── context_compressor.py # Auto context compression
│ ├── prompt_caching.py # Anthropic prompt caching
│ ├── auxiliary_client.py # Auxiliary LLM client (vision, summarization)
│ ├── model_metadata.py # Model context lengths, token estimation
│ ├── models_dev.py # models.dev registry integration
│ ├── display.py # KawaiiSpinner, tool preview formatting
│ ├── skill_commands.py # Skill slash commands (shared CLI/gateway)
│ └── trajectory.py # Trajectory saving helpers
│
├── hermes_cli/ # CLI subcommands and setup
│ ├── main.py # Entry point — all `hermes` subcommands
│ ├── config.py # DEFAULT_CONFIG, OPTIONAL_ENV_VARS, migration
│ ├── commands.py # Slash command definitions + SlashCommandCompleter
│ ├── callbacks.py # Terminal callbacks (clarify, sudo, approval)
│ ├── setup.py # Interactive setup wizard
│ ├── skin_engine.py # Skin/theme engine
│ ├── skills_config.py # `hermes skills` — skill management
│ ├── tools_config.py # `hermes tools` — tool management
│ ├── skills_hub.py # Skills Hub integration
│ ├── models.py # Model catalog, provider model lists
│ ├── model_switch.py # Shared /model switch pipeline
│ └── auth.py # Provider credential resolution
│
├── tools/ # Tool implementations (one file per tool)
│ ├── registry.py # Central tool registry
│ ├── approval.py # Dangerous command detection
│ ├── terminal_tool.py # Terminal/shell execution
│ ├── process_registry.py # Background process management
│ ├── file_tools.py # File read/write/search/patch
│ ├── web_tools.py # Web search/extract
│ ├── browser_tool.py # Browser automation
│ ├── code_execution_tool.py # execute_code sandbox
│ ├── delegate_tool.py # Subagent delegation
│ ├── mcp_tool.py # MCP client integration
│ ├── skills_tool.py # Skill management tool
│ ├── todo_tool.py # Todo/task tracking tool
│ ├── memory_tool.py # Memory read/write tool
│ ├── tts_tool.py # Text-to-speech
│ ├── vision_tool.py # Image analysis
│ ├── image_gen_tool.py # Image generation
│ └── environments/ # Terminal backends
│ ├── base.py # BaseEnvironment ABC
│ ├── local.py # Local execution
│ ├── docker.py # Docker containers
│ ├── ssh.py # SSH remote execution
│ ├── modal.py # Modal serverless
│ ├── managed_modal.py # Nous-hosted Modal
│ ├── daytona.py # Daytona serverless
│ ├── singularity.py # Singularity HPC containers
│ └── persistent_shell.py # Persistent shell mixin
│
├── gateway/ # Messaging platform gateway
│ ├── run.py # GatewayRunner — main message loop
│ ├── session.py # SessionStore — conversation persistence
│ ├── status.py # Gateway status, token locks
│ └── platforms/ # 16 platform adapters
│ ├── base.py # BasePlatformAdapter ABC
│ ├── telegram.py # Telegram (polling + webhook)
│ ├── discord.py # Discord
│ ├── slack.py # Slack
│ ├── whatsapp.py # WhatsApp
│ ├── matrix.py # Matrix (E2EE)
│ ├── signal.py # Signal
│ ├── email.py # Email (IMAP/SMTP)
│ ├── homeassistant.py # Home Assistant
│ ├── sms.py # SMS (Twilio)
│ ├── mattermost.py # Mattermost
│ ├── dingtalk.py # DingTalk
│ ├── feishu.py # Feishu/Lark
│ ├── wecom.py # WeCom (Enterprise WeChat)
│ ├── webhook.py # Generic webhook
│ └── api_server.py # OpenAI-compatible API server
│
├── acp_adapter/ # ACP server (IDE integration)
│ ├── server.py # HermesACPAgent class
│ ├── session.py # SessionManager
│ ├── events.py # Streaming callbacks
│ ├── permissions.py # Approval callbacks
│ └── entry.py # Entry point
│
├── cron/ # Scheduler
│ ├── scheduler.py # tick() — job execution engine
│ └── jobs.py # Job storage and CRUD
│
├── plugins/ # Plugin system
│ └── memory/ # 8 memory provider plugins
│ ├── openviking/
│ ├── mem0/
│ ├── hindsight/
│ ├── holographic/
│ ├── honcho/
│ ├── retaindb/
│ └── byterover/
│
├── environments/ # RL training environments (Atropos)
│ ├── hermes_base_env.py # Abstract base RL environment
│ ├── agent_loop.py # HermesAgentLoop — rollout execution
│ ├── tool_context.py # ToolContext — sandbox for RL
│ ├── web_research_env.py # Web research tasks
│ └── agentic_opd_env.py # Observation-Prediction-Demo env
│
├── skills/ # 70+ bundled skills across 28 categories
├── optional-skills/ # Additional optional skills
├── tests/ # ~3000 pytest tests
├── scripts/ # Install, update, packaging scripts
├── docker/ # Docker build files
├── docs/ # Documentation source (Docusaurus)
├── website/ # Landing page
├── desktop/ # Desktop app (Electron, separate repo)
├── tinker-atropos/ # RL submodule
│
├── pyproject.toml # Python package config
├── AGENTS.md # Developer guide for AI assistants
├── RELEASE_v0.2.0.md → v0.7.0.md # Release notes
└── cli-config.yaml.example # Example config
User config directory: ~/.hermes/
~/.hermes/
├── config.yaml # User settings
├── .env # API keys and secrets
├── MEMORY.md # Persistent agent memory
├── USER.md # User profile
├── SOUL.md # Agent personality/identity
├── sessions.db # SQLite session database
├── skills/ # User-installed skills
├── skins/ # Custom CLI themes
├── plugins/ # User plugins
├── cron/ # Cron jobs and output
│ ├── jobs.json
│ └── output/
├── cache/ # Image/audio cache
├── plans/ # Generated plans
├── profiles/ # Multi-instance profiles
└── mcp/ # MCP server configs
5. Core Architecture
5.1 AIAgent Class (run_agent.py)
The AIAgent class is the heart of the system — the core conversation loop that orchestrates LLM calls, tool execution, context management, and response delivery.
Constructor (~60 parameters):
class AIAgent:
def __init__(self,
model: str = "anthropic/claude-opus-4.6",
max_iterations: int = 90,
enabled_toolsets: list = None,
disabled_toolsets: list = None,
quiet_mode: bool = False,
save_trajectories: bool = False,
platform: str = None, # "cli", "telegram", etc.
session_id: str = None,
session_db: SessionDB = None,
skip_context_files: bool = False,
skip_memory: bool = False,
base_url: str = None,
api_key: str = None,
provider: str = None,
api_mode: str = "chat_completions", # or "anthropic_messages" or "codex_responses"
tool_progress_callback = None,
stream_delta_callback = None,
thinking_callback = None,
status_callback = None,
iteration_budget: IterationBudget = None,
credential_pool = None,
checkpoints_enabled: bool = False,
# ... plus provider, routing, callback params
)
Main Methods:
| Method |
Returns |
Purpose |
chat(message, stream_callback) |
str |
Simple interface — returns final response text |
run_conversation(user_message, system_message, conversation_history, task_id) |
dict |
Full interface — returns {final_response, messages, completed, api_calls, error} |
_interruptible_api_call(api_kwargs) |
Response |
Runs API request in background thread with interrupt support |
_interruptible_streaming_api_call(api_kwargs, on_first_delta) |
Response |
Streaming variant with delta callbacks |
The Core Agent Loop (inside run_conversation()):
while api_call_count < self.max_iterations and self.iteration_budget.remaining > 0:
response = client.chat.completions.create(
model=model, messages=messages, tools=tool_schemas
)
if response.tool_calls:
for tool_call in response.tool_calls:
result = handle_function_call(tool_call.name, tool_call.args, task_id)
messages.append(tool_result_message(result))
api_call_count += 1
else:
return response.content # Final text response
Key Behaviors:
- Three API modes:
chat_completions (OpenAI-compatible), anthropic_messages (Anthropic SDK), codex_responses (OpenAI Codex)
- Parallel tool execution: Independent tool calls run concurrently via ThreadPoolExecutor (unless they share file paths or are in the never-parallel list)
- Interrupt support: Background threads allow interrupt detection without blocking on HTTP
- Error recovery: Automatic fallback chain (primary → fallback model), retry with exponential backoff, context compression on token overflow
- Budget pressure: Warnings at 70% (caution) and 90% (urgent) of iteration budget
- Oversized results: Tool results >100K chars are saved to temp files with a preview
- Stale connection detection: 90s timeout for streaming, 60s read timeout
IterationBudget (thread-safe):
class IterationBudget:
def consume() -> bool # Check and consume one iteration
def refund() # Give back iteration (for execute_code turns)
@property remaining # Remaining iterations
5.2 Tool Orchestration (model_tools.py)
Bridges the agent and tool registry — handles discovery, schema generation, and dispatch.
Key Functions:
| Function |
Purpose |
_discover_tools() |
Imports all tool modules (each calls registry.register() on import) |
get_tool_definitions(enabled_toolsets, disabled_toolsets, quiet_mode) |
Returns OpenAI-format tool schemas filtered by toolset |
handle_function_call(function_name, function_args, task_id, user_task, enabled_tools) |
Main dispatcher — routes calls to registry with arg coercion |
coerce_tool_args(tool_name, args) |
Type coercion for LLM-generated arguments (string→int, string→bool, etc.) |
Tool Discovery Order:
- Static tools (web_tools, terminal_tool, file_tools, browser_tool, etc.)
- Optional tools (fal_client for image gen, honcho, etc.) — graceful fallback if missing
- Plugin-registered tools
- MCP server tools (dynamic, via tools/list_changed notifications)
Special Tool Handling:
- Agent-level tools (todo, memory, session_search, delegate_task): Intercepted by
run_agent.py before handle_function_call()
- execute_code: Passes
enabled_tools for sandbox tool list
- Dynamic schema adjustments:
browser_navigate strips web_search reference if tools unavailable
Async Bridging:
- Persistent event loops (not
asyncio.run()) to prevent "Event loop is closed" errors
- Main thread uses shared loop; worker threads get per-thread loops
_run_async() detects running loop and spins up disposable thread if needed
5.3 Toolset System (toolsets.py)
Provides flexible tool grouping and composition.
Core Toolsets:
| Toolset |
Tools Included |
web |
web_search, web_extract, web_crawl |
terminal |
terminal |
file |
read_file, write_file, edit_file, list_files, search_files |
browser |
browser_navigate, browser_snapshot, browser_click, browser_type, browser_scroll, browser_extract |
vision |
analyze_image |
image_gen |
generate_image |
tts |
text_to_speech |
todo |
todo_read, todo_write |
memory |
memory_read, memory_write |
session_search |
session_search |
delegation |
delegate_task |
code_execution |
execute_code |
cronjob |
create_job, list_jobs, delete_job |
messaging |
send_message |
homeassistant |
ha_get_states, ha_call_service, ... |
Composite Toolsets:
hermes-cli — All core tools for CLI platform
hermes-telegram, hermes-discord, etc. — Platform-specific tool sets
hermes-gateway — Union of all platform tools
debugging — terminal + file + web
safe — Everything except terminal
Resolution:
resolve_toolset(name, visited=None) → List[str]
# Recursively resolves toolset to tool names
# Handles composition (includes) and cycle detection
# Special aliases: "all" or "*" = all tools
5.4 Tool Registry (tools/registry.py)
Singleton managing all tool schemas and handlers. Circular-import safe — has no tool dependencies.
ToolEntry (per-tool metadata):
@dataclass(slots=True)
class ToolEntry:
name: str
toolset: str
schema: dict # OpenAI-format tool definition
handler: Callable # Sync or async handler function
check_fn: Callable # Returns True if tool is available
requires_env: list # Required environment variables
is_async: bool
description: str
emoji: str
Key Methods:
registry.register(name, toolset, schema, handler, check_fn, requires_env)
registry.get_definitions(tool_names, quiet) # Returns filtered schemas
registry.dispatch(name, args, **kwargs) # Execute with async bridging
registry.deregister(name) # Remove (for MCP tool refresh)
registry.check_tool_availability() # Returns (available, unavailable)
5.5 Session Database (hermes_state.py)
SQLite-based persistent session storage with FTS5 full-text search.
Schema (v6):
-- Sessions table
sessions (
id TEXT PRIMARY KEY,
source TEXT, user_id TEXT, model TEXT, model_config TEXT,
system_prompt TEXT, parent_session_id TEXT,
started_at TEXT, ended_at TEXT, end_reason TEXT,
message_count INTEGER, tool_call_count INTEGER,
input_tokens INTEGER, output_tokens INTEGER,
cache_read_tokens INTEGER, cache_write_tokens INTEGER, reasoning_tokens INTEGER,
estimated_cost_usd REAL, actual_cost_usd REAL,
title TEXT -- UNIQUE INDEX
)
-- Messages table
messages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
session_id TEXT, role TEXT, content TEXT,
tool_call_id TEXT, tool_calls TEXT, -- JSON
tool_name TEXT, timestamp TEXT,
token_count INTEGER, finish_reason TEXT,
reasoning TEXT, reasoning_details TEXT, codex_reasoning_items TEXT
)
-- FTS5 virtual table (auto-synced via triggers)
messages_fts (content)
Concurrency Model:
- WAL (Write-Ahead Logging) for concurrent readers + single writer
BEGIN IMMEDIATE for write transactions (lock at start, not commit)
- Jitter retry on lock: 20-150ms random backoff, max 15 retries
- Periodic WAL checkpoint every 50 writes
Key Operations:
create_session(), end_session(), reopen_session()
add_message(), get_messages()
search_sessions(query) — FTS5 full-text search
update_token_counts() — Supports both incremental (CLI) and absolute (gateway) modes
5.6 Constants & Home Directory (hermes_constants.py)
Import-safe constants module with no circular dependencies.
get_hermes_home() → Path # HERMES_HOME env var or ~/.hermes
display_hermes_home() → str # User-friendly display: "~/.hermes"
get_optional_skills_dir() → Path # HERMES_OPTIONAL_SKILLS env var
parse_reasoning_effort(str) → Dict # "high" → {"enabled": True, "effort": "high"}
# Key constants
OPENROUTER_BASE_URL = "https://openrouter.ai/api/v1"
NOUS_API_BASE_URL = "https://inference-api.nousresearch.com/v1"
AI_GATEWAY_BASE_URL = "https://ai-gateway.vercel.sh/v1"
VALID_REASONING_EFFORTS = ("xhigh", "high", "medium", "low", "minimal")
6. CLI System
6.1 Interactive CLI (cli.py)
The HermesCLI class provides the interactive terminal interface.
Features:
- Rich for banner/panels, prompt_toolkit for input with autocomplete
- KawaiiSpinner — animated faces during API calls,
┊ activity feed for tool results
- Multiline editing with Shift+Enter
- Slash-command autocomplete
- Session history with up/down arrow navigation
- Clipboard image paste (Alt+V / Ctrl+V)
- Status bar showing model, provider, and token counts
- Inline diff previews for file write/patch operations
Configuration Loading:
load_cli_config() → dict
# Loads from ~/.hermes/config.yaml (or ./cli-config.yaml fallback)
# Merges with hardcoded defaults
# Expands ${ENV_VAR} references
# Maps terminal config → env vars
6.2 CLI Entry Point (hermes_cli/main.py)
All hermes subcommands are dispatched from here:
hermes # Default: interactive chat
hermes chat # Explicit interactive mode
hermes gateway start|stop|status|install|uninstall
hermes setup # Setup wizard
hermes model # Select model/provider
hermes tools # Configure tools
hermes skills # Manage skills
hermes config set|get # Direct config manipulation
hermes cron list|delete # Cron job management
hermes doctor # Diagnose issues
hermes sessions browse # Session picker
hermes profile create|list|switch|delete|export|import
hermes mcp serve|add|remove # MCP management
hermes acp # Start ACP server
hermes update|uninstall|version
Profile System:
_apply_profile_override() runs BEFORE any imports to set HERMES_HOME
- Pre-parses
--profile/-p from argv
- Allows fully isolated agent instances with separate config, memory, sessions, skills
6.3 Configuration System (hermes_cli/config.py)
Key Configuration Sections:
model: "anthropic/claude-opus-4.6" # or dict with provider/base_url/api_key
providers: {} # Provider-specific configs
fallback_providers: [] # Ordered failover list
credential_pool: {} # Multiple API keys per provider
agent:
max_turns: 90
gateway_timeout: 1800
tool_use_enforcement: "auto"
terminal:
backend: "local" # local|docker|modal|daytona|ssh|singularity
timeout: 180
persistent_shell: true
docker_image: "nikolaik/python-nodejs:..."
compression:
enabled: true
threshold: 0.50 # Compress when 50% of context used
target_ratio: 0.20 # Summary = 20% of compressed content
protect_last_n: 20
auxiliary:
vision: { provider, model }
web_extract: { provider, model }
compression: { provider, model }
memory:
memory_enabled: true
provider: "" # "" | "honcho" | "mem0" | etc.
memory_char_limit: 2200
display:
personality: "kawaii"
show_reasoning: false
inline_diffs: true
skin: "default"
streaming: true
tts:
provider: "edge" # edge|elevenlabs|openai|neutts
stt:
enabled: true
provider: "local" # local|groq|openai
privacy:
redact_pii: false
mcp_servers: {} # MCP server configurations
skills:
external_dirs: [] # Additional skill directories
approvals:
mode: "smart" # smart|always|off
Config Files:
~/.hermes/config.yaml — User settings (authoritative)
~/.hermes/.env — API keys and secrets
- Config version migration system (currently v5)
6.4 Slash Command Registry (hermes_cli/commands.py)
All slash commands defined centrally in COMMAND_REGISTRY:
CommandDef(name, description, category, aliases, args_hint, cli_only, gateway_only)
Derived automatically by:
- CLI
process_command() — dispatch on canonical name
- Gateway dispatch + help
- Telegram BotCommand menu
- Slack
/hermes subcommands
- Autocomplete + help text
Key Commands:
| Command |
Aliases |
Description |
/new |
/reset |
Start fresh conversation |
/model |
|
Show/switch model |
/personality |
|
Set agent personality |
/retry |
|
Retry last turn |
/undo |
|
Remove last turn |
/compress |
/compact |
Compress context |
/usage |
/cost |
Show token usage |
/insights |
|
Usage analytics |
/skills |
|
Browse/install skills |
/background |
/bg |
Manage background processes |
/plan |
|
Generate implementation plan |
/rollback |
|
Restore filesystem checkpoint |
/verbose |
|
Toggle debug output |
/reasoning |
|
Set reasoning effort |
/yolo |
|
Toggle approval bypass |
/btw |
|
Ephemeral side question |
/stop |
|
Kill current agent run |
/queue |
|
Queue next prompt |
/browser |
|
Interactive browser session |
/history |
/resume |
Session browser |
/skin |
|
Switch CLI theme |
6.5 Setup Wizard (hermes_cli/setup.py)
Modular interactive wizard with independent sections:
- Model & Provider — Select AI provider, enter API keys, choose model
- Terminal Backend — Choose execution environment
- Agent Settings — Max iterations, compression, session policies
- Messaging Platforms — Configure Telegram, Discord, Slack, etc.
- Tools — TTS, STT, web search, image generation, browser
Features:
- Live credential validation
- Real-time model list fetching from provider APIs
- Automatic OpenClaw migration detection
- Atomic config file writes
6.6 Model Catalog (hermes_cli/models.py)
Provider-specific model lists:
_PROVIDER_MODELS = {
"nous": ["anthropic/claude-opus-4.6", "anthropic/claude-sonnet-4.6", ...], # 25+
"openrouter": ["anthropic/claude-opus-4.6", "google/gemini-3-flash", ...], # 30+
"anthropic": ["claude-opus-4-6", "claude-sonnet-4-6", ...],
"openai": ["gpt-5", "gpt-5.4-mini", "gpt-4.1", "gpt-4o", ...],
"copilot": ["gpt-5.4", "gpt-5.4-mini", "gpt-5.3-codex", ...],
"huggingface": [...],
"minimax": [...],
"kimi-coding": [...],
"alibaba": [...],
"deepseek": [...],
# ... more providers
}
Features:
- Dynamic fetching via provider
/models endpoints
- Curated lists used when live probe returns fewer models
- Fuzzy matching for typo correction
- Validation against provider catalog
6.7 Skin/Theme Engine (hermes_cli/skin_engine.py)
Data-driven CLI visual customization — no code changes needed.
Customizable Elements:
| Element |
Key |
Used By |
| Banner border/title/accent |
colors.* |
banner.py |
| Response box border |
colors.response_border |
cli.py |
| Spinner faces (waiting/thinking) |
spinner.* |
display.py |
| Spinner verbs/wings |
spinner.* |
display.py |
| Tool output prefix |
tool_prefix |
display.py |
| Per-tool emojis |
tool_emojis |
display.py |
| Agent name/welcome/prompt |
branding.* |
banner.py, cli.py |
Built-in Skins: default, ares, mono, slate, poseidon, sisyphus, charizard
User Skins: Drop ~/.hermes/skins/<name>.yaml and activate with /skin <name>
7. Tool System
7.1 Terminal Tool (tools/terminal_tool.py)
Shell command execution across multiple backends.
def terminal_tool(
command: str,
background: bool = False,
timeout: Optional[int] = None,
task_id: Optional[str] = None,
force: bool = False, # Skip approval for dangerous commands
workdir: Optional[str] = None,
check_interval: Optional[int] = None, # Background task polling
pty: bool = False,
) -> str # JSON result
Features:
- Multi-backend: Selects based on
TERMINAL_ENV (local/docker/ssh/modal/daytona/singularity)
- Per-task_id sandboxes with thread-safe creation locks
- Dangerous command routing through approval system
- Background task support with file-based IPC
- Interrupt handling — polls
is_interrupted() during execution
- Auto-cleanup daemon thread for idle environments (>300s)
- Disk usage warnings at configurable threshold
7.2 File Tools (tools/file_tools.py)
Safe file operations with size guards and sensitive path protection.
read_file_tool(path, offset, limit) — Read with pagination (default 100K char limit)
write_file_tool(path, content) — Write with approval for sensitive paths
edit_file_tool(path, old_text, new_text) — String replacement editing
list_files_tool(path) — Directory listing
search_files_tool(pattern, path) — Glob/regex file search
Safety:
- Device path blocklist (
/dev/zero, /dev/stdin, etc.)
- Read dedup tracking — returns stub on re-read if mtime unchanged
- Sensitive path blocking:
/etc/, /boot/, ~/.ssh without approval
- Prompt injection protection for known dangerous paths
7.3 Web Tools (tools/web_tools.py)
Web search and content extraction.
web_search_tool(query, limit) — Search via configurable backend
web_extract_tool(urls, format) — Extract content from URLs
- `web_crawl_tool(url, ins
…(truncated)
1---2name: hermes-agent3description: Expert in building self-improving AI agents with tool use, multi-platform messaging, and a closed learning loop. Proficient in LLM orchestration, tool integration, session management, and agent autonomy.4---56# Hermes Agent - Complete Project Guide (A-Z)78> **Purpose of this document:** A single, comprehensive reference that explains everything about the Hermes Agent project — its architecture, source code, features, release history, and design patterns — so that any AI or developer can fully understand the system.910---1112## Table of Contents13141. [Project Overview](#1-project-overview)152. [Key Features Summary](#2-key-features-summary)163. [Installation & Getting Started](#3-installation--getting-started)174. [Project Structure](#4-project-structure)185. [Core Architecture](#5-core-architecture)19 - 5.1 [AIAgent Class (run_agent.py)](#51-aiagent-class-run_agentpy)20 - 5.2 [Tool Orchestration (model_tools.py)](#52-tool-orchestration-model_toolspy)21 - 5.3 [Toolset System (toolsets.py)](#53-toolset-system-toolsetspy)22 - 5.4 [Tool Registry (tools/registry.py)](#54-tool-registry-toolsregistrypy)23 - 5.5 [Session Database (hermes_state.py)](#55-session-database-hermes_statepy)24 - 5.6 [Constants & Home Directory (hermes_constants.py)](#56-constants--home-directory-hermes_constantspy)256. [CLI System](#6-cli-system)26 - 6.1 [Interactive CLI (cli.py)](#61-interactive-cli-clipy)27 - 6.2 [CLI Entry Point (hermes_cli/main.py)](#62-cli-entry-point-hermes_climainpy)28 - 6.3 [Configuration System (hermes_cli/config.py)](#63-configuration-system-hermes_cliconfigpy)29 - 6.4 [Slash Command Registry (hermes_cli/commands.py)](#64-slash-command-registry-hermes_clicommandspy)30 - 6.5 [Setup Wizard (hermes_cli/setup.py)](#65-setup-wizard-hermes_clisetupy)31 - 6.6 [Model Catalog (hermes_cli/models.py)](#66-model-catalog-hermes_climodelspy)32 - 6.7 [Skin/Theme Engine (hermes_cli/skin_engine.py)](#67-skintheme-engine-hermes_cliskin_enginepy)337. [Tool System](#7-tool-system)34 - 7.1 [Terminal Tool (tools/terminal_tool.py)](#71-terminal-tool-toolsterminal_toolpy)35 - 7.2 [File Tools (tools/file_tools.py)](#72-file-tools-toolsfile_toolspy)36 - 7.3 [Web Tools (tools/web_tools.py)](#73-web-tools-toolsweb_toolspy)37 - 7.4 [Browser Tool (tools/browser_tool.py)](#74-browser-tool-toolsbrowser_toolpy)38 - 7.5 [Delegate Tool (tools/delegate_tool.py)](#75-delegate-tool-toolsdelegate_toolpy)39 - 7.6 [MCP Tool (tools/mcp_tool.py)](#76-mcp-tool-toolsmcp_toolpy)40 - 7.7 [Approval System (tools/approval.py)](#77-approval-system-toolsapprovalpy)41 - 7.8 [Terminal Backends (tools/environments/)](#78-terminal-backends-toolsenvironments)428. [Agent Internals](#8-agent-internals)43 - 8.1 [Prompt Builder (agent/prompt_builder.py)](#81-prompt-builder-agentprompt_builderpy)44 - 8.2 [Context Compressor (agent/context_compressor.py)](#82-context-compressor-agentcontext_compressorpy)45 - 8.3 [Prompt Caching (agent/prompt_caching.py)](#83-prompt-caching-agentprompt_cachingpy)46 - 8.4 [Auxiliary Client (agent/auxiliary_client.py)](#84-auxiliary-client-agentauxiliary_clientpy)47 - 8.5 [Display & Spinner (agent/display.py)](#85-display--spinner-agentdisplaypy)48 - 8.6 [Skill Commands (agent/skill_commands.py)](#86-skill-commands-agentskill_commandspy)499. [Messaging Gateway](#9-messaging-gateway)50 - 9.1 [GatewayRunner (gateway/run.py)](#91-gatewayrunner-gatewayrunpy)51 - 9.2 [Session Store (gateway/session.py)](#92-session-store-gatewaysessionpy)52 - 9.3 [Platform Adapters (gateway/platforms/)](#93-platform-adapters-gatewayplatforms)5310. [Cron Scheduling](#10-cron-scheduling)5411. [Skills System](#11-skills-system)5512. [Plugin System](#12-plugin-system)5613. [Memory System](#13-memory-system)5714. [ACP Server (IDE Integration)](#14-acp-server-ide-integration)5815. [API Server](#15-api-server)5916. [MCP Server Mode](#16-mcp-server-mode)6017. [RL Training Environments](#17-rl-training-environments)6118. [Profiles (Multi-Instance)](#18-profiles-multi-instance)6219. [Security Model](#19-security-model)6320. [Provider & Model System](#20-provider--model-system)6421. [Streaming & Reasoning](#21-streaming--reasoning)6522. [Release History](#22-release-history)6623. [File Dependency Chain](#23-file-dependency-chain)6724. [Key Design Patterns](#24-key-design-patterns)6825. [Configuration Reference](#25-configuration-reference)6926. [Known Pitfalls](#26-known-pitfalls)7071---7273## 1. Project Overview7475**Hermes Agent** is a self-improving AI agent built by [Nous Research](https://nousresearch.com). It is an open-source (MIT licensed), Python-based project that provides:7677- A **full interactive terminal UI** (CLI) for conversing with LLMs78- A **messaging gateway** supporting 16+ platforms (Telegram, Discord, Slack, WhatsApp, Signal, Matrix, Email, etc.)79- A **closed learning loop** — the agent creates skills from experience, improves them during use, nudges itself to persist knowledge, searches past conversations, and builds a deepening model of who you are80- **40+ built-in tools** — terminal execution, file manipulation, web search, browser automation, code execution, image generation, TTS/STT, and more81- **Any LLM provider** — OpenRouter (200+ models), Nous Portal (400+ models), OpenAI, Anthropic, Hugging Face, GitHub Copilot, z.ai/GLM, Kimi/Moonshot, MiniMax, Alibaba/DashScope, custom endpoints82- **Six terminal backends** — local, Docker, SSH, Modal (serverless), Daytona (serverless), Singularity (HPC)83- **Scheduled automations** via built-in cron scheduler84- **IDE integration** via ACP (Agent Communication Protocol) for VS Code, Zed, JetBrains85- **MCP integration** — both client (connect to any MCP server) and server (expose Hermes to MCP clients)86- **RL training** via Atropos environments for training the next generation of tool-calling models8788**Tech Stack:**8990- Python 3.11+ (core agent, tools, gateway, cron)91- Node.js (browser automation via agent-browser)92- SQLite with WAL mode and FTS5 (session storage, full-text search)93- OpenAI-compatible API (primary inference interface)94- Anthropic SDK (native Anthropic support)95- Rich + prompt_toolkit (CLI rendering)9697**Repository:** `github.com/NousResearch/hermes-agent`98**Version:** 0.7.0 (as of April 2026)99**License:** MIT100101---102103## 2. Key Features Summary104105| Feature | Description |106| ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |107| **Terminal UI** | Full TUI with multiline editing, slash-command autocomplete, conversation history, interrupt-and-redirect, streaming tool output |108| **Multi-Platform Messaging** | Telegram, Discord, Slack, WhatsApp, Signal, Matrix, Email, Home Assistant, DingTalk, Feishu/Lark, WeCom, Mattermost, SMS, Webhook — all from a single gateway process |109| **Learning Loop** | Agent-curated memory with periodic nudges, autonomous skill creation, skills self-improve during use, FTS5 session search with LLM summarization, Honcho dialectic user modeling |110| **Scheduled Tasks** | Built-in cron scheduler with delivery to any platform (daily reports, nightly backups, weekly audits) |111| **Subagent Delegation** | Spawn isolated subagents for parallel workstreams with restricted toolsets |112| **Execute Code** | Python scripts that call tools via RPC, collapsing multi-step pipelines into zero-context-cost turns |113| **Terminal Backends** | Local, Docker, SSH, Modal, Daytona, Singularity — run on a $5 VPS or a GPU cluster |114| **Skills** | 70+ bundled skills across 28 categories, Skills Hub for community discovery, agentskills.io compatibility |115| **Plugins** | Drop-in Python plugins with lifecycle hooks (pre_llm_call, post_llm_call, on_session_start, on_session_end) |116| **MCP** | Client (connect to MCP servers for extended tools) and Server (expose conversations to MCP clients) |117| **IDE Integration** | VS Code, Zed, JetBrains via ACP server with session management and tool streaming |118| **API Server** | OpenAI-compatible `/v1/chat/completions` endpoint for headless integrations |119| **Profiles** | Multi-instance support — each profile gets isolated config, memory, sessions, skills, gateway |120| **Security** | Command approval system, secret redaction, SSRF protection, PII redaction, injection detection, credential directory protection |121| **RL Training** | Atropos environments for batch trajectory generation and agent policy optimization |122123---124125## 3. Installation & Getting Started126127```bash128# One-line install (Linux, macOS, WSL2)129curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash130131# After install132source ~/.bashrc # or: source ~/.zshrc133hermes # start chatting134135# Key commands136hermes model # Choose LLM provider and model137hermes tools # Configure which tools are enabled138hermes config set # Set individual config values139hermes gateway # Start the messaging gateway140hermes setup # Run the full setup wizard141hermes update # Update to latest version142hermes doctor # Diagnose any issues143```144145**For development:**146147```bash148git clone https://github.com/NousResearch/hermes-agent.git149cd hermes-agent150curl -LsSf https://astral.sh/uv/install.sh | sh151uv venv venv --python 3.11152source venv/bin/activate153uv pip install -e ".[all,dev]"154python -m pytest tests/ -q # ~3000 tests155```156157---158159## 4. Project Structure160161```162hermes-agent/163├── run_agent.py # AIAgent class — core conversation loop164├── model_tools.py # Tool orchestration, _discover_tools(), handle_function_call()165├── toolsets.py # Toolset definitions, _HERMES_CORE_TOOLS list166├── toolset_distributions.py # Toolset sampling distributions for RL167├── cli.py # HermesCLI class — interactive CLI orchestrator168├── hermes_state.py # SessionDB — SQLite session store (FTS5 search)169├── hermes_constants.py # Shared constants, get_hermes_home()170├── hermes_time.py # Timezone handling171├── utils.py # Shared utility functions172├── batch_runner.py # Parallel batch processing173├── trajectory_compressor.py # Trajectory compression for RL training174├── mcp_serve.py # MCP server mode entry point175├── mini_swe_runner.py # Minimal SWE benchmark runner176├── rl_cli.py # RL CLI commands177│178├── agent/ # Agent internals179│ ├── prompt_builder.py # System prompt assembly180│ ├── context_compressor.py # Auto context compression181│ ├── prompt_caching.py # Anthropic prompt caching182│ ├── auxiliary_client.py # Auxiliary LLM client (vision, summarization)183│ ├── model_metadata.py # Model context lengths, token estimation184│ ├── models_dev.py # models.dev registry integration185│ ├── display.py # KawaiiSpinner, tool preview formatting186│ ├── skill_commands.py # Skill slash commands (shared CLI/gateway)187│ └── trajectory.py # Trajectory saving helpers188│189├── hermes_cli/ # CLI subcommands and setup190│ ├── main.py # Entry point — all `hermes` subcommands191│ ├── config.py # DEFAULT_CONFIG, OPTIONAL_ENV_VARS, migration192│ ├── commands.py # Slash command definitions + SlashCommandCompleter193│ ├── callbacks.py # Terminal callbacks (clarify, sudo, approval)194│ ├── setup.py # Interactive setup wizard195│ ├── skin_engine.py # Skin/theme engine196│ ├── skills_config.py # `hermes skills` — skill management197│ ├── tools_config.py # `hermes tools` — tool management198│ ├── skills_hub.py # Skills Hub integration199│ ├── models.py # Model catalog, provider model lists200│ ├── model_switch.py # Shared /model switch pipeline201│ └── auth.py # Provider credential resolution202│203├── tools/ # Tool implementations (one file per tool)204│ ├── registry.py # Central tool registry205│ ├── approval.py # Dangerous command detection206│ ├── terminal_tool.py # Terminal/shell execution207│ ├── process_registry.py # Background process management208│ ├── file_tools.py # File read/write/search/patch209│ ├── web_tools.py # Web search/extract210│ ├── browser_tool.py # Browser automation211│ ├── code_execution_tool.py # execute_code sandbox212│ ├── delegate_tool.py # Subagent delegation213│ ├── mcp_tool.py # MCP client integration214│ ├── skills_tool.py # Skill management tool215│ ├── todo_tool.py # Todo/task tracking tool216│ ├── memory_tool.py # Memory read/write tool217│ ├── tts_tool.py # Text-to-speech218│ ├── vision_tool.py # Image analysis219│ ├── image_gen_tool.py # Image generation220│ └── environments/ # Terminal backends221│ ├── base.py # BaseEnvironment ABC222│ ├── local.py # Local execution223│ ├── docker.py # Docker containers224│ ├── ssh.py # SSH remote execution225│ ├── modal.py # Modal serverless226│ ├── managed_modal.py # Nous-hosted Modal227│ ├── daytona.py # Daytona serverless228│ ├── singularity.py # Singularity HPC containers229│ └── persistent_shell.py # Persistent shell mixin230│231├── gateway/ # Messaging platform gateway232│ ├── run.py # GatewayRunner — main message loop233│ ├── session.py # SessionStore — conversation persistence234│ ├── status.py # Gateway status, token locks235│ └── platforms/ # 16 platform adapters236│ ├── base.py # BasePlatformAdapter ABC237│ ├── telegram.py # Telegram (polling + webhook)238│ ├── discord.py # Discord239│ ├── slack.py # Slack240│ ├── whatsapp.py # WhatsApp241│ ├── matrix.py # Matrix (E2EE)242│ ├── signal.py # Signal243│ ├── email.py # Email (IMAP/SMTP)244│ ├── homeassistant.py # Home Assistant245│ ├── sms.py # SMS (Twilio)246│ ├── mattermost.py # Mattermost247│ ├── dingtalk.py # DingTalk248│ ├── feishu.py # Feishu/Lark249│ ├── wecom.py # WeCom (Enterprise WeChat)250│ ├── webhook.py # Generic webhook251│ └── api_server.py # OpenAI-compatible API server252│253├── acp_adapter/ # ACP server (IDE integration)254│ ├── server.py # HermesACPAgent class255│ ├── session.py # SessionManager256│ ├── events.py # Streaming callbacks257│ ├── permissions.py # Approval callbacks258│ └── entry.py # Entry point259│260├── cron/ # Scheduler261│ ├── scheduler.py # tick() — job execution engine262│ └── jobs.py # Job storage and CRUD263│264├── plugins/ # Plugin system265│ └── memory/ # 8 memory provider plugins266│ ├── openviking/267│ ├── mem0/268│ ├── hindsight/269│ ├── holographic/270│ ├── honcho/271│ ├── retaindb/272│ └── byterover/273│274├── environments/ # RL training environments (Atropos)275│ ├── hermes_base_env.py # Abstract base RL environment276│ ├── agent_loop.py # HermesAgentLoop — rollout execution277│ ├── tool_context.py # ToolContext — sandbox for RL278│ ├── web_research_env.py # Web research tasks279│ └── agentic_opd_env.py # Observation-Prediction-Demo env280│281├── skills/ # 70+ bundled skills across 28 categories282├── optional-skills/ # Additional optional skills283├── tests/ # ~3000 pytest tests284├── scripts/ # Install, update, packaging scripts285├── docker/ # Docker build files286├── docs/ # Documentation source (Docusaurus)287├── website/ # Landing page288├── desktop/ # Desktop app (Electron, separate repo)289├── tinker-atropos/ # RL submodule290│291├── pyproject.toml # Python package config292├── AGENTS.md # Developer guide for AI assistants293├── RELEASE_v0.2.0.md → v0.7.0.md # Release notes294└── cli-config.yaml.example # Example config295```296297**User config directory:** `~/.hermes/`298299```300~/.hermes/301├── config.yaml # User settings302├── .env # API keys and secrets303├── MEMORY.md # Persistent agent memory304├── USER.md # User profile305├── SOUL.md # Agent personality/identity306├── sessions.db # SQLite session database307├── skills/ # User-installed skills308├── skins/ # Custom CLI themes309├── plugins/ # User plugins310├── cron/ # Cron jobs and output311│ ├── jobs.json312│ └── output/313├── cache/ # Image/audio cache314├── plans/ # Generated plans315├── profiles/ # Multi-instance profiles316└── mcp/ # MCP server configs317```318319---320321## 5. Core Architecture322323### 5.1 AIAgent Class (run_agent.py)324325The `AIAgent` class is the heart of the system — the core conversation loop that orchestrates LLM calls, tool execution, context management, and response delivery.326327**Constructor (~60 parameters):**328329```python330class AIAgent:331 def __init__(self,332 model: str = "anthropic/claude-opus-4.6",333 max_iterations: int = 90,334 enabled_toolsets: list = None,335 disabled_toolsets: list = None,336 quiet_mode: bool = False,337 save_trajectories: bool = False,338 platform: str = None, # "cli", "telegram", etc.339 session_id: str = None,340 session_db: SessionDB = None,341 skip_context_files: bool = False,342 skip_memory: bool = False,343 base_url: str = None,344 api_key: str = None,345 provider: str = None,346 api_mode: str = "chat_completions", # or "anthropic_messages" or "codex_responses"347 tool_progress_callback = None,348 stream_delta_callback = None,349 thinking_callback = None,350 status_callback = None,351 iteration_budget: IterationBudget = None,352 credential_pool = None,353 checkpoints_enabled: bool = False,354 # ... plus provider, routing, callback params355 )356```357358**Main Methods:**359360| Method | Returns | Purpose |361| ------------------------------------------------------------------------------- | -------- | ---------------------------------------------------------------------------------- |362| `chat(message, stream_callback)` | `str` | Simple interface — returns final response text |363| `run_conversation(user_message, system_message, conversation_history, task_id)` | `dict` | Full interface — returns `{final_response, messages, completed, api_calls, error}` |364| `_interruptible_api_call(api_kwargs)` | Response | Runs API request in background thread with interrupt support |365| `_interruptible_streaming_api_call(api_kwargs, on_first_delta)` | Response | Streaming variant with delta callbacks |366367**The Core Agent Loop** (inside `run_conversation()`):368369```python370while api_call_count < self.max_iterations and self.iteration_budget.remaining > 0:371 response = client.chat.completions.create(372 model=model, messages=messages, tools=tool_schemas373 )374 if response.tool_calls:375 for tool_call in response.tool_calls:376 result = handle_function_call(tool_call.name, tool_call.args, task_id)377 messages.append(tool_result_message(result))378 api_call_count += 1379 else:380 return response.content # Final text response381```382383**Key Behaviors:**384385- **Three API modes:** `chat_completions` (OpenAI-compatible), `anthropic_messages` (Anthropic SDK), `codex_responses` (OpenAI Codex)386- **Parallel tool execution:** Independent tool calls run concurrently via ThreadPoolExecutor (unless they share file paths or are in the never-parallel list)387- **Interrupt support:** Background threads allow interrupt detection without blocking on HTTP388- **Error recovery:** Automatic fallback chain (primary → fallback model), retry with exponential backoff, context compression on token overflow389- **Budget pressure:** Warnings at 70% (caution) and 90% (urgent) of iteration budget390- **Oversized results:** Tool results >100K chars are saved to temp files with a preview391- **Stale connection detection:** 90s timeout for streaming, 60s read timeout392393**IterationBudget** (thread-safe):394395```python396class IterationBudget:397 def consume() -> bool # Check and consume one iteration398 def refund() # Give back iteration (for execute_code turns)399 @property remaining # Remaining iterations400```401402---403404### 5.2 Tool Orchestration (model_tools.py)405406Bridges the agent and tool registry — handles discovery, schema generation, and dispatch.407408**Key Functions:**409410| Function | Purpose |411| --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- |412| `_discover_tools()` | Imports all tool modules (each calls `registry.register()` on import) |413| `get_tool_definitions(enabled_toolsets, disabled_toolsets, quiet_mode)` | Returns OpenAI-format tool schemas filtered by toolset |414| `handle_function_call(function_name, function_args, task_id, user_task, enabled_tools)` | Main dispatcher — routes calls to registry with arg coercion |415| `coerce_tool_args(tool_name, args)` | Type coercion for LLM-generated arguments (string→int, string→bool, etc.) |416417**Tool Discovery Order:**4184191. Static tools (web_tools, terminal_tool, file_tools, browser_tool, etc.)4202. Optional tools (fal_client for image gen, honcho, etc.) — graceful fallback if missing4213. Plugin-registered tools4224. MCP server tools (dynamic, via tools/list_changed notifications)423424**Special Tool Handling:**425426- **Agent-level tools** (todo, memory, session_search, delegate_task): Intercepted by `run_agent.py` before `handle_function_call()`427- **execute_code**: Passes `enabled_tools` for sandbox tool list428- **Dynamic schema adjustments**: `browser_navigate` strips web_search reference if tools unavailable429430**Async Bridging:**431432- Persistent event loops (not `asyncio.run()`) to prevent "Event loop is closed" errors433- Main thread uses shared loop; worker threads get per-thread loops434- `_run_async()` detects running loop and spins up disposable thread if needed435436---437438### 5.3 Toolset System (toolsets.py)439440Provides flexible tool grouping and composition.441442**Core Toolsets:**443444| Toolset | Tools Included |445| ---------------- | ------------------------------------------------------------------------------------------------ |446| `web` | web_search, web_extract, web_crawl |447| `terminal` | terminal |448| `file` | read_file, write_file, edit_file, list_files, search_files |449| `browser` | browser_navigate, browser_snapshot, browser_click, browser_type, browser_scroll, browser_extract |450| `vision` | analyze_image |451| `image_gen` | generate_image |452| `tts` | text_to_speech |453| `todo` | todo_read, todo_write |454| `memory` | memory_read, memory_write |455| `session_search` | session_search |456| `delegation` | delegate_task |457| `code_execution` | execute_code |458| `cronjob` | create_job, list_jobs, delete_job |459| `messaging` | send_message |460| `homeassistant` | ha_get_states, ha_call_service, ... |461462**Composite Toolsets:**463464- `hermes-cli` — All core tools for CLI platform465- `hermes-telegram`, `hermes-discord`, etc. — Platform-specific tool sets466- `hermes-gateway` — Union of all platform tools467- `debugging` — terminal + file + web468- `safe` — Everything except terminal469470**Resolution:**471472```python473resolve_toolset(name, visited=None) → List[str]474# Recursively resolves toolset to tool names475# Handles composition (includes) and cycle detection476# Special aliases: "all" or "*" = all tools477```478479---480481### 5.4 Tool Registry (tools/registry.py)482483Singleton managing all tool schemas and handlers. Circular-import safe — has no tool dependencies.484485**ToolEntry** (per-tool metadata):486487```python488@dataclass(slots=True)489class ToolEntry:490 name: str491 toolset: str492 schema: dict # OpenAI-format tool definition493 handler: Callable # Sync or async handler function494 check_fn: Callable # Returns True if tool is available495 requires_env: list # Required environment variables496 is_async: bool497 description: str498 emoji: str499```500501**Key Methods:**502503```python504registry.register(name, toolset, schema, handler, check_fn, requires_env)505registry.get_definitions(tool_names, quiet) # Returns filtered schemas506registry.dispatch(name, args, **kwargs) # Execute with async bridging507registry.deregister(name) # Remove (for MCP tool refresh)508registry.check_tool_availability() # Returns (available, unavailable)509```510511---512513### 5.5 Session Database (hermes_state.py)514515SQLite-based persistent session storage with FTS5 full-text search.516517**Schema (v6):**518519```sql520-- Sessions table521sessions (522 id TEXT PRIMARY KEY,523 source TEXT, user_id TEXT, model TEXT, model_config TEXT,524 system_prompt TEXT, parent_session_id TEXT,525 started_at TEXT, ended_at TEXT, end_reason TEXT,526 message_count INTEGER, tool_call_count INTEGER,527 input_tokens INTEGER, output_tokens INTEGER,528 cache_read_tokens INTEGER, cache_write_tokens INTEGER, reasoning_tokens INTEGER,529 estimated_cost_usd REAL, actual_cost_usd REAL,530 title TEXT -- UNIQUE INDEX531)532533-- Messages table534messages (535 id INTEGER PRIMARY KEY AUTOINCREMENT,536 session_id TEXT, role TEXT, content TEXT,537 tool_call_id TEXT, tool_calls TEXT, -- JSON538 tool_name TEXT, timestamp TEXT,539 token_count INTEGER, finish_reason TEXT,540 reasoning TEXT, reasoning_details TEXT, codex_reasoning_items TEXT541)542543-- FTS5 virtual table (auto-synced via triggers)544messages_fts (content)545```546547**Concurrency Model:**548549- WAL (Write-Ahead Logging) for concurrent readers + single writer550- `BEGIN IMMEDIATE` for write transactions (lock at start, not commit)551- Jitter retry on lock: 20-150ms random backoff, max 15 retries552- Periodic WAL checkpoint every 50 writes553554**Key Operations:**555556- `create_session()`, `end_session()`, `reopen_session()`557- `add_message()`, `get_messages()`558- `search_sessions(query)` — FTS5 full-text search559- `update_token_counts()` — Supports both incremental (CLI) and absolute (gateway) modes560561---562563### 5.6 Constants & Home Directory (hermes_constants.py)564565Import-safe constants module with no circular dependencies.566567```python568get_hermes_home() → Path # HERMES_HOME env var or ~/.hermes569display_hermes_home() → str # User-friendly display: "~/.hermes"570get_optional_skills_dir() → Path # HERMES_OPTIONAL_SKILLS env var571parse_reasoning_effort(str) → Dict # "high" → {"enabled": True, "effort": "high"}572573# Key constants574OPENROUTER_BASE_URL = "https://openrouter.ai/api/v1"575NOUS_API_BASE_URL = "https://inference-api.nousresearch.com/v1"576AI_GATEWAY_BASE_URL = "https://ai-gateway.vercel.sh/v1"577VALID_REASONING_EFFORTS = ("xhigh", "high", "medium", "low", "minimal")578```579580---581582## 6. CLI System583584### 6.1 Interactive CLI (cli.py)585586The `HermesCLI` class provides the interactive terminal interface.587588**Features:**589590- **Rich** for banner/panels, **prompt_toolkit** for input with autocomplete591- **KawaiiSpinner** — animated faces during API calls, `┊` activity feed for tool results592- Multiline editing with Shift+Enter593- Slash-command autocomplete594- Session history with up/down arrow navigation595- Clipboard image paste (Alt+V / Ctrl+V)596- Status bar showing model, provider, and token counts597- Inline diff previews for file write/patch operations598599**Configuration Loading:**600601```python602load_cli_config() → dict603# Loads from ~/.hermes/config.yaml (or ./cli-config.yaml fallback)604# Merges with hardcoded defaults605# Expands ${ENV_VAR} references606# Maps terminal config → env vars607```608609---610611### 6.2 CLI Entry Point (hermes_cli/main.py)612613All `hermes` subcommands are dispatched from here:614615```616hermes # Default: interactive chat617hermes chat # Explicit interactive mode618hermes gateway start|stop|status|install|uninstall619hermes setup # Setup wizard620hermes model # Select model/provider621hermes tools # Configure tools622hermes skills # Manage skills623hermes config set|get # Direct config manipulation624hermes cron list|delete # Cron job management625hermes doctor # Diagnose issues626hermes sessions browse # Session picker627hermes profile create|list|switch|delete|export|import628hermes mcp serve|add|remove # MCP management629hermes acp # Start ACP server630hermes update|uninstall|version631```632633**Profile System:**634635- `_apply_profile_override()` runs BEFORE any imports to set `HERMES_HOME`636- Pre-parses `--profile/-p` from argv637- Allows fully isolated agent instances with separate config, memory, sessions, skills638639---640641### 6.3 Configuration System (hermes_cli/config.py)642643**Key Configuration Sections:**644645```yaml646model: "anthropic/claude-opus-4.6" # or dict with provider/base_url/api_key647providers: {} # Provider-specific configs648fallback_providers: [] # Ordered failover list649credential_pool: {} # Multiple API keys per provider650651agent:652 max_turns: 90653 gateway_timeout: 1800654 tool_use_enforcement: "auto"655656terminal:657 backend: "local" # local|docker|modal|daytona|ssh|singularity658 timeout: 180659 persistent_shell: true660 docker_image: "nikolaik/python-nodejs:..."661662compression:663 enabled: true664 threshold: 0.50 # Compress when 50% of context used665 target_ratio: 0.20 # Summary = 20% of compressed content666 protect_last_n: 20667668auxiliary:669 vision: { provider, model }670 web_extract: { provider, model }671 compression: { provider, model }672673memory:674 memory_enabled: true675 provider: "" # "" | "honcho" | "mem0" | etc.676 memory_char_limit: 2200677678display:679 personality: "kawaii"680 show_reasoning: false681 inline_diffs: true682 skin: "default"683 streaming: true684685tts:686 provider: "edge" # edge|elevenlabs|openai|neutts687688stt:689 enabled: true690 provider: "local" # local|groq|openai691692privacy:693 redact_pii: false694695mcp_servers: {} # MCP server configurations696697skills:698 external_dirs: [] # Additional skill directories699700approvals:701 mode: "smart" # smart|always|off702```703704**Config Files:**705706- `~/.hermes/config.yaml` — User settings (authoritative)707- `~/.hermes/.env` — API keys and secrets708- Config version migration system (currently v5)709710---711712### 6.4 Slash Command Registry (hermes_cli/commands.py)713714All slash commands defined centrally in `COMMAND_REGISTRY`:715716```python717CommandDef(name, description, category, aliases, args_hint, cli_only, gateway_only)718```719720**Derived automatically by:**721722- CLI `process_command()` — dispatch on canonical name723- Gateway dispatch + help724- Telegram BotCommand menu725- Slack `/hermes` subcommands726- Autocomplete + help text727728**Key Commands:**729730| Command | Aliases | Description |731| -------------- | ---------- | ----------------------------- |732| `/new` | `/reset` | Start fresh conversation |733| `/model` | | Show/switch model |734| `/personality` | | Set agent personality |735| `/retry` | | Retry last turn |736| `/undo` | | Remove last turn |737| `/compress` | `/compact` | Compress context |738| `/usage` | `/cost` | Show token usage |739| `/insights` | | Usage analytics |740| `/skills` | | Browse/install skills |741| `/background` | `/bg` | Manage background processes |742| `/plan` | | Generate implementation plan |743| `/rollback` | | Restore filesystem checkpoint |744| `/verbose` | | Toggle debug output |745| `/reasoning` | | Set reasoning effort |746| `/yolo` | | Toggle approval bypass |747| `/btw` | | Ephemeral side question |748| `/stop` | | Kill current agent run |749| `/queue` | | Queue next prompt |750| `/browser` | | Interactive browser session |751| `/history` | `/resume` | Session browser |752| `/skin` | | Switch CLI theme |753754---755756### 6.5 Setup Wizard (hermes_cli/setup.py)757758Modular interactive wizard with independent sections:7597601. **Model & Provider** — Select AI provider, enter API keys, choose model7612. **Terminal Backend** — Choose execution environment7623. **Agent Settings** — Max iterations, compression, session policies7634. **Messaging Platforms** — Configure Telegram, Discord, Slack, etc.7645. **Tools** — TTS, STT, web search, image generation, browser765766Features:767768- Live credential validation769- Real-time model list fetching from provider APIs770- Automatic OpenClaw migration detection771- Atomic config file writes772773---774775### 6.6 Model Catalog (hermes_cli/models.py)776777Provider-specific model lists:778779```python780_PROVIDER_MODELS = {781 "nous": ["anthropic/claude-opus-4.6", "anthropic/claude-sonnet-4.6", ...], # 25+782 "openrouter": ["anthropic/claude-opus-4.6", "google/gemini-3-flash", ...], # 30+783 "anthropic": ["claude-opus-4-6", "claude-sonnet-4-6", ...],784 "openai": ["gpt-5", "gpt-5.4-mini", "gpt-4.1", "gpt-4o", ...],785 "copilot": ["gpt-5.4", "gpt-5.4-mini", "gpt-5.3-codex", ...],786 "huggingface": [...],787 "minimax": [...],788 "kimi-coding": [...],789 "alibaba": [...],790 "deepseek": [...],791 # ... more providers792}793```794795Features:796797- Dynamic fetching via provider `/models` endpoints798- Curated lists used when live probe returns fewer models799- Fuzzy matching for typo correction800- Validation against provider catalog801802---803804### 6.7 Skin/Theme Engine (hermes_cli/skin_engine.py)805806Data-driven CLI visual customization — no code changes needed.807808**Customizable Elements:**809810| Element | Key | Used By |811| -------------------------------- | ------------------------ | ----------------- |812| Banner border/title/accent | `colors.*` | banner.py |813| Response box border | `colors.response_border` | cli.py |814| Spinner faces (waiting/thinking) | `spinner.*` | display.py |815| Spinner verbs/wings | `spinner.*` | display.py |816| Tool output prefix | `tool_prefix` | display.py |817| Per-tool emojis | `tool_emojis` | display.py |818| Agent name/welcome/prompt | `branding.*` | banner.py, cli.py |819820**Built-in Skins:** default, ares, mono, slate, poseidon, sisyphus, charizard821822**User Skins:** Drop `~/.hermes/skins/<name>.yaml` and activate with `/skin <name>`823824---825826## 7. Tool System827828### 7.1 Terminal Tool (tools/terminal_tool.py)829830Shell command execution across multiple backends.831832```python833def terminal_tool(834 command: str,835 background: bool = False,836 timeout: Optional[int] = None,837 task_id: Optional[str] = None,838 force: bool = False, # Skip approval for dangerous commands839 workdir: Optional[str] = None,840 check_interval: Optional[int] = None, # Background task polling841 pty: bool = False,842) -> str # JSON result843```844845**Features:**846847- Multi-backend: Selects based on `TERMINAL_ENV` (local/docker/ssh/modal/daytona/singularity)848- Per-task_id sandboxes with thread-safe creation locks849- Dangerous command routing through approval system850- Background task support with file-based IPC851- Interrupt handling — polls `is_interrupted()` during execution852- Auto-cleanup daemon thread for idle environments (>300s)853- Disk usage warnings at configurable threshold854855---856857### 7.2 File Tools (tools/file_tools.py)858859Safe file operations with size guards and sensitive path protection.860861- `read_file_tool(path, offset, limit)` — Read with pagination (default 100K char limit)862- `write_file_tool(path, content)` — Write with approval for sensitive paths863- `edit_file_tool(path, old_text, new_text)` — String replacement editing864- `list_files_tool(path)` — Directory listing865- `search_files_tool(pattern, path)` — Glob/regex file search866867**Safety:**868869- Device path blocklist (`/dev/zero`, `/dev/stdin`, etc.)870- Read dedup tracking — returns stub on re-read if mtime unchanged871- Sensitive path blocking: `/etc/`, `/boot/`, `~/.ssh` without approval872- Prompt injection protection for known dangerous paths873874---875876### 7.3 Web Tools (tools/web_tools.py)877878Web search and content extraction.879880- `web_search_tool(query, limit)` — Search via configurable backend881- `web_extract_tool(urls, format)` — Extract content from URLs882- `web_crawl_tool(url, ins883884…(truncated)