# Hermes — git-репозиторий конфига и агента **Дата:** 2026-09-15 **Статус:** актуально ## Структура (важно!) Git-репозиторий лежит **в `~/.hermes/`**, а НЕ в `~/.hermes/hermes-whale/`. Это главный подвох: `git status` из `hermes-whale/` показывает пути вида `../config.yaml`, `../skills/` — потому что корень на уровень выше. ``` ~/.hermes/ ← git repo root (branch: main, origin/main) ├── .gitignore ├── .gitmodules ├── config.yaml ← глобальный конфиг ├── SOUL.md ├── channel_directory.json ← в .gitignore, но УЖЕ ЗАКОММИЧЕН (см. долги) ├── thread_ownership.json ← состояние whale-thread-guard плагина ├── webhook_subscriptions.json ← секреты! в .gitignore (не коммитить) ├── hermes-agent/ ← SUBMODULE: исходники Hermes Agent (Python) ├── hermes-whale/ ← профиль Whale (конфиг + память + промпты) │ ├── config.yaml ← конфиг профиля Whale │ ├── SOUL.md ← идентичность Кита │ ├── review/ ← prompt_overrides: 7 .md блоков + memory/skill prompt │ ├── memories/ │ │ ├── MEMORY.md, USER.md ← глобальные │ │ └── threads//MEMORY.md ← thread-scoped память │ ├── cron/jobs.json │ └── lsp/ ← ⚠️ 39M бинарников закоммичено (долг) ├── memories/ ← глобальные (не профиля) ├── plugins/whale-thread-guard/ ← роутинг ботов в Zulip ├── scripts/refresh-claude-token.sh └── skills/ ← курируемые скиллы ``` ## Два репозитория | Репо | Что | Ветка | |------|-----|-------| | `~/.hermes/` | Конфиг Whale, скиллы, память, плагины, пин сабмодуля | main | | `~/.hermes/hermes-agent/` | Исходники Hermes Agent (Python) — сабмодуль | main | Правки Python-кода Hermes (`agent/*.py`) коммитятся **в сабмодуле**, затем в родительском репо обновляется пин: `git add hermes-agent`. Если пин не обновить — в родительском `git status` видно `hermes-agent (new commits, modified content)`, а сам сабмодуль чист. **Как проверить, всё ли закоммичено:** ```bash cd ~/.hermes && git status --porcelain | head cd ~/.hermes/hermes-agent && git status --porcelain # должно быть пусто ``` ## Правила .gitignore (обновлено 2026-09-15) До 2026-09-15 игнорировался только `.env` — вариант `**`.env.bak`/`.env.new` НЕ покрывался, хотя в них лежали живые токены. Один `git add .` затащил бы их в историю. Добавлены секции: ```gitignore # Secrets .env / .env.bak / .env.new / .env.local / .env.*.bak **/.env / **/.env.bak / **/.env.new # Webhook subscriptions (содержат per-endpoint secret, 16 символов) webhook_subscriptions.json **/webhook_subscriptions.json # Config/state бэкапы (могут содержать секреты) config.yaml.bak* / config.yaml.*.bak / config.yaml.whale-bak* config.yaml.work / config.yaml.transitional / config.yaml.corrupt* **/config.yaml.bak* / **/config.yaml.*.bak / **/config.yaml.whale-bak* *.tmp # Node node_modules/ / **/node_modules/ ``` ### Проверка игнора (обязательно после правки .gitignore) ```bash cd ~/.hermes && git check-ignore -v .env.bak .env.new \ hermes-whale/.env.bak hermes-whale/.env.new \ webhook_subscriptions.json config.yaml.bak ``` Каждый файл должен вывести строку `.gitignore::\t`. **Pitfall:** `.gitignore` НЕ влияет на уже отслеживаемые файлы. `hermes-whale/lsp/node_modules/` оставался в репо несмотря на правило `node_modules/` (закрыто коммитом `9b111fc` через `git rm -r --cached`). Вывод — применять `git add` по именам файлов, а не `git add .`, иначе новое правило может дать ложное чувство защиты. **Второй pitfall — `git add -f`:** после добавления правила `node_modules/` попытка `git add` файла внутри него (например `lsp/node_modules/.package-lock.json`) падает с «paths are ignored by one of your .gitignore files». Уже отслеживаемые файлы коммитятся нормально без `-f` — правило на них не действует. ## Что коммитить / что не коммитить **Коммитим:** - `config.yaml`, `hermes-whale/config.yaml` — конфиги - `hermes-whale/review/*.md` — prompt_overrides (без них подмены промпта теряются!) - `hermes-whale/memories/`, `memories/` — память - `plugins/`, `skills/`, `scripts/` - `hermes-agent` (пин сабмодуля) **Не коммитим (в .gitignore):** - `.env*` любые варианты - `webhook_subscriptions.json` — секреты - `config.yaml*.bak*` — 10+ бэкапов могут содержать секреты - `node_modules/`, `.restart_last_processed.json`, `config.yaml.zulip-router` - `lsp/`, `review/` в корне — дубликаты `hermes-whale/lsp/` и `hermes-whale/review/` ## Долги (не исправлено, требуют решения Alex) 1. **`channel_directory.json` в .gitignore, но отслеживается** — правило добавлено после коммита. В коммите `7fd200c` из него удалено 869 строк (файл в основном генерируемый). Также живёт как ` M` в статусе постоянно — это рантайм-запись текущей сессии, коммитить бессмысленно. Решение: `git rm --cached channel_directory.json`. 2. **История git не похудела.** 43M node_modules убраны из трекинга, но остаются в истории. Для реальной экономии — `filter-repo` + force push (ломает клоны). ### Закрыто 2026-09-15 - ~~`hermes-whale/lsp/node_modules/` в git~~ — **убрано из трекинга** коммитом `9b111fc`: 1957 файлов / 43M. Файлы **остались на диске** (108 каталогов), `git rm -r --cached` индекс не удаляет. Проверка: `git ls-files | grep -c node_modules` → 0. ## Коммиты и push (2026-09-15) | Коммит | Что | |--------|-----| | `207a1de16` (submodule) | load stable system-prompt blocks from config prompt_overrides | | `7fd200c` | wire prompt_overrides + whale-thread-guard multi-bot routing | | `7893c35` | sync skills — curator consolidation (516 удалений, 55 новых) | | `bdf84da` | add vue/dockerfile/pyright/yaml language servers | | `176ce9c` | thread-scoped memory store + claude token refresh script | | `9b111fc` | untrack lsp/node_modules (1957 files, 43M) | **Запушено:** - `hermes-agent` → `github.com:mallexxx/hermes-agent` — 20 коммитов - `~/.hermes` → `git.mallexxx.duckdns.org/git_admin/eagle-hermes` — 9 коммитов Оба репо: `main...origin/main` синхронно, секретов в истории нет. ## Утечка секретов (закрыта 2026-09-15) `.env.bak` и `.env.new` (в `~/.hermes/` и `~/.hermes/hermes-whale/`) содержали **живые токены**: `TELEGRAM_BOT_TOKEN`, `OPENROUTER_API_KEY`, `DISCORD_BOT_TOKEN`, `ZULIP_API_KEY`, `DEEPSEEK_API_KEY`. Игнорился только `.env` — варианты `.bak`/`.new` НЕ покрывались. Один `git add .` затащил бы их в публичную историю. Также `webhook_subscriptions.json` (16-символьные per-endpoint секреты) — не был игнорирован. Проверено фактически: `jq -r '.whale.secret | length'` → 16. Проверка, что секреты не попали в историю: ```bash cd ~/.hermes && git log --all --diff-filter=A --name-only --pretty=format: | grep '\.env' # пусто = чисто ``` `scripts/refresh-claude-token.sh` — **не секрет**: refresh token читается из `~/.claude/.credentials.json` в рантайме, `CLIENT_ID` — публичный OAuth идентификатор. ## Команды ```bash # Статус обоих репо cd ~/.hermes && git status -sb cd ~/.hermes/hermes-agent && git status -sb # Закоммитить Python-правки Hermes cd ~/.hermes/hermes-agent && git add agent/*.py && git commit -m "..." cd ~/.hermes && git add hermes-agent && git commit -m "chore: bump submodule" # Проверить, что секреты не в истории cd ~/.hermes && git log --all --diff-filter=A --name-only --pretty=format: | grep '\.env' ``` ## Связанное - [[hermes-whale-system-prompt]] — состав system prompt, prompt_overrides - [[hermes-agent-improvements]] — вынос хардкода промптов в файлы (механизм + коммиты) - [[hermes-memory-architecture]] — thread-scoped память - [[hermes-fork-vs-upstream]] — расхождение с апстримом (24k коммитов) - [[tirith-trust]] — снятие блокировок tirith (raw_ip_url и др.)