Skip to main content

hermes-ssh

CI License: MIT Python 3.11+

SSH remote execution plugin for Hermes Agent.

Run commands on remote servers, track sessions, reuse connections — all from inside Hermes.

/ssh web1 uptime
ssh_machines action=add name=web1 host=192.168.1.50 user=deploy
ssh_sessions action=list

quick start

hermes-ssh is for named multi-host operations. Hermes's core SSH backend is useful for one configured remote terminal; this plugin adds a reusable machine inventory, aliases, per-command targeting, background sessions, and audit history.

Requires Python 3.11+, Hermes Agent, and an OpenSSH client named ssh.

Install the package into the same Python environment that runs Hermes:

python -m pip install hermes-ssh
hermes plugins enable hermes-ssh --no-allow-tool-override

Run /reset or restart Hermes, then verify:

python -m pip show hermes-ssh
hermes plugins list --enabled --plain

If Hermes cannot see the package, the python command above was not Hermes's Python. Follow the environment procedure in the repository AGENTS.md.

For source development:

git clone https://github.com/TheEpTic/hermes-plugins.git
cd hermes-plugins/hermes-ssh
./deploy.sh
hermes plugins enable hermes-ssh --no-allow-tool-override

Run /reset or restart Hermes after changing the source tree.

Features

ssh_terminal — Run Commands

Execute any command on a remote machine. Commands run through bash -c with pipefail, so pipelines work correctly.

# Synchronous (waits for completion)
ssh_terminal machine=web1 command="df -h"

# Background (returns immediately)
ssh_terminal machine=web1 command="tail -f /var/log/syslog" background=true

# With timeout
ssh_terminal machine=web1 command="make -j4" timeout=300

Output truncation: When output exceeds max_output_chars (default: 50,000), the full output is saved under the plugin's restricted output directory and a summary with the file path is returned. The LLM can then use read_file to access the complete output.

Background commands: Long-running commands spool stdout and stderr to restricted files, avoiding pipe-buffer deadlocks. The plugin tracks the process and lets you poll for status or retrieve output later.

# Check if still running
ssh_terminal poll=<session_id>

# Read output from completed command
ssh_terminal read_output=<session_id>

# Or via ssh_sessions
ssh_sessions action=poll session_id=<session_id>
ssh_sessions action=read_output session_id=<session_id>

ssh_machines — Machine Registry

Register servers once, refer to them by name or alias.

# Add a server
ssh_machines action=add name=web1 host=192.168.1.50 user=deploy key=~/.ssh/id_ed25519

# Add with aliases and tags
ssh_machines action=add name=prod-web host=10.0.0.1 aliases=web1,tags=production,web

# List all machines
ssh_machines action=list

# Test connectivity
ssh_machines action=test name=web1

# Get full details
ssh_machines action=inspect name=web1

Machine names must be alphanumeric with dots, hyphens, or underscores (1-64 chars). Slashes, spaces, and glob characters are rejected.

ssh_sessions — Session Tracking

Every command creates a session. Sessions track the PID, machine, command count, and idle time.

# List active sessions
ssh_sessions action=list

# Kill a session (terminates the SSH process)
ssh_sessions action=kill session_id=<session_id>

# Clean up all idle sessions (>30 min)
ssh_sessions action=cleanup

# Remove old closed sessions (>24 hours)
ssh_sessions action=prune

Idle sessions are automatically killed by a background checker after 30 minutes. Closed sessions are pruned after 24 hours.

/ssh Slash Command

Quick access from chat without remembering tool names:

/ssh                     # List machines and sessions
/ssh web1                # Inspect a machine
/ssh web1 uptime         # Run a command
/ssh web1 docker ps      # Run a command
/ssh test                # Test connectivity to all machines
/ssh cleanup             # Kill all idle sessions
/ssh help                # Show help

Configuration

All settings live in src/ssh_tools/config.py as an SSHConfig dataclass:

Setting Default Description
default_port 22 SSH port for new machines
default_user current local user SSH user for new machines
connect_timeout 5s SSH handshake timeout
command_timeout 30s Command execution timeout
max_output_chars 50,000 Output truncation threshold
audit_log_mode redacted redacted, metadata, or off
idle_check_interval 60s Seconds between idle checks
idle_timeout_minutes 30m Auto-kill after this idle time
closed_prune_hours 24h Remove closed sessions after this
strict_host_key_checking accept-new SSH host key verification

Architecture

src/ssh_tools/
├── __init__.py          # Plugin registration + Hermes hooks
├── config.py            # SSHConfig (immutable dataclass)
├── manager.py           # SSHManager — all state and operations
├── models.py            # Machine, Session dataclasses
├── schemas.py           # Tool schemas (LLM-facing)
├── utils.py             # ok(), err(), require() helpers
├── py.typed             # PEP 561 marker
└── handlers/
    ├── terminal.py      # ssh_terminal (execute, poll, read_output)
    ├── machines.py      # ssh_machines (add/list/remove/test/inspect)
    ├── sessions.py      # ssh_sessions (list/kill/cleanup/prune/poll/read_output)
    └── slash.py         # /ssh slash command

Key design decisions:

  • SSHManager owns all state. Thread-safe. No module-level mutable state.
  • Handlers are thin closures — validate params, dispatch to manager, return JSON.
  • JSON files use atomic writes (temp file + os.replace) for crash safety.
  • Data directory has restricted permissions (0o700). Audit log and output files use 0o600.
  • Machine names are validated to prevent path traversal and glob injection.
  • Connection reuse via ControlMaster with 5-minute persist window.

Security

See SECURITY.md for the full picture.

Defaults you should know about:

  • StrictHostKeyChecking=accept-new — accepts first-seen host keys but rejects changed keys. Set to yes for strict production hosts.
  • Machine credentials are encrypted at rest in ~/.hermes/ssh-tools/machines.json. Data directory is 0o700.
  • Audit logs redact common inline credentials by default. Use metadata mode when command text must not be stored.
  • All commands execute with the permissions of the Hermes agent process.

Hardening applied:

  • Machine names validated against ^[a-zA-Z0-9][a-zA-Z0-9._-]{0,63}$
  • Output files written with 0o600 permissions
  • Audit log created with 0o600 permissions
  • Atomic JSON writes prevent corruption on crash
  • Orphaned temp files cleaned on startup

Requirements

Troubleshooting

Connection refused The remote host may not be listening on the expected port, or a firewall is blocking the connection. Verify with ssh -v user@host outside of Hermes.

Permission denied (publickey) The SSH key path stored in the machine registry may be incorrect, or the remote host doesn't have the corresponding public key in ~/.ssh/authorized_keys. Verify with ssh -i /path/to/key user@host.

Command timeout Commands exceeding command_timeout (default 30s) are killed. Increase the timeout or use background=true for long-running work.

Output looks truncated This is intentional — large outputs are saved under the restricted plugin output directory and a summary is returned. Use read_output or read_file on the returned path for the full output.

Session stuck as "active" after process died If the agent restarted, background process references are lost. Use ssh_sessions action=cleanup to kill stale sessions, or ssh_sessions action=prune to remove old closed ones.

Development

git clone https://github.com/TheEpTic/hermes-plugins.git
cd hermes-plugins/hermes-ssh
python -m venv .venv && source .venv/bin/activate
pip install -e '.[dev]'

# Run checks
black --check src/ssh_tools/ tests/
mypy src/ssh_tools/
pytest

See CONTRIBUTING.md for guidelines.

License

MIT — see LICENSE.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

hermes_ssh-0.3.4.tar.gz (78.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

hermes_ssh-0.3.4-py3-none-any.whl (30.3 kB view details)

Uploaded Python 3

File details

Details for the file hermes_ssh-0.3.4.tar.gz.

File metadata

  • Download URL: hermes_ssh-0.3.4.tar.gz
  • Upload date:
  • Size: 78.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for hermes_ssh-0.3.4.tar.gz
Algorithm Hash digest
SHA256 6fd9d35b923b7049b61bc683f023b8b0a2686b6deb934e2708666030be553372
MD5 4cc75f42b472de852f3b6847cc16e33f
BLAKE2b-256 3a37d8b691e14c73f047a6132111391ead8b813f00b4dbbca914647755637db3

See more details on using hashes here.

Provenance

The following attestation bundles were made for hermes_ssh-0.3.4.tar.gz:

Publisher: pypi-publish-ssh.yml on TheEpTic/hermes-plugins

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file hermes_ssh-0.3.4-py3-none-any.whl.

File metadata

  • Download URL: hermes_ssh-0.3.4-py3-none-any.whl
  • Upload date:
  • Size: 30.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for hermes_ssh-0.3.4-py3-none-any.whl
Algorithm Hash digest
SHA256 a8acd2037259ccb405532c194ce6de694af074cc3b2edd3601dd7e0c2ac9198f
MD5 d190b0b0d9fa9e79d4e6ac9ebbd369ae
BLAKE2b-256 b185b631fc6e656d5a8a4dfcc54a58566fcc32d6b340cfcf7560de186c7b741d

See more details on using hashes here.

Provenance

The following attestation bundles were made for hermes_ssh-0.3.4-py3-none-any.whl:

Publisher: pypi-publish-ssh.yml on TheEpTic/hermes-plugins

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.4.8

2 files

0.4.7

2 files

0.4.4

2 files

0.4.3

2 files

0.4.2

2 files

0.4.0

2 files

This release

0.3.4 This release

2 files

0.3.3

2 files

0.3.2

2 files

0.3.1

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page