let execute ?timeout t argl =
  let final_log = ref Log.empty in
  let ret out err exited =
    let kv k v = Log.(brakets (s k % s " → " % v) |> indent) in
    final_log := Log.(
        !final_log %n % s "Success: " % kv "status" (sf "exit:%d" exited)
        % kv "stdout" (sf "%S" out) % kv "stderr" (sf "%S" err));
    return (object
      method stdout = out method stderr = err method exited = exited
    end)
  in
  let run ~log () =
    final_log := Log.( !final_log % s "Host.execute " % s (to_string_hum t)
                       % OCaml.list s argl % sp % log);
    match connection t  with
    | `Localhost ->
      begin Ketrew_unix_process.exec argl
        >>< function
        | `Ok (out, err, `Exited n) -> ret out err n
        | `Ok (out, err, other) ->
          fail_exec t ~out ~err (System.Shell.status_to_string other)
        | `Error (`Process _ as process_error) ->
          let msg = Ketrew_unix_process.error_to_string process_error in
          Log.(s "Ssh-cmd " % OCaml.list (sf "%S") argl
               % s " failed: " %s msg @ verbose);
          fail_exec t msg
      end
    | `Ssh ssh ->
      begin Ssh.generic_ssh_exec ssh argl
        >>< function
        | `Ok (out, err, exited) -> ret out err exited
        | `Error e -> fail (`Host e)
      end
  in
  begin run_with_timeout ?timeout t ~run
    >>< fun result ->
    Log.(!final_log @ very_verbose);
    match result with
    | `Ok o -> return o
    | `Error (`Host e) -> fail (`Host e)
    | `Error (`System _ as e)
    | `Error (`Timeout _ as e) -> fail (`Host e)
  end