Model or dataset
badseal/ssh-skill avatar
badseal/ssh-skill

ssh-skill, a guarded SSH workflow Skill for Codex and Claude Code

面向 Codex 和 Claude Code 的跨平台 SSH 工作流 Skill,支持 Windows、macOS、Linux

548 stars55 forksPythonLicense varies

At a glance

What is it?
ssh-skill is a Skill for Codex and Claude Code that wraps remote commands, file transfer, server to server transfer, batch operations, tunnels and a connection daemon in one Python CLI with a single JSON result envelope. It suits an agent that must touch production machines, because the design puts preview before apply, refuses plaintext passwords and caps what reaches the model, and the safety rules are written as an explicit list of things the tool refuses to do.
Who is it for?
Adopt ssh-skill if you are letting a coding agent operate SSH connections to real hosts and need the blast radius of each command bounded, since the result envelope, the outcome_unknown code, the preview and confirm gate for production and the size caps on output are the substance of the project rather than the SSH wrapper itself.
Can I use it commercially?
Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
Is it still maintained?
Yes. The repository last received commits 60 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One CLI, one JSON envelope, every platform

ssh-skill is a cross-platform SSH workflow Skill for Codex and Claude Code, and it is described as a unified Python CLI wrapping remote commands, file transfer, transfer between servers, batch operations, configuration management, tunnels and a connection daemon, with consistent result protocol across Windows, macOS and Linux.

The stable main version is v4.0.0, and the README is explicit that new AI invocations should use the unified entry point and the v4 result protocol, with the old scripts kept only as migration compatibility entry points.

The v4 rules are the interesting part, and they are worth reading as a set of design decisions rather than a feature list.

All new calls go through scripts/ssh_skill.py. Stdout carries a single JSON document with schema_version=1.0. Remote commands are passed as separate arguments and do not go through a second parse by a local PowerShell, Bash or Zsh. When OpenSSH, Paramiko or a cluster execution times out after the request was sent, the result is uniformly outcome_unknown with retryable=false, to stop an AI from automatically replaying a side effect. The unified entry point can forward bounded JSONL progress on stderr, with events in ASCII-safe JSON that parse reliably in a Windows console and on the three desktop platforms.

The output caps are equally deliberate. The top level JSON result is limited to 256 KiB, and recursive transfer details keep at most 100 first and last samples while preserving the true totals, so a large directory does not fill the AI's context.

Host keys, passwords, agent forwarding: the defaults that matter

The security defaults are the second thing the README spends space on, and they are the reason to look at this project at all.

Host keys are accepted with accept-new by default, and a known host key conflict is rejected. New configuration refuses plaintext passwords, while old passwords are only read for compatibility and are always redacted. Agent forwarding is off by default.

There is a separate cluster confirmation gate. The default is preview only, meaning no SSH connection is established, and execution requires --apply, and production targets additionally require --confirm-production. The README also warns against inferring the real scope from filter conditions, and tells you to check the targets, target_count and production_targets fields in the result before executing.

The stated safety boundary is a short list of things the tool will not do. It does not assemble ssh, scp, sftp or rsync commands directly. It does not disable host key verification or discard known_hosts on the daily path. It does not write passwords, private key contents, tokens or askpass data into the output. It does not connect to servers in bulk without a preview. It does not execute production cluster operations or delete configuration without confirmation. And it does not repeat a mutating command because the output was truncated. The detailed rules live in references/safety.md.

For an agent that can run shell commands, that last rule is the important one. Truncated output is a signal to re-read the state, not to run the command again.

Installing the Skill where the agent will actually find it

The installation story is about placement rather than packages, and the README is careful about it.

The Skill root is the directory where the SKILL.md that the AI actually loads lives, and the instruction is not to hardcode any one directory as the only install location. Common candidates are listed: for Codex at user level, $CODEX_HOME/skills/ssh-skill/ or .agents/skills/ssh-skill/, for Codex at project level .codex/skills/ssh-skill/ or .agents/skills/ssh-skill/, and for Claude Code at user or project level .claude/skills/ssh-skill/.

The doctor command lists the current copy and the candidate copies with their versions, content hashes and drift status, but it does not copy, overwrite or select another copy. The advice is to resolve the path once per task rather than running doctor before every operation.

The invocation is the same shape on every platform, with the remote path staying POSIX format on all three systems and no local shell wrapper layer. On Windows PowerShell it is:

powershell
python "<SSH_SKILL_ROOT>\scripts\ssh_skill.py" doctor --json
python "<SSH_SKILL_ROOT>\scripts\ssh_skill.py" exec example-host "hostname"

And on macOS and Linux it is the same two commands with python3 and forward slashes.

The command surface, from exec to tunnel to daemon

The common commands section assumes the current directory is the source root, and it is a compact list of what an agent would actually reach for:

text
python scripts/ssh_skill.py doctor --json
python scripts/ssh_skill.py config list-servers
python scripts/ssh_skill.py exec example-host "uname -a"
python scripts/ssh_skill.py upload example-host ./app.tar.gz /tmp/app.tar.gz
python scripts/ssh_skill.py download example-host /var/log/app.log ./app.log
python scripts/ssh_skill.py transfer source-host /data/file destination-host /backup/file
python scripts/ssh_skill.py tunnel start example-host --remote-port 5432

The shape is consistent: a verb, a host, and the payload. The transfer command takes a source host and path, and a destination host and path, which is the server to server case. The tunnel command starts a tunnel to a remote port, which is the case where a database sits behind a bastion and the agent needs to reach it.

The full parameter reference is in references/commands.md, and the platform specific notes are split across references/platforms-windows.md, references/platforms-macos.md and references/platforms-linux.md.

The examples directory gives a sense of the shape of a configuration file, with single server, multi server, jump host, password, single key, key with passphrase, temporary access and usage example files, plus a Python file of basic usage, one of concurrency examples and one of interactive session examples, and a PowerShell smoke test script.

The result envelope and what outcome_unknown obliges you to do

The result protocol is the contract between the tool and the model, and the README shows what success and failure both look like.

json
{
  "schema_version": "1.0",
  "success": true,
  "operation": "exec",
  "data": {},
  "error": null,
  "meta": {
    "request_id": null,
    "platform": "windows",
    "transport": "openssh",
    "elapsed_ms": 120,
    "warnings": []
  }
}

Success and failure return the same structure, with the error object populated instead of data. The meta block carries the request_id, the platform, the transport, the elapsed time and a warnings list.

The rule that matters is what to do when error.code is outcome_unknown. The command may already have executed on the remote host. The obligation is to keep the request ID, stop automatic retries, and confirm the remote state with a separate read-only check.

The size rules are part of the same contract. The stdout top level result never exceeds 256 KiB, recursive transfer results keep at most 100 first and last samples, and total fields such as total_files still reflect the real scale. Explicitly enabled live progress goes to stderr as independent ASCII-safe JSONL and must not be merged into the stdout result.

Compatibility, tests, and the part that is not open source

The compatibility table is simple: Codex and Claude Code are each supported on Windows, macOS and Linux. The release gate covers Python 3.10, 3.11, 3.12 and 3.13, with 3.8 and 3.9 best effort and outside the formal test matrix. At runtime the tool needs Python, an OpenSSH client and Paramiko.

The v4.0.0 release baseline is 115 offline tests, verified by GitHub Actions on Windows, macOS and Ubuntu across Python 3.10 to 3.13. The local verification section lists the help commands that do not connect to servers and are executed automatically by the tests:

text
python scripts/ssh_skill.py --help
python scripts/ssh_skill.py exec --help
python scripts/ssh_skill.py upload --help
python scripts/ssh_skill.py download --help
python scripts/ssh_skill.py transfer --help
python scripts/ssh_skill.py cluster --help
python scripts/ssh_skill.py config --help
python scripts/ssh_skill.py tunnel --help
python scripts/ssh_skill.py daemon --help
python scripts/ssh_skill.py doctor --help

The full suite runs with python -m unittest discover -s tests -v. The README is clear that the automated tests never connect to a real server, and that real SSH smoke tests, installation sync, push, tagging and release are separately approved steps.

The licence is MIT, and the documentation is the part of the project that carries the rules. The AI facing contract lives in SKILL.md, the command reference in references/commands.md, and the safety rules in references/safety.md, with a per platform file for Windows, macOS and Linux. There is also an evals/ directory in the tree, which suggests the Skill is evaluated as well as used.

One last note on the old entry points. The scripts ssh_execute.py, ssh_upload.py, ssh_download.py, ssh_server_transfer.py, ssh_config_manager_v3.py, ssh_tunnel.py and ssh_daemon.py are all retained, and their default output has already switched to the v4 envelope. The --legacy-json flag is only for known legacy callers, and it converts result fields only, without restoring unsafe host key handling, retries, unbounded output or cluster behaviour.

Editorial conclusion

Adopt ssh-skill if you are letting a coding agent operate SSH connections to real hosts and need the blast radius of each command bounded, since the result envelope, the outcome_unknown code, the preview and confirm gate for production and the size caps on output are the substance of the project rather than the SSH wrapper itself. Do not adopt it for a simple script that runs one command, and do not expect the tool to hide anything from the model, since the whole design is to make every result inspectable in the JSON envelope. Before you deploy it, read SKILL.md and references/safety.md, decide where the Skill directory lives so the agent loads the copy you intend, and note the maintenance picture, with v4.0.0 published on 2026-08-24 and the last push on the same day.

Frequently asked questions

What is ssh-skill and which AI tools does it support?

It is a cross-platform SSH workflow Skill for Codex and Claude Code, wrapping remote commands, file transfer, transfer between servers, batch operations, configuration management, tunnels and a connection daemon in a single Python CLI. The compatibility table lists Codex and Claude Code as supported on Windows, macOS and Linux.

How does the ssh-skill cluster confirmation gate work?

Clusters default to preview only, with no SSH connection established, and execution requires --apply, while production targets additionally require --confirm-production. The README tells you to check the targets, target_count and production_targets fields in the result rather than inferring scope from the filter conditions.

What does error.code outcome_unknown mean in ssh-skill results?

It means the command may already have executed on the remote host, which happens when OpenSSH, Paramiko or a cluster execution times out after the request was sent. You must keep the request ID, stop automatic retries, and confirm the remote state with a separate read-only check.

Where should I install the ssh-skill directory?

The Skill root is wherever the SKILL.md the AI actually loads sits, and the README says not to hardcode one location. Candidates are $CODEX_HOME/skills/ssh-skill/ or .agents/skills/ssh-skill/ for Codex at user level, .codex/skills/ssh-skill/ or .agents/skills/ssh-skill/ at project level, and .claude/skills/ssh-skill/ for Claude Code.

How do I run the ssh-skill tests?

The full suite runs with python -m unittest discover -s tests -v, and the v4.0.0 release baseline is 115 tests passed. The automated tests never connect to a real server, and the help commands are executed automatically as offline checks, with real SSH smoke tests and releases handled as separately approved steps.

Official sources

  1. badseal/ssh-skill on GitHub
  2. Issues
  3. README
  4. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/badseal-ssh-skill.svg)](https://hysenlabs.com/projects/badseal-ssh-skill)

Was this useful?