         ss-api             (atom {})
         ;; ???: Do the perf implications of anonymous functions mean these
         ;; shouldn't be in a tight loop?
-        fn-desc->rpc       (fn fn-desc->rpc [remote-name desc]
-                             (let [f (fn [& all-args]
-                                       ;; TODO: Check if last argument is a channel, an
-                                       (let [cb-or-ch (last all-args)
-                                             cb       (cond
-                                                        (fn? cb-or-ch)   cb-or-ch
-                                                        (chan? cb-or-ch) #(put! cb-or-ch %)
-                                                        :else            false)
-                                             args     (if cb
-                                                        (drop-last 1 all-args)
-                                                        all-args)
-                                             uuid     (d/squuid)]
-                                         (when (fn? cb)
-                                           (swap! pending-rpc assoc uuid cb-or-ch))
-                                         (dato-send! remote-name {:args   args
-                                                                  :rpc/id uuid})
-                                         (if (chan? cb-or-ch)
-                                           cb-or-ch
-                                           uuid)))]
-                               f))]
+        fn-desc->rpc       (fn [remote-name desc]
+                             (fn [& all-args]
+                               ;; TODO: Check if last argument is a channel, an
+                               (let [cb-or-ch (last all-args)
+                                     cb       (cond
+                                                (fn? cb-or-ch)   cb-or-ch
+                                                (chan? cb-or-ch) #(put! cb-or-ch %)
+                                                :else            false)
+                                     args     (if cb
+                                                (drop-last 1 all-args)
+                                                all-args)]
+                                 (when (fn? cb)
+                                   (swap! pending-rpc assoc uuid cb-or-ch))
+                                 (tal/queue-msg! tal-state
+                                                 {:op remote-name
+                                                  :data {:args args}}
+                                                 30000
+                                                 (fn [reply]
+                                                   (if (fn? cb)
+                                                     (cb reply)
+                                                     (when (:event reply)
+                                                       (put! dato-ch reply)))))
+                                 (if (chan? cb-or-ch)
+                                   cb-or-ch
+                                   uuid))))]
     {:comms    comms
      ;; Just for debugging to simulate messages coming in from the
      ;; server
      :ss-cast! ss-cast!
-     :ws       {:ch    ws-ch
-                :host  dato-host
-                :path  dato-path
-                :send! dato-send!
-                :ws    ws}
      :conn     app-db
      :db       (fn
                  ([] @(app-db))

     key
     update-history!)
    (go
      (loop []
        (alt!
          dato-ch ([{:keys [sender event data] :as payload}]
                   (cond
                     ;; Special-case waiting on https://github.com/tonsky/datascript/issues/76
                     ;; Can eliminate this branch afterwards
                     (= :server/database-transacted event)
                     (let [previous-state @conn]
                       (def f-tx data)
                       ;; This is the abstraction not yet supported
                       ;; (two-phase commit, plus intermediate
                       ;; processing)
                       (db/consume-foreign-tx! conn data)
                       (con/effect! context previous-state @conn payload))
                     :else
                     (let [previous-state @conn
                           tx-data        (con/transition @conn payload)
                           tx-meta        (meta tx-data)
                           full-tx-meta   (-> (if tx-meta
                                                tx-meta
                                                {:tx/transient? true})
                                              (update-in [:tx/intent] (fn [intent]
                                                                        (or intent event))))]
                       (when-not (:tx/transient? full-tx-meta)
                         (js/console.log "\tevent: " (pr-str event))
                         (js/console.log "\ttx-data: " (pr-str tx-data))
                         (js/console.log "\ttx-meta: " (pr-str full-tx-meta)))
                       (if tx-data
                         (d/transact! conn tx-data full-tx-meta)
                         (update-history! {:tx-meta full-tx-meta}))
                       (con/effect! context previous-state @conn payload)))
                   (recur)))))))

;; Component stuff


(defn bootstrapped? [db]
  (dsu/qe-by db :dato.meta/bootrapped? true))

(defmulti ws-message-handler (fn [dato-ch msg] (:op msg)))
(defmethod ws-message-handler :default
  [dato-ch msg]
  ;; TODO replace the dato-ch handler with this
  (put! dato-ch msg))

(defn new-dato [dato-host dato-port dato-path app-db cs-schema]
  (let [cast-bootstrapped? (atom false)
        ws-ch              (async/chan)
        dato-ch            (async/chan)
        ;; XXX: can we get rid of this?
        ss-cast!           #(put! ws-ch %)
        ;; XXX: can we get rid of this?
        pending-rpc        (atom {})
        tal-state          (tal/init {:port dato-port
                                      :transit-reader transit-reader
                                      :transit-writer transit-writer})
        _                  (tal/start-message-consumer tal-state (fn [msg]
                                                                   (ws-message-handler dato-ch msg)))
        dato-send!         (fn [event data]
                             (tal/queue-msg! tal-state {:op event :data data}))
        controls-ch        (async/chan)
        comms              {:controls controls-ch
                            :stop     (async/chan)
