396 lines
24 KiB
Markdown
396 lines
24 KiB
Markdown
# 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 | каталог плагинов |
|
||
|
||
Команда для повторной проверки:
|
||
```bash
|
||
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 как у нас?
|
||
|
||
**Нет, аналога не существует.** Проверено:
|
||
```bash
|
||
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 память — возможно, у них готовое решение лучше нашей реализации.
|
||
|
||
**Статус:** стратегия подтяжки по-прежнему **не выбрана**. Форк запушен и стабилен.
|
||
|
||
## Команды для проверки расхождения
|
||
|
||
```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 память (наша фича)
|