diff --git a/desktop/src-tauri/src/archive/mod.rs b/desktop/src-tauri/src/archive/mod.rs
index a65b126a4d..42c6812674 100644
--- a/desktop/src-tauri/src/archive/mod.rs
+++ b/desktop/src-tauri/src/archive/mod.rs
@@ -483,21 +483,23 @@ pub async fn list_save_subscriptions(
 /// Does NOT purge already-archived event data — retention is decoupled in v1.
 /// GC of orphaned event rows happens in P4 purge commands, not here.
 #[tauri::command]
-pub fn delete_save_subscription(
+pub async fn delete_save_subscription(
     state: State<'_, AppState>,
     scope_type: ScopeType,
     scope_value: String,
 ) -> Result<bool, String> {
     let identity_pk = identity_pubkey(&state)?;
     let relay_url = relay_ws_url_with_override(&state);
-    let conn = open_db()?;
-    store::delete_save_subscription(
-        &conn,
-        &identity_pk,
-        &relay_url,
-        scope_type.as_str(),
-        &scope_value,
-    )
+    run_archive_db_task(move |conn| {
+        store::delete_save_subscription(
+            conn,
+            &identity_pk,
+            &relay_url,
+            scope_type.as_str(),
+            &scope_value,
+        )
+    })
+    .await
 }
 
 // ── read_archived_events ─────────────────────────────────────────────────────
@@ -516,7 +518,7 @@ pub fn delete_save_subscription(
 /// newest-first order. Compound cursor `(before_created_at, before_id)` works
 /// identically to `read_archived_events`.
 #[tauri::command]
-pub fn read_archived_observer_events_for_channel(
+pub async fn read_archived_observer_events_for_channel(
     state: State<'_, AppState>,
     channel_id: String,
     before_created_at: Option<i64>,
@@ -525,16 +527,18 @@ pub fn read_archived_observer_events_for_channel(
 ) -> Result<Vec<String>, String> {
     let identity_pk = identity_pubkey(&state)?;
     let relay_url = relay_ws_url_with_override(&state);
-    let conn = open_db()?;
-    store::read_archived_observer_events_for_channel(
-        &conn,
-        &identity_pk,
-        &relay_url,
-        &channel_id,
-        before_created_at,
-        before_id.as_deref(),
-        limit.unwrap_or(DEFAULT_READ_LIMIT),
-    )
+    run_archive_db_task(move |conn| {
+        store::read_archived_observer_events_for_channel(
+            conn,
+            &identity_pk,
+            &relay_url,
+            &channel_id,
+            before_created_at,
+            before_id.as_deref(),
+            limit.unwrap_or(DEFAULT_READ_LIMIT),
+        )
+    })
+    .await
 }
 
 // ── index_observer_channel_id ─────────────────────────────────────────────────
@@ -548,24 +552,26 @@ pub fn read_archived_observer_events_for_channel(
 ///
 /// Idempotent: rows that are already indexed are left unchanged.
 #[tauri::command]
-pub fn index_observer_channel_id(
+pub async fn index_observer_channel_id(
     state: State<'_, AppState>,
     entries: Vec<ObserverChannelIndexEntry>,
 ) -> Result<(), String> {
     let identity_pk = identity_pubkey(&state)?;
     let relay_url = relay_ws_url_with_override(&state);
-    let conn = open_db()?;
-    for entry in &entries {
-        store::upsert_observer_channel_index(
-            &conn,
-            &identity_pk,
-            &relay_url,
-            &entry.event_id,
-            entry.channel_id.as_deref(),
-            entry.created_at,
-        )?;
-    }
-    Ok(())
+    run_archive_db_task(move |conn| {
+        for entry in &entries {
+            store::upsert_observer_channel_index(
+                conn,
+                &identity_pk,
+                &relay_url,
+                &entry.event_id,
+                entry.channel_id.as_deref(),
+                entry.created_at,
+            )?;
+        }
+        Ok(())
+    })
+    .await
 }
 
 /// A single (event_id, channel_id?, created_at) record used by
@@ -591,21 +597,23 @@ pub struct ObserverChannelIndexEntry {
 /// Together these constitute the one-shot idempotent backfill required by the
 /// Slice 1 acceptance criteria (Thufir Pass 4).
 #[tauri::command]
-pub fn read_unindexed_observer_rows(
+pub async fn read_unindexed_observer_rows(
     state: State<'_, AppState>,
 ) -> Result<Vec<RawObserverRow>, String> {
     let identity_pk = identity_pubkey(&state)?;
     let relay_url = relay_ws_url_with_override(&state);
-    let conn = open_db()?;
-    let rows = store::read_unindexed_observer_rows(&conn, &identity_pk, &relay_url)?;
-    Ok(rows
-        .into_iter()
-        .map(|(id, raw_json, created_at)| RawObserverRow {
-            id,
-            raw_json,
-            created_at,
-        })
-        .collect())
+    run_archive_db_task(move |conn| {
+        let rows = store::read_unindexed_observer_rows(conn, &identity_pk, &relay_url)?;
+        Ok(rows
+            .into_iter()
+            .map(|(id, raw_json, created_at)| RawObserverRow {
+                id,
+                raw_json,
+                created_at,
+            })
+            .collect())
+    })
+    .await
 }
 
 /// Wire type returned by `read_unindexed_observer_rows`.
diff --git a/desktop/src-tauri/src/commands/identity.rs b/desktop/src-tauri/src/commands/identity.rs
index 33783c05a5..2840c0ade6 100644
--- a/desktop/src-tauri/src/commands/identity.rs
+++ b/desktop/src-tauri/src/commands/identity.rs
@@ -135,23 +135,29 @@ pub async fn sign_event(
 }
 
 #[tauri::command]
-pub fn decrypt_observer_event(
+pub async fn decrypt_observer_event(
     event_json: String,
     state: State<'_, AppState>,
 ) -> Result<serde_json::Value, String> {
     let keys = state.signing_keys()?;
-    let event = Event::from_json(event_json).map_err(|error| format!("invalid event: {error}"))?;
 
-    // Defense-in-depth: verify event ID and signature before decrypting.
-    if !event.verify_id() {
-        return Err("observer event has invalid ID".into());
-    }
-    if !event.verify_signature() {
-        return Err("observer event has invalid signature".into());
-    }
+    tauri::async_runtime::spawn_blocking(move || {
+        let event =
+            Event::from_json(event_json).map_err(|error| format!("invalid event: {error}"))?;
 
-    buzz_core_pkg::observer::decrypt_observer_payload(&keys, &event)
-        .map_err(|error| format!("decrypt observer event failed: {error}"))
+        // Defense-in-depth: verify event ID and signature before decrypting.
+        if !event.verify_id() {
+            return Err("observer event has invalid ID".into());
+        }
+        if !event.verify_signature() {
+            return Err("observer event has invalid signature".into());
+        }
+
+        buzz_core_pkg::observer::decrypt_observer_payload(&keys, &event)
+            .map_err(|error| format!("decrypt observer event failed: {error}"))
+    })
+    .await
+    .map_err(|e| format!("spawn_blocking failed: {e}"))?
 }
 
 #[tauri::command]
