Skip to main content

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
  2. Cross-platform compatibility — macOS, different Linux distros, WSL2
  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)
  6. New tools — rarely needed; most capabilities should be skills
  7. Documentation — fixes, clarifications, new examples

Common contribution paths​

Development Setup​

Prerequisites​

RequirementNotes
GitWith --recurse-submodules support
Python 3.11+uv will install it if missing
uvFast Python package manager (install)
Node.js 18+Optional — needed for browser tools and WhatsApp bridge

Clone and Install​

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​

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​

# 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​

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)
  • 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 for full rules.

Cross-Platform Compatibility​

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:

1. termios and fcntl are Unix-only​

Always catch both ImportError and NotImplementedError:

try:
from simple_term_menu import TerminalMenu
menu = TerminalMenu(options)
idx = menu.show()
except (ImportError, NotImplementedError):
# Fallback: numbered menu
for i, opt in enumerate(options):
print(f" {i+1}. {opt}")
idx = int(input("Choice: ")) - 1

2. File encoding​

Some environments may save .env files in non-UTF-8 encodings:

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

3. Process management​

os.setsid(), os.killpg(), and signal handling differ across platforms:

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​

LayerImplementation
Sudo password pipingUses shlex.quote() to prevent shell injection
Dangerous command detectionRegex patterns in tools/approval.py with user approval flow
Cron prompt injectionScanner blocks instruction-override patterns
Write deny listProtected paths resolved via os.path.realpath() to prevent symlink bypass
Skills guardSecurity scanner for hub-installed skills
Code execution sandboxChild process runs with API keys stripped
Container hardeningDocker: 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
  3. Check cross-platform impact: Consider macOS and different Linux distros
  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:

<type>(<scope>): <description>
TypeUse for
fixBug fixes
featNew features
docsDocumentation
testTests
refactorCode restructuring
choreBuild, 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
  • 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
  • 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.