Files
obsidian-vault/personal/tech/hermes-fork-vs-upstream.md
Taiga b53dd70a15 [2026-09-26 09:10:28] syncthing: personal/tech/archive-org-collection-harvest.md personal/tech/balda-go-fx-pitfalls.md personal/tech/bilety-oxota-interaktiv.md personal/tech/cloudflare-tunnel-ssh-published-route.md personal/tech/deepseek-language-drift.md personal/tech/docker-data-root-mount-race.md personal/tech/docker-mac-disk-issues.md personal/tech/docker_colima_setup.md personal/tech/eagle-dashboard-launchd.md personal/tech/hermes-agent-improvements.md personal/tech/hermes-browser-toolsets.md personal/tech/hermes-fork-vs-upstream.md personal/tech/hermes-git-repo.md personal/tech/hermes-memory-architecture.md personal/tech/hermes-secret-redaction-bypass.md personal/tech/hermes-self-improvement-review.md personal/tech/home-network-config.md personal/tech/inter-site-throughput-taiga-to-mac.md personal/tech/inter-site-throughput-taiga-to-mac.md.bak-nedstab2 personal/tech/jellyfin-db-schema-mismatch.md personal/tech/karabiner-keyboard-config.md personal/tech/kraken-media-inventory-facts.md personal/tech/kraken-truenas-media-copies.md personal/tech/lampa-jellyfin-plugin.md personal/tech/lampac-deployment.md personal/tech/lampac-torrserver.md personal/tech/llm-model-selection-2026.md personal/tech/mac-print-shared-services.md personal/tech/modbus-rtu-sniffer-debugging.md personal/tech/multistream-single-flow-limit.md personal/tech/multistream-single-flow-limit.md.bak-nedstab2 personal/tech/music-tags-repair-truenas.md personal/tech/obsidian-mcp-ecosystem.md personal/tech/original-xbox-2025-guide.md personal/tech/prowlarr-flaresolverr-cloudflare.md personal/tech/radarr-sonarr-phantom-records.md personal/tech/roundtrip-key-verification.md personal/tech/ryujinx-mac-setup.md personal/tech/skill-arr-media-stack-setup-additions.md personal/tech/skill-docker-data-root-mount-race.md personal/tech/skill-lampac-kraken-deploy.md personal/tech/tirith-trust.md personal/tech/truenas-local-tree-comparison.md personal/tech/truenas-nfs4-acl-and-arrmultiuser.md personal/tech/truenas-zfs-panic-recovery.md personal/tech/vault-doc-pruning.md personal/tech/vless-space-subscription-egress.md personal/tech/watchlist-sync-feed.md personal/tech/watchtower-docker-updates.md personal/tech/xray-outbound-subscription-3xui.md personal/tech/xray-reverse-limits-private-network.md personal/tech/xray-reverse-tunnel-kraken-truenas.md personal/tech/xray-reverse-tunnel-kraken-truenas.md.bak-nedstab2 personal/tech/yandex-music-api.md
2026-09-26 09:10:28 +00:00

24 KiB
Executable File
Raw Permalink Blame History

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) — ровно в эпицентре этого рефакторинга.

Масштаб по коду (не «перетаскивание папок»)

Апстрим — это не реорганизация, а +322 новых модуля. Считать так:

Область У нас У апстрима Нового
agent/ 88 файлов 229 +144
tools/ 86 файлов 262 +178
hermes_state* 1 монолит 25 модулей разбит
apps/ — 2674 файла desktop-приложение
evals/ — 203 файла eval-фреймворк
contributors/ — 1176 данные контрибьюторов
plugin-catalog/ — 27 каталог плагинов

Команда для повторной проверки:

cd ~/.hermes/hermes-agent
comm -13 <(git ls-tree --name-only main:agent/ | sort) \
         <(git ls-tree --name-only upstream/main:agent/ | sort) | wc -l

Что реально нового в апстриме (по функциональности)

1. Desktop-приложение (apps/desktop, 2674 файла) — крупнейшая подсистема (773 коммита в скоупе desktop). Нативный GUI. Внутри — bootstrap-installer, shared. Это фронт на TypeScript/Ink.

2. Bot Mode (website/docs/user-guide/bot-mode.md) — прямо про наш кейс. Профили превращаются в roster именованных ботов: у каждого своя роль, модель, память, скиллы, аватар. Боты ходят в групповые чаты и пишут друг другу. Ключевое: «A Bot is a Hermes profile» — никакого нового примитива, всё видно из CLI (hermes -p <bot> chat), роутины в hermes cron list. Есть «forever-chat» на бота: /new внутри перехватывается в /compact. Секции (папки) для группировки, скрытие ботов, фильтр «Active now».

Сопоставление с нашим: у нас Eagle + Whale + Balda роутятся через самодельный plugins/whale-thread-guard (файл thread_ownership.json). У апстрима это нативная фича с UI. ⚠️ Открытый вопрос для Alex — не выбрасывается ли наш роутинг в пользу нативного (см. «Ключевой вопрос» ниже).

3. Автономные циклы — три механизма:

  • /goal — стоящая цель через turns; lightweight judge-модель после каждого turn проверяет достижение, агент сам кормит continuation prompt до успеха. Их версия Ralph loop (вдохновлено Codex CLI 0.128.0).
  • /loop — перезапуск промпта по таймеру внутри сессии; каждый wakeup — это реальный turn. Их версия Claude Code /loop (алиас /proactive).
  • /heartbeat — один промпт на сессию, срабатывает когда сессия idle. Разница: /goal judge-driven («работай пока не достигнешь»), /loop timer-driven («делай это каждые N минут»).

4. Encrypted credential vault (agent/vault_store.py) — зашифрованное (Fernet) локальное хранилище для browser autofill. Profile-scoped, model-blind: модель видит только opaque handles + метаданные (kind, label, origin), значения резолвятся server-side и не попадают в tool results / логи / session DB. Три вида: login, payment, address. Ключ и файл 0600 в <HERMES_HOME>/vault/. Портировано из Merit-Systems/OpenInstinct (MIT).

5. Turn-цикл разобран на 29 модулей — turn_facade, turn_preflight, turn_preflight_gate, turn_recovery, turn_overflow, turn_truncation, turn_tool_round, turn_finalizer, turn_liveness, turn_retry_state и др. run_conversation из монолита стал конвейером.

6. MCP переписан — 20 модулей: mcp_tool_discovery, mcp_oauth_provider, mcp_death_supervisor, mcp_tool_sampling, mcp_tool_schema, mcp_schema_cache, mcp_tool_health, mcp_tool_scope, mcp_oauth_device и др.

7. Браузер — 16 модулей browser_tool_*: CDP, cloud, lightpanda fallback, snapshot, vision, origin, session, lifecycle, install, real_profile, supervisor_dialogs/frames, eval_policy, vault_tool.

8. native/fts5_cjk — C-расширение SQLite FTS5 для китайского/японского/ корейского токенизации полнотекстового поиска. Нативная сборка (build.sh + vendor/sqlite3.h). Прямо относится к багу китайского вывода — см. deepseek-language-drift.

9. Skills Hub — 8 модулей: skills_hub_github, skills_hub_official, skills_hub_clawhub, skills_hub_skillssh, skills_hub_search, skills_hub_install, skills_hub_sources, skills_hub_models. Плюс skill_linter, skill_ledger, skill_manager_batch, skill_manager_guards.

10. Прочее новое: pets (питомцы в UI), skins, personality, mixture-of-agents (moa_loop.py, moa_trace.py), honcho (memory-провайдер), code_kernel + code_kernel_remote (Python-кирнел), deliverable-mode (файлы как нативные вложения в мессенджерах), credential-pools, provider-routing, subscription-proxy, tool-gateway, tool-search, kanban-multi-gateway, relay (NeMo Relay runtimes, 54 коммита), lsp, heartbeat, goals, loops, curator, skills, context-references, document-extraction, batch-processing, computer-use, codex-app-server-runtime, plugin-catalog, extending-the-dashboard.

Новые top-level каталоги: apps/, native/, evals/, contributors/, plugin-catalog/, providers/, locales/, web/, website/i18n.

Ответ: есть ли замена Zulip?

Нет. Проверено по существу — по модели общения, а не по имени платформы.

Платформа Треды Self-hosted Stream+topic
matrix ✅ threads ✅ ❌ room-based
mattermost ✅ thread-mode replies ✅ ❌ channel-based
slack ✅ threads ❌ SaaS ❌
teams ✅ ❌ SaaS ❌
google_chat ❌ ❌ SaaS ❌
irc ❌ ✅ ❌ flat
simplex ❌ groups ✅ p2p ❌
a2a — ✅ — (agent-to-agent, не чат)

Проверка на stream+topic: git grep -li 'stream.*topic' upstream/main -- plugins/platforms/ → только dingtalk и telegram, и там это не топик-модель.

Ключевое различие: Zulip — единственная известная чат-платформа с нативной моделью «поток → топик», где топик = адресуемая сущность с собственным именем. Matrix и Mattermost дают треды как свойство сообщения (reply-thread), а не как адресуемую сущность. У нас stream::topic — это ключ роутинга (thread_ownership.json: "stream::topic": "eagle"|"whale"), на их модели такой ключ не построить.

Вывод: миграция на matrix/mattermost = потеря топик-роутинга между ботами. whale-thread-guard на их модели не переносится.

Подробности платформ: plugins/platforms/<name>/plugin.yaml — там description, requires_env, optional_env с описаниями (MATTERMOST_REPLY_MODE: 'thread'|'off', MATRIX_HOMESERVER, mention-gating и т.д.).

Ответ: сделаны ли custom prompts как у нас?

Нет, аналога не существует. Проверено:

git grep -l 'prompt_overrides' upstream/main   # пусто
git grep -l '_load_prompt_block' upstream/main # пусто

В апстриме все блоки промпта — захардкоженные константы в agent/prompt_builder.py: MEMORY_GUIDANCE, USER_PROFILE_GUIDANCE, SESSION_SEARCH_GUIDANCE, SKILLS_GUIDANCE, KANBAN_GUIDANCE, TOOL_USE_ENFORCEMENT_GUIDANCE, TASK_COMPLETION_GUIDANCE, PARALLEL_TOOL_CALL_GUIDANCE, OPENAI_MODEL_EXECUTION_GUIDANCE, GOOGLE_MODEL_OPERATIONAL_GUIDANCE, HERMES_AGENT_HELP_GUIDANCE (+ вариант _NO_SKILLS), DEFAULT_AGENT_IDENTITY, PLATFORM_HINTS (по платформе).

build_system_prompt_parts() в апстриме просто делает stable_parts.append(CONST) — точки подмены из файла нет.

Что у апстрима ЕСТЬ для кастомизации:

  • SOUL.md — идентичность агента (есть и у нас, грузится через load_soul_md())
  • context-файлы из CWD (AGENTS.md, HERMES.md) — _find_hermes_md(), _scan_context_content(), _strip_yaml_frontmatter()
  • system_message из конфига

Чего НЕТ: подмены отдельных блоков промпта файлами. То есть наш _load_prompt_block() + agent.prompt_overrides — уникальная фича форка (коммит 207a1de16). См. hermes-agent-improvements.

Практический смысл различия: у нас правка промпта = редактирование .md в hermes-whale/review/ без касания Python. У них = правка Python-константы в prompt_builder.py, который апстрим постоянно переписывает (131 коммит).

agent/thread_scoped_output.py — существует в апстриме. У нас thread-scoped память сделана с нуля (972004546f). Стоит сравнить перед вариантом B: возможно, у апстрима есть готовое решение лучше. Не проверено детально.

НАШИ 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), не таща весь долг.

Что уточнилось 2026-09-15 (второй проход)

Alex задал три прямых вопроса, ответы получены (детали — в разделах выше):

Вопрос Ответ
Что нового в апстриме? Не только платформы: +322 модуля, desktop, Bot Mode, /goal /loop /heartbeat, vault, turn-рефакторинг, MCP, Skills Hub
Есть ли замена Zulip? Нет — ни одна платформа не даёт stream+topic как адресуемую сущность
Сделаны ли custom prompts как у нас? Нет — блоки захардкожены, prompt_overrides уникален для форка

Новый открытый вопрос (важнее прежних): Bot Mode апстрима делает нативно то, что у нас держится на самодельном whale-thread-guard + thread_ownership.json. Если переезжать на вариант B — надо решить, переносить наш роутинг или выбрасывать в пользу нативного Bot Mode. Этот вопрос не задан Alex'у явно, вынесен как следующий шаг.

Также не проверено: agent/thread_scoped_output.py в апстриме vs наша thread-scoped память — возможно, у них готовое решение лучше нашей реализации.

Статус: стратегия подтяжки по-прежнему не выбрана. Форк запушен и стабилен.

Команды для проверки расхождения

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

Связанное