感謝你為 Hermes Agent 做出貢獻!本指南涵蓋設定開發環境、理解程式碼庫,以及讓你的 PR 被合併。
貢獻優先順序
我們按以下順序重視貢獻:
- 錯誤修正 — 崩潰、不正確的行為、資料遺失
- 跨平台相容性 — macOS、不同的 Linux 發行版、WSL2
- 安全性強化 — shell 注入、提示注入、路徑遍歷
- 效能與穩健性 — 重試邏輯、錯誤處理、優雅降級
- 新技能 — 廣泛有用的技能(參見建立技能)
- 新工具 — 很少需要;大部分功能應該用技能實作
- 文件 — 修正、說明、新範例
常見貢獻路徑
- 不修改 Hermes 核心,建構自訂/本地工具?從建構 Hermes 外掛開始
- 為 Hermes 本身建構新的內建核心工具?從新增工具開始
- 建構新技能?從建立技能開始
- 建構新的推論供應商?從新增供應商開始
開發環境設定
前置需求
| 需求 | 備註 |
|---|---|
| Git | 需安裝 git-lfs 擴充 |
| Python 3.11+ | 若缺少,uv 會自動安裝 |
| uv | 快速 Python 套件管理器(安裝方式) |
| Node.js 20+ | 選用——瀏覽器工具和 WhatsApp 橋接需要(與根目錄 package.json engines 一致) |
使用標準安裝器安裝
對於大多數貢獻者,最佳的開發引導方式與使用者相同:執行標準安裝器,然後在它克隆的儲存庫內工作。安裝器會建立 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 入口點;使用系統的 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"
# 安裝所有額外套件(訊息、排程、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 或明確地建立此克隆的虛擬環境符號連結:
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(見下文)
- Profile 安全路徑:永遠不要硬編碼
~/.hermes——程式碼路徑使用hermes_constants中的get_hermes_home(),面向使用者的訊息使用display_hermes_home()。完整規則參見 AGENTS.md。
跨平台相容性
Hermes 官方支援 Linux、macOS、WSL2 和原生 Windows(透過 PowerShell 安裝)。原生 Windows 使用 Git Bash(來自 Git for Windows)執行 shell 命令。部分功能需要 POSIX 核心原語並受到閘控:儀表板的嵌入式 PTY 終端機面板(/chat 標籤頁)僅限 WSL2。如果你大量進行 Windows 開發,在推送前執行 Windows 殺手檢查(scripts/check-windows-footguns.py)。
撰寫貢獻程式碼時,請牢記以下規則:
- 不要加入未受保護的
signal.SIGKILL引用。 它在 Windows 上未定義。改用gateway.status.terminate_pid(pid, force=True)(在 Windows 上執行taskkill /T /F、在 POSIX 上執行 SIGKILL 的集中化原語),或使用getattr(signal, "SIGKILL", signal.SIGTERM)做回退。 - 在
os.kill(pid, 0)探測中,除了ProcessLookupError外也要捕捉OSError。 Windows 對已結束的 PID 拋出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——永遠不要手動用/串接。 這對 OS 回傳的字串影響較小,但對我們建構並傳給子程序的字串很重要。
關鍵模式:
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. 檔案編碼
某些環境可能以非 UTF-8 編碼儲存 .env 檔案:
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 注入 |
| 危險指令偵測 | tools/approval.py 中的正則表達式模式,搭配使用者審核流程 |
| 排程提示注入 | 掃描器阻擋指令覆寫模式 |
| 寫入拒絕清單 | 受保護路徑透過 os.path.realpath() 解析以防止符號連結繞過 |
| 技能防護 | 針對 hub 安裝技能的安全掃描器 |
| 程式碼執行沙箱 | 子程序以移除 API 金鑰的狀態運行 |
| 容器強化 | Docker:移除所有能力、禁止權限提升、PID 限制 |
負責安全敏感程式碼的貢獻
- 將使用者輸入插值到 shell 命令時,永遠使用
shlex.quote() - 在存取控制檢查前,使用
os.path.realpath()解析符號連結 - 不要記錄密鑰
- 在工具執行周圍捕捉廣泛例外
- 如果你的變更涉及檔案路徑或程序,請在所有平台上測試
Pull Request 流程
分支命名
fix/description # 錯誤修正
feat/description # 新功能
docs/description # 文件
test/description # 測試
refactor/description # 程式碼重構
提交前
- 執行測試:
pytest tests/ -v - 手動測試:執行
hermes並測試你修改的程式碼路徑 - 檢查跨平台影響:考慮 macOS 和不同的 Linux 發行版
- 保持 PR 專注:每個 PR 一個邏輯變更
PR 描述
包含:
- 改了什麼以及為什麼
- 如何測試
- 在哪些平台上測試過
- 引用任何相關的 issue
提交訊息
我們使用 Conventional Commits:
<type>(<scope>): <description>
| 類型 | 用途 |
|---|---|
fix | 錯誤修正 |
feat | 新功能 |
docs | 文件 |
test | 測試 |
refactor | 程式碼重構 |
chore | 建構、CI、依賴更新 |
Scopes: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 License 下授權。