---
name: hermes-startup-fix
description: "Diagnose and fix slow Hermes startup or runtime lag."
version: 1.1.0
author: Hermes Agent
license: MIT
platforms: [linux, macos, windows]
metadata:
  hermes:
    tags: [hermes, performance, startup, latency, profiling, optimization]
    related_skills: [hermes-agent, systematic-debugging]
---

# Hermes Performance

## When to Use

- Hermes CLI (`hermes chat`, `hermes`) or gateway takes more than ~3 seconds to become interactive.
- Any Hermes surface (CLI, TUI, desktop) feels sluggish or hangs on first turn.
- You are behind a firewall, in mainland China, or on a slow network and suspect timeouts.
- User reports "hermes 启动很慢" or "hermes 启动效果" issues.

## Diagnostic Report Format (from real-world troubleshooting)

When diagnosing Hermes startup issues, follow this structured report format:

1. **问题描述** — 精确描述现象和量化基准（如 "hermes chat -q 平均耗时 ~20 秒"）
2. **排查方法与步骤** — 表格列出每步操作和目的
3. **根因分析（带证据）** — Profiler 输出 + 网络测试 + 源码分析
4. **解决方案** — 具体操作命令和文件内容
5. **效果验证** — 修复前后对比表格（指标 / 修复前 / 修复后 / 提升）
6. **剩余瓶颈说明** — 无法消除的开销及性质说明
7. **附注** — hermes doctor 等额外发现

## Quick Diagnosis

### 1. Measure total startup time

```bash
time hermes chat -q "hello" 2>&1 | tail -5
```

- **< 3 s**: Normal for a warm Python import on SSD.
- **3–8 s**: Acceptable on Windows / HDD / many skills loaded.
- **> 8 s**: Investigate; likely a blocking network call or heavy import chain.
- **> 15 s**: Almost certainly a network timeout or misconfiguration.

### 2. Profile the startup path

```bash
# Linux / macOS
python -m cProfile -o /tmp/hermes.prof -m hermes_cli.main chat -q "hi"
python -c "
import pstats
p = pstats.Stats('/tmp/hermes.prof')
p.sort_stats('cumtime')
p.print_stats(30)
"

# Windows (Git Bash)
python -m cProfile -o C:/Users/$USER/hermes.prof -m hermes_cli.main chat -q "hi"
python -c "
import pstats
p = pstats.Stats('C:/Users/$USER/hermes.prof')
p.sort_stats('cumtime')
p.print_stats(30)
"
```

Look at the top cumulative-time entries. Common culprits:

| Symptom | Likely cause | Fix |
|---|---|---|
| `socket.connect` dominates | Network timeout (models.dev, OpenRouter, provider endpoint unreachable) | See **Network Timeouts** below |
| `io.open` dominates (500+ calls, several seconds) | Antivirus / Windows Defender scanning every file open | See **Windows Defender / Antivirus** below |
| `importlib._bootstrap` dominates | Cold Python import cache | Pre-compile with `python -m compileall`, or warm cache by running once |
| `threading.lock acquire` dominates | Background threads (MCP discovery, model metadata fetch) blocked on network | Same as socket timeouts |
| `mcp_startup.py` dominates | MCP server discovery slow or hanging | Disable MCP or reduce timeout |

### 3. Check `hermes doctor`

```bash
hermes doctor
```

Flags stale config keys, missing credentials, and database issues that can add latency.

## Network Timeouts (most common cause of >10 s startup)

### The `models.dev` fetch

Hermes calls `https://models.dev/api.json` on every cold start to resolve provider metadata. If this domain is unreachable (firewall, mainland China, DNS failure), the request times out after **5 s connect + 10 s read = up to 15 s of dead wait**.

**Profiler signature:**
```
_fetch_models_dev_from_network   10.025
requests.get                      10.025
urllib3.connectionpool.urlopen    10.025
socket.connect                    10.004
```

**Workaround — create a local disk cache:**

1. Locate your Hermes home directory (where `config.yaml` lives):
   ```bash
   # Usually one of:
   ~/.hermes/                              # Linux / macOS
   ~/AppData/Local/hermes/                 # Windows
   $HERMES_HOME/                           # if env var set
   ```

2. Create `models_dev_cache.json` with at least the providers you use. See `references/models_dev_cache_template.json` for a starter file. Common providers to include:
   - kimi-for-coding, openai, anthropic, deepseek, openrouter, google, xai, alibaba, fireworks-ai
   - Each entry needs: name, env variable name, API endpoint, etc.

3. **Critical:** the file must be **valid JSON and non-empty** — an empty `{}` is treated as a missing cache and the network fetch still runs.

4. Verify network connectivity is the issue:
   ```bash
   curl -m 8 https://models.dev/api.json
   # exit=28 (connection timeout) confirms the domain is unreachable
   ```

5. Verify the fix:
   ```bash
   time hermes chat -q "hi"
   ```
   Startup should drop from ~20 s to ~7–10 s on Windows.

### Other network timeouts

- **OpenRouter model metadata pre-warm** (`agent/agent_init.py:746`): only fires when provider is `openrouter`. Switch provider or set `OPENROUTER_API_KEY` with good connectivity.
- **MCP discovery** (`hermes_cli/mcp_startup.py`): waits up to 1.5 s (interactive) or 15 s (`chat -q`) for MCP servers to register. If no MCP servers are configured, this is usually fast. To skip: `hermes chat -q --ignore-rules "..."` (also skips context-file injection).

## Reducing Python Import Overhead

On Windows with many skills, Python cold-import of `pydantic`, `mcp`, `openai`, etc. can take 3–4 s.

- **Pre-compile bytecode:**
  ```bash
  python -m compileall $HERMES_HOME/hermes-agent/agent
  python -m compileall $HERMES_HOME/hermes-agent/hermes_cli
  ```
- **Use `--ignore-rules`** to skip loading `AGENTS.md`, `SOUL.md`, and context files (saves a small amount of file I/O).

## Windows Defender / Antivirus (common on Windows, 3–8 s overhead)

Windows Defender (or other antivirus) real-time protection scans every file open. Hermes imports ~2000+ Python files at startup; with Defender active, `io.open` can consume **5+ seconds** on 500–950 file-open calls. This is the most common cause of 7–10 s startup on Windows after network timeouts are resolved.

**Profiler signature:**
```
io.open                            5.000    950 calls
_imp.create_dynamic                0.910
nt.stat                            0.370   18181 calls
```
High `nt.stat` counts confirm the OS is querying file metadata for every import.

**Check if Defender is active:**
```powershell
Get-MpPreference | Select-Object -ExpandProperty DisableRealtimeMonitoring
# False = protection is ON (scanning files)
```

**Fix — add exclusion (requires admin PowerShell):**
```powershell
Add-MpExclusion -Path "C:\Users\<you>\AppData\Local\hermes"
Add-MpExclusion -Path "C:\Users\<you>\AppData\Roaming\uv\python\cpython-3.11-windows-x86_64-none"
```

Or manually: Windows Security → Virus & threat protection → Manage settings → scroll to Exclusions → Add folder.

**Expected improvement:** 7–10 s → 2–3 s on Windows.

**Counter-intuitive finding:** Disabling bytecode compilation (`python -B` or `PYTHONDONTWRITEBYTECODE=1`) can be *slightly faster* when Defender is active, because reading `.pyc` files also triggers scanning, and `.py` reads may benefit from OS file-cache warmth. This is not a real optimization — just an observation that confirms Defender is the bottleneck, not cold bytecode.

## Remaining Bottlenecks (post-fix)

After fixing network timeouts, remaining 7–10 s startup on Windows is normal overhead:

| 阶段 | 耗时 | 性质 |
|------|------|------|
| Python 模块导入（pydantic、mcp、openai 等） | ~3-4 秒 | Windows 上大型库导入的正常开销 |
| 线程同步/锁等待 | ~2.5-4 秒 | import 锁 + MCP 发现等待 |
| Agent 初始化（SQLite session store、OpenAI client） | ~2-3 秒 | 必要初始化 |

These are framework-level overheads that cannot be eliminated through simple configuration.

## Pitfalls

1. **Empty `{}` cache is ignored.** `fetch_models_dev()` checks `if not data:` after `json.load`, so `{}` falls through to the network path.
2. **Cache path depends on `get_hermes_home()`.** On Windows this is `~/AppData/Local/hermes/`, not `~/.hermes/`. Always verify with `hermes config edit --dry-run` or `hermes config path`.
3. **The `provider` config key is deprecated.** `hermes config set provider X` saves at root level; `hermes doctor` warns it should be under `model:`. Use `hermes config set model.provider X` instead.
4. **Profiling inside the active Hermes session is unreliable.** The session's own agent loop competes with the profiled subprocess. Always profile from a fresh shell.
5. **Windows Defender creates a "second wave" of slowness.** After fixing network timeouts, you may still see 7–10 s startup. Check `io.open` call count in the profiler — if >500 calls with >3 s total, Defender is the bottleneck. The profiler will show `io.open` at the top of `tottime`, not `cumtime`, because the time is spent in the OS/AV layer, not in Python.
6. **`-m cProfile` on Windows with `-c` flag fails.** Use a wrapper script (`write_file` + `python script.py`) instead of `-c` inline code. The `-c` flag is not supported by `cProfile.py` on Windows.
7. **Stale config key warning from `hermes doctor`.** If you see `⚠ Stale root-level config keys: provider (should be under 'model:' section)`, the correct fix is:
   ```bash
   hermes config set model.provider kimi-coding-cn
   ```
   NOT `hermes config set provider ...` — the old root-level key is deprecated.
8. **Desktop app "对话不可用" = Gateway not running.** The Desktop app (`hermes desktop`) requires the Gateway to be running. If the user reports the Desktop shows "对话不可用" or similar, run `hermes gateway status` to confirm. Fix: `hermes gateway run` (foreground) or `hermes gateway install` (auto-start). On Windows, `gateway install` may prompt for UAC elevation; if skipped, it falls back to the Startup folder method (`Hermes_Gateway.vbs` in `shell:startup`).

## Verification Checklist

- [ ] `time hermes chat -q "hi"` reports < 10 s (Windows) or < 5 s (Linux/macOS)
- [ ] `models_dev_cache.json` exists in the Hermes home directory
- [ ] `hermes doctor` reports no stale config keys
- [ ] Profiler no longer shows `socket.connect` in top 10 cumulative time entries
- [ ] On Windows: `io.open` call count < 500 in profiler (if >500, add Defender exclusion)
- [ ] On Windows: `Get-MpPreference | Select DisableRealtimeMonitoring` — if False, consider adding hermes to exclusions