# Hermes Self Repair

> Fix broken Hermes updates, desktop rebuilds, and settings.

- Skill: `wcpaka-lgtm/hermes-self-repair` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add wcpaka-lgtm/hermes-self-repair`
- Raw SKILL.md: https://api.skillmd.com/api/skills/wcpaka-lgtm/hermes-self-repair/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- License: MIT
- Author: wcpaka-lgtm (https://skillmd.com/u/wcpaka-lgtm)
- Updated: 2026-09-21
- Page: https://skillmd.com/skills/wcpaka-lgtm/hermes-self-repair

---


# Hermes Self-Repair

Diagnose and fix a broken or stuck Hermes installation itself — failed/partial
updates, desktop app rebuilds, gateway not restarting, and provider config
rejections (HTTP 400 on model params). This is about repairing the tool; for
normal usage/configuration questions use the bundled `hermes-agent` skill.

## When to Use

- `hermes update` fails partway, hangs, or leaves the version stale.
- Desktop app (Electron) fails to rebuild after an update (`EBADENGINE`,
  `✗ Desktop dependency install failed`, or stamp says build needed but exe is old).
- Gateway doesn't come back after an update; sessions error on provider params.
- User reports "update keeps failing" from the desktop app's update button.
- User reports a desktop UI feature "missing" after an update — check
  hidden-by-state chrome before assuming a regression.

## Diagnosis First

Logs tell you which stage failed — read them before retrying anything:

```bash
# $LOCALAPPDATA/hermes/logs/ on Windows (Linux/macOS: ~/.hermes/logs/)
update.log        # per-stage update results; grep for "✗", "error", "fail"
desktop.log       # desktop updater: "[updates] venv-blocked", "Update aborted"
errors.log        # agent/runtime errors with tracebacks
gui.log           # desktop backend boot
```

Quick health snapshot:
```bash
hermes --version        # current version + "update available" line
hermes version          # "Up to date" confirmation
hermes gateway status   # gateway process detected?
```

## Windows Update Pitfalls

- **npm EBADENGINE on desktop build**: the repo's `package.json` engines block a
  gap range, e.g. `"npm": "<11.10.0 || >=11.17.0"` — npm versions *inside* the
  gap (11.10–11.16) fail with "Not compatible with your version of node/npm".
  Fix: `npm install -g npm@12` (or any version in an accepted range), then retry.
  Verify the accepted range from the repo `package.json` before choosing a version.
- **venv-blocked**: `desktop.log` shows
  `[updates] venv-blocked: N process(es) hold the install` /
  `Update aborted: another Hermes process is using this installation`.
  Any running Hermes process locks the venv on Windows. Run updates from a
  plain terminal with the desktop app closed, or use `hermes update --force`.
- **venv-blocked that survives gateway restarts (long-path truncation bug)**:
  if the reported holder is a `python.exe` whose path shows a *truncated*
  cmdline (e.g. ends mid-token at `...cpython-3.1`) and is the managed-runtime
  half of a gateway (`.hermes-runtime\python\generation-*\...\python.exe -m
  hermes_cli.main gateway run`), the pausable-gateway exemption fails because
  `_detect_venv_python_processes()` in `hermes_cli/update_cmd.py` truncates
  cmdlines to 120 chars (`cmdline_raw[:120]`) — the `gateway run` tokens land
  past the cut, so the preflight scan reports it as a hard blocker and the
  Desktop update aborts every time while the (auto-started, e.g. Startup
  folder `.vbs`) gateway runs. Fix: return the full `cmdline_raw` from the
  detector (truncate only in `_format_venv_python_holders_message` display).
  Regression test:
  `tests/hermes_cli/test_update_venv_health.py::test_detect_venv_python_keeps_full_cmdline_for_gateway_classification`.
  The updater's autostash (`_stash_local_changes_if_needed` / `_restore_stashed_changes`)
  carries local patches across `hermes update`.
- **Update killed mid-way by your own timeout**: a partial update leaves core
  upgraded (e.g. 0.19.1 → 0.20.0 done) but later stages (desktop rebuild,
  gateway restart) unfinished. Re-run `hermes update` — it prints
  `✓ Already up to date!` and completes the remaining stages (launcher refresh,
  gateway restart). Don't assume failure from an interrupted run.
- Long builds exceed foreground command limits: run `hermes update` or rebuilds
  with `terminal(background=true, notify_on_complete=true)`.

## Desktop App Rebuild Must Be Detached

**The trap**: `hermes desktop --build-only` stops running desktop instances
during packaging (`⚠ Stopped running desktop app to free the build output`).
If you launch it from inside the desktop app's own agent session, the agent's
process dies with the app and the build dies mid-npm-install. The process list
goes empty with no error and the old exe/stamp stays in place.

**Verified fix (Windows)** — detach via a scheduled task so it survives the
app restart (full script in `scripts/rebuild-desktop.bat`):

1. Write a bat that cd's to the install dir, runs
   `venv\Scripts\hermes.exe desktop --build-only` redirecting output to
   `logs/desktop-rebuild.log`, appends a `rebuild-finished exit=%ERRORLEVEL%`
   line, and self-deletes the task.
2. Register and fire it:
   ```
   schtasks /Create /TN "HermesDesktopRebuild" /TR "\"<path>\rebuild-desktop.bat\"" /SC ONCE /ST 23:59 /F
   schtasks /Run /TN "HermesDesktopRebuild"
   ```
3. Poll `logs/desktop-rebuild.log` until the `rebuild-finished` line appears
   (npm install + vite + electron-builder takes several minutes; the app window
   WILL close during packaging — warn the user first).

**Verification** (do not trust "it ran"):
```python
from hermes_cli.main import _desktop_build_needed, _desktop_packaged_executable
print(_desktop_build_needed(Path('apps/desktop'), Path('.').resolve(), source_mode=False))  # want False
print(_desktop_packaged_executable(Path('apps/desktop')))  # exe mtime should be fresh
```
The stamp at `$LOCALAPPDATA/hermes/desktop-build-stamp.json` (`builtAt`) should
also be current. Note `_desktop_build_needed` lives in `hermes_cli/main.py`,
not `hermes_cli/update_cmd.py`.

## reasoning_effort HTTP 400 (Config Rejection Class)

Symptom: new sessions fail immediately with
`HTTP 400 ... 'reasoning_effort' must be one of: 'none', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max'`
while older/existing sessions keep working.

Root-cause class: **effort-level pass-through vs. conversion**. Hermes converts
non-wire levels per adapter — Anthropic maps `ultra`→budgeted `max`, gpt-5.6 maps
`ultra`→`max`, Gemini clamps to `low/medium/high` — but the **custom provider
profile passes effort verbatim** as top-level `reasoning_effort`
(`plugins/model-providers/custom/__init__.py`). Any endpoint that doesn't accept
the level (qwen/token-plan DashScope accepts only `none…max`) rejects with 400.

Why only NEW sessions fail: config is read at session start and frozen for the
conversation (prompt caching) — open sessions keep the old value; the first
fresh session transmits the bad value. So "it broke on new session" points at a
config value, not the update itself.

Fix: check `agent.reasoning_effort` in `~/.hermes/config.yaml` against the
allowed list the error message itself prints; for qwen/alibaba endpoints use
`max` or below (`hermes config set agent.reasoning_effort max` in a foreground
session). Generalization: when ANY provider rejects a model param with an enum
error, compare the config value to the printed allowed set, and check whether
the provider plugin converts the value or passes it through.

## Desktop Feature "Missing" After an Update

Users often report UI features "disappeared" after an update. Before
assuming a regression, check whether the feature is **hidden-by-state**:
the desktop app hides chrome whenever the state that drives it is empty.

**Session tabs (browser-like tab bar)** are the recurring case. The tab
strip in the main zone only renders once at least one session is open as
a tab; after an app restart the window boots to a single main chat and
the strip is invisible, so the user concludes tabs were removed. The
feature is intact — restore with: session row ⋯ menu → **"Open in new
tab"**, **Ctrl+T** (fresh session as tab), or the **+** button on the
strip. Keybinds: Ctrl+Tab cycle, Ctrl+1–9 jump, Ctrl+W close. Full
walkthrough + verification via computer_use:
`references/desktop-session-tabs.md`.

## Verification

- `hermes version` → "Up to date"; `hermes gateway status` → process running.
- After desktop rebuild: stamp `builtAt` fresh, `_desktop_build_needed` False,
  new `Hermes.exe` mtime, app relaunches on the new build.
- After config fix: user opens a new session without the 400.

