   (add-edge!
     [_ src dest sig opts] (f/add-edge! g src dest sig opts))
   ITripleGraph
-  (add-triple
+  (add-triple!
     [_ t]
     (or (@triples t)
         (let [{:keys [subj pred obj]} indices
               v (f/add-vertex! g {:val t})]
-          (f/add-edge! g v subj signal-triple nil)
-          (f/add-edge! g v pred signal-triple nil)
-          (f/add-edge! g v obj  signal-triple nil)
+          (f/add-edge! g v subj signal-triple :add)
+          (f/add-edge! g v pred signal-triple :add)
+          (f/add-edge! g v obj  signal-triple :add)
           (f/signal! v)
-          (swap! triples conj t)
+          (swap! triples assoc t v)
           v)))
-  (add-query
+  (remove-triple!
+    [_ t]
+    (if-let [v (@triples t)]
+      (let [{:keys [subj pred obj]} indices]
+        (f/add-edge! g v subj signal-triple :remove)
+        (f/add-edge! g v pred signal-triple :remove)
+        (f/add-edge! g v obj  signal-triple :remove)
+        (f/signal! v)
+        (swap! triples dissoc t)
+        v)
+      (warn "attempting to remove unknown triple:" t)))
+  (add-query!
     [_ id [s p o]]
     ;; TODO figure out way how to at to a running context
     ;; TODO remove vertices if query ID already exists

      {:acc acc :result res}))
  (query-result
    [_ id] (when-let [q (@queries id)] @@(:res q)))
  (add-rule
    [_ id query production]
    (let [qid (keyword (str "inf-" (name id)))
          q   (add-query _ qid query)
          inf (f/add-vertex!
               g {:val #{}
                  ::f/collect-fn (collect-inference _ production)})]

  (f/simple-collect
   (fn [_ incoming]
     (let [res (vals (peek incoming))]
       ;;(info :agg-incoming res)
       (delay
        (when (every? #(not= [nil] %) res)
          (->> res
               (map #(disj % nil))
               (set)
