Участие в разработке
Спасибо за вклад в Hermes Agent! Здесь разобраны настройка рабочего окружения, устройство кодовой базы и путь от написания кода до принятого PR.
Приоритеты вкладов
Вклады мы ценим в таком порядке:
- Исправления багов — сбои, некорректное поведение, потеря данных
- Кросс-платформенная совместимость — macOS, разные дистрибутивы Linux, WSL2
- Укрепление безопасности — инъекции через shell, инъекции в промпт, обход каталогов
- Производительность и надёжность — логика повторных попыток, обработка ошибок, graceful degradation
- Новые навыки — широко применимые (см. Создание навыков)
- Новые инструменты — нужны редко; большинство возможностей лучше реализовывать как навыки
- Документация — исправления, уточнения, новые примеры
Распространённые сценарии участия
- Пишете собственный/локальный инструмент без правок ядра Hermes? Начните с Создание плагина Hermes
- Добавляете новый встроенный инструмент в само ядро Hermes? Начните с Добавление инструментов
- Создаёте новый навык? Начните с Создание навыков
- Добавляете нового провайдера инференса? Начните с Добавление провайдеров
Настройка окружения разработки
Требования
| Требование | Примечания |
|---|---|
| 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 # Рефакторинг кода
Перед отправкой
- Запустите тесты:
pytest tests/ -v - Протестируйте вручную: запустите
hermesи проверьте затронутый код - Оцените кросс-платформенное влияние: учтите macOS и разные дистрибутивы Linux
- Держите 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.