Hermes Agent plugin for project-level linting, type-checking, formatting, and security scanning
Project description
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.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file hermead-0.2.0.tar.gz.
File metadata
- Download URL: hermead-0.2.0.tar.gz
- Upload date:
- Size: 38.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3ddaa4b12c86a1fa324a876796d1dfe852560a80468183cad1b847567d15a75f
|
|
| MD5 |
ce7d08f61daca05256f1ccbd69e394b7
|
|
| BLAKE2b-256 |
47266fec4e68d5f09b853aeb678b7af8e64fa87d5330c74607776bce22565063
|
File details
Details for the file hermead-0.2.0-py3-none-any.whl.
File metadata
- Download URL: hermead-0.2.0-py3-none-any.whl
- Upload date:
- Size: 38.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fcc25a60213f44ab395423a963be37a31016786443a23083efe0532b32a52833
|
|
| MD5 |
32b33f6d35c57e61f6decefc6d975b03
|
|
| BLAKE2b-256 |
d3eae9dc13fd224057cd522da3531e8f5e2599054a1936a6bce142f437f0a25c
|