Academy → Developer GuideOfficial documentation · Arabic guidance

Contributing

المساهمة في المشروع

Advanced9 min readLesson 63 questions✓ 2026-08-18
Before you read

What this page is, and what it holds.

This page covers Contributing. You will use hermes update and hermes version here; about 9 minutes to read. Do not disable approvals to save time. Start read-only and widen once you trust the results.

10sections
14code examples
3tables
3commands
1,474source words
The official one-line description

How to contribute to Hermes Agent — dev setup, code style, PR process

What you will be able to do

Outcomes taken from this page, not a template.

  • Understand what الأمان والموافقات is and when you need it.
  • Run hermes update and hermes version and understand what happens next.
  • Read the table and take only the row that applies to you.
  • Set HERMES_HOME in the right place.
Identifiers you will meet

Exactly as they appear in Hermes.

Commands
  • hermes update
  • hermes version
  • hermes doctor hermes chat
Environment variables
  • HERMES_HOME
  • VIRTUAL_ENV
  • OPENROUTER_API_KEY
Page map

Jump to the part you need.

  1. 01Contribution Priorities
  2. 02Common contribution paths
  3. 03Development Setup
  4. 04Code Style
  5. 05Cross-Platform Compatibility
  6. 06Security Considerations
  7. 07Pull Request Process
  8. 08Reporting Issues
  9. 09Community
  10. 10License
The full official page

Nothing summarised away.

The documentation body below is reproduced from the official source so commands and identifiers stay exact. Each section carries a short note describing what it contains.

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

Explains the idea itself. Read it slowly; the later sections build on it.

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

Explains the idea itself. Read it slowly; the later sections build on it.

Development Setup

Ordered, practical steps. Run one and confirm it worked before moving on. Commands here: hermes update, hermes doctor hermes chat.

Prerequisites

RequirementNotes
GitWith the git-lfs extension installed
Python 3.11–3.13uv will install it if missing
uvFast Python package manager (install ↗)
Node.js 26+Optional — needed for browser tools and WhatsApp bridge (matches root package.json engines)

Install with the standard installer

For most contributors, the best development bootstrap is the same path users take: run the standard installer, then work inside the repository it cloned. The installer creates the Hermes venv, wires the hermes command, stamps the install method for hermes update, and clones the full git project into $HERMES_HOME/hermes-agent (usually ~/.hermes/hermes-agent). That keeps your development environment on the same layout the CLI, updater, lazy dependency installer, gateway, and docs assume.

Shell8 lines
curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash
cd "${HERMES_HOME:-$HOME/.hermes}/hermes-agent"

# Add dev/test extras on top of the standard install.
uv pip install -e ".[all,dev]"

# Optional: browser tools / docs site dependencies.
npm install

After that, create branches and run tests from that checkout:

Shell2 lines
git checkout -b fix/description
scripts/run_tests.sh

You can also run a fully isolated Hermes instance (throwaway HERMES_HOME, separate Electron userData, distinct Electron app name to avoid the single-instance lock):

Shell2 lines
scripts/dev-sandbox.sh python -m hermes_cli.main
scripts/dev-sandbox.sh --persistent python -m hermes_cli.main desktop  # state survives restarts, but lives in the worktree :)

Manual clone fallback

Use this only if you intentionally do not want Hermes' managed install layout (for example, a throwaway clone inside a container or CI job). If you install this way, make sure you run the hermes entrypoint from this venv; running the system python3 -m hermes_cli.main can pick up unrelated system Python packages.

Create the venv outside the cloned source tree. A venv that lives inside the directory the agent operates from can be wiped by a relative-path command the agent runs against its own checkout (rm -rf venv, uv venv venv, etc.), which silently destroys the running runtime mid-session. Keeping it outside the tree means no relative path from the workspace resolves to it.

Shell13 lines
git clone https://github.com/NousResearch/hermes-agent.git
cd hermes-agent

# Create venv with Python 3.11, OUTSIDE the source tree
uv venv ~/.hermes/venvs/hermes-dev --python 3.11
export VIRTUAL_ENV="$HOME/.hermes/venvs/hermes-dev"
export PATH="$VIRTUAL_ENV/bin:$PATH"

# Install with all extras (messaging, cron, CLI menus, dev tools)
uv pip install -e ".[all,dev]"

# Optional: browser tools
npm install

Configure for Development

Shell6 lines
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

Shell3 lines
# The standard installer already put `hermes` on PATH.
hermes doctor
hermes chat -q "Hello"

If you used the manual clone fallback, run ./hermes from the checkout or symlink this clone's venv explicitly:

Shell2 lines
mkdir -p ~/.local/bin
ln -sf "$(pwd)/venv/bin/hermes" ~/.local/bin/hermes

Run Tests

Shell1 line
scripts/run_tests.sh

Code Style

Explains the idea itself. Read it slowly; the later sections build on it.

  • 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

Explains the idea itself. Read it slowly; the later sections build on it.

See Platform Support. Native Windows uses Git Bash (from Git for Windows ↗) for shell commands. A few features require POSIX kernel primitives and are gated: the dashboard's embedded PTY terminal pane (/chat tab) needs a POSIX PTY (Linux, macOS, or WSL2). If you're doing Windows-heavy dev, run the Windows-footgun lint (scripts/check-windows-footguns.py) before pushing.

When contributing code, keep these rules in mind:

  • Don't add unguarded signal.SIGKILL references. It's not defined on Windows. Either route through gateway.status.terminate_pid(pid, force=True) (the centralized primitive that does taskkill /T /F on Windows and SIGKILL on POSIX), or fall back with getattr(signal, "SIGKILL", signal.SIGTERM).
  • Catch OSError alongside ProcessLookupError on os.kill(pid, 0) probes. Windows raises OSError (WinError 87, "parameter is incorrect") for an already-gone PID instead of ProcessLookupError.
  • Don't force the terminal to POSIX semantics. os.setsid, os.killpg, os.getpgid, os.fork all raise on Windows — gate them with if sys.platform != "win32": or if os.name != "nt":.
  • Open files with an explicit encoding="utf-8". The Python default on Windows is the system locale (often cp1252), which mojibakes or crashes on non-Latin text.
  • Use pathlib.Path / os.path.join — never manually concat with /. This matters less for strings the OS gives us back and more for strings we construct to hand to subprocesses.

Key patterns:

1. File encoding

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

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

2. Process management

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

Python3 lines

if platform.system() != "Windows":
    kwargs["preexec_fn"] = os.setsid

3. Path separators

Use pathlib.Path instead of string concatenation with /.

Security Considerations

A lookup table. Do not read it all; find the row that applies to you.

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

A lookup table. Do not read it all; find the row that applies to you.

Branch Naming

Text5 lines
fix/description        # Bug fixes
feat/description       # New features
docs/description       # Documentation
test/description       # Tests
refactor/description   # Code restructuring

Before Submitting

  1. Run tests: scripts/run_tests.sh for CI-parity. Use direct python -m pytest ... only when the wrapper is unavailable or you are intentionally debugging outside the wrapper.
  2. Test manually: Run hermes and exercise the code path you changed
  3. Check cross-platform impact: Consider macOS, Linux, WSL2, and native Windows. If you touch file I/O, process management, terminal handling, subprocesses, or signals, run scripts/check-windows-footguns.py.
  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 ↗:

Text1 line
<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:

Text3 lines
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

Repo-local review checklists: .agents/checks/.md

Projects built on (or reviewed by) Hermes can keep reviewer checklists inside the repository under .agents/checks/. Each file is a focused, plain-markdown checklist that an agent loads before reviewing a change touching the matching area:

Text5 lines
.agents/
  checks/
    security.md        # e.g. "grep the diff for shell interpolation; check subprocess calls quote args"
    migrations.md      # e.g. "every schema change ships a backfill and a rollback note"
    public-api.md      # e.g. "exported signatures changed? flag for semver review"

Conventions that make these work well:

  • One concern per file, named after the concern. Small files get read in full; a monolithic checklist.md gets skimmed.
  • Write checks as verifiable actions ("run X and confirm Y"), not aspirations ("code should be secure").
  • State the trigger at the top — which paths or change types the checklist applies to — so an agent (or human) can skip irrelevant ones cheaply.
  • Keep them in version control next to the code they guard: they evolve with the codebase, and a PR that changes the rules changes the checklist in the same diff.

When you ask Hermes to review a PR in a repository that has .agents/checks/, tell it (or teach it via a skill) to read the relevant checklists first and report against them. This gives review agents the project-specific bar that generic review prompts miss.

Reporting Issues

Commands you type in a terminal. Understand what one does before copying it. Commands here: hermes version.

  • 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

Explains the idea itself. Read it slowly; the later sections build on it.

  • Discord: discord.gg/NousResearch ↗
  • GitHub Discussions: For design proposals and architecture discussions
  • Skills Hub: Upload specialized skills and share with the community

License

Explains the idea itself. Read it slowly; the later sections build on it.

By contributing, you agree that your contributions will be licensed under the MIT License ↗.

Knowledge check

3 questions answered by this page alone.

Every option is a real identifier from the Hermes documentation. The wrong ones are real too, just from other pages.

1. In this lesson's table, what is the “Notes” for “Node.js 26+”?
2. Which of these environment variables actually appears in this lesson?
3. Which of these headings does not appear in this lesson?