# Hermes — апстрим vs наш форк **Дата:** 2026-09-15 **Статус:** актуально — анализ расхождения сделан, **стратегия подтяжки НЕ выбрана** **Репо:** `~/.hermes/hermes-agent` (сабмодуль, форк `mallexxx/hermes-agent`) ## Текущее решение: не принято На 2026-09-15 Alex'у представлены 3 варианта (A merge / B перенос на свежий апстрим / C заморозка). **Выбор не сделан.** Работа над подтяжкой не начата. Наш форк запушен и стабилен — можно спокойно решать. Открытый вопрос, определяющий выбор: **нужны ли нам вообще 24k коммитов апстрима?** Мы используем Hermes как Zulip-бота с webhook-флоу; апстрим растёт десктопом/TUI/платформами, которые нам не нужны. Точечный cherry-pick (security-фиксы, фиксы `agent/`, новые модели) может быть достаточен. ## Масштаб расхождения | Метрика | Значение | |---------|----------| | Коммитов апстрима впереди | **24 407** | | Наших коммитов | 32 | | Common ancestor | `4ed63170e4` (2026-06-04) | | Дата последнего коммита апстрима | 2026-09-15 | | Наша версия | `0.15.1` | | Версия апстрима | `0.21.3` | | Файлов изменено апстримом | 12 634 | | Строк: +2 362 152 / −763 849 | | **Вывод:** это не «догнать на пару недель», а **~3.5 месяца и 24k коммитов**. Апстрим ушёл на мажорные версии вперёд (0.15 → 0.21). ## Ремоуты | Remote | URL | Роль | |--------|-----|------| | `origin` | `git@github.com:mallexxx/hermes-agent.git` | наш форк | | `upstream` | `https://github.com/NousResearch/hermes-agent.git` | источник | ## Главные изменения апстрима ### 1. Платформы переехали из ядра в плагины ⚠️ КРИТИЧНО Апстрим **удалил** `telegram.py`, `slack.py`, `matrix.py`, `discord.py` из `gateway/platforms/` — теперь они живут в `plugins/platforms/`. **Состав `plugins/platforms/` у апстрима (19):** `a2a, buzz, dingtalk, discord, email, feishu, google_chat, homeassistant, irc, line, matrix, mattermost, ntfy, photon, raft, simplex, slack, sms, teams, telegram, wecom, whatsapp` **Наш `plugins/platforms/` (8):** `discord, google_chat, irc, line, mattermost, ntfy, simplex, teams` **⚠️ Zulip НЕТ ни в ядре апстрима, ни в `plugins/platforms/` апстрима.** Проверено: `git ls-tree -r upstream/main | grep -i zulip` → пусто. Zulip — **полностью наша разработка**: - `gateway/platforms/zulip.py` — не существует в апстриме - `tools/zulip_thread_tool.py` — не существует в апстриме Это значит: наш Zulip-адаптер живёт в **устаревшем месте** (`gateway/platforms/`), которое апстрим планомерно опустошает. При подтяжке его придётся переносить в `plugins/platforms/` — иначе он повиснет на api, которого больше нет. ### 2. Смежные подсистемы Топ-скоупы по числу feat/refactor коммитов: | Скоуп | Коммитов | Что это | |-------|----------|---------| | `desktop` | 773 | Десктоп-приложение — крупнейшая новая подсистема | | `hermes_cli` | 607 | CLI переработан | | `gateway` | 412 | Ядро гейтвея | | `tools` | 339 | Инструменты | | `agent` | 217 | Ядро агента | | `cli` / `tui` / `tui_gateway` | 141/100/76 | TUI (Ink/React) | | `state` | 106 | Персистентность сессий | | `cron` | 91 | Планировщик | | `computer_use` | 86 | Управление десктопом | | `mcp` | 79 | MCP-клиент | | `relay` | 54 | Новая подсистема релея | Типы коммитов: `fix` 10 994, `refactor` 4 158, `feat` 2 113, `test` 1 836. **Читается так:** апстрим прошёл большую волну рефакторинга (4158) + массовый десктоп/TUI-фронт. Наши правки в `gateway/run.py` (13 коммитов) и `gateway/stream_consumer.py` (9) — ровно в эпицентре этого рефакторинга. ## Наши 32 коммита Сгруппированы по темам: **Zulip-платформа (наша, в апстриме отсутствует):** - `b0f097a299` feat: add Zulip platform adapter (parallel to Discord) - `ce093b0a75` zulip: switch approval prompt emojis ✅/❌ → 👍/👎 - `b1e36eb2d7` fix(zulip): lock→locked emoji name - `f39671ba97` fix(routing): pre_gateway_dispatch before session guard - `d4e98a8b07` / `ef69e76413` / `40149225af` / `ddc6aa7c46` webhook: zulip in BUILTIN_DELIVER_PLATFORMS, session_chat_id из X-Chat-Id - `8255ea0c64` feat(zulip): session_search читает Zulip thread history - `049922d8cc` fix(session_search): dual Zulip+SQLite recall, FTS5 sanitization **Webhook no-edit streaming (наш флоу без редактирования сообщений):** - `fa271d2d19`, `ee41e8a847`, `9003d4cbbe` (revert), `1ac06d593a`, `9253fe52cc`, `88cbb77b95`, `6c95153aa8`, `eb8dd7b5ed`, `a92840dcde`, `a08527e85c`, `a88bec1762`, `5d3e95841b`, `ec9efce7e7` **Фичи профиля Whale:** - `972004546f` feat: thread-scoped memory + configurable memory instruction - `4ebad4f692` test: thread-scoped memory persistence, drift guard, snapshot - `da146da5fa` feat: configurable background review prompts and allowed toolsets - `207a1de16c` feat: load stable system-prompt blocks from config prompt_overrides **Прочее:** - `6e09a3704a` fix(approval): interrupt pending approvals on user message - `a17d02f31e` fix(api_server): tool.progress → plain-text chunks - `81f10c306f` approval: reaction emoji на webhook ## Риск конфликтов при merge Dry-run `git merge-tree` → **16 конфликтных файлов, 160 конфликтных маркеров**. | Файл | Наших коммитов | Коммитов апстрима | Риск | |------|---------------|-------------------|------| | `gateway/run.py` | 13 | **974** | 🔴 экстремальный | | `cron/scheduler.py` | 1 | 307 | 🟠 | | `agent/agent_init.py` | 3 | 226 | 🟠 | | `gateway/platforms/base.py` | 2 | 208 | 🟠 | | `gateway/platforms/api_server.py` | 1 | 177 | 🟠 | | `agent/model_metadata.py` | 1 | 164 | 🟡 | | `tools/approval.py` | 1 | 147 | 🟡 | | `agent/prompt_builder.py` | 0 | 131 | auto-merge ok | | `gateway/stream_consumer.py` | 9 | 73 | 🟠 (наш файл, апстрим переписал) | | `agent/system_prompt.py` | 2 | 65 | 🟡 | | `gateway/platforms/webhook.py` | 7 | 59 | 🟠 | | `toolsets.py` | 2 | 62 | 🟡 | | `tools/session_search_tool.py` | 2 | 41 | 🟢 | | `tools/memory_tool.py` | 1 | 34 | 🟢 | | остальные | 1 | <30 | 🟢 | **Худший случай:** `gateway/run.py` — 974 коммита апстрима против наших 13. Это фактически переписывание файла. Конфликты там будут не «принять/отклонить строку», а разбор чужой новой архитектуры. ## Стратегии подтяжки ### Вариант A: merge (сейчас) — НЕ рекомендуется `git merge upstream/main` → 16 конфликтных файлов, ручной разбор 160 маркеров в горячих файлах. Оценка: **дни на `run.py` + `stream_consumer.py`**, риск потерять наши webhook/Zulip-правки. ### Вариант B: перенос нашей функциональности на свежий апстрим (рекомендуется) Взять чистый `upstream/main` как новую базу, затем **перенести наши фичи патчами заново**: 1. Сохранить наши diff'ы как patch-файлы (`git format-patch`) 2. Форк от свежего апстрима 3. Переносить по темам: Zulip-адаптер (в `plugins/platforms/`!), 3 фичи Whale (thread-scoped memory, bg-review, prompt_overrides), webhook-стриминг 4. Webhook-стриминг — вероятно **уже решён апстримом**, проверить перед переносом **Плюс:** результат на актуальной кодовой базе, без 24k коммитов долга. **Минус:** ручная работа по переносу, ~1-2 дня. ### Вариант C: заморозить и жить на форке Принять, что мы отдельный продукт. Апстрим берём точечно (`git cherry-pick` отдельных фиксов безопасности). Дёшево сейчас, растёт долг потом. ## Ключевой вопрос перед подтяжкой **Нужны ли нам вообще 24k коммитов апстрима?** Мы используем Hermes как **Zulip-бота с webhook-флоу**. Ядро апстрима прирастает десктопом, TUI и платформами (telegram/slack/...), которые нам не нужны. Реальная ценность от апстрима для нас: - фиксы безопасности (`tools/tirith_security.py`, approval) - фиксы багов в `agent/` (метаданные моделей, сжатие контекста) - поддержка новых моделей/провайдеров Это можно брать точечно (cherry-pick), не таща весь долг. ## Команды для проверки расхождения ```bash cd ~/.hermes/hermes-agent # Обновить инфу об апстриме git fetch upstream # Насколько отстали git rev-list --count main..upstream/main # апстрим впереди git rev-list --count upstream/main..main # мы впереди # Общий предок git merge-base main upstream/main # Изменения по нашим файлам git diff --name-only $(git merge-base main upstream/main)..main | sort -u # Насколько апстрим трогал конкретный файл git rev-list --count $(git merge-base main upstream/main)..upstream/main -- gateway/run.py # Dry-run merge (безопасно, не трогает рабочую копию) git merge-tree --write-tree --name-only main upstream/main # Есть ли файл в апстриме git cat-file -e upstream/main:gateway/platforms/zulip.py && echo yes || echo NO ``` ## Связанное - [[hermes-git-repo]] — структура репо, .gitignore, что коммитить - [[hermes-whale-system-prompt]] — prompt_overrides (наша фича) - [[hermes-memory-architecture]] — thread-scoped память (наша фича)