SSHScript
SSHScript is a Python automation library and .spy script runner for executing
commands locally or over SSH. It provides a regular Python Session API and a
compact dollar syntax for automation scripts.
Installation
SSHScript requires Python 3.11 or newer.
Use sshscript --version to display the installed version, or
sshscript --check-updates to query PyPI for a newer stable release compatible
with the current Python version. The check only prints an upgrade command;
it does not install anything. --check remains an alias. A failed query exits
with status 1; a successful check exits with status 0, whether an update exists
or not. This checks release Python requirements, not dependency resolution or
platform availability.
python3 -m pip install sshscript
For a release checkout containing src/sshscript/, python3 -m pip install .
installs that checkout. The flat development checkout is not an installable
package; use the following checks instead:
python3 -m pip install 'paramiko>=2.11,<5' 'packaging>=21' build twine
python3 tools/run_checks.py
python3 tools/check_release.py --output /tmp/sshscript-candidate-UNIQUE
See RELEASING.md for synchronization and publishing. SSHScript 3.1 is the supported production line; a GitHub source update does not by itself publish a new version to PyPI. See the v3.1 documentation.
Python API
from sshscript import Session
session = Session()
try:
stdout, stderr = session.exec_command("uname -a", shell=False)
print(str(stdout))
print(session.exitcode)
finally:
session.close(strict=True)
Pass command arguments as a safely quoted string, for example with
shlex.join(), and use shell=False when shell expansion is not required.
Running .spy files
sshscript automation.spy
The CLI and run_file() execute exactly one file. Directories, globs, and
multiple paths are intentionally unsupported. Compose larger automation with
SSHScript include syntax or ordinary Python imports.
Importing SSHScript does not globally enable Python imports of .spy files.
Use the explicit, temporary importer when a regular Python program needs one:
import sshscript
with sshscript.spy_imports():
import automation # loads automation.spy
run_file() enables this importer only for the duration of the script, so
imports between .spy files continue to work without additional setup.
Threads created with threading.Thread(...) inside a .spy file inherit the
session that is active when the thread is constructed, without patching the
process-wide threading.Thread class.
SSH host-key security
SSH connections verify system host keys by default and reject unknown or
changed keys. Load the server key into known_hosts before connecting.
Accepting a new key without verification must be an explicit decision:
import paramiko
remote = session.connect(
"user@new-host.example",
policy=paramiko.AutoAddPolicy(),
)
Do this only in a trusted bootstrap environment. Interactive SSH sessions do
not forward the complete local process environment; only terminal/locale
defaults and values explicitly supplied through env={...} are sent.
Tests
The canonical credential-free release gate is:
python3 tools/run_checks.py
It includes normal and optimized unit tests, compile checks, the package assert
scan, and the .spy language smoke suite. Public CI additionally provisions a
disposable loopback OpenSSH server to validate real SSH, SFTP, host-key, PTY,
sudo/su and timeout behavior against the built wheel.
The .spy language smoke suite can also be run directly:
python3 sshscript.py unittest/dollar_syntax.spy
Site-specific and credentialed SSH tests live under unittest-v3/ and are not
part of the default release gate. See CONTRIBUTING.md before
running them.
Project status
Version 3.1 is production/stable software. Public behavior is covered by the credential-free release gates and isolated OpenSSH integration CI. Operators should still validate site-specific PAM, sudoers, network and host-key policy in a disposable environment before production rollout.
SSHScript is released under the MIT License. See SUPPORT.md, SECURITY.md, CONTRIBUTING.md, and CHANGELOG.md for project policies and release history.
Production exception contract
SSHScript validates runtime inputs in both normal and optimized Python modes.
See the stable exception matrix. AssertionError was never a
supported SSHScript API contract. User-written .spy assertions remain ordinary
Python assertions: python -O removes them. Production scripts must use explicit
status checks or check=True for command-success handling.
with Session() as session:
session.exec_command("false", check=True)
A nonzero exit status otherwise remains result data, available as
session.exitcode.
Release files for sshscript 3.1.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| sshscript-3.1.4.tar.gz | 125.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sshscript-3.1.4-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 218.6 kB
Release files / sshscript-3.1.4.tar.gz
| Download URL | sshscript-3.1.4.tar.gz |
|---|---|
| Size | 125.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e479fb93ad3fac4fd7f5e6b25fcc09d774c0b648999f26db85dab6f7549ca43b
|
|
BLAKE2b-256 checksum How to use checksums |
e37dbdba376d8ea576199865fdc347b42526f382c9bbf773a3b2f80188c7055c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 24, 2026.
Transparency logRelease files / sshscript-3.1.4-py3-none-any.whl
| Download URL | sshscript-3.1.4-py3-none-any.whl |
|---|---|
| Size | 93.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1c9a9a05bd7567e2800515a56e86a1820c9c930e67bf479070948bb86a5aeddb
|
|
BLAKE2b-256 checksum How to use checksums |
e30376030b63606837d58f08c47b27647c6f1b5518227c513b919a0692204335
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 24, 2026.
Transparency log