docs: add PR review guides, rework quickstart, slim down installation

Adds two complementary GitHub PR review guides from contest submissions:
- Cron-based PR review agent (from PR #5836 by @dieutx) — polls on a
  schedule, no server needed, teaches skills + memory authoring
- Webhook-based PR review (from PR #6503 by @gaijinkush) — real-time via
  GitHub webhooks, documents previously undocumented webhook feature
Both guides are cross-linked so users can pick the approach that fits.

Reworks quickstart.md by integrating the best content from PR #5744
by @aidil2105:
- Opinionated decision table ('The fastest path')
- Common failure modes table with causes and fixes
- Recovery toolkit sequence
- Session lifecycle verification step
- Better first-chat guidance with example prompts

Slims down installation.md:
- Removes 10-step manual/dev install section (already covered in
  developer-guide/contributing.md)
- Links to Contributing guide for dev setup
- Keeps focused on the automated installer + prerequisites + troubleshooting
This commit is contained in:
Teknium 2026-04-09 03:16:04 -07:00 committed by Teknium
parent d5fc8a5e00
commit 37524a574e
5 changed files with 784 additions and 301 deletions

View file

@ -6,7 +6,7 @@ description: "Install Hermes Agent on Linux, macOS, WSL2, or Android via Termux"
# Installation
Get Hermes Agent up and running in under two minutes with the one-line installer, or follow the manual steps for full control.
Get Hermes Agent up and running in under two minutes with the one-line installer.
## Quick Install
@ -82,202 +82,9 @@ If you use Nix (on NixOS, macOS, or Linux), there's a dedicated setup path with
---
## Manual Installation
## Manual / Developer Installation
If you prefer full control over the installation process, follow these steps.
### Step 1: Clone the Repository
Clone with `--recurse-submodules` to pull the required submodules:
```bash
git clone --recurse-submodules https://github.com/NousResearch/hermes-agent.git
cd hermes-agent
```
If you already cloned without `--recurse-submodules`:
```bash
git submodule update --init --recursive
```
### Step 2: Install uv & Create Virtual Environment
```bash
# Install uv (if not already installed)
curl -LsSf https://astral.sh/uv/install.sh | sh
# Create venv with Python 3.11 (uv downloads it if not present — no sudo needed)
uv venv venv --python 3.11
```
:::tip
You do **not** need to activate the venv to use `hermes`. The entry point has a hardcoded shebang pointing to the venv Python, so it works globally once symlinked.
:::
### Step 3: Install Python Dependencies
```bash
# Tell uv which venv to install into
export VIRTUAL_ENV="$(pwd)/venv"
# Install with all extras
uv pip install -e ".[all]"
```
If you only want the core agent (no Telegram/Discord/cron support):
```bash
uv pip install -e "."
```
<details>
<summary><strong>Optional extras breakdown</strong></summary>
| Extra | What it adds | Install command |
|-------|-------------|-----------------|
| `all` | Everything below | `uv pip install -e ".[all]"` |
| `messaging` | Telegram, Discord & Slack gateway | `uv pip install -e ".[messaging]"` |
| `cron` | Cron expression parsing for scheduled tasks | `uv pip install -e ".[cron]"` |
| `cli` | Terminal menu UI for setup wizard | `uv pip install -e ".[cli]"` |
| `modal` | Modal cloud execution backend | `uv pip install -e ".[modal]"` |
| `tts-premium` | ElevenLabs premium voices | `uv pip install -e ".[tts-premium]"` |
| `voice` | CLI microphone input + audio playback | `uv pip install -e ".[voice]"` |
| `pty` | PTY terminal support | `uv pip install -e ".[pty]"` |
| `termux` | Tested Android / Termux bundle (`cron`, `cli`, `pty`, `mcp`, `honcho`, `acp`) | `python -m pip install -e ".[termux]" -c constraints-termux.txt` |
| `honcho` | AI-native memory (Honcho integration) | `uv pip install -e ".[honcho]"` |
| `mcp` | Model Context Protocol support | `uv pip install -e ".[mcp]"` |
| `homeassistant` | Home Assistant integration | `uv pip install -e ".[homeassistant]"` |
| `acp` | ACP editor integration support | `uv pip install -e ".[acp]"` |
| `slack` | Slack messaging | `uv pip install -e ".[slack]"` |
| `dev` | pytest & test utilities | `uv pip install -e ".[dev]"` |
You can combine extras: `uv pip install -e ".[messaging,cron]"`
:::tip Termux users
`.[all]` is not currently available on Android because the `voice` extra pulls `faster-whisper`, which depends on `ctranslate2` wheels that are not published for Android. Use `.[termux]` for the tested mobile install path, then add individual extras only as needed.
:::
</details>
### Step 4: Install Optional Submodules (if needed)
```bash
# RL training backend (optional)
uv pip install -e "./tinker-atropos"
```
Both are optional — if you skip them, the corresponding toolsets simply won't be available.
### Step 5: Install Node.js Dependencies (Optional)
Only needed for **browser automation** (Browserbase-powered) and **WhatsApp bridge**:
```bash
npm install
```
### Step 6: Create the Configuration Directory
```bash
# Create the directory structure
mkdir -p ~/.hermes/{cron,sessions,logs,memories,skills,pairing,hooks,image_cache,audio_cache,whatsapp/session}
# Copy the example config file
cp cli-config.yaml.example ~/.hermes/config.yaml
# Create an empty .env file for API keys
touch ~/.hermes/.env
```
### Step 7: Add Your API Keys
Open `~/.hermes/.env` and add at minimum an LLM provider key:
```bash
# Required — at least one LLM provider:
OPENROUTER_API_KEY=sk-or-v1-your-key-here
# Optional — enable additional tools:
FIRECRAWL_API_KEY=fc-your-key # Web search & scraping (or self-host, see docs)
FAL_KEY=your-fal-key # Image generation (FLUX)
```
Or set them via the CLI:
```bash
hermes config set OPENROUTER_API_KEY sk-or-v1-your-key-here
```
### Step 8: Add `hermes` to Your PATH
```bash
mkdir -p ~/.local/bin
ln -sf "$(pwd)/venv/bin/hermes" ~/.local/bin/hermes
```
If `~/.local/bin` isn't on your PATH, add it to your shell config:
```bash
# Bash
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc && source ~/.bashrc
# Zsh
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc && source ~/.zshrc
# Fish
fish_add_path $HOME/.local/bin
```
### Step 9: Configure Your Provider
```bash
hermes model # Select your LLM provider and model
```
### Step 10: Verify the Installation
```bash
hermes version # Check that the command is available
hermes doctor # Run diagnostics to verify everything is working
hermes status # Check your configuration
hermes chat -q "Hello! What tools do you have available?"
```
---
## Quick-Reference: Manual Install (Condensed)
For those who just want the commands:
```bash
# Install uv
curl -LsSf https://astral.sh/uv/install.sh | sh
# Clone & enter
git clone --recurse-submodules https://github.com/NousResearch/hermes-agent.git
cd hermes-agent
# Create venv with Python 3.11
uv venv venv --python 3.11
export VIRTUAL_ENV="$(pwd)/venv"
# Install everything
uv pip install -e ".[all]"
uv pip install -e "./tinker-atropos"
npm install # optional, for browser tools and WhatsApp
# Configure
mkdir -p ~/.hermes/{cron,sessions,logs,memories,skills,pairing,hooks,image_cache,audio_cache,whatsapp/session}
cp cli-config.yaml.example ~/.hermes/config.yaml
touch ~/.hermes/.env
echo 'OPENROUTER_API_KEY=sk-or-v1-your-key' >> ~/.hermes/.env
# Make hermes available globally
mkdir -p ~/.local/bin
ln -sf "$(pwd)/venv/bin/hermes" ~/.local/bin/hermes
# Verify
hermes doctor
hermes
```
If you want to clone the repo and install from source — for contributing, running from a specific branch, or having full control over the virtual environment — see the [Development Setup](../developer-guide/contributing.md#development-setup) section in the Contributing guide.
---

View file

@ -1,12 +1,35 @@
---
sidebar_position: 1
title: "Quickstart"
description: "Your first conversation with Hermes Agent — from install to chatting in 2 minutes"
description: "Your first conversation with Hermes Agent — from install to chatting in under 5 minutes"
---
# Quickstart
This guide walks you through installing Hermes Agent, setting up a provider, and having your first conversation. By the end, you'll know the key features and how to explore further.
This guide gets you from zero to a working Hermes setup that survives real use. Install, choose a provider, verify a working chat, and know exactly what to do when something breaks.
## Who this is for
- Brand new and want the shortest path to a working setup
- Switching providers and don't want to lose time to config mistakes
- Setting up Hermes for a team, bot, or always-on workflow
- Tired of "it installed, but it still does nothing"
## The fastest path
Pick the row that matches your goal:
| Goal | Do this first | Then do this |
|---|---|---|
| I just want Hermes working on my machine | `hermes setup` | Run a real chat and verify it responds |
| I already know my provider | `hermes model` | Save the config, then start chatting |
| I want a bot or always-on setup | `hermes gateway setup` after CLI works | Connect Telegram, Discord, Slack, or another platform |
| I want a local or self-hosted model | `hermes model` → custom endpoint | Verify the endpoint, model name, and context length |
| I want multi-provider fallback | `hermes model` first | Add routing and fallback only after the base chat works |
**Rule of thumb:** if Hermes cannot complete a normal chat, do not add more features yet. Get one clean conversation working first, then layer on gateway, cron, skills, voice, or routing.
---
## 1. Install Hermes Agent
@ -31,86 +54,109 @@ After it finishes, reload your shell:
source ~/.bashrc # or source ~/.zshrc
```
## 2. Set Up a Provider
For detailed installation options, prerequisites, and troubleshooting, see the [Installation guide](./installation.md).
The installer configures your LLM provider automatically. To change it later, use one of these commands:
## 2. Choose a Provider
The single most important setup step. Use `hermes model` to walk through the choice interactively:
```bash
hermes model # Choose your LLM provider and model
hermes tools # Configure which tools are enabled
hermes setup # Or configure everything at once
hermes model
```
`hermes model` walks you through selecting an inference provider:
Good defaults:
| Provider | What it is | How to set up |
|----------|-----------|---------------|
| **Nous Portal** | Subscription-based, zero-config | OAuth login via `hermes model` |
| **OpenAI Codex** | ChatGPT OAuth, uses Codex models | Device code auth via `hermes model` |
| **Anthropic** | Claude models directly (Pro/Max or API key) | `hermes model` with Claude Code auth, or an Anthropic API key |
| **OpenRouter** | Multi-provider routing across many models | Enter your API key |
| **Z.AI** | GLM / Zhipu-hosted models | Set `GLM_API_KEY` / `ZAI_API_KEY` |
| **Kimi / Moonshot** | Moonshot-hosted coding and chat models | Set `KIMI_API_KEY` |
| **Kimi / Moonshot China** | China-region Moonshot endpoint | Set `KIMI_CN_API_KEY` |
| **Arcee AI** | Trinity models | Set `ARCEEAI_API_KEY` |
| **Xiaomi MiMo** | Xiaomi MiMo models via [platform.xiaomimimo.com](https://platform.xiaomimimo.com) | Set `XIAOMI_API_KEY` |
| **AWS Bedrock** | Anthropic Claude, Amazon Nova, DeepSeek v3.2, and Meta Llama via AWS | Standard boto3 auth (`AWS_PROFILE` or `AWS_ACCESS_KEY_ID` + `AWS_REGION`) |
| **Qwen Portal (OAuth)** | Qwen 3.5 / Qwen-Coder models via Alibaba's consumer Qwen Portal | OAuth via `hermes model` (optional: `HERMES_QWEN_BASE_URL`) |
| **MiniMax** | International MiniMax endpoint | Set `MINIMAX_API_KEY` |
| **MiniMax China** | China-region MiniMax endpoint | Set `MINIMAX_CN_API_KEY` |
| **Alibaba Cloud** | Qwen models via DashScope | Set `DASHSCOPE_API_KEY` |
| **Hugging Face** | 20+ open models via unified router (Qwen, DeepSeek, Kimi, etc.) | Set `HF_TOKEN` |
| **Kilo Code** | KiloCode-hosted models | Set `KILOCODE_API_KEY` |
| **OpenCode Zen** | Pay-as-you-go access to curated models | Set `OPENCODE_ZEN_API_KEY` |
| **OpenCode Go** | $10/month subscription for open models | Set `OPENCODE_GO_API_KEY` |
| **DeepSeek** | Direct DeepSeek API access | Set `DEEPSEEK_API_KEY` |
| **NVIDIA NIM** | Nemotron models via build.nvidia.com or local NIM | Set `NVIDIA_API_KEY` (optional: `NVIDIA_BASE_URL`) |
| **Ollama Cloud** | Managed Ollama catalog without local GPU | Set `OLLAMA_API_KEY` (or pick **Ollama Cloud** in `hermes model`) |
| **Google Gemini (OAuth)** | Gemini via Cloud Code Assist — free and paid tiers | OAuth via `hermes model` (optional: `HERMES_GEMINI_PROJECT_ID` for paid tiers) |
| **xAI (Grok)** | Grok 4 models via Responses API + prompt caching | Set `XAI_API_KEY` (alias: `grok`) |
| **GitHub Copilot** | GitHub Copilot subscription (GPT-5.x, Claude, Gemini, etc.) | OAuth via `hermes model`, or `COPILOT_GITHUB_TOKEN` / `GH_TOKEN` |
| **GitHub Copilot ACP** | Copilot ACP agent backend (spawns local `copilot` CLI) | `hermes model` (requires `copilot` CLI + `copilot login`) |
| **Vercel AI Gateway** | Vercel AI Gateway routing | Set `AI_GATEWAY_API_KEY` |
| **Custom Endpoint** | VLLM, SGLang, Ollama, or any OpenAI-compatible API | Set base URL + API key |
| Situation | Recommended path |
|---|---|
| Least friction | Nous Portal or OpenRouter |
| You already have Claude or Codex auth | Anthropic or OpenAI Codex |
| You want local/private inference | Ollama or any custom OpenAI-compatible endpoint |
| You want multi-provider routing | OpenRouter |
| You have a custom GPU server | vLLM, SGLang, LiteLLM, or any OpenAI-compatible endpoint |
For most first-time users: choose a provider, accept the defaults unless you know why you're changing them. The full provider catalog with env vars and setup steps lives on the [Providers](../integrations/providers.md) page.
:::caution Minimum context: 64K tokens
Hermes Agent requires a model with at least **64,000 tokens** of context. Models with smaller windows cannot maintain enough working memory for multi-step tool-calling workflows and will be rejected at startup. Most hosted models (Claude, GPT, Gemini, Qwen, DeepSeek) meet this easily. If you're running a local model, set its context size to at least 64K (e.g. `--ctx-size 65536` for llama.cpp or `-c 65536` for Ollama).
:::
:::tip
You can switch providers at any time with `hermes model` — no code changes, no lock-in. When configuring a custom endpoint, Hermes will prompt for the context window size and auto-detect it when possible. See [Context Length Detection](../integrations/providers.md#context-length-detection) for details.
You can switch providers at any time with `hermes model` — no lock-in. For a full list of all supported providers and setup details, see [AI Providers](../integrations/providers.md).
:::
## 3. Start Chatting
### How settings are stored
Hermes separates secrets from normal config:
- **Secrets and tokens**`~/.hermes/.env`
- **Non-secret settings**`~/.hermes/config.yaml`
The easiest way to set values correctly is through the CLI:
```bash
hermes config set model anthropic/claude-opus-4.6
hermes config set terminal.backend docker
hermes config set OPENROUTER_API_KEY sk-or-...
```
The right value goes to the right file automatically.
## 3. Run Your First Chat
```bash
hermes # classic CLI
hermes --tui # modern TUI (recommended)
```
That's it! You'll see a welcome banner with your model, available tools, and skills. Type a message and press Enter.
You'll see a welcome banner with your model, available tools, and skills. Use a prompt that's specific and easy to verify:
:::tip Pick your interface
Hermes ships with two terminal interfaces: the classic `prompt_toolkit` CLI and a newer [TUI](../user-guide/tui.md) with modal overlays, mouse selection, and non-blocking input. Both share the same sessions, slash commands, and config — try each with `hermes` vs `hermes --tui`.
:::
```
What can you help me with?
Summarize this repo in 5 bullets and tell me what the main entrypoint is.
```
The agent has access to tools for web search, file operations, terminal commands, and more — all out of the box.
```
Check my current directory and tell me what looks like the main project file.
```
## 4. Try Key Features
```
Help me set up a clean GitHub PR workflow for this codebase.
```
### Ask it to use the terminal
**What success looks like:**
- The banner shows your chosen model/provider
- Hermes replies without error
- It can use a tool if needed (terminal, file read, web search)
- The conversation continues normally for more than one turn
If that works, you're past the hardest part.
## 4. Verify Sessions Work
Before moving on, make sure resume works:
```bash
hermes --continue # Resume the most recent session
hermes -c # Short form
```
That should bring you back to the session you just had. If it doesn't, check whether you're in the same profile and whether the session actually saved. This matters later when you're juggling multiple setups or machines.
## 5. Try Key Features
### Use the terminal
```
What's my disk usage? Show the top 5 largest directories.
```
The agent will run terminal commands on your behalf and show you the results.
The agent runs terminal commands on your behalf and shows results.
### Use slash commands
### Slash commands
Type `/` to see an autocomplete dropdown of all commands:
@ -128,22 +174,27 @@ Press `Alt+Enter` or `Ctrl+J` to add a new line. Great for pasting code or writi
### Interrupt the agent
If the agent is taking too long, just type a new message and press Enter — it interrupts the current task and switches to your new instructions. `Ctrl+C` also works.
If the agent is taking too long, type a new message and press Enter — it interrupts the current task and switches to your new instructions. `Ctrl+C` also works.
### Resume a session
## 6. Add the Next Layer
When you exit, hermes prints a resume command:
Only after the base chat works. Pick what you need:
### Bot or shared assistant
```bash
hermes --continue # Resume the most recent session
hermes -c # Short form
hermes gateway setup # Interactive platform configuration
```
## 5. Explore Further
Connect [Telegram](/docs/user-guide/messaging/telegram), [Discord](/docs/user-guide/messaging/discord), [Slack](/docs/user-guide/messaging/slack), [WhatsApp](/docs/user-guide/messaging/whatsapp), [Signal](/docs/user-guide/messaging/signal), [Email](/docs/user-guide/messaging/email), or [Home Assistant](/docs/user-guide/messaging/homeassistant).
Here are some things to try next:
### Automation and tools
### Set up a sandboxed terminal
- `hermes tools` — tune tool access per platform
- `hermes skills` — browse and install reusable workflows
- Cron — only after your bot or CLI setup is stable
### Sandboxed terminal
For safety, run the agent in a Docker container or on a remote server:
@ -152,71 +203,25 @@ hermes config set terminal.backend docker # Docker isolation
hermes config set terminal.backend ssh # Remote server
```
### Connect messaging platforms
Chat with Hermes from your phone or other surfaces via Telegram, Discord, Slack, WhatsApp, Signal, Email, or Home Assistant:
```bash
hermes gateway setup # Interactive platform configuration
```
### Add voice mode
Want microphone input in the CLI or spoken replies in messaging?
### Voice mode
```bash
pip install "hermes-agent[voice]"
# Includes faster-whisper for free local speech-to-text
```
Then start Hermes and enable it inside the CLI:
Then in the CLI: `/voice on`. Press `Ctrl+B` to record. See [Voice Mode](../user-guide/features/voice-mode.md).
```text
/voice on
```
Press `Ctrl+B` to record, or use `/voice tts` to have Hermes speak its replies. See [Voice Mode](../user-guide/features/voice-mode.md) for the full setup across CLI, Telegram, Discord, and Discord voice channels.
### Schedule automated tasks
```
Every morning at 9am, check Hacker News for AI news and send me a summary on Telegram.
```
The agent will set up a cron job that runs automatically via the gateway.
### Browse and install skills
### Skills
```bash
hermes skills search kubernetes
hermes skills search react --source skills-sh
hermes skills search https://mintlify.com/docs --source well-known
hermes skills install openai/skills/k8s
hermes skills install official/security/1password
hermes skills install skills-sh/vercel-labs/json-render/json-render-react --force
```
Tips:
- Use `--source skills-sh` to search the public `skills.sh` directory.
- Use `--source well-known` with a docs/site URL to discover skills from `/.well-known/skills/index.json`.
- Use `--force` only after reviewing a third-party skill. It can override non-dangerous policy blocks, but not a `dangerous` scan verdict.
Or use `/skills` inside a chat session.
Or use the `/skills` slash command inside chat.
### Use Hermes inside an editor via ACP
Hermes can also run as an ACP server for ACP-compatible editors like VS Code, Zed, and JetBrains:
```bash
pip install -e '.[acp]'
hermes acp
```
See [ACP Editor Integration](../user-guide/features/acp.md) for setup details.
### Try MCP servers
Connect to external tools via the Model Context Protocol:
### MCP servers
```yaml
# Add to ~/.hermes/config.yaml
@ -228,6 +233,43 @@ mcp_servers:
GITHUB_PERSONAL_ACCESS_TOKEN: "ghp_xxx"
```
### Editor integration (ACP)
```bash
pip install -e '.[acp]'
hermes acp
```
See [ACP Editor Integration](../user-guide/features/acp.md).
---
## Common Failure Modes
These are the problems that waste the most time:
| Symptom | Likely cause | Fix |
|---|---|---|
| Hermes opens but gives empty or broken replies | Provider auth or model selection is wrong | Run `hermes model` again and confirm provider, model, and auth |
| Custom endpoint "works" but returns garbage | Wrong base URL, model name, or not actually OpenAI-compatible | Verify the endpoint in a separate client first |
| Gateway starts but nobody can message it | Bot token, allowlist, or platform setup is incomplete | Re-run `hermes gateway setup` and check `hermes gateway status` |
| `hermes --continue` can't find old session | Switched profiles or session never saved | Check `hermes sessions list` and confirm you're in the right profile |
| Model unavailable or odd fallback behavior | Provider routing or fallback settings are too aggressive | Keep routing off until the base provider is stable |
| `hermes doctor` flags config problems | Config values are missing or stale | Fix the config, retest a plain chat before adding features |
## Recovery Toolkit
When something feels off, use this order:
1. `hermes doctor`
2. `hermes model`
3. `hermes setup`
4. `hermes sessions list`
5. `hermes --continue`
6. `hermes gateway status`
That sequence gets you from "broken vibes" back to a known state fast.
---
## Quick Reference
@ -249,3 +291,6 @@ mcp_servers:
- **[Configuration](../user-guide/configuration.md)** — Customize your setup
- **[Messaging Gateway](../user-guide/messaging/index.md)** — Connect Telegram, Discord, Slack, WhatsApp, Signal, Email, or Home Assistant
- **[Tools & Toolsets](../user-guide/features/tools.md)** — Explore available capabilities
- **[AI Providers](../integrations/providers.md)** — Full provider list and setup details
- **[Skills System](../user-guide/features/skills.md)** — Reusable workflows and knowledge
- **[Tips & Best Practices](../guides/tips.md)** — Power user tips

View file

@ -0,0 +1,300 @@
---
sidebar_position: 10
title: "Tutorial: GitHub PR Review Agent"
description: "Build an automated AI code reviewer that monitors your repos, reviews pull requests, and delivers feedback — hands-free"
---
# Tutorial: Build a GitHub PR Review Agent
**The problem:** Your team opens PRs faster than you can review them. PRs sit for days waiting for eyeballs. Junior devs merge bugs because nobody had time to check. You spend your mornings catching up on diffs instead of building.
**The solution:** An AI agent that watches your repos around the clock, reviews every new PR for bugs, security issues, and code quality, and sends you a summary — so you only spend time on PRs that actually need human judgment.
**What you'll build:**
```
┌──────────────┐ ┌───────────────┐ ┌──────────────┐ ┌──────────────┐
│ Cron Timer │────▶│ Hermes Agent │────▶│ GitHub API │────▶│ Review to │
│ (every 2h) │ │ + gh CLI │ │ (PR diffs) │ │ Telegram/ │
│ │ │ + skill │ │ │ │ Discord/ │
│ │ │ + memory │ │ │ │ local file │
└──────────────┘ └───────────────┘ └──────────────┘ └──────────────┘
```
This guide uses **cron jobs** to poll for PRs on a schedule — no server or public endpoint needed. Works behind NAT and firewalls.
:::tip Want real-time reviews instead?
If you have a public endpoint available, check out [Automated GitHub PR Comments with Webhooks](./webhook-github-pr-review.md) — GitHub pushes events to Hermes instantly when PRs are opened or updated.
:::
---
## Prerequisites
- **Hermes Agent installed** — see the [Installation guide](/docs/getting-started/installation)
- **Gateway running** for cron jobs:
```bash
hermes gateway install # Install as a service
# or
hermes gateway # Run in foreground
```
- **GitHub CLI (`gh`) installed and authenticated**:
```bash
# Install
brew install gh # macOS
sudo apt install gh # Ubuntu/Debian
# Authenticate
gh auth login
```
- **Messaging configured** (optional) — [Telegram](/docs/user-guide/messaging/telegram) or [Discord](/docs/user-guide/messaging/discord)
:::tip No messaging? No problem
Use `deliver: "local"` to save reviews to `~/.hermes/cron/output/`. Great for testing before wiring up notifications.
:::
---
## Step 1: Verify the Setup
Make sure Hermes can access GitHub. Start a chat:
```bash
hermes
```
Test with a simple command:
```
Run: gh pr list --repo NousResearch/hermes-agent --state open --limit 3
```
You should see a list of open PRs. If this works, you're ready.
---
## Step 2: Try a Manual Review
Still in the chat, ask Hermes to review a real PR:
```
Review this pull request. Read the diff, check for bugs, security issues,
and code quality. Be specific about line numbers and quote problematic code.
Run: gh pr diff 3888 --repo NousResearch/hermes-agent
```
Hermes will:
1. Execute `gh pr diff` to fetch the code changes
2. Read through the entire diff
3. Produce a structured review with specific findings
If you're happy with the quality, time to automate it.
---
## Step 3: Create a Review Skill
A skill gives Hermes consistent review guidelines that persist across sessions and cron runs. Without one, review quality varies.
```bash
mkdir -p ~/.hermes/skills/code-review
```
Create `~/.hermes/skills/code-review/SKILL.md`:
```markdown
---
name: code-review
description: Review pull requests for bugs, security issues, and code quality
---
# Code Review Guidelines
When reviewing a pull request:
## What to Check
1. **Bugs** — Logic errors, off-by-one, null/undefined handling
2. **Security** — Injection, auth bypass, secrets in code, SSRF
3. **Performance** — N+1 queries, unbounded loops, memory leaks
4. **Style** — Naming conventions, dead code, missing error handling
5. **Tests** — Are changes tested? Do tests cover edge cases?
## Output Format
For each finding:
- **File:Line** — exact location
- **Severity** — Critical / Warning / Suggestion
- **What's wrong** — one sentence
- **Fix** — how to fix it
## Rules
- Be specific. Quote the problematic code.
- Don't flag style nitpicks unless they affect readability.
- If the PR looks good, say so. Don't invent problems.
- End with: APPROVE / REQUEST_CHANGES / COMMENT
```
Verify it loaded — start `hermes` and you should see `code-review` in the skills list at startup.
---
## Step 4: Teach It Your Conventions
This is what makes the reviewer actually useful. Start a session and teach Hermes your team's standards:
```
Remember: In our backend repo, we use Python with FastAPI.
All endpoints must have type annotations and Pydantic models.
We don't allow raw SQL — only SQLAlchemy ORM.
Test files go in tests/ and must use pytest fixtures.
```
```
Remember: In our frontend repo, we use TypeScript with React.
No `any` types allowed. All components must have props interfaces.
We use React Query for data fetching, never useEffect for API calls.
```
These memories persist forever — the reviewer will enforce your conventions without being told each time.
---
## Step 5: Create the Automated Cron Job
Now wire it all together. Create a cron job that runs every 2 hours:
```bash
hermes cron create "0 */2 * * *" \
"Check for new open PRs and review them.
Repos to monitor:
- myorg/backend-api
- myorg/frontend-app
Steps:
1. Run: gh pr list --repo REPO --state open --limit 5 --json number,title,author,createdAt
2. For each PR created or updated in the last 4 hours:
- Run: gh pr diff NUMBER --repo REPO
- Review the diff using the code-review guidelines
3. Format output as:
## PR Reviews — today
### [repo] #[number]: [title]
**Author:** [name] | **Verdict:** APPROVE/REQUEST_CHANGES/COMMENT
[findings]
If no new PRs found, say: No new PRs to review." \
--name "pr-review" \
--deliver telegram \
--skill code-review
```
Verify it's scheduled:
```bash
hermes cron list
```
### Other useful schedules
| Schedule | When |
|----------|------|
| `0 */2 * * *` | Every 2 hours |
| `0 9,13,17 * * 1-5` | Three times a day, weekdays only |
| `0 9 * * 1` | Weekly Monday morning roundup |
| `30m` | Every 30 minutes (high-traffic repos) |
---
## Step 6: Run It On Demand
Don't want to wait for the schedule? Trigger it manually:
```bash
hermes cron run pr-review
```
Or from within a chat session:
```
/cron run pr-review
```
---
## Going Further
### Post Reviews Directly to GitHub
Instead of delivering to Telegram, have the agent comment on the PR itself:
Add this to your cron prompt:
```
After reviewing, post your review:
- For issues: gh pr review NUMBER --repo REPO --comment --body "YOUR_REVIEW"
- For critical issues: gh pr review NUMBER --repo REPO --request-changes --body "YOUR_REVIEW"
- For clean PRs: gh pr review NUMBER --repo REPO --approve --body "Looks good"
```
:::caution
Make sure `gh` has a token with `repo` scope. Reviews are posted as whoever `gh` is authenticated as.
:::
### Weekly PR Dashboard
Create a Monday morning overview of all your repos:
```bash
hermes cron create "0 9 * * 1" \
"Generate a weekly PR dashboard:
- myorg/backend-api
- myorg/frontend-app
- myorg/infra
For each repo show:
1. Open PR count and oldest PR age
2. PRs merged this week
3. Stale PRs (older than 5 days)
4. PRs with no reviewer assigned
Format as a clean summary." \
--name "weekly-dashboard" \
--deliver telegram
```
### Multi-Repo Monitoring
Scale up by adding more repos to the prompt. The agent processes them sequentially — no extra setup needed.
---
## Troubleshooting
### "gh: command not found"
The gateway runs in a minimal environment. Ensure `gh` is in the system PATH and restart the gateway.
### Reviews are too generic
1. Add the `code-review` skill (Step 3)
2. Teach Hermes your conventions via memory (Step 4)
3. The more context it has about your stack, the better the reviews
### Cron job doesn't run
```bash
hermes gateway status # Is the gateway running?
hermes cron list # Is the job enabled?
```
### Rate limits
GitHub allows 5,000 API requests/hour for authenticated users. Each PR review uses ~3-5 requests (list + diff + optional comments). Even reviewing 100 PRs/day stays well within limits.
---
## What's Next?
- **[Webhook-Based PR Reviews](./webhook-github-pr-review.md)** — get instant reviews when PRs are opened (requires a public endpoint)
- **[Daily Briefing Bot](/docs/guides/daily-briefing-bot)** — combine PR reviews with your morning news digest
- **[Build a Plugin](/docs/guides/build-a-hermes-plugin)** — wrap the review logic into a shareable plugin
- **[Profiles](/docs/user-guide/profiles)** — run a dedicated reviewer profile with its own memory and config
- **[Fallback Providers](/docs/user-guide/features/fallback-providers)** — ensure reviews run even when one provider is down

View file

@ -0,0 +1,329 @@
---
sidebar_position: 11
sidebar_label: "GitHub PR Reviews via Webhook"
title: "Automated GitHub PR Comments with Webhooks"
description: "Connect Hermes to GitHub so it automatically fetches PR diffs, reviews code changes, and posts comments — triggered by webhooks with no manual prompting"
---
# Automated GitHub PR Comments with Webhooks
This guide walks you through connecting Hermes Agent to GitHub so it automatically fetches a pull request's diff, analyzes the code changes, and posts a comment — triggered by a webhook event with no manual prompting.
When a PR is opened or updated, GitHub sends a webhook POST to your Hermes instance. Hermes runs the agent with a prompt that instructs it to retrieve the diff via the `gh` CLI, and the response is posted back to the PR thread.
:::tip Want a simpler setup without a public endpoint?
If you don't have a public URL or just want to get started quickly, check out [Build a GitHub PR Review Agent](./github-pr-review-agent.md) — uses cron jobs to poll for PRs on a schedule, works behind NAT and firewalls.
:::
:::info Reference docs
For the full webhook platform reference (all config options, delivery types, dynamic subscriptions, security model) see [Webhooks](/docs/user-guide/messaging/webhooks).
:::
:::warning Prompt injection risk
Webhook payloads contain attacker-controlled data — PR titles, commit messages, and descriptions can contain malicious instructions. When your webhook endpoint is exposed to the internet, run the gateway in a sandboxed environment (Docker, SSH backend). See the [security section](#security-notes) below.
:::
---
## Prerequisites
- Hermes Agent installed and running (`hermes gateway`)
- [`gh` CLI](https://cli.github.com/) installed and authenticated on the gateway host (`gh auth login`)
- A publicly reachable URL for your Hermes instance (see [Local testing with ngrok](#local-testing-with-ngrok) if running locally)
- Admin access to the GitHub repository (required to manage webhooks)
---
## Step 1 — Enable the webhook platform
Add the following to your `~/.hermes/config.yaml`:
```yaml
platforms:
webhook:
enabled: true
extra:
port: 8644 # default; change if another service occupies this port
rate_limit: 30 # max requests per minute per route (not a global cap)
routes:
github-pr-review:
secret: "your-webhook-secret-here" # must match the GitHub webhook secret exactly
events:
- pull_request
# The agent is instructed to fetch the actual diff before reviewing.
# {number} and {repository.full_name} are resolved from the GitHub payload.
prompt: |
A pull request event was received (action: {action}).
PR #{number}: {pull_request.title}
Author: {pull_request.user.login}
Branch: {pull_request.head.ref} → {pull_request.base.ref}
Description: {pull_request.body}
URL: {pull_request.html_url}
If the action is "closed" or "labeled", stop here and do not post a comment.
Otherwise:
1. Run: gh pr diff {number} --repo {repository.full_name}
2. Review the code changes for correctness, security issues, and clarity.
3. Write a concise, actionable review comment and post it.
deliver: github_comment
deliver_extra:
repo: "{repository.full_name}"
pr_number: "{number}"
```
**Key fields:**
| Field | Description |
|---|---|
| `secret` (route-level) | HMAC secret for this route. Falls back to `extra.secret` global if omitted. |
| `events` | List of `X-GitHub-Event` header values to accept. Empty list = accept all. |
| `prompt` | Template; `{field}` and `{nested.field}` resolve from the GitHub payload. |
| `deliver` | `github_comment` posts via `gh pr comment`. `log` just writes to the gateway log. |
| `deliver_extra.repo` | Resolves to e.g. `org/repo` from the payload. |
| `deliver_extra.pr_number` | Resolves to the PR number from the payload. |
:::note The payload does not contain code
The GitHub webhook payload includes PR metadata (title, description, branch names, URLs) but **not the diff**. The prompt above instructs the agent to run `gh pr diff` to fetch the actual changes. The `terminal` tool is included in the default `hermes-webhook` toolset, so no extra configuration is needed.
:::
---
## Step 2 — Start the gateway
```bash
hermes gateway
```
You should see:
```
[webhook] Listening on 0.0.0.0:8644 — routes: github-pr-review
```
Verify it's running:
```bash
curl http://localhost:8644/health
# {"status": "ok", "platform": "webhook"}
```
---
## Step 3 — Register the webhook on GitHub
1. Go to your repository → **Settings****Webhooks** → **Add webhook**
2. Fill in:
- **Payload URL:** `https://your-public-url.example.com/webhooks/github-pr-review`
- **Content type:** `application/json`
- **Secret:** the same value you set for `secret` in the route config
- **Which events?** → Select individual events → check **Pull requests**
3. Click **Add webhook**
GitHub will immediately send a `ping` event to confirm the connection. It is safely ignored — `ping` is not in your `events` list — and returns `{"status": "ignored", "event": "ping"}`. It is only logged at DEBUG level, so it won't appear in the console at the default log level.
---
## Step 4 — Open a test PR
Create a branch, push a change, and open a PR. Within 3090 seconds (depending on PR size and model), Hermes should post a review comment.
To follow the agent's progress in real time:
```bash
tail -f "${HERMES_HOME:-$HOME/.hermes}/logs/gateway.log"
```
---
## Local testing with ngrok
If Hermes is running on your laptop, use [ngrok](https://ngrok.com/) to expose it:
```bash
ngrok http 8644
```
Copy the `https://...ngrok-free.app` URL and use it as your GitHub Payload URL. On the free ngrok tier the URL changes each time ngrok restarts — update your GitHub webhook each session. Paid ngrok accounts get a static domain.
You can smoke-test a static route directly with `curl` — no GitHub account or real PR needed.
:::tip Use `deliver: log` when testing locally
Change `deliver: github_comment` to `deliver: log` in your config while testing. Otherwise the agent will attempt to post a comment to the fake `org/repo#99` repo in the test payload, which will fail. Switch back to `deliver: github_comment` once you're satisfied with the prompt output.
:::
```bash
SECRET="your-webhook-secret-here"
BODY='{"action":"opened","number":99,"pull_request":{"title":"Test PR","body":"Adds a feature.","user":{"login":"testuser"},"head":{"ref":"feat/x"},"base":{"ref":"main"},"html_url":"https://github.com/org/repo/pull/99"},"repository":{"full_name":"org/repo"}}'
SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print "sha256="$2}')
curl -s -X POST http://localhost:8644/webhooks/github-pr-review \
-H "Content-Type: application/json" \
-H "X-GitHub-Event: pull_request" \
-H "X-Hub-Signature-256: $SIG" \
-d "$BODY"
# Expected: {"status":"accepted","route":"github-pr-review","event":"pull_request","delivery_id":"..."}
```
Then watch the agent run:
```bash
tail -f "${HERMES_HOME:-$HOME/.hermes}/logs/gateway.log"
```
:::note
`hermes webhook test <name>` only works for **dynamic subscriptions** created with `hermes webhook subscribe`. It does not read routes from `config.yaml`.
:::
---
## Filtering to specific actions
GitHub sends `pull_request` events for many actions: `opened`, `synchronize`, `reopened`, `closed`, `labeled`, etc. The `events` list filters only by the `X-GitHub-Event` header value — it cannot filter by action sub-type at the routing level.
The prompt in Step 1 already handles this by instructing the agent to stop early for `closed` and `labeled` events.
:::warning The agent still runs and consumes tokens
The "stop here" instruction prevents a meaningful review, but the agent still runs to completion for every `pull_request` event regardless of action. GitHub webhooks can only filter by event type (`pull_request`, `push`, `issues`, etc.) — not by action sub-type (`opened`, `closed`, `labeled`). There is no routing-level filter for sub-actions. For high-volume repos, accept this cost or filter upstream with a GitHub Actions workflow that calls your webhook URL conditionally.
:::
> There is no Jinja2 or conditional template syntax. `{field}` and `{nested.field}` are the only substitutions supported. Anything else is passed verbatim to the agent.
---
## Using a skill for consistent review style
Load a [Hermes skill](/docs/user-guide/features/skills) to give the agent a consistent review persona. Add `skills` to your route inside `platforms.webhook.extra.routes` in `config.yaml`:
```yaml
platforms:
webhook:
enabled: true
extra:
routes:
github-pr-review:
secret: "your-webhook-secret-here"
events: [pull_request]
prompt: |
A pull request event was received (action: {action}).
PR #{number}: {pull_request.title} by {pull_request.user.login}
URL: {pull_request.html_url}
If the action is "closed" or "labeled", stop here and do not post a comment.
Otherwise:
1. Run: gh pr diff {number} --repo {repository.full_name}
2. Review the diff using your review guidelines.
3. Write a concise, actionable review comment and post it.
skills:
- review
deliver: github_comment
deliver_extra:
repo: "{repository.full_name}"
pr_number: "{number}"
```
> **Note:** Only the first skill in the list that is found is loaded. Hermes does not stack multiple skills — subsequent entries are ignored.
---
## Sending responses to Slack or Discord instead
Replace the `deliver` and `deliver_extra` fields inside your route with your target platform:
```yaml
# Inside platforms.webhook.extra.routes.<route-name>:
# Slack
deliver: slack
deliver_extra:
chat_id: "C0123456789" # Slack channel ID (omit to use the configured home channel)
# Discord
deliver: discord
deliver_extra:
chat_id: "987654321012345678" # Discord channel ID (omit to use home channel)
```
The target platform must also be enabled and connected in the gateway. If `chat_id` is omitted, the response is sent to that platform's configured home channel.
Valid `deliver` values: `log` · `github_comment` · `telegram` · `discord` · `slack` · `signal` · `sms`
---
## GitLab support
The same adapter works with GitLab. GitLab uses `X-Gitlab-Token` for authentication (plain string match, not HMAC) — Hermes handles both automatically.
For event filtering, GitLab sets `X-GitLab-Event` to values like `Merge Request Hook`, `Push Hook`, `Pipeline Hook`. Use the exact header value in `events`:
```yaml
events:
- Merge Request Hook
```
GitLab payload fields differ from GitHub's — e.g. `{object_attributes.title}` for the MR title and `{object_attributes.iid}` for the MR number. The easiest way to discover the full payload structure is GitLab's **Test** button in your webhook settings, combined with the **Recent Deliveries** log. Alternatively, omit `prompt` from your route config — Hermes will then pass the full payload as formatted JSON directly to the agent, and the agent's response (visible in the gateway log with `deliver: log`) will describe its structure.
---
## Security notes
- **Never use `INSECURE_NO_AUTH`** in production — it disables signature validation entirely. It is only for local development.
- **Rotate your webhook secret** periodically and update it in both GitHub (webhook settings) and your `config.yaml`.
- **Rate limiting** is 30 req/min per route by default (configurable via `extra.rate_limit`). Exceeding it returns `429`.
- **Duplicate deliveries** (webhook retries) are deduplicated via a 1-hour idempotency cache. The cache key is `X-GitHub-Delivery` if present, then `X-Request-ID`, then a millisecond timestamp. When neither delivery ID header is set, retries are **not** deduplicated.
- **Prompt injection:** PR titles, descriptions, and commit messages are attacker-controlled. Malicious PRs could attempt to manipulate the agent's actions. Run the gateway in a sandboxed environment (Docker, VM) when exposed to the public internet.
---
## Troubleshooting
| Symptom | Check |
|---|---|
| `401 Invalid signature` | Secret in config.yaml doesn't match GitHub webhook secret |
| `404 Unknown route` | Route name in the URL doesn't match the key in `routes:` |
| `429 Rate limit exceeded` | 30 req/min per route exceeded — common when re-delivering test events from GitHub's UI; wait a minute or raise `extra.rate_limit` |
| No comment posted | `gh` not installed, not on PATH, or not authenticated (`gh auth login`) |
| Agent runs but no comment | Check the gateway log — if the agent output was empty or just "SKIP", delivery is still attempted |
| Port already in use | Change `extra.port` in config.yaml |
| Agent runs but reviews only the PR description | The prompt isn't including the `gh pr diff` instruction — the diff is not in the webhook payload |
| Can't see the ping event | Ignored events return `{"status":"ignored","event":"ping"}` at DEBUG log level only — check GitHub's delivery log (repo → Settings → Webhooks → your webhook → Recent Deliveries) |
**GitHub's Recent Deliveries tab** (repo → Settings → Webhooks → your webhook) shows the exact request headers, payload, HTTP status, and response body for every delivery. It is the fastest way to diagnose failures without touching your server logs.
---
## Full config reference
```yaml
platforms:
webhook:
enabled: true
extra:
host: "0.0.0.0" # bind address (default: 0.0.0.0)
port: 8644 # listen port (default: 8644)
secret: "" # optional global fallback secret
rate_limit: 30 # requests per minute per route
max_body_bytes: 1048576 # payload size limit in bytes (default: 1 MB)
routes:
<route-name>:
secret: "required-per-route"
events: [] # [] = accept all; otherwise list X-GitHub-Event values
prompt: "" # {field} / {nested.field} resolved from payload
skills: [] # first matching skill is loaded (only one)
deliver: "log" # log | github_comment | telegram | discord | slack | signal | sms
deliver_extra: {} # repo + pr_number for github_comment; chat_id for others
```
---
## What's Next?
- **[Cron-Based PR Reviews](./github-pr-review-agent.md)** — poll for PRs on a schedule, no public endpoint needed
- **[Webhook Reference](/docs/user-guide/messaging/webhooks)** — full config reference for the webhook platform
- **[Build a Plugin](/docs/guides/build-a-hermes-plugin)** — package review logic into a shareable plugin
- **[Profiles](/docs/user-guide/profiles)** — run a dedicated reviewer profile with its own memory and config

View file

@ -162,6 +162,8 @@ const sidebars: SidebarsConfig = {
'guides/cron-troubleshooting',
'guides/work-with-skills',
'guides/delegation-patterns',
'guides/github-pr-review-agent',
'guides/webhook-github-pr-review',
'guides/migrate-from-openclaw',
'guides/aws-bedrock',
],