Участие в разработке

Спасибо за вклад в Hermes Agent! Здесь разобраны настройка рабочего окружения, устройство кодовой базы и путь от написания кода до принятого PR.

Приоритеты вкладов

Вклады мы ценим в таком порядке:

  1. Исправления багов — сбои, некорректное поведение, потеря данных
  2. Кросс-платформенная совместимость — macOS, разные дистрибутивы Linux, WSL2
  3. Укрепление безопасности — инъекции через shell, инъекции в промпт, обход каталогов
  4. Производительность и надёжность — логика повторных попыток, обработка ошибок, graceful degradation
  5. Новые навыки — широко применимые (см. Создание навыков)
  6. Новые инструменты — нужны редко; большинство возможностей лучше реализовывать как навыки
  7. Документация — исправления, уточнения, новые примеры

Распространённые сценарии участия

Настройка окружения разработки

Требования

ТребованиеПримечания
GitС установленным расширением git-lfs
Python 3.11+uv установит его автоматически при отсутствии
uvБыстрый пакетный менеджер для Python (установка)
Node.js 20+Опционально — нужен для браузерных инструментов и WhatsApp-моста (соответствует полю engines в корневом package.json)

Установка через штатный установщик

Большинству контрибьюторов проще всего поднять окружение тем же путём, что и обычные пользователи: запустить штатный установщик, а дальше работать прямо в склонированном им репозитории. Установщик создаёт venv для Hermes, прописывает команду hermes, фиксирует метод установки для hermes update и клонирует полный git-проект в $HERMES_HOME/hermes-agent (обычно ~/.hermes/hermes-agent). Так ваше окружение разработки совпадёт по структуре с тем, на которое рассчитаны CLI, апдейтер, ленивый установщик зависимостей, шлюз и документация.

curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash
cd "${HERMES_HOME:-$HOME/.hermes}/hermes-agent"

# Доставить dev/test-дополнения поверх штатной установки.
uv pip install -e ".[all,dev]"

# Опционально: браузерные инструменты / зависимости сайта документации.
npm install

После этого создавайте ветки и запускайте тесты из этого чекаута:

git checkout -b fix/description
scripts/run_tests.sh

Запасной вариант: ручное клонирование

Прибегайте к нему только если вам осознанно не нужна управляемая структура установки Hermes (например, одноразовый клон в контейнере или CI-задаче). При такой установке убедитесь, что точку входа hermes вы запускаете именно из этого venv; запуск системного python3 -m hermes_cli.main может подхватить посторонние пакеты системного Python.

git clone https://github.com/NousResearch/hermes-agent.git
cd hermes-agent

# Создать виртуальное окружение с Python 3.11
uv venv venv --python 3.11
export VIRTUAL_ENV="$(pwd)/venv"

# Установить со всеми дополнениями (сообщения, cron, меню CLI, инструменты разработчика)
uv pip install -e ".[all,dev]"

# Опционально: браузерные инструменты
npm install

Конфигурация для разработки

mkdir -p ~/.hermes/{cron,sessions,logs,memories,skills}
cp cli-config.yaml.example ~/.hermes/config.yaml
touch ~/.hermes/.env

# Добавьте как минимум ключ провайдера LLM:
echo 'OPENROUTER_API_KEY=sk-or-v1-your-key' >> ~/.hermes/.env

Запуск

# Штатный установщик уже добавил `hermes` в PATH.
hermes doctor
hermes chat -q "Hello"

Если вы пошли по запасному пути с ручным клонированием, запускайте ./hermes из чекаута либо явно слинкуйте venv этого клона:

mkdir -p ~/.local/bin
ln -sf "$(pwd)/venv/bin/hermes" ~/.local/bin/hermes

Запуск тестов

scripts/run_tests.sh

Стиль кода

  • PEP 8 с разумными исключениями (строгое ограничение длины строки не применяется)
  • Комментарии: только там, где нужно пояснить неочевидный замысел, компромисс или особенность API
  • Обработка ошибок: перехватывайте конкретные исключения; для неожиданных ошибок используйте logger.warning()/logger.error() с exc_info=True
  • Кросс-платформенность: никогда не предполагайте Unix (подробнее ниже)
  • Пути, безопасные для профиля: никогда не хардкодьте ~/.hermes — для путей в коде берите get_hermes_home() из hermes_constants, а для пользовательских сообщений display_hermes_home(). Полные правила — в AGENTS.md.

Кросс-платформенная совместимость

Hermes официально поддерживает Linux, macOS, WSL2 и нативный Windows (через установщик PowerShell). На нативном Windows shell-команды выполняются через Git Bash (из Git for Windows). Часть функций опирается на примитивы POSIX-ядра и доступна с ограничениями: встроенная PTY-панель терминала на вкладке /chat дашборда работает только в WSL2. Если вы много разрабатываете под Windows, перед пушем прогоните линтер для типичных Windows-ошибок (scripts/check-windows-footguns.py).

При написании кода учитывайте следующие правила:

  • Не добавляйте незащищённые ссылки на signal.SIGKILL. На Windows этот сигнал не определён. Либо используйте gateway.status.terminate_pid(pid, force=True) (централизованный примитив, который вызывает taskkill /T /F на Windows и SIGKILL на POSIX), либо делайте фолбэк через getattr(signal, "SIGKILL", signal.SIGTERM).
  • Перехватывайте OSError вместе с ProcessLookupError при проверках os.kill(pid, 0). Для уже завершённого PID Windows поднимает OSError (WinError 87, «параметр неверен») вместо ProcessLookupError.
  • Не навязывайте терминалу POSIX-семантику. os.setsid, os.killpg, os.getpgid, os.fork на Windows бросают исключения — оборачивайте их в if sys.platform != "win32": или if os.name != "nt":.
  • Открывайте файлы с явным encoding="utf-8". По умолчанию на Windows Python берёт системную локаль (нередко cp1252), а та ломает или портит не-латинский текст.
  • Используйте pathlib.Path / os.path.join — никогда не склеивайте пути вручную через /. Это особенно важно для строк, которые мы сами формируем для передачи в подпроцессы.

Ключевые шаблоны:

1. termios и fcntl — только для Unix

Всегда перехватывайте и ImportError, и NotImplementedError:

try:
    from simple_term_menu import TerminalMenu
    menu = TerminalMenu(options)
    idx = menu.show()
except (ImportError, NotImplementedError):
    # Резервный вариант: нумерованное меню
    for i, opt in enumerate(options):
        print(f"  {i+1}. {opt}")
    idx = int(input("Choice: ")) - 1

2. Кодировка файлов

В некоторых окружениях .env-файлы сохраняются в кодировках, отличных от UTF-8:

try:
    load_dotenv(env_path)
except UnicodeDecodeError:
    load_dotenv(env_path, encoding="latin-1")

3. Управление процессами

os.setsid(), os.killpg() и обработка сигналов на разных платформах ведут себя по-разному:

import platform
if platform.system() != "Windows":
    kwargs["preexec_fn"] = os.setsid

4. Разделители путей

Используйте pathlib.Path вместо конкатенации строк через /.

Вопросы безопасности

У Hermes есть доступ к терминалу. Безопасность важна.

Существующие защитные механизмы

СлойРеализация
Передача пароля sudoИспользуется shlex.quote() для защиты от shell-инъекций
Обнаружение опасных командRegex-паттерны в tools/approval.py с запросом подтверждения у пользователя
Инъекция промпта через cronСканер блокирует паттерны переопределения инструкций
Список запрещённых путей на записьЗащищённые пути разрешаются через os.path.realpath(), чтобы исключить обход через симлинки
Защита навыковСканер безопасности для навыков, установленных из хаба
Песочница выполнения кодаДочерний процесс запускается без ключей API
Усиление контейнераDocker: все capabilities сброшены, нет эскалации привилегий, ограничения PID

Код, затрагивающий безопасность

  • Всегда используйте shlex.quote() при подстановке пользовательского ввода в shell-команды
  • Разрешайте симлинки через os.path.realpath() перед проверками контроля доступа
  • Не логируйте секреты
  • Оборачивайте выполнение инструментов в широкие блоки перехвата исключений
  • Тестируйте на всех платформах, если изменение касается файловых путей или процессов

Процесс pull request

Именование веток

fix/description        # Исправления багов
feat/description       # Новые функции
docs/description       # Документация
test/description       # Тесты
refactor/description   # Рефакторинг кода

Перед отправкой

  1. Запустите тесты: pytest tests/ -v
  2. Протестируйте вручную: запустите hermes и проверьте затронутый код
  3. Оцените кросс-платформенное влияние: учтите macOS и разные дистрибутивы Linux
  4. Держите PR сфокусированным: одно логическое изменение на PR

Описание PR

Включите:

  • Что изменено и зачем
  • Как протестировать изменение
  • На каких платформах вы проверяли
  • Ссылки на связанные issues

Сообщения коммитов

Мы используем Conventional Commits:

<type>(<scope>): <description>
ТипИспользование
fixИсправления багов
featНовые функции
docsДокументация
testТесты
refactorРефакторинг кода
choreСборка, CI, обновление зависимостей

Скоупы: cli, gateway, tools, skills, agent, install, whatsapp, security

Примеры:

fix(cli): prevent crash in save_config_value when model is a string
feat(gateway): add WhatsApp multi-user session isolation
fix(security): prevent shell injection in sudo password piping

Сообщения об ошибках

  • Используйте GitHub Issues
  • Указывайте: ОС, версию Python, версию Hermes (hermes version), полный стектрейс ошибки
  • Добавляйте шаги для воспроизведения
  • Проверяйте существующие issues, чтобы не создавать дубликаты
  • Уязвимости безопасности сообщайте в приватном порядке

Сообщество

  • Discord: discord.gg/NousResearch
  • GitHub Discussions: для обсуждения архитектурных решений и предложений по дизайну
  • Skills Hub: публикуйте специализированные навыки и делитесь ими с сообществом

Лицензия

Отправляя свои изменения, вы соглашаетесь с тем, что они будут распространяться под лицензией MIT.

ESC