HermeAd
HermeAd is a Hermes Agent plugin that automatically runs linters, type checkers, formatters, and security scanners on project files after every write_file or patch tool call.
No manual commands. No context switching. Files get checked the moment you write them.
How It Works
HermeAd registers a single post_tool_call hook. After each file modification:
- Detects the file type from extension or filename
- Walks up the tree to find the project root (
.git,.hg, or.hermesdirectory) - Loads config: built-in defaults → global
~/.hermes/hermead.yaml→ per-project.hermes/hermead.yaml - Auto-detects tooling from
pyproject.toml,package.json,go.mod,Cargo.toml,.shellcheckrc - Routes to the right runner for each check category (lint, type check, format, security)
Results appear inline in the session. Issues surface at the moment of introduction, not after a CI run.
Quick Install
pip install hermead
From source:
git clone https://github.com/asimons81/hermead.git
cd hermead
pip install -e ".[dev]"
Verify it loaded:
hermes plugin list
# → hermead should appear
Features
- Zero-config for common projects. Works out of the box with ruff + mypy for Python, eslint + prettier + tsc for JS/TS, golangci-lint + go vet + gofmt for Go, clippy + rustfmt for Rust, shellcheck for shell scripts, and rubocop + standardrb + brakeman for Ruby.
- Auto-detection. Reads
pyproject.toml,package.json,go.mod,Cargo.toml,.shellcheckrc, and.rubocop.yml/Gemfileto pick the right tools. Auto-detected tools take priority over config. - Per-project config.
.hermes/hermead.yamloverrides global~/.hermes/hermead.yaml, which overrides built-in defaults. - Threshold system. Set findings to
block,warn, orignoreper severity level (lint warnings, type errors, security findings). - 7 language runners. Python, JavaScript/TypeScript, Go, Rust, Shell, Ruby, and a Generic runner for config/script files (semgrep).
- Graceful degredation. Missing tools produce empty results. No crashes, no spurious errors. Use
which <tool>to check availability. - Ignore patterns. Skip
node_modules/,venv/, build output dirs, and anything else you add. - Extra CLI args. Pass custom flags per tool (e.g.
ruff: ["--line-length", "100"]).
Configuration
Quick Start
Create .hermes/hermead.yaml at your project root:
python:
lint: ruff
type_check: mypy
formatter: ruff
security: semgrep
thresholds:
lint_warnings: warn
type_errors: block
security_high: block
ignore_paths:
- node_modules/**
- venv/**
- __pycache__/**
Full Reference
# Per-language tool assignments (null = skip that check category)
python:
lint: ruff
type_check: mypy
formatter: ruff
security: semgrep
javascript:
lint: eslint
type_check: tsc
formatter: prettier
security: semgrep
go:
lint: golangci-lint
type_check: go vet
formatter: gofmt
security: gosec
rust:
lint: clippy
type_check: cargo check
formatter: rustfmt
security: cargo audit
shell:
lint: shellcheck
formatter: shfmt
generic:
lint: semgrep
security: semgrep
thresholds:
lint_warnings: warn # warn | block | ignore
type_errors: block
security_high: block
security_medium: warn
security_low: info
ignore_paths:
- node_modules/**
- venv/**
- .venv/**
- __pycache__/**
- .git/**
- dist/**
- build/**
- target/**
- .hermes/**
extra_args:
ruff: ["--line-length", "100"]
mypy: ["--strict"]
golangci-lint: ["--timeout", "5m"]
Supported Languages
| Language | Extensions | Lint | Type Check | Format | Security |
|---|---|---|---|---|---|
| Python | .py |
ruff | mypy | ruff / black | bandit / semgrep |
| JavaScript / TypeScript | .js, .ts, .jsx, .tsx, .mjs, .cjs |
eslint | tsc | prettier | semgrep |
| Go | .go |
golangci-lint | go vet | gofmt | gosec |
| Rust | .rs |
clippy | cargo check | rustfmt | cargo audit |
| Shell | .sh, .bash, .zsh, .fish |
shellcheck | — | shfmt | — |
| Ruby | .rb, Gemfile, Rakefile |
rubocop | — | standardrb | brakeman |
| Generic | Dockerfile, Makefile, .gitignore, etc. |
semgrep | — | — | semgrep |
Inline Reports
When HermeAd runs, findings appear in your session as structured results:
🔍 ruff: 1 error
🔍(line 42:5) F841 — local variable 'x' is assigned to but never used (F841)
Each result shows the tool, severity, source location, message, and rule code. Empty output means the file passed or the tool wasn't available.
Contributing
PRs welcome. HermeAd is a young project — the runner interface, result format, and hooks API are still finding their shape.
- Runners live in
hermead/runners/. Each module self-registers viaregister_runner(language, action, func). - The hook dispatcher lives in
hermead/hooks.py. - Config loading lives in
hermead/config.py. - The registry lives in
hermead/runners/__init__.py.
Before opening a PR, run the test suite:
pip install -e ".[dev]"
pytest -v
Plugin Architecture
HermeAd is a Hermes Agent plugin — no MCP server, no web server, no external API. It registers a single hook entry point in pyproject.toml:
[project.entry-points."hermes_agent.plugins"]
hermead = "hermead:register"
For more on building Hermes plugins, see the Hermes Agent Plugin Docs.
License
MIT — see LICENSE.
Metadata
Release files for hermead 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| hermead-0.2.0.tar.gz | 38.5 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| hermead-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 76.6 kB
Release files / hermead-0.2.0.tar.gz
| Download URL | hermead-0.2.0.tar.gz |
|---|---|
| Size | 38.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3ddaa4b12c86a1fa324a876796d1dfe852560a80468183cad1b847567d15a75f
|
|
BLAKE2b-256 checksum How to use checksums |
47266fec4e68d5f09b853aeb678b7af8e64fa87d5330c74607776bce22565063
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.15
|
Release files / hermead-0.2.0-py3-none-any.whl
| Download URL | hermead-0.2.0-py3-none-any.whl |
|---|---|
| Size | 38.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
fcc25a60213f44ab395423a963be37a31016786443a23083efe0532b32a52833
|
|
BLAKE2b-256 checksum How to use checksums |
d3eae9dc13fd224057cd522da3531e8f5e2599054a1936a6bce142f437f0a25c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.15
|
Security for hermead 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.