2026-03-05 05:24:55 -08:00
---
sidebar_position: 4
title: "Contributing"
description: "How to contribute to Hermes Agent — dev setup, code style, PR process"
---
# Contributing
Thank you for contributing to Hermes Agent! This guide covers setting up your dev environment, understanding the codebase, and getting your PR merged.
## Contribution Priorities
We value contributions in this order:
1. **Bug fixes ** — crashes, incorrect behavior, data loss
2026-03-05 06:36:18 -08:00
2. **Cross-platform compatibility ** — macOS, different Linux distros, WSL2
2026-03-05 05:24:55 -08:00
3. **Security hardening ** — shell injection, prompt injection, path traversal
4. **Performance and robustness ** — retry logic, error handling, graceful degradation
5. **New skills ** — broadly useful ones (see [Creating Skills ](creating-skills.md ))
6. **New tools ** — rarely needed; most capabilities should be skills
7. **Documentation ** — fixes, clarifications, new examples
2026-03-14 19:22:47 -07:00
## Common contribution paths
- Building a new tool? Start with [Adding Tools ](./adding-tools.md )
- Building a new skill? Start with [Creating Skills ](./creating-skills.md )
- Building a new inference provider? Start with [Adding Providers ](./adding-providers.md )
2026-03-05 05:24:55 -08:00
## Development Setup
### Prerequisites
| Requirement | Notes |
|-------------|-------|
| **Git ** | With `--recurse-submodules` support |
docs: fix 40+ discrepancies between documentation and codebase (#5818)
Comprehensive audit of all ~100 doc pages against the actual code, fixing:
Reference docs:
- HERMES_API_TIMEOUT default 900 -> 1800 (env-vars)
- TERMINAL_DOCKER_IMAGE default python:3.11 -> nikolaik/python-nodejs (env-vars)
- compression.summary_model default shown as gemini -> actually empty string (env-vars)
- Add missing GOOGLE_API_KEY, GEMINI_API_KEY, GEMINI_BASE_URL env vars (env-vars)
- Add missing /branch (/fork) slash command (slash-commands)
- Fix hermes-cli tool count 39 -> 38 (toolsets-reference)
- Fix hermes-api-server drop list to include text_to_speech (toolsets-reference)
- Fix total tool count 47 -> 48, standalone 14 -> 15 (tools-reference)
User guide:
- web_extract.timeout default 30 -> 360 (configuration)
- Remove display.theme_mode (not implemented in code) (configuration)
- Remove display.background_process_notifications (not in defaults) (configuration)
- Browser inactivity timeout 300/5min -> 120/2min (browser)
- Screenshot path browser_screenshots -> cache/screenshots (browser)
- batch_runner default model claude-sonnet-4-20250514 -> claude-sonnet-4.6
- Add minimax to TTS provider list (voice-mode)
- Remove credential_pool_strategies from auth.json example (credential-pools)
- Fix Slack token path platforms/slack/ -> root ~/.hermes/ (slack)
- Fix Matrix store path for new installs (matrix)
- Fix WhatsApp session path for new installs (whatsapp)
- Fix HomeAssistant config from gateway.json to config.yaml (homeassistant)
- Fix WeCom gateway start command (wecom)
Developer guide:
- Fix tool/toolset counts in architecture overview
- Update line counts: main.py ~5500, setup.py ~3100, run.py ~7500, mcp_tool ~2200
- Replace nonexistent agent/memory_store.py with memory_manager.py + memory_provider.py
- Update _discover_tools() list: remove honcho_tools, add skill_manager_tool
- Add session_search and delegate_task to intercepted tools list (agent-loop)
- Fix budget warning: two-tier system (70% caution, 90% warning) (agent-loop)
- Fix gateway auth order (per-platform first, global last) (gateway-internals)
- Fix email_adapter.py -> email.py, add webhook.py + api_server.py (gateway-internals)
- Add 7 missing providers to provider-runtime list
Other:
- Add Docker --cap-add entries to security doc
- Fix Python version 3.10+ -> 3.11+ (contributing)
- Fix AGENTS.md discovery claim (not hierarchical walk) (tips)
- Fix cron 'add' -> canonical 'create' (cron-internals)
- Add pre_api_request/post_api_request hooks to plugin guide
- Add Google/Gemini provider to providers page
- Clarify OPENAI_BASE_URL deprecation (providers)
2026-04-07 10:17:44 -07:00
| **Python 3.11+ ** | uv will install it if missing |
2026-03-05 05:24:55 -08:00
| **uv ** | Fast Python package manager ([install ](https://docs.astral.sh/uv/ )) |
| **Node.js 18+ ** | Optional — needed for browser tools and WhatsApp bridge |
### Clone and Install
```bash
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 with all extras (messaging, cron, CLI menus, dev tools)
uv pip install -e ".[all,dev]"
uv pip install -e "./tinker-atropos"
# Optional: browser tools
npm install
```
### Configure for Development
```bash
mkdir -p ~/.hermes/{cron,sessions,logs,memories,skills}
cp cli-config.yaml.example ~/.hermes/config.yaml
touch ~/.hermes/.env
# Add at minimum an LLM provider key:
echo 'OPENROUTER_API_KEY=sk-or-v1-your-key' >> ~/.hermes/.env
```
### Run
```bash
# Symlink for global access
mkdir -p ~/.local/bin
ln -sf "$(pwd)/venv/bin/hermes" ~/.local/bin/hermes
# Verify
hermes doctor
hermes chat -q "Hello"
```
### Run Tests
```bash
pytest tests/ -v
```
## Code Style
- **PEP 8** with practical exceptions (no strict line length enforcement)
- **Comments**: Only when explaining non-obvious intent, trade-offs, or API quirks
- **Error handling**: Catch specific exceptions. Use `logger.warning()` /`logger.error()` with `exc_info=True` for unexpected errors
- **Cross-platform**: Never assume Unix (see below)
feat: add profiles — run multiple isolated Hermes instances (#3681)
Each profile is a fully independent HERMES_HOME with its own config,
API keys, memory, sessions, skills, gateway, cron, and state.db.
Core module: hermes_cli/profiles.py (~900 lines)
- Profile CRUD: create, delete, list, show, rename
- Three clone levels: blank, --clone (config), --clone-all (everything)
- Export/import: tar.gz archive for backup and migration
- Wrapper alias scripts (~/.local/bin/<name>)
- Collision detection for alias names
- Sticky default via ~/.hermes/active_profile
- Skill seeding via subprocess (handles module-level caching)
- Auto-stop gateway on delete with disable-before-stop for services
- Tab completion generation for bash and zsh
CLI integration (hermes_cli/main.py):
- _apply_profile_override(): pre-import -p/--profile flag + sticky default
- Full 'hermes profile' subcommand: list, use, create, delete, show,
alias, rename, export, import
- 'hermes completion bash/zsh' command
- Multi-profile skill sync in hermes update
Display (cli.py, banner.py, gateway/run.py):
- CLI prompt: 'coder ❯' when using a non-default profile
- Banner shows profile name
- Gateway startup log includes profile name
Gateway safety:
- Token locks: Discord, Slack, WhatsApp, Signal (extends Telegram pattern)
- Port conflict detection: API server, webhook adapter
Diagnostics (hermes_cli/doctor.py):
- Profile health section: lists profiles, checks config, .env, aliases
- Orphan alias detection: warns when wrapper points to deleted profile
Tests (tests/hermes_cli/test_profiles.py):
- 71 automated tests covering: validation, CRUD, clone levels, rename,
export/import, active profile, isolation, alias collision, completion
- Full suite: 6760 passed, 0 new failures
Documentation:
- website/docs/user-guide/profiles.md: full user guide (12 sections)
- website/docs/reference/profile-commands.md: command reference (12 commands)
- website/docs/reference/faq.md: 6 profile FAQ entries
- website/sidebars.ts: navigation updated
2026-03-29 10:41:20 -07:00
- **Profile-safe paths**: Never hardcode `~/.hermes` — use `get_hermes_home()` from `hermes_constants` for code paths and `display_hermes_home()` for user-facing messages. See [AGENTS.md ](https://github.com/NousResearch/hermes-agent/blob/main/AGENTS.md#profiles-multi-instance-support ) for full rules.
2026-03-05 05:24:55 -08:00
## Cross-Platform Compatibility
2026-03-05 06:36:18 -08:00
Hermes officially supports Linux, macOS, and WSL2. Native Windows is **not supported ** , but the codebase includes some defensive coding patterns to avoid hard crashes in edge cases. Key rules:
2026-03-05 05:24:55 -08:00
### 1. `termios` and `fcntl` are Unix-only
Always catch both `ImportError` and `NotImplementedError` :
```python
try:
from simple_term_menu import TerminalMenu
menu = TerminalMenu(options)
idx = menu.show()
except (ImportError, NotImplementedError):
2026-03-05 06:36:18 -08:00
# Fallback: numbered menu
2026-03-05 05:24:55 -08:00
for i, opt in enumerate(options):
print(f" {i+1}. {opt}")
idx = int(input("Choice: ")) - 1
```
### 2. File encoding
2026-03-05 06:36:18 -08:00
Some environments may save `.env` files in non-UTF-8 encodings:
2026-03-05 05:24:55 -08:00
```python
try:
load_dotenv(env_path)
except UnicodeDecodeError:
load_dotenv(env_path, encoding="latin-1")
```
### 3. Process management
2026-03-05 06:36:18 -08:00
`os.setsid()` , `os.killpg()` , and signal handling differ across platforms:
2026-03-05 05:24:55 -08:00
```python
import platform
if platform.system() != "Windows":
kwargs["preexec_fn"] = os.setsid
```
### 4. Path separators
Use `pathlib.Path` instead of string concatenation with `/` .
## Security Considerations
Hermes has terminal access. Security matters.
### Existing Protections
| Layer | Implementation |
|-------|---------------|
| **Sudo password piping ** | Uses `shlex.quote()` to prevent shell injection |
| **Dangerous command detection ** | Regex patterns in `tools/approval.py` with user approval flow |
| **Cron prompt injection ** | Scanner blocks instruction-override patterns |
| **Write deny list ** | Protected paths resolved via `os.path.realpath()` to prevent symlink bypass |
| **Skills guard ** | Security scanner for hub-installed skills |
| **Code execution sandbox ** | Child process runs with API keys stripped |
| **Container hardening ** | Docker: all capabilities dropped, no privilege escalation, PID limits |
### Contributing Security-Sensitive Code
- Always use `shlex.quote()` when interpolating user input into shell commands
- Resolve symlinks with `os.path.realpath()` before access control checks
- Don't log secrets
- Catch broad exceptions around tool execution
- Test on all platforms if your change touches file paths or processes
## Pull Request Process
### Branch Naming
```
fix/description # Bug fixes
feat/description # New features
docs/description # Documentation
test/description # Tests
refactor/description # Code restructuring
```
### Before Submitting
1. **Run tests ** : `pytest tests/ -v`
2. **Test manually ** : Run `hermes` and exercise the code path you changed
2026-03-05 06:36:18 -08:00
3. **Check cross-platform impact ** : Consider macOS and different Linux distros
2026-03-05 05:24:55 -08:00
4. **Keep PRs focused ** : One logical change per PR
### PR Description
Include:
- **What** changed and **why **
- **How to test** it
- **What platforms** you tested on
- Reference any related issues
### Commit Messages
We use [Conventional Commits ](https://www.conventionalcommits.org/ ):
```
<type>(<scope>): <description>
```
| Type | Use for |
|------|---------|
| `fix` | Bug fixes |
| `feat` | New features |
| `docs` | Documentation |
| `test` | Tests |
| `refactor` | Code restructuring |
| `chore` | Build, CI, dependency updates |
Scopes: `cli` , `gateway` , `tools` , `skills` , `agent` , `install` , `whatsapp` , `security`
Examples:
```
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
```
## Reporting Issues
- Use [GitHub Issues ](https://github.com/NousResearch/hermes-agent/issues )
- Include: OS, Python version, Hermes version (`hermes version` ), full error traceback
- Include steps to reproduce
- Check existing issues before creating duplicates
- For security vulnerabilities, please report privately
## Community
- **Discord**: [discord.gg/NousResearch ](https://discord.gg/NousResearch )
- **GitHub Discussions**: For design proposals and architecture discussions
- **Skills Hub**: Upload specialized skills and share with the community
## License
By contributing, you agree that your contributions will be licensed under the [MIT License ](https://github.com/NousResearch/hermes-agent/blob/main/LICENSE ).