Step SSH (:ssh)
Quick Answer
Use this reference for running remote commands over SSH.
- Sync: the flow pauses until the remote command exits (or times out).
- Async agent pattern: kick off a long-running job over SSH, then use a
:waitcallback to resume later (see Remote Agents (SSH)). - VM setup: if you need to provision the host and wire secrets from scratch, start with Set Up A VPS Or VM For Breyta SSH.
- Important: treat sync
:sshas short-task execution. For long-running or output-silent jobs, use async kickoff + callback wait. - Testing: local mock mode + real-SSH walkthrough (see SSH Testing).
Canonical Shape
Core fields:
| Field | Type | Required | Notes |
|---|---|---|---|
:connection | keyword/string | Yes | Slot name (preferred) or connection id |
:command | string | Yes | Shell command executed via sh -lc on the remote host |
:workdir | string | No | Runs cd <workdir> && ... before the command |
:env | map | No | Environment variables passed to the command |
:stdin | string | No | Bytes written to the remote process stdin |
:pty? | boolean | No | Allocate a PTY (for interactive commands/tools) |
:timeout | int | No | Command timeout seconds (default 60) |
:connect-timeout-ms | int | No | Connection timeout in milliseconds |
:max-output-bytes | int | No | Combined stdout+stderr cap (bounded by server limits) |
:ok-exit-codes | vector | No | Allowed exit codes (default [0]) |
:log-command-preview? | boolean | No | If true, logs a short command preview (avoid secrets) |
Success result (when exit code is allowed):
{:success true
:exit 0
:stdout "..."
:stderr "..."
:duration-ms 123}
If the command exits with a disallowed exit code, the step fails and surfaces a structured error including the exit code and a stderr preview.
SSH Connection (:type ssh, :backend ssh)
The :ssh step expects an SSH connection with connection config like:
{
"host": "example.com",
"port": 22,
"username": "ubuntu",
"auth": {
"type": "private-key",
"secret-ref": "ssh-private-key",
"passphrase-secret-ref": "ssh-key-passphrase"
},
"known-hosts": { "secret-ref": "ssh-known-hosts" }
}
Auth:
auth.typesupportsprivate-keyandpassword.secret-refvalues are fetched from the workspace secret-store at runtime.
Host key verification:
- Prefer
known-hosts(a secret containing OpenSSHknown_hostscontent). - Dev-only escape hatch: set
insecure-skip-host-key-verification: trueon the connection config.
Local simulation (no network):
- Set
mode: "mock"on the connection config. The step returns a deterministic mock result.
Limits And Behavior
- The remote command is executed as:
sh -lc "<script>". - Output is bounded by
:max-output-bytesacross stdout + stderr; exceeding the cap fails the step. :envkeys must be valid env var names (FOO,MY_VAR_1).- In production-like environments, hosts that resolve to private IPs are blocked by default to reduce SSRF risk.
- Long sync SSH jobs are not the recommended execution model for agent-style work; workflow activity runtime limits can terminate the step before remote completion. Use the async agent pattern for jobs that can run several minutes or more.
Canonical Examples
Sync exec
'(let [res (flow/step :ssh :exec
{:type :ssh
:title "Run remote command"
:connection :vps
:command "echo hello; uname -a"
:timeout 60})]
res)
Async agent kickoff + callback wait
See: Remote Agents (SSH).