Add all 104 active skills from all 16 Hermes profiles
12 unversioned skills now versioned at 1.0.0: agent-communication, ascii-video, external-reasoning-augmentation, jotty-notes-api, minecraft-modpack-server, obsidian, pokemon-player, powerpoint, social-search, songwriting-and-ai-music, workspace-context-organization, youtube-content Total repo: 141 skills across all profile scopes
This commit is contained in:
339
hermes-webui-docker/SKILL.md
Normal file
339
hermes-webui-docker/SKILL.md
Normal file
@@ -0,0 +1,339 @@
|
||||
---
|
||||
name: hermes-webui-docker
|
||||
description: "Deploy and troubleshoot Hermes WebUI inside Docker containers — volume mounts, agent source resolution, compose wiring, and the 'AIAgent not available' failure path."
|
||||
version: 1.0.0
|
||||
author: Hermes Agent
|
||||
platforms: [linux, macos]
|
||||
metadata:
|
||||
hermes:
|
||||
tags: [hermes, webui, docker, deployment, troubleshooting]
|
||||
related_skills: [hermes-agent, lxc-container-gpu-tools]
|
||||
---
|
||||
|
||||
# Hermes WebUI Docker Deployment
|
||||
|
||||
Deploy and troubleshoot Hermes WebUI inside Docker containers. Covers volume mounts, agent source resolution, compose wiring, and the common "AIAgent not available" failure.
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
# Basic single-container (uses host ~/.hermes and ~/workspace)
|
||||
cd /path/to/hermes-webui
|
||||
docker compose up -d
|
||||
# Open http://localhost:8787
|
||||
```
|
||||
|
||||
## Key Volumes
|
||||
|
||||
| Host mount | Container mount | Purpose |
|
||||
|-----------|----------------|---------|
|
||||
| `~/.hermes` | `/home/hermeswebui/.hermes` | Config, sessions, state |
|
||||
| `~/workspace` | `/workspace` | Filesystem browser |
|
||||
| `~/.hermes/hermes-agent` | `/opt/hermes` | **Agent source code** (build + import dependency) |
|
||||
|
||||
## Why `/opt/hermes` is required
|
||||
|
||||
The WebUI container installs Hermes Agent at startup via `uv pip install /opt/hermes` (`docker_init.bash` line 347). Without this mount, the container has no hermes-agent code on `PYTHONPATH`.
|
||||
|
||||
At runtime the WebUI calls `from run_agent import AIAgent`. The startup script resolves the agent directory from `sys.path`; it copies the agent source from whichever path it finds into `/app/` and installs it into `/app/venv`, so `run_agent.py` is importable by the server Python.
|
||||
|
||||
## Common Failure: "AIAgent not available -- check that hermes-agent is on sys.path"
|
||||
|
||||
### Root causes
|
||||
|
||||
1. **Agent source not mounted into container** — the most common cause with a custom or adjusted `docker-compose.yml`.
|
||||
2. **Wrong profile path as HERMES_HOME** — if your HERMES_HOME is `~/.hermes/profiles/telegram`, the agent source at `~/.hermes/hermes-agent` is outside that mount and invisible inside the container.
|
||||
3. **Mount path mismatch** — the init script expects either `/home/hermeswebui/.hermes/hermes-agent` or `/opt/hermes`.
|
||||
|
||||
### Diagnostic commands
|
||||
|
||||
```bash
|
||||
# Is the container even importing the agent?
|
||||
docker exec hermes-webui /app/venv/bin/python -c "from run_agent import AIAgent; print('OK')"
|
||||
|
||||
# Where did the init script find the agent source?
|
||||
docker logs hermes-webui | grep -iE "agent dir|hermes-agent"
|
||||
|
||||
# Verify the mount exists in the container
|
||||
docker exec hermes-webui ls /opt/hermes/agent/__init__.py
|
||||
```
|
||||
|
||||
### Fix: docker-compose.yml
|
||||
|
||||
Add the agent source volume mount and set the environment variable so the WebUI bootstrap can locate it:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
hermes-webui:
|
||||
volumes:
|
||||
- ${HERMES_HOME:-${HOME}/.hermes}:/home/hermeswebui/.hermes
|
||||
- ${HERMES_WORKSPACE:-${HOME}/workspace}:/workspace
|
||||
- ${HERMES_AGENT_SRC:-${HOME}/.hermes/hermes-agent}:/opt/hermes # <-- REQUIRED
|
||||
environment:
|
||||
- HERMES_WEBUI_AGENT_DIR=/opt/hermes # <-- REQUIRED
|
||||
```
|
||||
|
||||
Then recreate:
|
||||
```bash
|
||||
cd /path/to/hermes-webui
|
||||
docker compose down
|
||||
docker compose up -d --force-recreate
|
||||
```
|
||||
|
||||
### Troubleshooting: WebUI starts but agent dir is "NOT FOUND"
|
||||
|
||||
Check startup log lines after "== Running hermes-webui". You want:
|
||||
```
|
||||
agent dir : /opt/hermes [ok]
|
||||
```
|
||||
|
||||
If you see:
|
||||
```
|
||||
agent dir : NOT FOUND [XX]
|
||||
```
|
||||
|
||||
Either the volume didn't mount, or `HERMES_WEBUI_AGENT_DIR` isn't pointing at it. Possible order-of-operations pitfall: if you change `docker-compose.yml` environment lines and do `docker restart` (not recreate), Docker may cache the old env. Always use `--force-recreate` after compose changes.
|
||||
|
||||
### Pitfall: `providers: {}` Docker artifact in profile configs
|
||||
|
||||
Docker WebUI containers sometimes write `providers: {}` into profile config.yaml files. This is the write-only bug — the key is empty and useless. The correct provider config lives in `custom_providers:` list and `model.provider`. During cleanup after a mount fix, delete this key from all affected configs.
|
||||
|
||||
### Pitfall: Stale sticky default after mount fix
|
||||
|
||||
When the WebUI container's profiles were copied to the local filesystem during a mount fix, `~/.hermes/active_profile` may point to a Docker-origin profile (e.g., `telegram`). Running plain `hermes` then targets that profile instead of the intended CLI profile. Fix: `hermes profile use general` or `hermes profile use default`.
|
||||
|
||||
### Full cleanup after Docker WebUI decommission
|
||||
|
||||
See `references/webui-removal-checklist.md` for the complete 8-section teardown checklist covering: inventory, pre-removal backups, container stop, Docker artifact removal, host source tree deletion, WebUI state cleanup inside bind mounts (global + per-profile `webui/` dirs, `state-snapshots/`, `providers: {}` config artifacts), explicit "DO NOT REMOVE" section for shared CLI paths, post-removal verification, and a copy-paste block for steps 2–5.
|
||||
|
||||
Quick summary of the most commonly missed items:
|
||||
1. Dangling `<none>` image layers from rebuilds (`docker image prune -f`)
|
||||
2. Per-profile `webui/` state dirs (not just the global `~/.hermes/webui/`)
|
||||
3. `providers: {}` empty-key lines in profile configs (Docker write-only artifact)
|
||||
4. `state-snapshots/` dirs at both `~/.hermes/` and `~/.hermes/profiles/<name>/`
|
||||
5. The `.env` file in the source tree contains `HERMES_WEBUI_PASSWORD` in plaintext — delete with the source tree, don't echo it
|
||||
|
||||
- `/opt/hermes` must be writable during init — the init script copies source into `/app`, installs into `/app/venv`, and `chown`s to the container user. Do **not** use `:ro` for this mount unless the build already happens at image-build time.
|
||||
- The `WANTED_UID`/`WANTED_GID` numeric values must match the filesystem owner of your bind mounts. When using profiles (e.g. `HERMES_HOME=~/.hermes/profiles/telegram`), the UID/GID of the host user must match what the container remaps to.
|
||||
|
||||
## Common Failure: Stale model dropdown (wrong models, old names, missing aliases)
|
||||
|
||||
The WebUI model selector reads `models_cache.json` from the profile's webui directory. When this cache is stale, the dropdown shows wrong models, raw technical IDs instead of friendly alias names, or models from a previous configuration.
|
||||
|
||||
### Root causes
|
||||
|
||||
1. **Fingerprint points to container path** — the cache's `_source_fingerprint.config_yaml.path` is `/home/hermeswebui/.hermes/config.yaml` (Docker-internal) instead of the actual host config path. The WebUI can't detect config changes and never regenerates.
|
||||
2. **Raw model IDs as labels** — the cache shows `kimi-k2.6:cloud` instead of the alias `kimi`. The WebUI doesn't auto-resolve `model_aliases` from config.yaml.
|
||||
3. **Missing badges** — no "Primary" or "Recommended" indicators on model groups, so users can't tell which model is the default.
|
||||
4. **`custom_providers` with `discover_models: true` not probed for live models** — `get_available_models()` in `/app/api/config.py` only probes `model.base_url` (the active provider) for live `/v1/models`. It never probes each `custom_provider`'s `base_url`, even when `discover_models: true` is set. The Ollama group shows only the static models from config.yaml, missing any models added since the config was last edited. See `references/custom-provider-live-discovery.md` for the code fix.
|
||||
|
||||
### Fix: rebuild models_cache.json
|
||||
|
||||
Delete the stale cache and rebuild it from the actual config:
|
||||
|
||||
```bash
|
||||
# Remove stale cache
|
||||
rm -f ~/.hermes/profiles/<profile>/webui/models_cache.json
|
||||
|
||||
# Rebuild from config.yaml (see hermes-agent skill reference: config-model-change-cleanup.md)
|
||||
# Key steps:
|
||||
# 1. Read config.yaml → custom_providers (group by name), model_aliases (map model→alias)
|
||||
# 2. Build groups with alias names as labels, raw model IDs as ids
|
||||
# 3. Set active_provider/default_model from model.default/model.provider
|
||||
# 4. Add badges: "primary" for default, "recommended" for smart_model_routing.cheap_model
|
||||
# 5. Set fingerprint to the actual host config path (not /home/hermeswebui/)
|
||||
|
||||
# Restart WebUI to pick up the new cache
|
||||
docker restart hermes-webui
|
||||
```
|
||||
|
||||
### Verification
|
||||
|
||||
```bash
|
||||
# Check the cache inside the container
|
||||
docker exec hermes-webui cat /home/hermeswebui/.hermes/profiles/<profile>/webui/models_cache.json | python3 -m json.tool | head -30
|
||||
|
||||
# Verify fingerprint path is the host path, not /home/hermeswebui/
|
||||
# Verify groups show alias names (kimi, deep, glm) not raw IDs
|
||||
# Verify badges include "primary" and "recommended" entries
|
||||
```
|
||||
|
||||
### Pitfall: host config edits vs WebUI dropdown cache
|
||||
|
||||
The WebUI bind-mounts `~/.hermes` from the host, so config.yaml changes are live **for the CLI picker and any code reading the config directly inside the container** — `docker exec hermes-webui grep discover_models /home/hermeswebui/.hermes/config.yaml` will reflect the host edit instantly. No container restart needed for `discover_models` flips or new `custom_providers` entries.
|
||||
|
||||
**However**, the WebUI's chat-page model dropdown reads a *separate* cache file: `~/.hermes/profiles/<profile>/webui/models_cache.json` (also mounted into the container). That file is generated once and fingerprinted; the WebUI only regenerates it when the host config path's mtime changes via the cache's own invalidation logic. If the dropdown still shows the old static list after you bulk-edited configs:
|
||||
|
||||
1. Delete the cache: `rm -f ~/.hermes/profiles/<profile>/webui/models_cache.json` (and equivalents in any other profile the WebUI uses)
|
||||
2. Hit the WebUI's model-list endpoint (or just open the dropdown) to trigger a rebuild
|
||||
3. Verify the new cache shows live-discovered models: `docker exec hermes-webui cat /home/hermeswebui/.hermes/profiles/<profile>/webui/models_cache.json | python3 -c 'import sys,json; d=json.load(sys.stdin); print([m["id"] for g in d.get("groups",[]) for m in g.get("models",[])][:20])'`
|
||||
|
||||
If `discover_models: true` is set and the dropdown still shows the old static 6, the cache is stale — not the config.
|
||||
|
||||
## Hindsight Memory in WebUI (canonical)
|
||||
|
||||
The canonical memory provider for all 20 Hermes profiles is **Hindsight** (since 2026-06-29). It runs against a local daemon (Qdrant for storage at 10.0.0.22:6333 + vLLM for LLM at 10.0.0.26:8000) and requires no per-container install — the host's `~/.hermes/hindsight/config.json` is read directly.
|
||||
|
||||
### Requirements
|
||||
|
||||
- `~/.hermes/hindsight/config.json` exists (single file shared by all profiles)
|
||||
- `memory.provider: hindsight` in the profile's `config.yaml`
|
||||
- vLLM reachable from host and any WebUI containers: `curl http://10.0.0.26:8000/v1/models`
|
||||
- Qdrant reachable: `curl http://10.0.0.22:6333/collections/memories` should report ~24K points
|
||||
|
||||
### Common Failure: Hindsight tools not appearing
|
||||
|
||||
**Root cause**: The Hindsight daemon isn't running, OR `~/.hermes/hindsight/config.json` is missing/malformed, OR vLLM at 10.0.0.26:8000 is unreachable. Check the daemon log and verify all three endpoints from the host and from the WebUI container (`docker exec hermes-webui curl ...`).
|
||||
|
||||
**Fix**: See `references/hindsight-setup-verification.md` (when it exists) for the full troubleshooting playbook. For now, verify:
|
||||
1. `cat ~/.hermes/hindsight/config.json` returns valid JSON with `bank_id: hermes`
|
||||
2. `curl http://10.0.0.26:8000/v1/models` lists at least one model
|
||||
3. `curl http://10.0.0.22:6333/collections/memories` returns points_count > 20000
|
||||
|
||||
Then `/reset` or start a new session — memory provider loads at session start.
|
||||
|
||||
### Profile replication for Hindsight
|
||||
|
||||
Hindsight config is a single file (`~/.hermes/hindsight/config.json`) shared by all profiles. There is **no per-profile replication needed** — each profile just needs `memory.provider: hindsight` in its `config.yaml`. See `devops/hermes-config-bulk-update/references/memory-provider-switch.md` for the bulk-migration playbook.
|
||||
|
||||
---
|
||||
|
||||
## Mem0 OSS Memory in WebUI — LEGACY (deprecated 2026-06-29)
|
||||
|
||||
The `mem0_oss` plugin was the canonical memory provider for all 20 profiles until 2026-06-29. It has been replaced by Hindsight. This section is preserved for historical reference and rollback only — **do not use these instructions for new setups**.
|
||||
|
||||
The original content covered:
|
||||
- `mem0.json` config file at `<HERMES_HOME>/mem0.json`
|
||||
- `mem0_oss` plugin directory at `<HERMES_HOME>/plugins/mem0_oss/`
|
||||
- `memory.provider: mem0_oss` in config.yaml
|
||||
- `pip install mem0ai ollama` in BOTH host and `/app/venv/`
|
||||
- Profile replication commands (`cp mem0.json`, `cp -r plugins/mem0_oss/`)
|
||||
- Common failure: `mem0ai`/`ollama` missing in WebUI container's venv
|
||||
- End-to-end verification script (`docker exec hermes-webui /app/venv/bin/python3 -c "..."`)
|
||||
|
||||
The full original section was replaced with the Hindsight version above. Original references still in tree:
|
||||
- `references/mem0-webui-verification.md` — full original verification script (preserved as legacy reference)
|
||||
- `references/mem0-cross-profile-replication.md` — original June 2026 replication procedure (preserved as legacy reference)
|
||||
|
||||
## Per-Profile Workspace Binding
|
||||
|
||||
The WebUI's file browser resolves each profile to its own workspace directory via the `workspace:` key in config.yaml. Without this key, every profile falls back to the global `/workspace` mount — all profiles share the same file browser view.
|
||||
|
||||
### How it works
|
||||
|
||||
`api/workspace.py::_profile_default_workspace()` checks config.yaml keys in priority order:
|
||||
1. `workspace` — explicit WebUI workspace key
|
||||
2. `default_workspace` — alternate explicit key
|
||||
3. `terminal.cwd` — agent working directory (most common fallback)
|
||||
|
||||
The WebUI container mounts `~/workspace` at `/workspace` via docker-compose, so config values must use `/workspace/<name>` (absolute container path), not `~/workspace/<name>` (host-relative).
|
||||
|
||||
### Setup: bind all profiles to their workspaces
|
||||
|
||||
```bash
|
||||
# 1. Create workspace directories on host
|
||||
for p in default ai automation coding comfy dgx experimental general llm minimal people personal research telegram tts work; do
|
||||
mkdir -p ~/workspace/$p
|
||||
done
|
||||
|
||||
# 2. Add workspace key to every profile config (use execute_code for bulk)
|
||||
# Pattern: insert `workspace: /workspace/<profile_name>` before `terminal:` section
|
||||
# in base config.yaml AND every ~/.hermes/profiles/<name>/config.yaml
|
||||
|
||||
# 3. Create AGENTS.md in each workspace (see workspace-context-organization skill)
|
||||
```
|
||||
|
||||
### Verification
|
||||
|
||||
```bash
|
||||
# Test per-profile resolution inside the container
|
||||
docker exec hermes-webui /app/venv/bin/python3 -c "
|
||||
from api.profiles import set_request_profile, clear_request_profile
|
||||
from api.workspace import _profile_default_workspace
|
||||
for p in ['general', 'telegram', 'ai', 'comfy']:
|
||||
set_request_profile(p)
|
||||
ws = _profile_default_workspace()
|
||||
print(f'{p}: {ws}')
|
||||
clear_request_profile()
|
||||
"
|
||||
# Expected: general: /workspace/general, telegram: /workspace/telegram, etc.
|
||||
```
|
||||
|
||||
### Pitfall: `~` expansion in container
|
||||
|
||||
Config values like `workspace: ~/workspace/general` expand to `/home/hermeswebui/workspace/general` inside the container — NOT `/workspace/general`. Always use absolute `/workspace/<name>` paths.
|
||||
|
||||
### Pitfall: missing workspace directories
|
||||
|
||||
If a profile's workspace directory doesn't exist on the host, the WebUI file browser shows an empty or error state. Create the directory on the host before adding the config key.
|
||||
|
||||
## WebUI-Host Mismatch Audit
|
||||
|
||||
When the WebUI shows wrong models, missing features, or stale state compared to the CLI, run this systematic audit. All checks read from the host filesystem (bind-mounted into the container).
|
||||
|
||||
### 1. `providers: {}` Docker Artifact
|
||||
```bash
|
||||
grep -rn 'providers: {}' ~/.hermes/profiles/*/config.yaml ~/.hermes/config.yaml
|
||||
```
|
||||
The WebUI container writes this empty key into config files. It's harmless clutter but indicates the container touched those files. Delete it during cleanup. The correct provider config lives in `custom_providers:` list and `model.provider`.
|
||||
|
||||
### 2. Missing `models_cache.json`
|
||||
```bash
|
||||
find ~/.hermes/profiles -name 'models_cache.json'
|
||||
```
|
||||
If no cache files exist, the WebUI model dropdown may be empty or using a fallback. The cache is generated on first dropdown open. If the dropdown shows nothing, trigger a rebuild by opening the model selector in the WebUI, or delete any stale cache to force regeneration.
|
||||
|
||||
### 3. Stale Model Dropdown (Wrong Models)
|
||||
```bash
|
||||
# Check cache fingerprint — must point to host path, not /home/hermeswebui/
|
||||
docker exec hermes-webui cat /home/hermeswebui/.hermes/profiles/<profile>/webui/models_cache.json | python3 -m json.tool | grep -A5 fingerprint
|
||||
```
|
||||
If the fingerprint path is `/home/hermeswebui/.hermes/config.yaml` (container-internal), the WebUI can't detect host config changes and never regenerates. Delete the cache to force rebuild.
|
||||
|
||||
### 4. Profile Mount Leak
|
||||
```bash
|
||||
find ~/.hermes/profiles -name 'profiles' -type d
|
||||
```
|
||||
Nested `profiles/<name>/profiles/` directories indicate the WebUI container created profile trees inside the bind mount. These persist on the host after decommission. Remove them.
|
||||
|
||||
### 5. Sticky Default Profile
|
||||
```bash
|
||||
cat ~/.hermes/active_profile
|
||||
```
|
||||
If this points to a Docker-origin profile (e.g., `telegram`), running plain `hermes` targets the wrong profile. Fix: `hermes profile use general`.
|
||||
|
||||
### 6. Hindsight Config (single-file, all profiles)
|
||||
```bash
|
||||
# Verify ~/.hermes/hindsight/config.json exists
|
||||
test -f ~/.hermes/hindsight/config.json && echo "OK" || echo "MISSING"
|
||||
# Verify every profile has memory.provider: hindsight
|
||||
for p in ~/.hermes/profiles/*/config.yaml; do
|
||||
grep -q "memory.provider: hindsight" "$p" || echo "NOT HINDSIGHT: $p"
|
||||
done
|
||||
```
|
||||
Hindsight config is a single file (`~/.hermes/hindsight/config.json`) shared by all profiles — no per-profile replication needed. Each profile only needs `memory.provider: hindsight` in its `config.yaml`.
|
||||
|
||||
### 7. Per-Profile Workspace Binding
|
||||
```bash
|
||||
for p in default ai automation coding comfy dgx experimental general llm minimal people personal research telegram tts work; do
|
||||
cfg="$HOME/.hermes/profiles/$p/config.yaml"
|
||||
test "$p" = "default" && cfg="$HOME/.hermes/config.yaml"
|
||||
grep "^workspace:" "$cfg" 2>/dev/null || echo "MISSING: $p"
|
||||
done
|
||||
```
|
||||
Without a `workspace:` key, all profiles share the global `/workspace` mount in the WebUI file browser.
|
||||
|
||||
### Quick Audit Script
|
||||
```bash
|
||||
echo "=== 1. providers:{} ===" && grep -rn 'providers: {}' ~/.hermes/profiles/*/config.yaml ~/.hermes/config.yaml | wc -l
|
||||
echo "=== 2. models_cache.json ===" && find ~/.hermes/profiles -name 'models_cache.json' | wc -l
|
||||
echo "=== 3. Stale fingerprint ===" && docker exec hermes-webui cat /home/hermeswebui/.hermes/profiles/general/webui/models_cache.json 2>/dev/null | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('_source_fingerprint',{}).get('config_yaml',{}).get('path','N/A'))" 2>/dev/null || echo "(no cache)"
|
||||
echo "=== 4. Mount leak ===" && find ~/.hermes/profiles -name 'profiles' -type d | wc -l
|
||||
echo "=== 5. Sticky default ===" && cat ~/.hermes/active_profile 2>/dev/null || echo "(default)"
|
||||
echo "=== 6. Hindsight config ===" && test -f ~/.hermes/hindsight/config.json && echo "OK" || echo "MISSING"
|
||||
echo "=== 7. Workspace keys ===" && for p in default general telegram; do cfg="$HOME/.hermes/profiles/$p/config.yaml"; test "$p" = "default" && cfg="$HOME/.hermes/config.yaml"; echo -n "$p: "; grep "^workspace:" "$cfg" 2>/dev/null || echo "MISSING"; done
|
||||
```
|
||||
|
||||
## Docker Profile Mount Leak
|
||||
|
||||
When the WebUI container creates profile directories inside the bind-mounted `HERMES_HOME`, those directories persist on the host after the container is decommissioned or the mount is fixed. This leaves nested `profiles/<name>/profiles/` trees, stale `state-snapshots/`, and container-internal fingerprint paths in caches. See `references/profile-mount-leak-migration.md` for identification and cleanup steps.
|
||||
Reference in New Issue
Block a user