Operate

Remote Agents (SSH)

Run long-lived “agent” processes on a VM/VPS over SSH and resume the flow later with structured results.

Quick Answer

Use a two-step pattern:

  1. :ssh kickoff step starts the remote agent/job quickly.
  2. :wait callback step pauses the flow until the agent calls back.

This pattern is more robust than trying to keep a single SSH session open for hours.

If you still need to provision the machine, create the SSH connection, or wire the key material, start with Set Up A VPS Or VM For Breyta SSH.

Long-Running Job Guidance

For long-running or output-silent workloads, do not model the entire job as one sync :ssh
step. Workflow activity runtime limits can end a long sync SSH activity before the remote
process completes, even if the step :timeout is higher.

Authoritative guidance:

  • Use sync :ssh for short remote commands only.
  • For long or variable-duration jobs, use :ssh kickoff + :wait callback.
  • Add a safety timeout callback path from the remote worker so runs resolve deterministically.

Pattern: Kickoff + Callback

1) Generate a correlation key

Use a deterministic key derived from the workflow id:

(let [ctx (:flow/ctx (flow/input))
      workflow-id (:workflow-id ctx)
      wait-key (str "agent-" workflow-id)]
  ...)

2) Compute a callback URL

The callback endpoint is:

  • POST /:workspace-id/events/<wait-key>

Example:

(let [base "https://<your-flows-api-host>/<workspace-id>"
      callback-url (str base "/events/" wait-key)]
  ...)

Important:

  • Your VM/VPS must be able to reach the callback URL.
  • For local testing, use a tunnel (ngrok/cloudflared) or run flows-api on a reachable host.

3) Kick off the agent over SSH

Pass callback values to the remote process as environment variables:

(flow/step :ssh :kickoff
           {:type :ssh
            :title "Kick off remote agent"
            :connection :vps
            :command "nohup ./run-agent.sh >/tmp/agent.log 2>&1 & echo started"
            :env {"BREYTA_WAIT_KEY" wait-key
                  "BREYTA_CALLBACK_URL" callback-url}
            :timeout 60})

4) Wait for the callback

(flow/step :wait :await-callback
           {:type :wait
            :title "Wait for agent callback"
            :key wait-key
            :webhook {:auth {:type :none}} ; dev-friendly; use HMAC/signature in production
            :timeout 3600
            :on-timeout :fail})

5) Remote agent posts final output

The remote agent should POST JSON to BREYTA_CALLBACK_URL.

Example:

curl -X POST "$BREYTA_CALLBACK_URL" \
  -H 'content-type: application/json' \
  -d '{"status":"ok","result":{"answer":42}}'

The JSON payload becomes the :wait step result.

When To Use Sync SSH Instead

Use a single :ssh step (sync) when:

  • the remote work is short-lived (seconds/minutes)
  • you want the flow to wait naturally on the command exit status

See: Step SSH.

Should We Add An “Agent” Step?

Maybe later — but it’s usually best to start with the primitive (:ssh) and document the agent pattern.

What a dedicated :agent step could do (as a wrapper around :ssh + :wait):

  • Standardize correlation (wait-key) and callback URL generation.
  • Provide a canonical env contract (BREYTA_WAIT_KEY, BREYTA_CALLBACK_URL, optional auth headers).
  • Offer a higher-level “kickoff + await result” interface with sensible defaults (timeouts, retries, max-output).
  • Normalize the callback payload into a stable result shape (e.g. {status, result, logsUrl, artifacts}).
  • Optionally stream progress via UI notifications (and/or accept progress callbacks).

Why start with :ssh first:

  • It keeps the platform composable: :ssh works for many non-agent tasks.
  • It avoids baking an “agent runtime” contract too early.
  • You can still market “Remote Agent Kickoff” as a documented pattern and ship a :agent step once you see repeated configs in user flows.

VPS Provisioning (Options)

Bring your own VPS (BYO)

You provide:

  • host/port/username
  • SSH auth (private key or password via secret refs)
  • host key verification (known_hosts)

Pros:

  • Works with any provider
  • Maximum flexibility

Cons:

  • More setup work (keys, host keys, firewalling)

Breyta-managed VPS per workspace (future direction)

In this model, Breyta would provision and manage a small VM per workspace and provide a standard “agent runtime”.

Potential benefits:

  • Faster onboarding (“it just works”)
  • Predictable runtime environment and paths
  • Easier support and upgrades

Operational considerations:

  • lifecycle + billing + quotas
  • security posture, patching, auditing
  • abuse prevention and network egress controls
  • escape hatches (BYO VPS remains supported)
  • secrets management UX (keys, host keys, callback auth) and rotation story

Related

As of Mar 13, 2026