Operate

SSH Testing

Test the :ssh step locally (mock mode), and against a real VM/VPS (real SSH).

If you still need to set up the VPS/VM, SSH user, key material, and Breyta connection from scratch, start with Set Up A VPS Or VM For Breyta SSH.

Local (Mock) — Sync SSH

Use this only for short command validation. For long-running agent workloads, test the async
pattern in this guide (ssh-async-callback) instead of a single sync :ssh step.

1) Start a local flows-api with demo flows

From breyta/:

./scripts/start-flows-api.sh --profile=memory --seed --demos

This starts:

  • API: http://localhost:8090
  • nREPL: localhost:7889
  • Demo flows are seeded into workspace ws-acme

The breyta commands below assume your local CLI defaults are already pointing at that local dev API and workspace, so the commands omit explicit --api, --workspace, and --token flags.

2) Create a mock SSH connection

breyta --dev \
  connections create \
  --type ssh --backend ssh --name "Mock VPS (SSH)" \
  --config '{"host":"example.com","port":22,"username":"ubuntu","mode":"mock"}'

Copy the returned connection-id.

3) Configure the demo flow and run it

Bind the SSH connection to the flow’s :vps slot:

breyta --dev \
  flows configure ssh-exec --set vps.conn=<CONN_ID>

Run and wait:

breyta --dev \
  flows run ssh-exec --wait \
  --input '{"command":"echo hi"}'

Expected: a completed run whose step result includes stdout starting with MOCK SSH.

Local (Mock) — Async Agent Callback Pattern

This uses the demo flow ssh-async-callback, which:

  • kicks off an “agent/job” via :ssh (quick)
  • pauses via :wait
  • resumes when something POSTs JSON to the callback URL

1) Configure the demo flow

breyta --dev \
  flows configure ssh-async-callback --set vps.conn=<CONN_ID>

2) Start the run (don’t wait yet)

breyta --dev \
  flows run ssh-async-callback \
  --input '{"command":"echo started"}'

Copy the returned workflowId (looks like flow-ssh-async-callback-ws-acme-r1).

3) Compute the wait key and POST the callback

In this demo flow, the wait key is deterministic:

wait-key = "agent-" + workflowId

Example callback:

curl -X POST \
  "http://localhost:8090/ws-acme/events/agent-<WORKFLOW_ID>" \
  -H 'content-type: application/json' \
  -d '{"status":"ok","result":{"answer":42}}'

4) Confirm the run completes

breyta --dev \
  runs show <WORKFLOW_ID>

Expected: status completed and result.callback.result.answer == 42.

Real SSH — Connect To A VM/VPS

For production-like long jobs, validate with the async kickoff + callback flow pattern.
Do not rely on a single sync :ssh step to prove long-duration reliability.

To connect to a real host, you need:

  • host (DNS or IP)
  • port (usually 22)
  • username (Linux user)
  • auth: private key (recommended) or password
  • host key verification: known_hosts (recommended)

1) Create known_hosts for the target host

mkdir -p ./tmp
ssh-keyscan -H -p 22 <HOST> > ./tmp/ssh-known-hosts

2) Store secrets in the workspace secret-store (via flow configuration)

The seeded demo flows declare optional secret slots that store secrets under these refs:

  • ssh-private-key
  • ssh-known-hosts
  • ssh-key-passphrase (optional)

Bind secret values using --set ...=@file for multiline content. Use @/absolute/path or @./relative/path; do not use @~/.ssh/..., because shells do not expand ~ reliably in that form:

breyta --dev \
  flows configure ssh-exec \
  --set ssh-private-key.secret=@$HOME/.ssh/id_ed25519 \
  --set ssh-known-hosts.secret=@./tmp/ssh-known-hosts

Use the same key file here that already works in a direct manual SSH check. Do not assume your local SSH agent and Breyta are using the same key automatically.

If your key is encrypted:

breyta --dev \
  flows configure ssh-exec \
  --set ssh-key-passphrase.secret=@./tmp/ssh-passphrase.txt

3) Create a real SSH connection that references those secret refs

breyta --dev \
  connections create \
  --type ssh --backend ssh --name "My VPS (SSH)" \
  --config '{
    "host":"<HOST>",
    "port":22,
    "username":"<USER>",
    "auth":{"type":"private-key","secret-ref":"ssh-private-key","passphrase-secret-ref":"ssh-key-passphrase"},
    "known-hosts":{"secret-ref":"ssh-known-hosts"}
  }'

4) Bind the real connection and run

breyta --dev \
  flows configure ssh-exec --set vps.conn=<REAL_CONN_ID>
breyta --dev \
  flows run ssh-exec --wait \
  --input '{"command":"uname -a"}'

Related

As of Mar 13, 2026