Skip to main content
Back to Hermes Guide
Lesson 7 of 814 min read
By the SetupOpenClaw teamPublished Apr 23, 2026

Developer Guide: Architecture, Contributing, and Extending Hermes

Repo setup with uv, cross-platform and security invariants, the three extension paths (tools / skills / providers), testing, and the commit/PR conventions.

Table of contents

Building On and Into Hermes

Hermes is an open source Python project, MIT-licensed, and actively accepts outside contributions. This lesson covers the dev environment, the code-quality rules, the cross-platform and security invariants the reviewers care about, the three extension paths, and the commit/PR conventions.

Primary source: the contributing guide at https://hermes-agent.nousresearch.com/docs/developer-guide/contributing. Always cross-check against that page before you send a PR — conventions can drift.

Contribution Priorities

Hermes ranks contributions clearly — this is worth internalising before you pick what to work on:

  1. Bug fixes — crashes, incorrect behaviour, data loss.
  2. Cross-platform compatibility.
  3. Security hardening.
  4. Performance improvements.
  5. New features.

An agent with terminal access has more to lose than gain from speculative new features, so the ordering reflects that.

Dev Environment Setup

You'll need:

  • Python 3.11+.
  • Git with LFS — the repo uses LFS for some assets.
  • uv as the package manager (not pip directly).
  • A ~/.hermes/ config tree with config.yaml, .env, and the standard subdirectories (sessions, logs, memories, skills).
  • At least one LLM provider API key in .env for local testing.

Clone with submodules (git clone --recurse-submodules), create a venv with uv venv, and install dependencies with all extras enabled so tests for optional integrations can run.

Code Quality Standards

The codebase follows PEP 8 with practical exceptions, and the style guide is explicit: minimal, intent-focused comments. Prefer a clear name and a short docstring over a paragraph explaining what the code already shows.

On error handling: catch specific exceptions, not broad ones. Log unexpected errors with logger.warning() or logger.error() and exc_info=True so the traceback actually lands in the logs.

One non-obvious rule worth knowing: never hardcode paths like ~/.hermes. Use get_hermes_home() for internal logic and display_hermes_home() for anything user-facing. Multi-profile installs rely on this — hardcoding breaks them silently.

Cross-Platform Invariants

Officially supported: Linux, macOS, WSL2. But the code is written defensively enough to run on raw Windows too. Three patterns come up repeatedly:

  • Unix-only modules (termios, fcntl) must be imported in a try/except that catches both ImportError and NotImplementedError.
  • File encoding must fall back to latin-1 when the locale isn't UTF-8 — assume nothing about the environment.
  • Paths are always pathlib.Path, not string concatenation. This is enforced by review.

Security-First Design

Hermes runs with terminal capabilities by default, so security is treated as a code-review invariant, not a feature:

  • Shell injection prevention with shlex.quote() for any user input interpolated into shell commands.
  • Symlink resolution via os.path.realpath() before access-control checks.
  • A regex-based dangerous command detector that forces user approval on risky commands.
  • Hub-downloaded skills are security-scanned before use.
  • Sandboxed code execution strips API keys from child process environments.
  • Container deployments drop all Linux capabilities and enforce PID limits.

Don't log secrets. If you're changing anything that touches file paths or subprocess management, manually test on multiple platforms — reviewers will ask.

Extension: Three Paths

There are three well-defined ways to extend Hermes without forking:

  • Tools — the lowest-level primitive. Follow the 'Adding Tools' doc.
  • Skills — higher-level procedures. Follow the 'Creating Skills' doc and the agentskills.io open standard.
  • Providers — new inference backends. Follow the 'Adding Providers' doc.

These three layers are deliberately separated. If you find yourself wanting to reach from a provider implementation into terminal tool internals, step back — that's usually a sign the work belongs in a different layer.

Testing and PR Etiquette

Before sending a PR: pytest tests/ -v. Manually test any changed code path. Keep PRs to one logical change — atomic is easier to review than heroic.

Branch names follow a strict prefix convention: fix/, feat/, docs/, test/, refactor/. Commits are Conventional Commits with scope qualifiers (cli, gateway, tools, skills, agent, install, whatsapp, security). A commit message like feat(gateway): add Matrix voice support signals exactly what changed and where.

PR descriptions should cover: what changed, why, how you tested, which platforms you tested on, and any related issues. Issue reports need OS info, Python version, hermes version output, the full traceback, and a reproduction.

Community

Contributions happen on GitHub via Issues and Discussions; realtime discussion happens on Discord. MIT licensed throughout, so the legal story is simple for both enterprise users and community contributors.

Next Steps

Lesson 8 is the CLI command reference — handy both for day-to-day use and for understanding the surface area before writing a plugin. If you want the reference to stay with you, bookmark /learn/hermes/reference/ and come back to it per command.

Continue learning