diff --git a/README.md b/README.md
index 20352a54b69d74dfb65d6802ae37095dd410dc2d..2dcb392d7953a78e4a3ec9bba954125de3d64538 100644
--- a/README.md
+++ b/README.md
@@ -3,3 +3,11 @@
  [![pipeline status](https://git.kuschku.de/justJanne/libquassel/badges/main/pipeline.svg)](https://git.kuschku.de/justJanne/libquassel/-/commits/main) [![coverage report](https://git.kuschku.de/justJanne/libquassel/badges/main/coverage.svg)](https://git.kuschku.de/justJanne/libquassel/-/commits/main)
 
 libquassel is a pure kotlin implementation of the Quassel protocol.
+
+# TODO
+
+- idea: separate db per account, no multi-tenancy or weird compound ids
+- got alias persistence working. sync in transaction is awesome
+- using dtos to convert from/to variantmap for update/requestUpdate seems like a good idea
+- should be only busywork from here, right? :D
+- good luck future janne ^^
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 6e07830da2e1b736d3774edacedd5f2d89be6420..530f548d205b3bf0c4998b5af7dd062ff5fa5d24 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -13,7 +13,9 @@ kotlinx-coroutines = "1.9.0"
 kotlinx-serialization = "2.0.21"
 ktlint = "12.1.1"
 nexus-publish = "2.0.0"
+room = "2.7.0-alpha07"
 slf4j = "1.7.30"
+sqlite = "2.5.0-alpha07"
 threetenbp = "1.7.0"
 
 [libraries]
@@ -36,6 +38,10 @@ junit-params = { module = "org.junit.jupiter:junit-jupiter-params", version.ref
 junit-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junit"}
 junit-kotlin = { module = "org.jetbrains.kotlin:kotlin-test-junit5", version.ref = "kotlin"}
 
+room-compiler = { module = "androidx.room:room-compiler", version.ref = "room" }
+room-runtime = { module = "androidx.room:room-runtime", version.ref = "room" }
+sqlite = { module = "androidx.sqlite:sqlite-bundled", version.ref = "sqlite" }
+
 nexus-publish-gradlePlugin = { module = "io.github.gradle-nexus:publish-plugin", version.ref = "nexus-publish" }
 kotlin-gradlePlugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
 dokka-gradlePlugin = { module = "org.jetbrains.dokka:dokka-gradle-plugin", version.ref = "dokka" }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/AliasManagerClientApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/AliasManagerClientApi.kt
index 64a2d0e7fc77eedb12947df46b67e3e8679caf41..da7c82e8073baf76ce1b8941714d36eaa5de480a 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/AliasManagerClientApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/AliasManagerClientApi.kt
@@ -18,5 +18,5 @@ import de.justjanne.libquassel.protocol.variant.QVariantMap
 @RpcApi("AliasManager", side = ProtocolSide.CORE)
 interface AliasManagerClientApi {
   @RpcCall("update")
-  fun update(@RpcParam.QVariantMap properties: QVariantMap)
+  suspend fun update(@RpcParam.QVariantMap properties: QVariantMap)
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/BacklogManagerClientApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/BacklogManagerClientApi.kt
index f67f237d333d0bae40c7f0fba7b3e52408fab691..31458443c58579b7cac04ecc9c7d8e94918088fa 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/BacklogManagerClientApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/BacklogManagerClientApi.kt
@@ -11,8 +11,8 @@ package de.justjanne.libquassel.protocol.api.client
 
 import de.justjanne.libquassel.annotations.ProtocolSide
 import de.justjanne.libquassel.annotations.RpcApi
-import de.justjanne.libquassel.annotations.RpcParam
 import de.justjanne.libquassel.annotations.RpcCall
+import de.justjanne.libquassel.annotations.RpcParam
 import de.justjanne.libquassel.protocol.models.ids.BufferId
 import de.justjanne.libquassel.protocol.models.ids.MsgId
 import de.justjanne.libquassel.protocol.variant.QVariantList
@@ -23,8 +23,8 @@ interface BacklogManagerClientApi {
    * Response to the corresponding [requestBacklog] call.
    * [messages] contains the messages as `QVariant<Message>`
    */
-      @RpcCall("receiveBacklog")
-  fun receiveBacklog(
+  @RpcCall("receiveBacklog")
+  suspend fun receiveBacklog(
     @RpcParam.UserType.BufferId bufferId: BufferId,
     @RpcParam.UserType.MsgId first: MsgId = MsgId(-1),
     @RpcParam.UserType.MsgId last: MsgId = MsgId(-1),
@@ -37,8 +37,8 @@ interface BacklogManagerClientApi {
    * Response to the corresponding [requestBacklogFiltered] call.
    * [messages] contains the messages as `QVariant<Message>`
    */
-      @RpcCall("receiveBacklogFiltered")
-  fun receiveBacklogFiltered(
+  @RpcCall("receiveBacklogFiltered")
+  suspend fun receiveBacklogFiltered(
     @RpcParam.UserType.BufferId bufferId: BufferId,
     @RpcParam.UserType.MsgId first: MsgId = MsgId(-1),
     @RpcParam.UserType.MsgId last: MsgId = MsgId(-1),
@@ -53,8 +53,8 @@ interface BacklogManagerClientApi {
    * Response to the corresponding [requestBacklogForward] call.
    * [messages] contains the messages as `QVariant<Message>`
    */
-      @RpcCall("receiveBacklogForward")
-  fun receiveBacklogForward(
+  @RpcCall("receiveBacklogForward")
+  suspend fun receiveBacklogForward(
     @RpcParam.UserType.BufferId bufferId: BufferId,
     @RpcParam.UserType.MsgId first: MsgId = MsgId(-1),
     @RpcParam.UserType.MsgId last: MsgId = MsgId(-1),
@@ -68,8 +68,8 @@ interface BacklogManagerClientApi {
    * Response to the corresponding [requestBacklogAll] call.
    * [messages] contains the messages as `QVariant<Message>`
    */
-      @RpcCall("receiveBacklogAll")
-  fun receiveBacklogAll(
+  @RpcCall("receiveBacklogAll")
+  suspend fun receiveBacklogAll(
     @RpcParam.UserType.MsgId first: MsgId = MsgId(-1),
     @RpcParam.UserType.MsgId last: MsgId = MsgId(-1),
     @RpcParam.Int limit: Int = -1,
@@ -81,8 +81,8 @@ interface BacklogManagerClientApi {
    * Response to the corresponding [requestBacklogAllFiltered] call.
    * [messages] contains the messages as `QVariant<Message>`
    */
-      @RpcCall("receiveBacklogAllFiltered")
-  fun receiveBacklogAllFiltered(
+  @RpcCall("receiveBacklogAllFiltered")
+  suspend fun receiveBacklogAllFiltered(
     @RpcParam.UserType.MsgId first: MsgId = MsgId(-1),
     @RpcParam.UserType.MsgId last: MsgId = MsgId(-1),
     @RpcParam.Int limit: Int = -1,
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/BufferSyncerClientApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/BufferSyncerClientApi.kt
index 72055ad9b0b1e6ab62cc4f0ab9d18e257a7bdac1..c4b103b01e9462285f5b02beb4bd6f2de6b652e7 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/BufferSyncerClientApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/BufferSyncerClientApi.kt
@@ -20,29 +20,29 @@ import de.justjanne.libquassel.protocol.variant.QVariantMap
 @RpcApi("BufferSyncer", side = ProtocolSide.CORE)
 interface BufferSyncerClientApi {
   @RpcCall("markBufferAsRead")
-  fun markBufferAsRead( @RpcParam.UserType.BufferId buffer: BufferId)
+  suspend fun markBufferAsRead( @RpcParam.UserType.BufferId buffer: BufferId)
 
   @RpcCall("mergeBuffersPermanently")
-  fun mergeBuffersPermanently(@RpcParam.UserType.BufferId buffer: BufferId, @RpcParam.UserType.BufferId buffer2: BufferId)
+  suspend fun mergeBuffersPermanently(@RpcParam.UserType.BufferId buffer: BufferId, @RpcParam.UserType.BufferId buffer2: BufferId)
 
   @RpcCall("removeBuffer")
-  fun removeBuffer(@RpcParam.UserType.BufferId buffer: BufferId)
+  suspend fun removeBuffer(@RpcParam.UserType.BufferId buffer: BufferId)
 
   @RpcCall("renameBuffer")
-  fun renameBuffer(@RpcParam.UserType.BufferId buffer: BufferId, @RpcParam.QString newName: String)
+  suspend fun renameBuffer(@RpcParam.UserType.BufferId buffer: BufferId, @RpcParam.QString newName: String)
 
   @RpcCall("setMarkerLine")
-  fun setMarkerLine(@RpcParam.UserType.BufferId buffer: BufferId, @RpcParam.UserType.MsgId msgId: MsgId)
+  suspend fun setMarkerLine(@RpcParam.UserType.BufferId buffer: BufferId, @RpcParam.UserType.MsgId msgId: MsgId)
 
   @RpcCall("setLastSeenMsg")
-  fun setLastSeenMsg(@RpcParam.UserType.BufferId buffer: BufferId, @RpcParam.UserType.MsgId msgId: MsgId)
+  suspend fun setLastSeenMsg(@RpcParam.UserType.BufferId buffer: BufferId, @RpcParam.UserType.MsgId msgId: MsgId)
 
   @RpcCall("setBufferActivity")
-  fun setBufferActivity(@RpcParam.UserType.BufferId buffer: BufferId, @RpcParam.Int types: Int)
+  suspend fun setBufferActivity(@RpcParam.UserType.BufferId buffer: BufferId, @RpcParam.Int types: Int)
 
   @RpcCall("setHighlightCount")
-  fun setHighlightCount(@RpcParam.UserType.BufferId buffer: BufferId, @RpcParam.Int count: Int)
+  suspend fun setHighlightCount(@RpcParam.UserType.BufferId buffer: BufferId, @RpcParam.Int count: Int)
 
   @RpcCall("update")
-  fun update(@RpcParam.QVariantMap properties: QVariantMap)
+  suspend fun update(@RpcParam.QVariantMap properties: QVariantMap)
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/BufferViewConfigClientApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/BufferViewConfigClientApi.kt
index 69ec39856d382406ee0b22087205fa0d2fb3393a..6868a03bd595275f9c94b19f98121610de4624ec 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/BufferViewConfigClientApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/BufferViewConfigClientApi.kt
@@ -21,47 +21,47 @@ import de.justjanne.libquassel.protocol.variant.QVariantMap
 @RpcApi("BufferViewConfig", side = ProtocolSide.CORE)
 interface BufferViewConfigClientApi {
   @RpcCall("addBuffer")
-  fun addBuffer(@RpcParam.UserType.BufferId buffer: BufferId, @RpcParam.Int pos: Int)
+  suspend fun addBuffer(@RpcParam.UserType.BufferId buffer: BufferId, @RpcParam.Int pos: Int)
 
   @RpcCall("moveBuffer")
-  fun moveBuffer(@RpcParam.UserType.BufferId buffer: BufferId, @RpcParam.Int pos: Int)
+  suspend fun moveBuffer(@RpcParam.UserType.BufferId buffer: BufferId, @RpcParam.Int pos: Int)
 
   @RpcCall("removeBuffer")
-  fun removeBuffer(@RpcParam.UserType.BufferId buffer: BufferId)
+  suspend fun removeBuffer(@RpcParam.UserType.BufferId buffer: BufferId)
 
   @RpcCall("removeBufferPermanently")
-  fun removeBufferPermanently(@RpcParam.UserType.BufferId buffer: BufferId)
+  suspend fun removeBufferPermanently(@RpcParam.UserType.BufferId buffer: BufferId)
 
   @RpcCall("setBufferViewName")
-  fun setBufferViewName(@RpcParam.QString value: String)
+  suspend fun setBufferViewName(@RpcParam.QString value: String)
 
   @RpcCall("setAddNewBuffersAutomatically")
-  fun setAddNewBuffersAutomatically(@RpcParam.Bool value: Boolean)
+  suspend fun setAddNewBuffersAutomatically(@RpcParam.Bool value: Boolean)
 
   @RpcCall("setAllowedBufferTypes")
-  fun setAllowedBufferTypes(@RpcParam.Int value: Int)
+  suspend fun setAllowedBufferTypes(@RpcParam.Int value: Int)
 
   @RpcCall("setDisableDecoration")
-  fun setDisableDecoration(@RpcParam.Bool value: Boolean)
+  suspend fun setDisableDecoration(@RpcParam.Bool value: Boolean)
 
   @RpcCall("setHideInactiveBuffers")
-  fun setHideInactiveBuffers(@RpcParam.Bool value: Boolean)
+  suspend fun setHideInactiveBuffers(@RpcParam.Bool value: Boolean)
 
   @RpcCall("setHideInactiveNetworks")
-  fun setHideInactiveNetworks(@RpcParam.Bool value: Boolean)
+  suspend fun setHideInactiveNetworks(@RpcParam.Bool value: Boolean)
 
   @RpcCall("setMinimumActivity")
-  fun setMinimumActivity(@RpcParam.Int value: Int)
+  suspend fun setMinimumActivity(@RpcParam.Int value: Int)
 
   @RpcCall("setNetworkId")
-  fun setNetworkId(@RpcParam.UserType.NetworkId value: NetworkId)
+  suspend fun setNetworkId(@RpcParam.UserType.NetworkId value: NetworkId)
 
   @RpcCall("setShowSearch")
-  fun setShowSearch(@RpcParam.Bool value: Boolean)
+  suspend fun setShowSearch(@RpcParam.Bool value: Boolean)
 
   @RpcCall("setSortAlphabetically")
-  fun setSortAlphabetically(@RpcParam.Bool value: Boolean)
+  suspend fun setSortAlphabetically(@RpcParam.Bool value: Boolean)
 
   @RpcCall("update")
-  fun update(@RpcParam.QVariantMap properties: QVariantMap)
+  suspend fun update(@RpcParam.QVariantMap properties: QVariantMap)
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/BufferViewManagerClientApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/BufferViewManagerClientApi.kt
index 0196cc1789f6d62354e6dce6cf402b7772eed3eb..4e4996163bb42aaf9bda7ff9cb4c84eadbbb1e73 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/BufferViewManagerClientApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/BufferViewManagerClientApi.kt
@@ -18,11 +18,11 @@ import de.justjanne.libquassel.protocol.variant.QVariantMap
 @RpcApi("BufferViewManager", side = ProtocolSide.CORE)
 interface BufferViewManagerClientApi {
   @RpcCall("addBufferViewConfig")
-  fun addBufferViewConfig(@RpcParam.Int bufferViewConfigId: Int)
+  suspend fun addBufferViewConfig(@RpcParam.Int bufferViewConfigId: Int)
 
   @RpcCall("deleteBufferViewConfig")
-  fun deleteBufferViewConfig(@RpcParam.Int bufferViewConfigId: Int)
+  suspend fun deleteBufferViewConfig(@RpcParam.Int bufferViewConfigId: Int)
 
   @RpcCall("update")
-  fun update(@RpcParam.QVariantMap properties: QVariantMap)
+  suspend fun update(@RpcParam.QVariantMap properties: QVariantMap)
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/CertManagerClientApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/CertManagerClientApi.kt
index a2b2e3085e15eff66bcadde7954696255a4ef0f7..483dc46f42417963bd934589179f33af8b2e49c3 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/CertManagerClientApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/CertManagerClientApi.kt
@@ -20,11 +20,11 @@ import java.nio.ByteBuffer
 @RpcApi("CertManager", side = ProtocolSide.CORE)
 interface CertManagerClientApi {
       @RpcCall("setSslCert")
-  fun setSslCert(objectName: ObjectName, @RpcParam.QByteArray encoded: ByteBuffer)
+  suspend fun setSslCert(objectName: ObjectName, @RpcParam.QByteArray encoded: ByteBuffer)
 
       @RpcCall("setSslKey")
-  fun setSslKey(objectName: ObjectName, @RpcParam.QByteArray encoded: ByteBuffer)
+  suspend fun setSslKey(objectName: ObjectName, @RpcParam.QByteArray encoded: ByteBuffer)
 
       @RpcCall("update")
-  fun update(objectName: ObjectName, @RpcParam.QVariantMap properties: QVariantMap)
+  suspend fun update(objectName: ObjectName, @RpcParam.QVariantMap properties: QVariantMap)
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/CoreInfoClientApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/CoreInfoClientApi.kt
index 0290a7c4cea93003841fce535e952762693eabf3..bc11a73aa4ca38191d9bff35784b414aa7f6f3a8 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/CoreInfoClientApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/CoreInfoClientApi.kt
@@ -18,8 +18,8 @@ import de.justjanne.libquassel.protocol.variant.QVariantMap
 @RpcApi("CoreInfo", side = ProtocolSide.CORE)
 interface CoreInfoClientApi {
   @RpcCall("setCoreData")
-  fun setCoreData(@RpcParam.QVariantMap data: QVariantMap)
+  suspend fun setCoreData(@RpcParam.QVariantMap data: QVariantMap)
 
   @RpcCall("update")
-  fun update(@RpcParam.QVariantMap properties: QVariantMap)
+  suspend fun update(@RpcParam.QVariantMap properties: QVariantMap)
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/HighlightRuleManagerClientApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/HighlightRuleManagerClientApi.kt
index 5773ffd8490bf903cfe764f080d1e08fca54ae3e..6161e4a7acda073fba3599d9c7b1bf77931a830e 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/HighlightRuleManagerClientApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/HighlightRuleManagerClientApi.kt
@@ -19,13 +19,13 @@ import de.justjanne.libquassel.protocol.variant.QVariantMap
 interface HighlightRuleManagerClientApi {
 
   @RpcCall("removeHighlightRule")
-  fun removeHighlightRule(@RpcParam.Int highlightRule: Int)
+  suspend fun removeHighlightRule(@RpcParam.Int highlightRule: Int)
 
   @RpcCall("toggleHighlightRule")
-  fun toggleHighlightRule(@RpcParam.Int highlightRule: Int)
+  suspend fun toggleHighlightRule(@RpcParam.Int highlightRule: Int)
 
   @RpcCall("addHighlightRule")
-  fun addHighlightRule(
+  suspend fun addHighlightRule(
     @RpcParam.Int id: Int,
     @RpcParam.QString content: String?,
     @RpcParam.Bool isRegEx: Boolean,
@@ -37,11 +37,11 @@ interface HighlightRuleManagerClientApi {
   )
 
   @RpcCall("setHighlightNick")
-  fun setHighlightNick(@RpcParam.Int highlightNick: Int)
+  suspend fun setHighlightNick(@RpcParam.Int highlightNick: Int)
 
   @RpcCall("setNicksCaseSensitive")
-  fun setNicksCaseSensitive(@RpcParam.Bool nicksCaseSensitive: Boolean)
+  suspend fun setNicksCaseSensitive(@RpcParam.Bool nicksCaseSensitive: Boolean)
 
   @RpcCall("update")
-  fun update(@RpcParam.QVariantMap properties: QVariantMap)
+  suspend fun update(@RpcParam.QVariantMap properties: QVariantMap)
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/IdentityClientApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/IdentityClientApi.kt
index 88406d95bb7ac1728159676d2507b2b1dd4551e2..56de68320835cb82352db92667922df101f22f15 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/IdentityClientApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/IdentityClientApi.kt
@@ -21,81 +21,81 @@ import de.justjanne.libquassel.protocol.variant.QVariantMap
 @RpcApi("Identity", side = ProtocolSide.CORE)
 interface IdentityClientApi {
   @RpcCall("setAutoAwayEnabled")
-  fun setAutoAwayEnabled(objectName: ObjectName, @RpcParam.Bool enabled: Boolean)
+  suspend fun setAutoAwayEnabled(objectName: ObjectName, @RpcParam.Bool enabled: Boolean)
 
 
   @RpcCall("setAutoAwayReason")
-  fun setAutoAwayReason(objectName: ObjectName, @RpcParam.QString reason: String?)
+  suspend fun setAutoAwayReason(objectName: ObjectName, @RpcParam.QString reason: String?)
 
 
   @RpcCall("setAutoAwayReasonEnabled")
-  fun setAutoAwayReasonEnabled(objectName: ObjectName, @RpcParam.Bool enabled: Boolean)
+  suspend fun setAutoAwayReasonEnabled(objectName: ObjectName, @RpcParam.Bool enabled: Boolean)
 
 
   @RpcCall("setAutoAwayTime")
-  fun setAutoAwayTime(objectName: ObjectName, @RpcParam.Int time: Int)
+  suspend fun setAutoAwayTime(objectName: ObjectName, @RpcParam.Int time: Int)
 
 
   @RpcCall("setAwayNick")
-  fun setAwayNick(objectName: ObjectName, @RpcParam.QString awayNick: String?)
+  suspend fun setAwayNick(objectName: ObjectName, @RpcParam.QString awayNick: String?)
 
 
   @RpcCall("setAwayNickEnabled")
-  fun setAwayNickEnabled(objectName: ObjectName, @RpcParam.Bool enabled: Boolean)
+  suspend fun setAwayNickEnabled(objectName: ObjectName, @RpcParam.Bool enabled: Boolean)
 
 
   @RpcCall("setAwayReason")
-  fun setAwayReason(objectName: ObjectName, @RpcParam.QString awayReason: String?)
+  suspend fun setAwayReason(objectName: ObjectName, @RpcParam.QString awayReason: String?)
 
 
   @RpcCall("setAwayReasonEnabled")
-  fun setAwayReasonEnabled(objectName: ObjectName, @RpcParam.Bool enabled: Boolean)
+  suspend fun setAwayReasonEnabled(objectName: ObjectName, @RpcParam.Bool enabled: Boolean)
 
 
   @RpcCall("setDetachAwayEnabled")
-  fun setDetachAwayEnabled(objectName: ObjectName, @RpcParam.Bool enabled: Boolean)
+  suspend fun setDetachAwayEnabled(objectName: ObjectName, @RpcParam.Bool enabled: Boolean)
 
 
   @RpcCall("setDetachAwayReason")
-  fun setDetachAwayReason(objectName: ObjectName, @RpcParam.QString reason: String?)
+  suspend fun setDetachAwayReason(objectName: ObjectName, @RpcParam.QString reason: String?)
 
 
   @RpcCall("setDetachAwayReasonEnabled")
-  fun setDetachAwayReasonEnabled(objectName: ObjectName, @RpcParam.Bool enabled: Boolean)
+  suspend fun setDetachAwayReasonEnabled(objectName: ObjectName, @RpcParam.Bool enabled: Boolean)
 
 
   @RpcCall("setId")
-  fun setId(objectName: ObjectName, @RpcParam.UserType.IdentityId id: IdentityId)
+  suspend fun setId(objectName: ObjectName, @RpcParam.UserType.IdentityId id: IdentityId)
 
 
   @RpcCall("setIdent")
-  fun setIdent(objectName: ObjectName, @RpcParam.QString ident: String?)
+  suspend fun setIdent(objectName: ObjectName, @RpcParam.QString ident: String?)
 
 
   @RpcCall("setIdentityName")
-  fun setIdentityName(objectName: ObjectName, @RpcParam.QString name: String?)
+  suspend fun setIdentityName(objectName: ObjectName, @RpcParam.QString name: String?)
 
 
   @RpcCall("setKickReason")
-  fun setKickReason(objectName: ObjectName, @RpcParam.QString reason: String?)
+  suspend fun setKickReason(objectName: ObjectName, @RpcParam.QString reason: String?)
 
 
   @RpcCall("setNicks")
-  fun setNicks(objectName: ObjectName, @RpcParam.QStringList nicks: QStringList)
+  suspend fun setNicks(objectName: ObjectName, @RpcParam.QStringList nicks: QStringList)
 
 
   @RpcCall("setPartReason")
-  fun setPartReason(objectName: ObjectName, @RpcParam.QString reason: String?)
+  suspend fun setPartReason(objectName: ObjectName, @RpcParam.QString reason: String?)
 
 
   @RpcCall("setQuitReason")
-  fun setQuitReason(objectName: ObjectName, @RpcParam.QString reason: String?)
+  suspend fun setQuitReason(objectName: ObjectName, @RpcParam.QString reason: String?)
 
 
   @RpcCall("setRealName")
-  fun setRealName(objectName: ObjectName, @RpcParam.QString realName: String?)
+  suspend fun setRealName(objectName: ObjectName, @RpcParam.QString realName: String?)
 
 
   @RpcCall("update")
-  fun update(objectName: ObjectName, @RpcParam.QVariantMap properties: QVariantMap)
+  suspend fun update(objectName: ObjectName, @RpcParam.QVariantMap properties: QVariantMap)
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/IgnoreListManagerClientApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/IgnoreListManagerClientApi.kt
index 7d9d18d12d6d2e93e8934663e39bad3978019c8f..b4141640dbe98aaf5a5d77a5d13b0b722f570c3a 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/IgnoreListManagerClientApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/IgnoreListManagerClientApi.kt
@@ -18,7 +18,7 @@ import de.justjanne.libquassel.protocol.variant.QVariantMap
 @RpcApi("IgnoreListManager", side = ProtocolSide.CORE)
 interface IgnoreListManagerClientApi {
   @RpcCall("addIgnoreListItem")
-  fun addIgnoreListItem(
+  suspend fun addIgnoreListItem(
     @RpcParam.Int type: Int,
     @RpcParam.QString ignoreRule: String?,
     @RpcParam.Bool isRegEx: Boolean,
@@ -29,11 +29,11 @@ interface IgnoreListManagerClientApi {
   )
 
   @RpcCall("removeIgnoreListItem")
-  fun removeIgnoreListItem(@RpcParam.QString ignoreRule: String?)
+  suspend fun removeIgnoreListItem(@RpcParam.QString ignoreRule: String?)
 
   @RpcCall("requestToggleIgnoreRule")
-  fun toggleIgnoreRule(@RpcParam.QString ignoreRule: String?)
+  suspend fun toggleIgnoreRule(@RpcParam.QString ignoreRule: String?)
 
   @RpcCall("update")
-  fun update(@RpcParam.QVariantMap properties: QVariantMap)
+  suspend fun update(@RpcParam.QVariantMap properties: QVariantMap)
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/IrcChannelClientApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/IrcChannelClientApi.kt
index 2741c6a01b57cb4b198bfb02993cd182a15defc4..4b0c8d08b38cf13e3fa9d0fe166b979381928dcb 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/IrcChannelClientApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/IrcChannelClientApi.kt
@@ -20,45 +20,45 @@ import de.justjanne.libquassel.protocol.variant.QVariantMap
 @RpcApi("IrcChannel", side = ProtocolSide.CORE)
 interface IrcChannelClientApi  {
   @RpcCall("addChannelMode")
-  fun addChannelMode( objectName: ObjectName, @RpcParam.QChar mode: Char, @RpcParam.QString value: String? = null)
+  suspend fun addChannelMode( objectName: ObjectName, @RpcParam.QChar mode: Char, @RpcParam.QString value: String? = null)
 
 
   @RpcCall("addUserMode")
-  fun addUserMode(objectName: ObjectName, @RpcParam.QString nick: String, @RpcParam.QString mode: String? = null)
+  suspend fun addUserMode(objectName: ObjectName, @RpcParam.QString nick: String, @RpcParam.QString mode: String? = null)
 
 
   @RpcCall("joinIrcUsers")
-  fun joinIrcUsers(objectName: ObjectName, @RpcParam.QStringList nicks: QStringList, @RpcParam.QStringList modes: QStringList)
+  suspend fun joinIrcUsers(objectName: ObjectName, @RpcParam.QStringList nicks: QStringList, @RpcParam.QStringList modes: QStringList)
 
 
   @RpcCall("part")
-  fun part(objectName: ObjectName, @RpcParam.QString nick: String)
+  suspend fun part(objectName: ObjectName, @RpcParam.QString nick: String)
 
 
   @RpcCall("removeChannelMode")
-  fun removeChannelMode(objectName: ObjectName, @RpcParam.QChar mode: Char, @RpcParam.QString value: String? = null)
+  suspend fun removeChannelMode(objectName: ObjectName, @RpcParam.QChar mode: Char, @RpcParam.QString value: String? = null)
 
 
   @RpcCall("removeUserMode")
-  fun removeUserMode(objectName: ObjectName, @RpcParam.QString nick: String, @RpcParam.QString mode: String? = null)
+  suspend fun removeUserMode(objectName: ObjectName, @RpcParam.QString nick: String, @RpcParam.QString mode: String? = null)
 
 
   @RpcCall("setEncrypted")
-  fun setEncrypted(objectName: ObjectName, @RpcParam.Bool encrypted: Boolean)
+  suspend fun setEncrypted(objectName: ObjectName, @RpcParam.Bool encrypted: Boolean)
 
 
   @RpcCall("setPassword")
-  fun setPassword(objectName: ObjectName, @RpcParam.QString password: String)
+  suspend fun setPassword(objectName: ObjectName, @RpcParam.QString password: String)
 
 
   @RpcCall("setTopic")
-  fun setTopic(objectName: ObjectName, @RpcParam.QString topic: String)
+  suspend fun setTopic(objectName: ObjectName, @RpcParam.QString topic: String)
 
 
   @RpcCall("setUserModes")
-  fun setUserModes(objectName: ObjectName, @RpcParam.QString nick: String, @RpcParam.QString modes: String? = null)
+  suspend fun setUserModes(objectName: ObjectName, @RpcParam.QString nick: String, @RpcParam.QString modes: String? = null)
 
 
   @RpcCall("update")
-  fun update(objectName: ObjectName, @RpcParam.QVariantMap properties: QVariantMap)
+  suspend fun update(objectName: ObjectName, @RpcParam.QVariantMap properties: QVariantMap)
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/IrcListHelperClientApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/IrcListHelperClientApi.kt
index a142edf0c28576a4424be6a65e97d6a84d382b61..ed9bedbddebf03fbda92fd245d5639ee09123271 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/IrcListHelperClientApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/IrcListHelperClientApi.kt
@@ -20,11 +20,11 @@ import de.justjanne.libquassel.protocol.variant.QVariantList
 @RpcApi("IrcListHelper", side = ProtocolSide.CORE)
 interface IrcListHelperClientApi  {
   @RpcCall("receiveChannelList")
-  fun receiveChannelList(@RpcParam.UserType.NetworkId netId: NetworkId, @RpcParam.QStringList channelFilters: QStringList, @RpcParam.QVariantList channels: QVariantList)
+  suspend fun receiveChannelList(@RpcParam.UserType.NetworkId netId: NetworkId, @RpcParam.QStringList channelFilters: QStringList, @RpcParam.QVariantList channels: QVariantList)
 
   @RpcCall("reportError")
-  fun reportError(@RpcParam.QString error: String?)
+  suspend fun reportError(@RpcParam.QString error: String?)
 
   @RpcCall("reportFinishedList")
-  fun reportFinishedList(@RpcParam.UserType.NetworkId netId: NetworkId)
+  suspend fun reportFinishedList(@RpcParam.UserType.NetworkId netId: NetworkId)
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/IrcUserClientApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/IrcUserClientApi.kt
index 88a4aaa0c0b1a05b422da7e6f85f6f4f68d7f616..3af403320059554b9e6f9814ce51933597e85989 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/IrcUserClientApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/IrcUserClientApi.kt
@@ -20,75 +20,75 @@ import org.threeten.bp.temporal.Temporal
 @RpcApi("IrcUser", side = ProtocolSide.CORE)
 interface IrcUserClientApi {
   @RpcCall("addUserModes")
-  fun addUserModes(objectName: ObjectName, @RpcParam.QString modes: String)
+  suspend fun addUserModes(objectName: ObjectName, @RpcParam.QString modes: String)
 
   @RpcCall("joinChannel")
-  fun joinChannel(objectName: ObjectName, @RpcParam.QString channelname: String)
+  suspend fun joinChannel(objectName: ObjectName, @RpcParam.QString channelname: String)
 
   @RpcCall("partChannel")
-  fun partChannel(objectName: ObjectName, @RpcParam.QString channelname: String)
+  suspend fun partChannel(objectName: ObjectName, @RpcParam.QString channelname: String)
 
   @RpcCall("quit")
-  fun quit(objectName: ObjectName)
+  suspend fun quit(objectName: ObjectName)
 
   @RpcCall("removeUserModes")
-  fun removeUserModes(objectName: ObjectName, @RpcParam.QString modes: String)
+  suspend fun removeUserModes(objectName: ObjectName, @RpcParam.QString modes: String)
 
   @RpcCall("setAccount")
-  fun setAccount(objectName: ObjectName, @RpcParam.QString account: String)
+  suspend fun setAccount(objectName: ObjectName, @RpcParam.QString account: String)
 
   @RpcCall("setAway")
-  fun setAway(objectName: ObjectName, @RpcParam.Bool away: Boolean)
+  suspend fun setAway(objectName: ObjectName, @RpcParam.Bool away: Boolean)
 
   @RpcCall("setAwayMessage")
-  fun setAwayMessage(objectName: ObjectName, @RpcParam.QString awayMessage: String)
+  suspend fun setAwayMessage(objectName: ObjectName, @RpcParam.QString awayMessage: String)
 
   @RpcCall("setEncrypted")
-  fun setEncrypted(objectName: ObjectName, @RpcParam.Bool encrypted: Boolean)
+  suspend fun setEncrypted(objectName: ObjectName, @RpcParam.Bool encrypted: Boolean)
 
   @RpcCall("setHost")
-  fun setHost(objectName: ObjectName, @RpcParam.QString host: String)
+  suspend fun setHost(objectName: ObjectName, @RpcParam.QString host: String)
 
   @RpcCall("setIdleTime")
-  fun setIdleTime(objectName: ObjectName, @RpcParam.QDateTime idleTime: Temporal)
+  suspend fun setIdleTime(objectName: ObjectName, @RpcParam.QDateTime idleTime: Temporal)
 
   @RpcCall("setIrcOperator")
-  fun setIrcOperator(objectName: ObjectName, @RpcParam.QString ircOperator: String)
+  suspend fun setIrcOperator(objectName: ObjectName, @RpcParam.QString ircOperator: String)
 
   @RpcCall("setLastAwayMessage")
-  fun setLastAwayMessage(objectName: ObjectName, @RpcParam.Int lastAwayMessage: Int)
+  suspend fun setLastAwayMessage(objectName: ObjectName, @RpcParam.Int lastAwayMessage: Int)
 
   @RpcCall("setLastAwayMessageTime")
-  fun setLastAwayMessageTime(objectName: ObjectName, @RpcParam.QDateTime lastAwayMessageTime: Temporal)
+  suspend fun setLastAwayMessageTime(objectName: ObjectName, @RpcParam.QDateTime lastAwayMessageTime: Temporal)
 
   @RpcCall("setLoginTime")
-  fun setLoginTime(objectName: ObjectName, @RpcParam.QDateTime loginTime: Temporal)
+  suspend fun setLoginTime(objectName: ObjectName, @RpcParam.QDateTime loginTime: Temporal)
 
   @RpcCall("setNick")
-  fun setNick(objectName: ObjectName, @RpcParam.QString newNick: String)
+  suspend fun setNick(objectName: ObjectName, @RpcParam.QString newNick: String)
 
   @RpcCall("setRealName")
-  fun setRealName(objectName: ObjectName, @RpcParam.QString realName: String)
+  suspend fun setRealName(objectName: ObjectName, @RpcParam.QString realName: String)
 
   @RpcCall("setServer")
-  fun setServer(objectName: ObjectName, @RpcParam.QString server: String)
+  suspend fun setServer(objectName: ObjectName, @RpcParam.QString server: String)
 
   @RpcCall("setSuserHost")
-  fun setSuserHost(objectName: ObjectName, @RpcParam.QString suserHost: String)
+  suspend fun setSuserHost(objectName: ObjectName, @RpcParam.QString suserHost: String)
 
   @RpcCall("setUser")
-  fun setUser(objectName: ObjectName, @RpcParam.QString user: String)
+  suspend fun setUser(objectName: ObjectName, @RpcParam.QString user: String)
 
   @RpcCall("setUserModes")
-  fun setUserModes(objectName: ObjectName, @RpcParam.QString modes: String)
+  suspend fun setUserModes(objectName: ObjectName, @RpcParam.QString modes: String)
 
   @RpcCall("setWhoisServiceReply")
-  fun setWhoisServiceReply(objectName: ObjectName, @RpcParam.QString whoisServiceReply: String)
+  suspend fun setWhoisServiceReply(objectName: ObjectName, @RpcParam.QString whoisServiceReply: String)
 
   @RpcCall("updateHostmask")
-  fun updateHostmask(objectName: ObjectName, @RpcParam.QString mask: String)
+  suspend fun updateHostmask(objectName: ObjectName, @RpcParam.QString mask: String)
 
   @RpcCall("update")
-  fun update(objectName: ObjectName, @RpcParam.QVariantMap properties: QVariantMap)
+  suspend fun update(objectName: ObjectName, @RpcParam.QVariantMap properties: QVariantMap)
 }
 
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/NetworkClientApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/NetworkClientApi.kt
index b44fc81cd0c5fd82735b7c213a35c56d28d258fb..256dc966427ec192b5c3b42e42b4260c7b926483 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/NetworkClientApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/NetworkClientApi.kt
@@ -23,152 +23,152 @@ import java.nio.ByteBuffer
 @RpcApi("Network", side = ProtocolSide.CORE)
 interface NetworkClientApi {
   @RpcCall("setNetworkName")
-  fun setNetworkName(objectName: ObjectName, @RpcParam.QString networkName: String)
+  suspend fun setNetworkName(objectName: ObjectName, @RpcParam.QString networkName: String)
 
 
   @RpcCall("setCurrentServer")
-  fun setCurrentServer(objectName: ObjectName, @RpcParam.QString currentServer: String?)
+  suspend fun setCurrentServer(objectName: ObjectName, @RpcParam.QString currentServer: String?)
 
 
   @RpcCall("setMyNick")
-  fun setMyNick(objectName: ObjectName, @RpcParam.QString myNick: String?)
+  suspend fun setMyNick(objectName: ObjectName, @RpcParam.QString myNick: String?)
 
 
   @RpcCall("setLatency")
-  fun setLatency(objectName: ObjectName, @RpcParam.Int latency: Int)
+  suspend fun setLatency(objectName: ObjectName, @RpcParam.Int latency: Int)
 
 
   @RpcCall("setCodecForServer")
-  fun setCodecForServer(objectName: ObjectName, @RpcParam.QByteArray codecForServer: ByteBuffer)
+  suspend fun setCodecForServer(objectName: ObjectName, @RpcParam.QByteArray codecForServer: ByteBuffer)
 
 
   @RpcCall("setCodecForEncoding")
-  fun setCodecForEncoding(objectName: ObjectName, @RpcParam.QByteArray codecForEncoding: ByteBuffer)
+  suspend fun setCodecForEncoding(objectName: ObjectName, @RpcParam.QByteArray codecForEncoding: ByteBuffer)
 
 
   @RpcCall("setCodecForDecoding")
-  fun setCodecForDecoding(objectName: ObjectName, @RpcParam.QByteArray codecForDecoding: ByteBuffer)
+  suspend fun setCodecForDecoding(objectName: ObjectName, @RpcParam.QByteArray codecForDecoding: ByteBuffer)
 
 
   @RpcCall("setIdentity")
-  fun setIdentity(objectName: ObjectName, @RpcParam.UserType.IdentityId identityId: IdentityId)
+  suspend fun setIdentity(objectName: ObjectName, @RpcParam.UserType.IdentityId identityId: IdentityId)
 
 
   @RpcCall("setConnected")
-  fun setConnected(objectName: ObjectName, @RpcParam.Bool isConnected: Boolean)
+  suspend fun setConnected(objectName: ObjectName, @RpcParam.Bool isConnected: Boolean)
 
 
   @RpcCall("setConnectionState")
-  fun setConnectionState(objectName: ObjectName, @RpcParam.Int connectionState: Int)
+  suspend fun setConnectionState(objectName: ObjectName, @RpcParam.Int connectionState: Int)
 
 
   @RpcCall("setUseRandomServer")
-  fun setUseRandomServer(objectName: ObjectName, @RpcParam.Bool useRandomServer: Boolean)
+  suspend fun setUseRandomServer(objectName: ObjectName, @RpcParam.Bool useRandomServer: Boolean)
 
 
   @RpcCall("setPerform")
-  fun setPerform(objectName: ObjectName, @RpcParam.QStringList perform: QStringList)
+  suspend fun setPerform(objectName: ObjectName, @RpcParam.QStringList perform: QStringList)
 
 
   @RpcCall("setSkipCaps")
-  fun setSkipCaps(objectName: ObjectName, @RpcParam.QStringList skipCaps: QStringList)
+  suspend fun setSkipCaps(objectName: ObjectName, @RpcParam.QStringList skipCaps: QStringList)
 
 
   @RpcCall("setUseAutoIdentify")
-  fun setUseAutoIdentify(objectName: ObjectName, @RpcParam.Bool useAutoIdentify: Boolean)
+  suspend fun setUseAutoIdentify(objectName: ObjectName, @RpcParam.Bool useAutoIdentify: Boolean)
 
 
   @RpcCall("setAutoIdentifyService")
-  fun setAutoIdentifyService(objectName: ObjectName, @RpcParam.QString autoIdentifyService: String)
+  suspend fun setAutoIdentifyService(objectName: ObjectName, @RpcParam.QString autoIdentifyService: String)
 
 
   @RpcCall("setAutoIdentifyPassword")
-  fun setAutoIdentifyPassword(objectName: ObjectName, @RpcParam.QString autoIdentifyPassword: String)
+  suspend fun setAutoIdentifyPassword(objectName: ObjectName, @RpcParam.QString autoIdentifyPassword: String)
 
 
   @RpcCall("setUseSasl")
-  fun setUseSasl(objectName: ObjectName, @RpcParam.Bool useSasl: Boolean)
+  suspend fun setUseSasl(objectName: ObjectName, @RpcParam.Bool useSasl: Boolean)
 
 
   @RpcCall("setSaslAccount")
-  fun setSaslAccount(objectName: ObjectName, @RpcParam.QString saslAccount: String)
+  suspend fun setSaslAccount(objectName: ObjectName, @RpcParam.QString saslAccount: String)
 
 
   @RpcCall("setSaslPassword")
-  fun setSaslPassword(objectName: ObjectName, @RpcParam.QString saslPassword: String)
+  suspend fun setSaslPassword(objectName: ObjectName, @RpcParam.QString saslPassword: String)
 
 
   @RpcCall("setUseAutoReconnect")
-  fun setUseAutoReconnect(objectName: ObjectName, @RpcParam.Bool useAutoReconnect: Boolean)
+  suspend fun setUseAutoReconnect(objectName: ObjectName, @RpcParam.Bool useAutoReconnect: Boolean)
 
 
   @RpcCall("setAutoReconnectInterval")
-  fun setAutoReconnectInterval(objectName: ObjectName, @RpcParam.UInt autoReconnectInterval: UInt)
+  suspend fun setAutoReconnectInterval(objectName: ObjectName, @RpcParam.UInt autoReconnectInterval: UInt)
 
 
   @RpcCall("setAutoReconnectRetries")
-  fun setAutoReconnectRetries(objectName: ObjectName, @RpcParam.UShort autoReconnectRetries: UShort)
+  suspend fun setAutoReconnectRetries(objectName: ObjectName, @RpcParam.UShort autoReconnectRetries: UShort)
 
 
   @RpcCall("setUnlimitedReconnectRetries")
-  fun setUnlimitedReconnectRetries(objectName: ObjectName, @RpcParam.Bool unlimitedReconnectRetries: Boolean)
+  suspend fun setUnlimitedReconnectRetries(objectName: ObjectName, @RpcParam.Bool unlimitedReconnectRetries: Boolean)
 
 
   @RpcCall("setRejoinChannels")
-  fun setRejoinChannels(objectName: ObjectName, @RpcParam.Bool rejoinChannels: Boolean)
+  suspend fun setRejoinChannels(objectName: ObjectName, @RpcParam.Bool rejoinChannels: Boolean)
 
 
   @RpcCall("setUseCustomMessageRate")
-  fun setUseCustomMessageRate(objectName: ObjectName, @RpcParam.Bool useCustomMessageRate: Boolean)
+  suspend fun setUseCustomMessageRate(objectName: ObjectName, @RpcParam.Bool useCustomMessageRate: Boolean)
 
 
   @RpcCall("setMessageRateBurstSize")
-  fun setMessageRateBurstSize(objectName: ObjectName, @RpcParam.UInt messageRateBurstSize: UInt)
+  suspend fun setMessageRateBurstSize(objectName: ObjectName, @RpcParam.UInt messageRateBurstSize: UInt)
 
 
   @RpcCall("setMessageRateDelay")
-  fun setMessageRateDelay(objectName: ObjectName, @RpcParam.UInt messageRateDelay: UInt)
+  suspend fun setMessageRateDelay(objectName: ObjectName, @RpcParam.UInt messageRateDelay: UInt)
 
 
   @RpcCall("setUnlimitedMessageRate")
-  fun setUnlimitedMessageRate(objectName: ObjectName, @RpcParam.Bool unlimitedMessageRate: Boolean)
+  suspend fun setUnlimitedMessageRate(objectName: ObjectName, @RpcParam.Bool unlimitedMessageRate: Boolean)
 
 
   @RpcCall("setServerList")
-  fun setServerList(objectName: ObjectName, @RpcParam.QVariantList serverList: QVariantList)
+  suspend fun setServerList(objectName: ObjectName, @RpcParam.QVariantList serverList: QVariantList)
 
 
   @RpcCall("addSupport")
-  fun addSupport(objectName: ObjectName, @RpcParam.QString param: String, @RpcParam.QString value: String = "")
+  suspend fun addSupport(objectName: ObjectName, @RpcParam.QString param: String, @RpcParam.QString value: String = "")
 
 
   @RpcCall("removeSupport")
-  fun removeSupport(objectName: ObjectName, @RpcParam.QString param: String)
+  suspend fun removeSupport(objectName: ObjectName, @RpcParam.QString param: String)
 
 
   @RpcCall("addCap")
-  fun addCap(objectName: ObjectName, @RpcParam.QString capability: String, @RpcParam.QString value: String = "")
+  suspend fun addCap(objectName: ObjectName, @RpcParam.QString capability: String, @RpcParam.QString value: String = "")
 
 
   @RpcCall("acknowledgeCap")
-  fun acknowledgeCap(objectName: ObjectName, @RpcParam.QString capability: String)
+  suspend fun acknowledgeCap(objectName: ObjectName, @RpcParam.QString capability: String)
 
 
   @RpcCall("removeCap")
-  fun removeCap(objectName: ObjectName, @RpcParam.QString capability: String)
+  suspend fun removeCap(objectName: ObjectName, @RpcParam.QString capability: String)
 
 
   @RpcCall("clearCaps")
-  fun clearCaps(objectName: ObjectName)
+  suspend fun clearCaps(objectName: ObjectName)
 
 
   @RpcCall("addIrcUser")
-  fun addIrcUser(objectName: ObjectName, @RpcParam.QString hostmask: String)
+  suspend fun addIrcUser(objectName: ObjectName, @RpcParam.QString hostmask: String)
 
 
   @RpcCall("addIrcChannel")
-  fun addIrcChannel(objectName: ObjectName, @RpcParam.QString channel: String)
+  suspend fun addIrcChannel(objectName: ObjectName, @RpcParam.QString channel: String)
 
   @RpcCall("update")
-  fun update(objectName: ObjectName, @RpcParam.QVariantMap properties: QVariantMap)
+  suspend fun update(objectName: ObjectName, @RpcParam.QVariantMap properties: QVariantMap)
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/NetworkConfigClientApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/NetworkConfigClientApi.kt
index 3582d61c0614755c2717b2bb639e912507953fce..979dc070415ec82446256d5edaa7252dfff3d20c 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/NetworkConfigClientApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/NetworkConfigClientApi.kt
@@ -18,29 +18,29 @@ import de.justjanne.libquassel.protocol.variant.QVariantMap
 @RpcApi("NetworkConfig", side = ProtocolSide.CORE)
 interface NetworkConfigClientApi {
   @RpcCall("setAutoWhoDelay")
-  fun setAutoWhoDelay(@RpcParam.Int delay: Int)
+  suspend fun setAutoWhoDelay(@RpcParam.Int delay: Int)
 
   @RpcCall("setAutoWhoEnabled")
-  fun setAutoWhoEnabled(@RpcParam.Bool enabled: Boolean)
+  suspend fun setAutoWhoEnabled(@RpcParam.Bool enabled: Boolean)
 
   @RpcCall("setAutoWhoInterval")
-  fun setAutoWhoInterval(@RpcParam.Int interval: Int)
+  suspend fun setAutoWhoInterval(@RpcParam.Int interval: Int)
 
   @RpcCall("setAutoWhoNickLimit")
-  fun setAutoWhoNickLimit(@RpcParam.Int limit: Int)
+  suspend fun setAutoWhoNickLimit(@RpcParam.Int limit: Int)
 
   @RpcCall("setMaxPingCount")
-  fun setMaxPingCount(@RpcParam.Int count: Int)
+  suspend fun setMaxPingCount(@RpcParam.Int count: Int)
 
   @RpcCall("setPingInterval")
-  fun setPingInterval(@RpcParam.Int interval: Int)
+  suspend fun setPingInterval(@RpcParam.Int interval: Int)
 
   @RpcCall("setPingTimeoutEnabled")
-  fun setPingTimeoutEnabled(@RpcParam.Bool enabled: Boolean)
+  suspend fun setPingTimeoutEnabled(@RpcParam.Bool enabled: Boolean)
 
   @RpcCall("setStandardCtcp")
-  fun setStandardCtcp(@RpcParam.Bool enabled: Boolean)
+  suspend fun setStandardCtcp(@RpcParam.Bool enabled: Boolean)
 
   @RpcCall("update")
-  fun update(@RpcParam.QVariantMap properties: QVariantMap)
+  suspend fun update(@RpcParam.QVariantMap properties: QVariantMap)
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/RpcClientApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/RpcClientApi.kt
index 73b3461d2f8e16fabf5df52f5aa129ba799ce1e8..9c6b6d44cdbc4261b61b2e978e23dbc90197e417 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/RpcClientApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/client/RpcClientApi.kt
@@ -23,32 +23,32 @@ import java.nio.ByteBuffer
 @RpcApi(side = ProtocolSide.CORE)
 interface RpcClientApi {
   @RpcCall("__objectRenamed__")
-  fun objectRenamed(@RpcParam.QByteArray classname: ByteBuffer, @RpcParam.QString newName: String?, @RpcParam.QString oldName: String?)
+  suspend fun objectRenamed(@RpcParam.QByteArray classname: ByteBuffer, @RpcParam.QString newName: String?, @RpcParam.QString oldName: String?)
 
   @RpcCall("2displayMsg(Message)")
-  fun displayMsg(@RpcParam.UserType.Message message: Message)
+  suspend fun displayMsg(@RpcParam.UserType.Message message: Message)
 
   @RpcCall("2displayStatusMsg(QString,QString)")
-  fun displayStatusMsg(@RpcParam.QString net: String?, @RpcParam.QString msg: String?)
+  suspend fun displayStatusMsg(@RpcParam.QString net: String?, @RpcParam.QString msg: String?)
 
   @RpcCall("2bufferInfoUpdated(BufferInfo)")
-  fun bufferInfoUpdated(@RpcParam.UserType.BufferInfo bufferInfo: BufferInfo)
+  suspend fun bufferInfoUpdated(@RpcParam.UserType.BufferInfo bufferInfo: BufferInfo)
 
   @RpcCall("2identityCreated(Identity)")
-  fun identityCreated(@RpcParam.QVariantMap identity: QVariantMap)
+  suspend fun identityCreated(@RpcParam.QVariantMap identity: QVariantMap)
 
   @RpcCall("2identityRemoved(IdentityId)")
-  fun identityRemoved(@RpcParam.UserType.IdentityId identityId: IdentityId)
+  suspend fun identityRemoved(@RpcParam.UserType.IdentityId identityId: IdentityId)
 
   @RpcCall("2networkCreated(NetworkId)")
-  fun networkCreated(@RpcParam.UserType.NetworkId networkId: NetworkId)
+  suspend fun networkCreated(@RpcParam.UserType.NetworkId networkId: NetworkId)
 
   @RpcCall("2networkRemoved(NetworkId)")
-  fun networkRemoved(@RpcParam.UserType.NetworkId networkId: NetworkId)
+  suspend fun networkRemoved(@RpcParam.UserType.NetworkId networkId: NetworkId)
 
   @RpcCall("2passwordChanged(PeerPtr,bool)")
-  fun passwordChanged(@RpcParam.UserType.PeerPtr peer: ULong, @RpcParam.Bool success: Boolean)
+  suspend fun passwordChanged(@RpcParam.UserType.PeerPtr peer: ULong, @RpcParam.Bool success: Boolean)
 
   @RpcCall("2disconnectFromCore()")
-  fun disconnectFromCore()
+  suspend fun disconnectFromCore()
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/dispatcher/RpcDispatcher.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/dispatcher/RpcDispatcher.kt
index 4355ae17af6ecfb9ad2f20885f05ddda52c2b0b0..1b47c35041919363ffd9b91155fb94abc1323174 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/dispatcher/RpcDispatcher.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/dispatcher/RpcDispatcher.kt
@@ -14,5 +14,5 @@ import de.justjanne.libquassel.protocol.variant.QVariantList
 
 interface RpcDispatcher {
   @Throws(RpcInvocationFailedException::class)
-  fun invoke(method: String, params: QVariantList)
+  suspend fun invoke(method: String, params: QVariantList)
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/dispatcher/SyncDispatcher.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/dispatcher/SyncDispatcher.kt
index 9f20fa053dd754b84c62f9da5641f9d6b2cae0b8..269541f8319e6a0e7f4ba81dc4d327fc0c05cefa 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/dispatcher/SyncDispatcher.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/dispatcher/SyncDispatcher.kt
@@ -15,5 +15,5 @@ import de.justjanne.libquassel.protocol.variant.QVariantList
 
 interface SyncDispatcher {
   @Throws(RpcInvocationFailedException::class)
-  fun invoke(objectName: ObjectName, method: String, params: QVariantList)
+  suspend fun invoke(objectName: ObjectName, method: String, params: QVariantList)
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/dispatcher/SyncHandler.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/dispatcher/SyncHandler.kt
index 3e242eb3f656fa3ba4a608a15c7727520ecbaa53..d33fe37d48d5dd1bc61cf1f7b0c9f9c84e0de0f8 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/dispatcher/SyncHandler.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/dispatcher/SyncHandler.kt
@@ -18,7 +18,7 @@ class SyncHandler @Inject constructor(
   private val dispatchers: Map<String, @JvmSuppressWildcards SyncDispatcher>,
 ) {
   @Throws(RpcInvocationFailedException::class)
-  fun invoke(className: String, objectName: ObjectName, method: String, params: QVariantList) {
+  suspend fun invoke(className: String, objectName: ObjectName, method: String, params: QVariantList) {
     dispatchers[className]?.invoke(objectName, method, params)
       ?: throw RpcInvocationFailedException.InvokerNotFoundException(className)
   }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/dto/AliasManagerDto.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/dto/AliasManagerDto.kt
new file mode 100644
index 0000000000000000000000000000000000000000..1bc2087326410a0e3f1ed9bb6480f51b4a90559e
--- /dev/null
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/dto/AliasManagerDto.kt
@@ -0,0 +1,47 @@
+/*
+ * libquassel
+ * Copyright (c) 2025 Janne Mareike Koschinski
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.protocol.api.dto
+
+import de.justjanne.libquassel.protocol.models.QStringList
+import de.justjanne.libquassel.protocol.models.types.QtType
+import de.justjanne.libquassel.protocol.variant.QVariantMap
+import de.justjanne.libquassel.protocol.variant.into
+import de.justjanne.libquassel.protocol.variant.qVariant
+
+data class AliasManagerDto(
+  val aliases: AliasesDto
+) {
+  data class AliasesDto(
+    val names: List<String?>,
+    val expansions: List<String?>
+  ) {
+    fun serialize(): QVariantMap = mapOf(
+      "names" to qVariant(names, QtType.QStringList),
+      "expansions" to qVariant(expansions, QtType.QStringList)
+    )
+
+    companion object {
+      fun deserialize(data: QVariantMap) = AliasesDto(
+        names = data["names"].into<QStringList>().orEmpty(),
+        expansions = data["expansions"].into<QStringList>().orEmpty(),
+      )
+    }
+  }
+
+  fun serialize(): QVariantMap = mapOf(
+    "Aliases" to qVariant(aliases.serialize(), QtType.QVariantMap)
+  )
+
+  companion object {
+    fun deserialize(data: QVariantMap) = AliasManagerDto(
+      aliases = data["Aliases"].into<QVariantMap>().orEmpty().let(AliasesDto::deserialize)
+    )
+  }
+}
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/AliasManagerServerApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/AliasManagerServerApi.kt
index 5596794efda1226630202bca5ea1ec901e51e971..47c371021aca3133a039f39c791630cfeec98eef 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/AliasManagerServerApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/AliasManagerServerApi.kt
@@ -18,13 +18,13 @@ import de.justjanne.libquassel.protocol.variant.QVariantMap
 @RpcApi("AliasManager", side = ProtocolSide.CLIENT)
 interface AliasManagerServerApi {
   @RpcCall("addAlias")
-  fun addAlias(
+  suspend fun addAlias(
     @RpcParam.QString name: String,
     @RpcParam.QString expansion: String
   )
 
   @RpcCall("requestUpdate")
-  fun requestUpdate(
+  suspend fun requestUpdate(
     @RpcParam.QVariantMap properties: QVariantMap
   )
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/BacklogManagerServerApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/BacklogManagerServerApi.kt
index 64e406c223c31c668dfef2962155dd65a72b78e1..786db4502dc53a4e6273965d62eb80ed3be27c9c 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/BacklogManagerServerApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/BacklogManagerServerApi.kt
@@ -28,7 +28,7 @@ interface BacklogManagerServerApi {
    * [additional] messages will be loaded before [last].
    */
   @RpcCall("requestBacklog")
-  fun requestBacklog(
+  suspend fun requestBacklog(
     @RpcParam.UserType.BufferId bufferId: BufferId,
     @RpcParam.UserType.MsgId first: MsgId = MsgId(-1),
     @RpcParam.UserType.MsgId last: MsgId = MsgId(-1),
@@ -48,7 +48,7 @@ interface BacklogManagerServerApi {
    * Only messages matching [type] and [flags] will be returned and counted.
    */
   @RpcCall("requestBacklogFiltered")
-  fun requestBacklogFiltered(
+  suspend fun requestBacklogFiltered(
     @RpcParam.UserType.BufferId bufferId: BufferId,
     @RpcParam.UserType.MsgId first: MsgId = MsgId(-1),
     @RpcParam.UserType.MsgId last: MsgId = MsgId(-1),
@@ -67,7 +67,7 @@ interface BacklogManagerServerApi {
    * Only messages matching [type] and [flags] will be returned and counted.
    */
   @RpcCall("requestBacklogForward")
-  fun requestBacklogForward(
+  suspend fun requestBacklogForward(
     @RpcParam.UserType.BufferId bufferId: BufferId,
     @RpcParam.UserType.MsgId first: MsgId = MsgId(-1),
     @RpcParam.UserType.MsgId last: MsgId = MsgId(-1),
@@ -86,7 +86,7 @@ interface BacklogManagerServerApi {
    * [additional] messages will be loaded before [last].
    */
   @RpcCall("requestBacklogAll")
-  fun requestBacklogAll(
+  suspend fun requestBacklogAll(
     @RpcParam.UserType.MsgId first: MsgId = MsgId(-1),
     @RpcParam.UserType.MsgId last: MsgId = MsgId(-1),
     @RpcParam.Int limit: Int = -1,
@@ -105,7 +105,7 @@ interface BacklogManagerServerApi {
    * Only messages matching [type] and [flags] will be returned and counted.
    */
   @RpcCall("requestBacklogAllFiltered")
-  fun requestBacklogAllFiltered(
+  suspend fun requestBacklogAllFiltered(
     @RpcParam.UserType.MsgId first: MsgId = MsgId(-1),
     @RpcParam.UserType.MsgId last: MsgId = MsgId(-1),
     @RpcParam.Int limit: Int = -1,
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/BufferSyncerServerApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/BufferSyncerServerApi.kt
index 3bde5a7c64f8aaff4b8c9908553465ee0d1ead62..785f142b680cdcc5d50e236e4acf143f4707c7ae 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/BufferSyncerServerApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/BufferSyncerServerApi.kt
@@ -20,38 +20,38 @@ import de.justjanne.libquassel.protocol.variant.QVariantMap
 @RpcApi("BufferSyncer", side = ProtocolSide.CLIENT)
 interface BufferSyncerServerApi {
   @RpcCall("requestMarkBufferAsRead")
-  fun requestMarkBufferAsRead(@RpcParam.UserType.BufferId buffer: BufferId)
+  suspend fun requestMarkBufferAsRead(@RpcParam.UserType.BufferId buffer: BufferId)
 
   @RpcCall("requestMergeBuffersPermanently")
-  fun requestMergeBuffersPermanently(
+  suspend fun requestMergeBuffersPermanently(
     @RpcParam.UserType.BufferId buffer: BufferId,
     @RpcParam.UserType.BufferId buffer2: BufferId
   )
 
   @RpcCall("requestRemoveBuffer")
-  fun requestRemoveBuffer(@RpcParam.UserType.BufferId buffer: BufferId)
+  suspend fun requestRemoveBuffer(@RpcParam.UserType.BufferId buffer: BufferId)
 
   @RpcCall("requestRenameBuffer")
-  fun requestRenameBuffer(
+  suspend fun requestRenameBuffer(
     @RpcParam.UserType.BufferId buffer: BufferId,
     @RpcParam.QString newName: String
   )
 
   @RpcCall("requestSetLastSeenMsg")
-  fun requestSetLastSeenMsg(
+  suspend fun requestSetLastSeenMsg(
     @RpcParam.UserType.BufferId buffer: BufferId,
     @RpcParam.UserType.MsgId msgId: MsgId
   )
 
   @RpcCall("requestSetMarkerLine")
-  fun requestSetMarkerLine(
+  suspend fun requestSetMarkerLine(
     @RpcParam.UserType.BufferId buffer: BufferId,
     @RpcParam.UserType.MsgId msgId: MsgId
   )
 
   @RpcCall("requestPurgeBufferIds")
-  fun requestPurgeBufferIds()
+  suspend fun requestPurgeBufferIds()
 
   @RpcCall("requestUpdate")
-  fun requestUpdate(@RpcParam.QVariantMap properties: QVariantMap)
+  suspend fun requestUpdate(@RpcParam.QVariantMap properties: QVariantMap)
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/BufferViewConfigServerApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/BufferViewConfigServerApi.kt
index 17aa3d61c30edbea3b1213f937f2ecf4161a8e1b..b4e1805c9f5ead1c19c425ad3f85d149f9303278 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/BufferViewConfigServerApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/BufferViewConfigServerApi.kt
@@ -20,20 +20,20 @@ import de.justjanne.libquassel.protocol.variant.QVariantMap
 @RpcApi("BufferViewConfig", side = ProtocolSide.CLIENT)
 interface BufferViewConfigServerApi {
   @RpcCall("requestAddBuffer")
-  fun requestAddBuffer(objectName: ObjectName, @RpcParam.UserType.BufferId buffer: BufferId, @RpcParam.Int pos: Int)
+  suspend fun requestAddBuffer(objectName: ObjectName, @RpcParam.UserType.BufferId buffer: BufferId, @RpcParam.Int pos: Int)
 
   @RpcCall("requestMoveBuffer")
-  fun requestMoveBuffer(objectName: ObjectName, @RpcParam.UserType.BufferId buffer: BufferId, @RpcParam.Int pos: Int)
+  suspend fun requestMoveBuffer(objectName: ObjectName, @RpcParam.UserType.BufferId buffer: BufferId, @RpcParam.Int pos: Int)
 
   @RpcCall("requestRemoveBuffer")
-  fun requestHideBuffer(objectName: ObjectName, @RpcParam.UserType.BufferId buffer: BufferId)
+  suspend fun requestHideBuffer(objectName: ObjectName, @RpcParam.UserType.BufferId buffer: BufferId)
 
   @RpcCall("requestRemoveBufferPermanently")
-  fun requestRemoveBuffer(objectName: ObjectName, @RpcParam.UserType.BufferId buffer: BufferId)
+  suspend fun requestRemoveBuffer(objectName: ObjectName, @RpcParam.UserType.BufferId buffer: BufferId)
 
   @RpcCall("requestSetBufferViewName")
-  fun requestSetBufferViewName(objectName: ObjectName, @RpcParam.QString value: String)
+  suspend fun requestSetBufferViewName(objectName: ObjectName, @RpcParam.QString value: String)
 
   @RpcCall("requestUpdate")
-  fun requestUpdate(objectName: ObjectName, @RpcParam.QVariantMap properties: QVariantMap)
+  suspend fun requestUpdate(objectName: ObjectName, @RpcParam.QVariantMap properties: QVariantMap)
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/BufferViewManagerServerApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/BufferViewManagerServerApi.kt
index 21da360152818e8d6601fbf8196e6f9f7bde2313..6a2e77c132efbdbd51a1c2f96abb2282b7251451 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/BufferViewManagerServerApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/BufferViewManagerServerApi.kt
@@ -19,12 +19,12 @@ import de.justjanne.libquassel.protocol.variant.QVariantMap
 @RpcApi("BufferViewManager", side = ProtocolSide.CLIENT)
 interface BufferViewManagerServerApi {
   @RpcCall("requestCreateBufferView")
-  fun requestCreateBufferView(@RpcParam.QVariantMap properties: QVariantMap)
+  suspend fun requestCreateBufferView(@RpcParam.QVariantMap properties: QVariantMap)
 
   @RpcCall("requestCreateBufferViews")
-  fun requestCreateBufferViews(@RpcParam.QVariantList properties: QVariantList)
+  suspend fun requestCreateBufferViews(@RpcParam.QVariantList properties: QVariantList)
 
   @RpcCall("requestDeleteBufferView")
-  fun requestDeleteBufferView(@RpcParam.Int bufferViewConfigId: Int)
+  suspend fun requestDeleteBufferView(@RpcParam.Int bufferViewConfigId: Int)
 }
 
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/CertManagerServerApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/CertManagerServerApi.kt
index 9ad60c12774cb7f7adfb91d6f801a38929fcfa91..c8b86931875508d70857ec81bc1ae6eaf4000344 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/CertManagerServerApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/CertManagerServerApi.kt
@@ -19,5 +19,5 @@ import de.justjanne.libquassel.protocol.variant.QVariantMap
 @RpcApi("CertManager", side = ProtocolSide.CLIENT)
 interface CertManagerServerApi {
   @RpcCall("requestUpdate")
-  fun requestUpdate(objectName: ObjectName, @RpcParam.QVariantMap properties: QVariantMap)
+  suspend fun requestUpdate(objectName: ObjectName, @RpcParam.QVariantMap properties: QVariantMap)
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/HighlightRuleManagerServerApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/HighlightRuleManagerServerApi.kt
index 48ee75a0c79d8689847f65d8e1615f45bd2b243c..9751f27a344d67eda0482298f7cc3f5493e5340c 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/HighlightRuleManagerServerApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/HighlightRuleManagerServerApi.kt
@@ -17,13 +17,13 @@ import de.justjanne.libquassel.annotations.RpcParam
 @RpcApi("HighlightRuleManager", side = ProtocolSide.CLIENT)
 interface HighlightRuleManagerServerApi {
   @RpcCall("requestRemoveHighlightRule")
-  fun requestRemoveHighlightRule(@RpcParam.Int highlightRule: Int)
+  suspend fun requestRemoveHighlightRule(@RpcParam.Int highlightRule: Int)
 
   @RpcCall("requestToggleHighlightRule")
-  fun requestToggleHighlightRule(@RpcParam.Int highlightRule: Int)
+  suspend fun requestToggleHighlightRule(@RpcParam.Int highlightRule: Int)
 
   @RpcCall("requestAddHighlightRule")
-  fun requestAddHighlightRule(
+  suspend fun requestAddHighlightRule(
     @RpcParam.Int id: Int,
     @RpcParam.QString content: String?,
     @RpcParam.Bool isRegEx: Boolean,
@@ -36,8 +36,8 @@ interface HighlightRuleManagerServerApi {
 
   @RpcCall(
     "requestSetHighlightNick")
-  fun requestSetHighlightNick(@RpcParam.Int highlightNick: Int)
+  suspend fun requestSetHighlightNick(@RpcParam.Int highlightNick: Int)
 
   @RpcCall("requestSetNicksCaseSensitive")
-  fun requestSetNicksCaseSensitive(@RpcParam.Bool nicksCaseSensitive: Boolean)
+  suspend fun requestSetNicksCaseSensitive(@RpcParam.Bool nicksCaseSensitive: Boolean)
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/IdentityServerApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/IdentityServerApi.kt
index e3ba9a2d29f21938e7dd192dec16797453e58eb9..05fe4baf77dbb0f787bef997f49652d76356380b 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/IdentityServerApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/IdentityServerApi.kt
@@ -19,5 +19,5 @@ import de.justjanne.libquassel.protocol.variant.QVariantMap
 @RpcApi("Identity", side = ProtocolSide.CLIENT)
 interface IdentityServerApi {
   @RpcCall("requestUpdate")
-  fun requestUpdate(objectName: ObjectName, @RpcParam.QVariantMap properties: QVariantMap)
+  suspend fun requestUpdate(objectName: ObjectName, @RpcParam.QVariantMap properties: QVariantMap)
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/IgnoreListManagerServerApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/IgnoreListManagerServerApi.kt
index 30384d8310b9dab8af7bd089af52cffe09a9b701..ed5716512f72902d2cd990c13edfc70b8781d908 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/IgnoreListManagerServerApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/IgnoreListManagerServerApi.kt
@@ -17,7 +17,7 @@ import de.justjanne.libquassel.annotations.RpcParam
 @RpcApi("IgnoreListManager", side = ProtocolSide.CLIENT)
 interface IgnoreListManagerServerApi {
   @RpcCall("requestAddIgnoreListItem")
-  fun requestAddIgnoreListItem(
+  suspend fun requestAddIgnoreListItem(
     @RpcParam.Int type: Int,
     @RpcParam.QString ignoreRule: String?,
     @RpcParam.Bool isRegEx: Boolean,
@@ -28,8 +28,8 @@ interface IgnoreListManagerServerApi {
   )
 
   @RpcCall("requestRemoveIgnoreListItem")
-  fun requestRemoveIgnoreListItem(@RpcParam.QString ignoreRule: String?)
+  suspend fun requestRemoveIgnoreListItem(@RpcParam.QString ignoreRule: String?)
 
   @RpcCall("requestToggleIgnoreRule")
-  fun requestToggleIgnoreRule(@RpcParam.QString ignoreRule: String?)
+  suspend fun requestToggleIgnoreRule(@RpcParam.QString ignoreRule: String?)
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/IrcListHelperServerApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/IrcListHelperServerApi.kt
index 75d4bb467d0d03bf6ff935c3b19c2d298fb380be..2e2eff212a676c47c2490a1a6e2550882b6d1abd 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/IrcListHelperServerApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/IrcListHelperServerApi.kt
@@ -19,5 +19,5 @@ import de.justjanne.libquassel.protocol.models.ids.NetworkId
 @RpcApi("IrcListHelper", side = ProtocolSide.CLIENT)
 interface IrcListHelperServerApi {
   @RpcCall("requestChannelList")
-  fun requestChannelList(@RpcParam.UserType.NetworkId netId: NetworkId, @RpcParam.QStringList channelFilters: QStringList)
+  suspend fun requestChannelList(@RpcParam.UserType.NetworkId netId: NetworkId, @RpcParam.QStringList channelFilters: QStringList)
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/NetworkConfigServerApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/NetworkConfigServerApi.kt
index ecaa232085ddee538fe47b08e43b3297b555a78f..7e8e6e43f032710ee771a082687fea01c3517c7f 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/NetworkConfigServerApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/NetworkConfigServerApi.kt
@@ -17,26 +17,26 @@ import de.justjanne.libquassel.annotations.RpcParam
 @RpcApi("NetworkConfig", side = ProtocolSide.CLIENT)
 interface NetworkConfigServerApi {
   @RpcCall("requestSetAutoWhoDelay")
-  fun requestSetAutoWhoDelay(@RpcParam.Int delay: Int)
+  suspend fun requestSetAutoWhoDelay(@RpcParam.Int delay: Int)
 
   @RpcCall("requestSetAutoWhoEnabled")
-  fun requestSetAutoWhoEnabled(@RpcParam.Bool enabled: Boolean)
+  suspend fun requestSetAutoWhoEnabled(@RpcParam.Bool enabled: Boolean)
 
   @RpcCall("requestSetAutoWhoInterval")
-  fun requestSetAutoWhoInterval(@RpcParam.Int interval: Int)
+  suspend fun requestSetAutoWhoInterval(@RpcParam.Int interval: Int)
 
   @RpcCall("requestSetAutoWhoNickLimit")
-  fun requestSetAutoWhoNickLimit(@RpcParam.Int limit: Int)
+  suspend fun requestSetAutoWhoNickLimit(@RpcParam.Int limit: Int)
 
   @RpcCall("requestSetMaxPingCount")
-  fun requestSetMaxPingCount(@RpcParam.Int count: Int)
+  suspend fun requestSetMaxPingCount(@RpcParam.Int count: Int)
 
   @RpcCall("requestSetPingInterval")
-  fun requestSetPingInterval(@RpcParam.Int interval: Int)
+  suspend fun requestSetPingInterval(@RpcParam.Int interval: Int)
 
   @RpcCall("requestSetPingTimeoutEnabled")
-  fun requestSetPingTimeoutEnabled(@RpcParam.Bool enabled: Boolean)
+  suspend fun requestSetPingTimeoutEnabled(@RpcParam.Bool enabled: Boolean)
 
   @RpcCall("requestSetStandardCtcp")
-  fun requestSetStandardCtcp(@RpcParam.Bool enabled: Boolean)
+  suspend fun requestSetStandardCtcp(@RpcParam.Bool enabled: Boolean)
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/NetworkServerApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/NetworkServerApi.kt
index d7f8c42fd153e5057ea650bbdd466a2f10e2fe9a..14b73286cbf98bf19301a745d438f1b5bd2c6383 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/NetworkServerApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/NetworkServerApi.kt
@@ -19,11 +19,11 @@ import de.justjanne.libquassel.protocol.models.network.NetworkInfoDto
 @RpcApi("Network", side = ProtocolSide.CLIENT)
 interface NetworkServerApi {
   @RpcCall("requestConnect")
-  fun requestConnect(objectName: ObjectName)
+  suspend fun requestConnect(objectName: ObjectName)
 
   @RpcCall("requestDisconnect")
-  fun requestDisconnect(objectName: ObjectName)
+  suspend fun requestDisconnect(objectName: ObjectName)
 
   @RpcCall("requestSetNetworkInfo")
-  fun requestSetNetworkInfo(objectName: ObjectName, @RpcParam.UserType.NetworkInfo info: NetworkInfoDto)
+  suspend fun requestSetNetworkInfo(objectName: ObjectName, @RpcParam.UserType.NetworkInfo info: NetworkInfoDto)
 }
diff --git a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/RpcServerApi.kt b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/RpcServerApi.kt
index 4e64777630ed68d7dd5ced363e82e5379a9f590d..5dfae0da550320e4f0c5e641c5692bc20a70c7c4 100644
--- a/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/RpcServerApi.kt
+++ b/libquassel-api/src/main/kotlin/de/justjanne/libquassel/protocol/api/server/RpcServerApi.kt
@@ -23,23 +23,23 @@ import de.justjanne.libquassel.protocol.variant.QVariantMap
 @RpcApi(side = ProtocolSide.CLIENT)
 interface RpcServerApi {
   @RpcCall(name = "2createIdentity(Identity,QVariantMap)")
-  fun createIdentity(@RpcParam.UserType.Identity identity: IdentityDto, @RpcParam.QVariantMap additional: QVariantMap)
+  suspend fun createIdentity(@RpcParam.UserType.Identity identity: IdentityDto, @RpcParam.QVariantMap additional: QVariantMap)
 
   @RpcCall(name = "2removeIdentity(IdentityId)")
-  fun removeIdentity(@RpcParam.UserType.IdentityId identityId: IdentityId)
+  suspend fun removeIdentity(@RpcParam.UserType.IdentityId identityId: IdentityId)
 
   @RpcCall(name = "2createNetwork(NetworkInfo,QStringList)")
-  fun createNetwork(@RpcParam.UserType.NetworkInfo networkInfo: NetworkInfoDto, @RpcParam.QStringList channels: List<String>)
+  suspend fun createNetwork(@RpcParam.UserType.NetworkInfo networkInfo: NetworkInfoDto, @RpcParam.QStringList channels: List<String>)
 
   @RpcCall(name = "2removeNetwork(NetworkId)")
-  fun removeNetwork(@RpcParam.UserType.NetworkId networkId: NetworkId)
+  suspend fun removeNetwork(@RpcParam.UserType.NetworkId networkId: NetworkId)
 
   @RpcCall(name = "2changePassword(PeerPtr,QString,QString,QString)")
-  fun changePassword(@RpcParam.UserType.PeerPtr peerPtr: ULong, @RpcParam.QString user: String?, @RpcParam.QString old: String?, @RpcParam.QString new: String?)
+  suspend fun changePassword(@RpcParam.UserType.PeerPtr peerPtr: ULong, @RpcParam.QString user: String?, @RpcParam.QString old: String?, @RpcParam.QString new: String?)
 
   @RpcCall(name = "2kickClient(int)")
-  fun requestKickClient(@RpcParam.Int id: Int)
+  suspend fun requestKickClient(@RpcParam.Int id: Int)
 
   @RpcCall(name = "2sendInput(BufferInfo,QString)")
-  fun sendInput(@RpcParam.UserType.BufferInfo bufferInfo: BufferInfo, @RpcParam.QString message: String?)
+  suspend fun sendInput(@RpcParam.UserType.BufferInfo bufferInfo: BufferInfo, @RpcParam.QString message: String?)
 }
diff --git a/libquassel-client/build.gradle.kts b/libquassel-client/build.gradle.kts
index 6bf17dc5066b2c92b5d3dc7fa9e3aa669266ac86..57e714e3ae88c170860bbe99c65c57371687dac5 100644
--- a/libquassel-client/build.gradle.kts
+++ b/libquassel-client/build.gradle.kts
@@ -12,10 +12,21 @@ plugins {
   id("justjanne.publication")
 }
 
+repositories {
+  google()
+  mavenCentral()
+}
+
 dependencies {
-  api(project(":libquassel-protocol"))
   api(project(":libquassel-api"))
-  implementation(libs.slf4j)
+  api(project(":libquassel-persistence"))
+  api(project(":libquassel-protocol"))
+
   implementation(libs.dagger.core)
   ksp(libs.dagger.compiler)
+
+  implementation(libs.slf4j)
+
+  testImplementation(libs.room.runtime)
+  testImplementation(libs.sqlite)
 }
diff --git a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/AliasManagerPersister.kt b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/AliasManagerPersister.kt
index 603edc1d2166f76b7b113076ef173db6002cf7e1..56e55a5114e75aa5892fae64a8ae4503b146a9a0 100644
--- a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/AliasManagerPersister.kt
+++ b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/AliasManagerPersister.kt
@@ -9,10 +9,28 @@
 
 package de.justjanne.libquassel.backend
 
+import de.justjanne.libquassel.persistence.AliasEntity
+import de.justjanne.libquassel.persistence.AliasRepository
 import de.justjanne.libquassel.protocol.api.client.AliasManagerClientApi
+import de.justjanne.libquassel.protocol.api.dto.AliasManagerDto
 import de.justjanne.libquassel.protocol.variant.QVariantMap
 import javax.inject.Inject
 
-class AliasManagerPersister @Inject constructor() : AliasManagerClientApi {
-  override fun update(properties: QVariantMap)  = Unit
+class AliasManagerPersister @Inject constructor(
+  private val repository: AliasRepository,
+) : AliasManagerClientApi {
+  override suspend fun update(properties: QVariantMap) {
+    val data = AliasManagerDto.deserialize(properties)
+    val names = data.aliases.names.requireNoNulls()
+    val expansions = data.aliases.expansions.requireNoNulls()
+    require(names.size == expansions.size) {
+      "Sizes do not match: names=${names.size}, expansions=${expansions.size}"
+    }
+
+    val aliases = names.zip(expansions).mapIndexed { index, (name, expansion) ->
+      AliasEntity(index, name, expansion)
+    }
+
+    repository.sync(aliases)
+  }
 }
diff --git a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/BacklogManagerPersister.kt b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/BacklogManagerPersister.kt
index fbe4314f531eab7dfe8882765b894eedd1f46198..ce3001a058c6bef2f266d2395aea42bb4e229df6 100644
--- a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/BacklogManagerPersister.kt
+++ b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/BacklogManagerPersister.kt
@@ -9,16 +9,24 @@
 
 package de.justjanne.libquassel.backend
 
+import de.justjanne.libquassel.persistence.MessageEntity
+import de.justjanne.libquassel.persistence.MessageRepository
 import de.justjanne.libquassel.protocol.api.client.BacklogManagerClientApi
+import de.justjanne.libquassel.protocol.models.Message
 import de.justjanne.libquassel.protocol.models.ids.BufferId
 import de.justjanne.libquassel.protocol.models.ids.MsgId
 import de.justjanne.libquassel.protocol.variant.QVariantList
+import de.justjanne.libquassel.protocol.variant.into
 import javax.inject.Inject
 
-class BacklogManagerPersister @Inject constructor() : BacklogManagerClientApi {
-  override fun receiveBacklog(bufferId: BufferId, first: MsgId, last: MsgId, limit: Int, additional: Int, messages: QVariantList)  = Unit
-  override fun receiveBacklogFiltered(bufferId: BufferId, first: MsgId, last: MsgId, limit: Int, additional: Int, type: Int, flags: Int, messages: QVariantList)  = Unit
-  override fun receiveBacklogForward(bufferId: BufferId, first: MsgId, last: MsgId, limit: Int, type: Int, flags: Int, messages: QVariantList)  = Unit
-  override fun receiveBacklogAll(first: MsgId, last: MsgId, limit: Int, additional: Int, messages: QVariantList)  = Unit
-  override fun receiveBacklogAllFiltered(first: MsgId, last: MsgId, limit: Int, additional: Int, type: Int, flags: Int, messages: QVariantList)  = Unit
+class BacklogManagerPersister @Inject constructor(
+  private val repository: MessageRepository,
+) : BacklogManagerClientApi {
+  override suspend fun receiveBacklog(bufferId: BufferId, first: MsgId, last: MsgId, limit: Int, additional: Int, messages: QVariantList) {
+    repository.sync(bufferId, messages.mapNotNull { it.into<Message>() }.map(MessageEntity.Companion::fromDto))
+  }
+  override suspend fun receiveBacklogFiltered(bufferId: BufferId, first: MsgId, last: MsgId, limit: Int, additional: Int, type: Int, flags: Int, messages: QVariantList)  = Unit
+  override suspend fun receiveBacklogForward(bufferId: BufferId, first: MsgId, last: MsgId, limit: Int, type: Int, flags: Int, messages: QVariantList)  = Unit
+  override suspend fun receiveBacklogAll(first: MsgId, last: MsgId, limit: Int, additional: Int, messages: QVariantList)  = Unit
+  override suspend fun receiveBacklogAllFiltered(first: MsgId, last: MsgId, limit: Int, additional: Int, type: Int, flags: Int, messages: QVariantList)  = Unit
 }
diff --git a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/BufferSyncerPersister.kt b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/BufferSyncerPersister.kt
index 4e46bb5c779a581cdff1e65f2d8e6f914888f7e1..c28b7f8f6b575b9190a0a900478d9da7f0a899a5 100644
--- a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/BufferSyncerPersister.kt
+++ b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/BufferSyncerPersister.kt
@@ -16,13 +16,13 @@ import de.justjanne.libquassel.protocol.variant.QVariantMap
 import javax.inject.Inject
 
 class BufferSyncerPersister @Inject constructor() : BufferSyncerClientApi {
-  override fun markBufferAsRead(buffer: BufferId)  = Unit
-  override fun mergeBuffersPermanently(buffer: BufferId, buffer2: BufferId)  = Unit
-  override fun removeBuffer(buffer: BufferId)  = Unit
-  override fun renameBuffer(buffer: BufferId, newName: String)  = Unit
-  override fun setMarkerLine(buffer: BufferId, msgId: MsgId)  = Unit
-  override fun setLastSeenMsg(buffer: BufferId, msgId: MsgId)  = Unit
-  override fun setBufferActivity(buffer: BufferId, types: Int)  = Unit
-  override fun setHighlightCount(buffer: BufferId, count: Int)  = Unit
-  override fun update(properties: QVariantMap)  = Unit
+  override suspend fun markBufferAsRead(buffer: BufferId)  = Unit
+  override suspend fun mergeBuffersPermanently(buffer: BufferId, buffer2: BufferId)  = Unit
+  override suspend fun removeBuffer(buffer: BufferId)  = Unit
+  override suspend fun renameBuffer(buffer: BufferId, newName: String)  = Unit
+  override suspend fun setMarkerLine(buffer: BufferId, msgId: MsgId)  = Unit
+  override suspend fun setLastSeenMsg(buffer: BufferId, msgId: MsgId)  = Unit
+  override suspend fun setBufferActivity(buffer: BufferId, types: Int)  = Unit
+  override suspend fun setHighlightCount(buffer: BufferId, count: Int)  = Unit
+  override suspend fun update(properties: QVariantMap)  = Unit
 }
diff --git a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/BufferViewConfigPersister.kt b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/BufferViewConfigPersister.kt
index c8184f95b1885045eaba3fb5e718c432ae2454b3..d237e96b25e5a9f6a5fa482822ef9e0ed6d96396 100644
--- a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/BufferViewConfigPersister.kt
+++ b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/BufferViewConfigPersister.kt
@@ -16,19 +16,19 @@ import de.justjanne.libquassel.protocol.variant.QVariantMap
 import javax.inject.Inject
 
 class BufferViewConfigPersister @Inject constructor(): BufferViewConfigClientApi {
-  override fun addBuffer(buffer: BufferId, pos: Int)  = Unit
-  override fun moveBuffer(buffer: BufferId, pos: Int)  = Unit
-  override fun removeBuffer(buffer: BufferId)  = Unit
-  override fun removeBufferPermanently(buffer: BufferId)  = Unit
-  override fun setBufferViewName(value: String)  = Unit
-  override fun setAddNewBuffersAutomatically(value: Boolean)  = Unit
-  override fun setAllowedBufferTypes(value: Int)  = Unit
-  override fun setDisableDecoration(value: Boolean)  = Unit
-  override fun setHideInactiveBuffers(value: Boolean)  = Unit
-  override fun setHideInactiveNetworks(value: Boolean)  = Unit
-  override fun setMinimumActivity(value: Int)  = Unit
-  override fun setNetworkId(value: NetworkId)  = Unit
-  override fun setShowSearch(value: Boolean)  = Unit
-  override fun setSortAlphabetically(value: Boolean)  = Unit
-  override fun update(properties: QVariantMap)  = Unit
+  override suspend fun addBuffer(buffer: BufferId, pos: Int)  = Unit
+  override suspend fun moveBuffer(buffer: BufferId, pos: Int)  = Unit
+  override suspend fun removeBuffer(buffer: BufferId)  = Unit
+  override suspend fun removeBufferPermanently(buffer: BufferId)  = Unit
+  override suspend fun setBufferViewName(value: String)  = Unit
+  override suspend fun setAddNewBuffersAutomatically(value: Boolean)  = Unit
+  override suspend fun setAllowedBufferTypes(value: Int)  = Unit
+  override suspend fun setDisableDecoration(value: Boolean)  = Unit
+  override suspend fun setHideInactiveBuffers(value: Boolean)  = Unit
+  override suspend fun setHideInactiveNetworks(value: Boolean)  = Unit
+  override suspend fun setMinimumActivity(value: Int)  = Unit
+  override suspend fun setNetworkId(value: NetworkId)  = Unit
+  override suspend fun setShowSearch(value: Boolean)  = Unit
+  override suspend fun setSortAlphabetically(value: Boolean)  = Unit
+  override suspend fun update(properties: QVariantMap)  = Unit
 }
diff --git a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/BufferViewManagerPersister.kt b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/BufferViewManagerPersister.kt
index f826a156261c0200fab0284a99d33a1b5ef8ba70..4d627c49dead708e3ca46e6948e5f19ea701d8b0 100644
--- a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/BufferViewManagerPersister.kt
+++ b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/BufferViewManagerPersister.kt
@@ -14,7 +14,7 @@ import de.justjanne.libquassel.protocol.variant.QVariantMap
 import javax.inject.Inject
 
 class BufferViewManagerPersister @Inject constructor(): BufferViewManagerClientApi {
-  override fun addBufferViewConfig(bufferViewConfigId: Int)  = Unit 
-  override fun deleteBufferViewConfig(bufferViewConfigId: Int)  = Unit 
-  override fun update(properties: QVariantMap)  = Unit
+  override suspend fun addBufferViewConfig(bufferViewConfigId: Int)  = Unit 
+  override suspend fun deleteBufferViewConfig(bufferViewConfigId: Int)  = Unit 
+  override suspend fun update(properties: QVariantMap)  = Unit
 }
diff --git a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/CertManagerPersister.kt b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/CertManagerPersister.kt
index d34fcec65e1956a93c61cf721b63f052da95d9b2..c9082e6ec3bac52cc07c2209b142784dec4111ce 100644
--- a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/CertManagerPersister.kt
+++ b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/CertManagerPersister.kt
@@ -16,7 +16,7 @@ import java.nio.ByteBuffer
 import javax.inject.Inject
 
 class CertManagerPersister @Inject constructor(): CertManagerClientApi {
-  override fun setSslCert(objectName: ObjectName, encoded: ByteBuffer)  = Unit 
-  override fun setSslKey(objectName: ObjectName, encoded: ByteBuffer)  = Unit 
-  override fun update(objectName: ObjectName, properties: QVariantMap)  = Unit
+  override suspend fun setSslCert(objectName: ObjectName, encoded: ByteBuffer)  = Unit 
+  override suspend fun setSslKey(objectName: ObjectName, encoded: ByteBuffer)  = Unit 
+  override suspend fun update(objectName: ObjectName, properties: QVariantMap)  = Unit
 }
diff --git a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/CoreInfoPersister.kt b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/CoreInfoPersister.kt
index d71103848e1b6d1d60969b09b4b6bb729db42707..461393b27d57a5615c329d20f4dd285e9108a5da 100644
--- a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/CoreInfoPersister.kt
+++ b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/CoreInfoPersister.kt
@@ -14,6 +14,6 @@ import de.justjanne.libquassel.protocol.variant.QVariantMap
 import javax.inject.Inject
 
 class CoreInfoPersister @Inject constructor(): CoreInfoClientApi {
-  override fun setCoreData(data: QVariantMap)  = Unit 
-  override fun update(properties: QVariantMap)  = Unit
+  override suspend fun setCoreData(data: QVariantMap)  = Unit 
+  override suspend fun update(properties: QVariantMap)  = Unit
 }
diff --git a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/HighlightRuleManagerPersister.kt b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/HighlightRuleManagerPersister.kt
index 620f871f5e54411db95c697ccf25a178c2d1abe5..7fd5c0cb730d4460c51a4a9ef5b03300791c1dfe 100644
--- a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/HighlightRuleManagerPersister.kt
+++ b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/HighlightRuleManagerPersister.kt
@@ -14,10 +14,10 @@ import de.justjanne.libquassel.protocol.variant.QVariantMap
 import javax.inject.Inject
 
 class HighlightRuleManagerPersister @Inject constructor(): HighlightRuleManagerClientApi {
-  override fun removeHighlightRule(highlightRule: Int)  = Unit 
-  override fun toggleHighlightRule(highlightRule: Int)  = Unit 
-  override fun addHighlightRule(id: Int, content: String?, isRegEx: Boolean, isCaseSensitive: Boolean, isEnabled: Boolean, isInverse: Boolean, sender: String?, channel: String?)  = Unit
-  override fun setHighlightNick(highlightNick: Int)  = Unit 
-  override fun setNicksCaseSensitive(nicksCaseSensitive: Boolean)  = Unit 
-  override fun update(properties: QVariantMap)  = Unit
+  override suspend fun removeHighlightRule(highlightRule: Int)  = Unit 
+  override suspend fun toggleHighlightRule(highlightRule: Int)  = Unit 
+  override suspend fun addHighlightRule(id: Int, content: String?, isRegEx: Boolean, isCaseSensitive: Boolean, isEnabled: Boolean, isInverse: Boolean, sender: String?, channel: String?)  = Unit
+  override suspend fun setHighlightNick(highlightNick: Int)  = Unit 
+  override suspend fun setNicksCaseSensitive(nicksCaseSensitive: Boolean)  = Unit 
+  override suspend fun update(properties: QVariantMap)  = Unit
 }
diff --git a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/IdentityPersister.kt b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/IdentityPersister.kt
index 92a96b86847a41bf7eca50dc4ca2925259e63017..444020452cafead8cca92cbdba190fb87d46034d 100644
--- a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/IdentityPersister.kt
+++ b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/IdentityPersister.kt
@@ -17,24 +17,24 @@ import de.justjanne.libquassel.protocol.variant.QVariantMap
 import javax.inject.Inject
 
 class IdentityPersister @Inject constructor(): IdentityClientApi {
-  override fun setAutoAwayEnabled(objectName: ObjectName, enabled: Boolean)  = Unit 
-  override fun setAutoAwayReason(objectName: ObjectName, reason: String?)  = Unit 
-  override fun setAutoAwayReasonEnabled(objectName: ObjectName, enabled: Boolean)  = Unit 
-  override fun setAutoAwayTime(objectName: ObjectName, time: Int)  = Unit 
-  override fun setAwayNick(objectName: ObjectName, awayNick: String?)  = Unit 
-  override fun setAwayNickEnabled(objectName: ObjectName, enabled: Boolean)  = Unit 
-  override fun setAwayReason(objectName: ObjectName, awayReason: String?)  = Unit 
-  override fun setAwayReasonEnabled(objectName: ObjectName, enabled: Boolean)  = Unit 
-  override fun setDetachAwayEnabled(objectName: ObjectName, enabled: Boolean)  = Unit 
-  override fun setDetachAwayReason(objectName: ObjectName, reason: String?)  = Unit 
-  override fun setDetachAwayReasonEnabled(objectName: ObjectName, enabled: Boolean)  = Unit 
-  override fun setId(objectName: ObjectName, id: IdentityId)  = Unit 
-  override fun setIdent(objectName: ObjectName, ident: String?)  = Unit 
-  override fun setIdentityName(objectName: ObjectName, name: String?)  = Unit 
-  override fun setKickReason(objectName: ObjectName, reason: String?)  = Unit 
-  override fun setNicks(objectName: ObjectName, nicks: QStringList)  = Unit 
-  override fun setPartReason(objectName: ObjectName, reason: String?)  = Unit 
-  override fun setQuitReason(objectName: ObjectName, reason: String?)  = Unit 
-  override fun setRealName(objectName: ObjectName, realName: String?)  = Unit 
-  override fun update(objectName: ObjectName, properties: QVariantMap)  = Unit
+  override suspend fun setAutoAwayEnabled(objectName: ObjectName, enabled: Boolean)  = Unit 
+  override suspend fun setAutoAwayReason(objectName: ObjectName, reason: String?)  = Unit 
+  override suspend fun setAutoAwayReasonEnabled(objectName: ObjectName, enabled: Boolean)  = Unit 
+  override suspend fun setAutoAwayTime(objectName: ObjectName, time: Int)  = Unit 
+  override suspend fun setAwayNick(objectName: ObjectName, awayNick: String?)  = Unit 
+  override suspend fun setAwayNickEnabled(objectName: ObjectName, enabled: Boolean)  = Unit 
+  override suspend fun setAwayReason(objectName: ObjectName, awayReason: String?)  = Unit 
+  override suspend fun setAwayReasonEnabled(objectName: ObjectName, enabled: Boolean)  = Unit 
+  override suspend fun setDetachAwayEnabled(objectName: ObjectName, enabled: Boolean)  = Unit 
+  override suspend fun setDetachAwayReason(objectName: ObjectName, reason: String?)  = Unit 
+  override suspend fun setDetachAwayReasonEnabled(objectName: ObjectName, enabled: Boolean)  = Unit 
+  override suspend fun setId(objectName: ObjectName, id: IdentityId)  = Unit 
+  override suspend fun setIdent(objectName: ObjectName, ident: String?)  = Unit 
+  override suspend fun setIdentityName(objectName: ObjectName, name: String?)  = Unit 
+  override suspend fun setKickReason(objectName: ObjectName, reason: String?)  = Unit 
+  override suspend fun setNicks(objectName: ObjectName, nicks: QStringList)  = Unit 
+  override suspend fun setPartReason(objectName: ObjectName, reason: String?)  = Unit 
+  override suspend fun setQuitReason(objectName: ObjectName, reason: String?)  = Unit 
+  override suspend fun setRealName(objectName: ObjectName, realName: String?)  = Unit 
+  override suspend fun update(objectName: ObjectName, properties: QVariantMap)  = Unit
 }
diff --git a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/IgnoreListManagerPersister.kt b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/IgnoreListManagerPersister.kt
index 2de3d4ad46738e84e93226a4599fabf14ffec319..a05757977048c4081f9969ca5bfd4c63ebaa925c 100644
--- a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/IgnoreListManagerPersister.kt
+++ b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/IgnoreListManagerPersister.kt
@@ -14,8 +14,8 @@ import de.justjanne.libquassel.protocol.variant.QVariantMap
 import javax.inject.Inject
 
 class IgnoreListManagerPersister @Inject constructor(): IgnoreListManagerClientApi {
-  override fun addIgnoreListItem(type: Int, ignoreRule: String?, isRegEx: Boolean, strictness: Int, scope: Int, scopeRule: String?, isActive: Boolean)  = Unit
-  override fun removeIgnoreListItem(ignoreRule: String?)  = Unit 
-  override fun toggleIgnoreRule(ignoreRule: String?)  = Unit 
-  override fun update(properties: QVariantMap)  = Unit
+  override suspend fun addIgnoreListItem(type: Int, ignoreRule: String?, isRegEx: Boolean, strictness: Int, scope: Int, scopeRule: String?, isActive: Boolean)  = Unit
+  override suspend fun removeIgnoreListItem(ignoreRule: String?)  = Unit 
+  override suspend fun toggleIgnoreRule(ignoreRule: String?)  = Unit 
+  override suspend fun update(properties: QVariantMap)  = Unit
 }
diff --git a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/IrcChannelPersister.kt b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/IrcChannelPersister.kt
index 91bc7267134949ab31600e066c69ad0642d61ac9..a3d750404c0d4206311312589b1120bf46f2a1d3 100644
--- a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/IrcChannelPersister.kt
+++ b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/IrcChannelPersister.kt
@@ -16,15 +16,15 @@ import de.justjanne.libquassel.protocol.variant.QVariantMap
 import javax.inject.Inject
 
 class  IrcChannelPersister @Inject constructor(): IrcChannelClientApi {
-  override fun addChannelMode(objectName: ObjectName, mode: Char, value: String?)  = Unit 
-  override fun addUserMode(objectName: ObjectName, nick: String, mode: String?)  = Unit 
-  override fun joinIrcUsers(objectName: ObjectName, nicks: QStringList, modes: QStringList)  = Unit 
-  override fun part(objectName: ObjectName, nick: String)  = Unit 
-  override fun removeChannelMode(objectName: ObjectName, mode: Char, value: String?)  = Unit 
-  override fun removeUserMode(objectName: ObjectName, nick: String, mode: String?)  = Unit 
-  override fun setEncrypted(objectName: ObjectName, encrypted: Boolean)  = Unit 
-  override fun setPassword(objectName: ObjectName, password: String)  = Unit 
-  override fun setTopic(objectName: ObjectName, topic: String)  = Unit 
-  override fun setUserModes(objectName: ObjectName, nick: String, modes: String?)  = Unit 
-  override fun update(objectName: ObjectName, properties: QVariantMap)  = Unit
+  override suspend fun addChannelMode(objectName: ObjectName, mode: Char, value: String?)  = Unit 
+  override suspend fun addUserMode(objectName: ObjectName, nick: String, mode: String?)  = Unit 
+  override suspend fun joinIrcUsers(objectName: ObjectName, nicks: QStringList, modes: QStringList)  = Unit 
+  override suspend fun part(objectName: ObjectName, nick: String)  = Unit 
+  override suspend fun removeChannelMode(objectName: ObjectName, mode: Char, value: String?)  = Unit 
+  override suspend fun removeUserMode(objectName: ObjectName, nick: String, mode: String?)  = Unit 
+  override suspend fun setEncrypted(objectName: ObjectName, encrypted: Boolean)  = Unit 
+  override suspend fun setPassword(objectName: ObjectName, password: String)  = Unit 
+  override suspend fun setTopic(objectName: ObjectName, topic: String)  = Unit 
+  override suspend fun setUserModes(objectName: ObjectName, nick: String, modes: String?)  = Unit 
+  override suspend fun update(objectName: ObjectName, properties: QVariantMap)  = Unit
 }
diff --git a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/IrcListHelperPersister.kt b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/IrcListHelperPersister.kt
index 16d1243ab4c62985d3e98fcff6f7f513d596d443..0484ff3f456c4fef661f210dd8ee60c10fb4bc69 100644
--- a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/IrcListHelperPersister.kt
+++ b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/IrcListHelperPersister.kt
@@ -16,7 +16,7 @@ import de.justjanne.libquassel.protocol.variant.QVariantList
 import javax.inject.Inject
 
 class IrcListHelperPersister @Inject constructor(): IrcListHelperClientApi {
-  override fun receiveChannelList(netId: NetworkId, channelFilters: QStringList, channels: QVariantList)  = Unit 
-  override fun reportError(error: String?)  = Unit 
-  override fun reportFinishedList(netId: NetworkId)  = Unit
+  override suspend fun receiveChannelList(netId: NetworkId, channelFilters: QStringList, channels: QVariantList)  = Unit 
+  override suspend fun reportError(error: String?)  = Unit 
+  override suspend fun reportFinishedList(netId: NetworkId)  = Unit
 }
diff --git a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/IrcUserPersister.kt b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/IrcUserPersister.kt
index 0ecdaa5117db4fabd581d6b628631b0fac1ad8ac..d546757c85bca3d837af869ab11b6f4e795308ce 100644
--- a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/IrcUserPersister.kt
+++ b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/IrcUserPersister.kt
@@ -16,28 +16,28 @@ import org.threeten.bp.temporal.Temporal
 import javax.inject.Inject
 
 class IrcUserPersister @Inject constructor(): IrcUserClientApi {
-  override fun addUserModes(objectName: ObjectName, modes: String)  = Unit 
-  override fun joinChannel(objectName: ObjectName, channelname: String)  = Unit 
-  override fun partChannel(objectName: ObjectName, channelname: String)  = Unit 
-  override fun quit(objectName: ObjectName)  = Unit 
-  override fun removeUserModes(objectName: ObjectName, modes: String)  = Unit 
-  override fun setAccount(objectName: ObjectName, account: String)  = Unit 
-  override fun setAway(objectName: ObjectName, away: Boolean)  = Unit 
-  override fun setAwayMessage(objectName: ObjectName, awayMessage: String)  = Unit 
-  override fun setEncrypted(objectName: ObjectName, encrypted: Boolean)  = Unit 
-  override fun setHost(objectName: ObjectName, host: String)  = Unit 
-  override fun setIdleTime(objectName: ObjectName, idleTime: Temporal)  = Unit 
-  override fun setIrcOperator(objectName: ObjectName, ircOperator: String)  = Unit 
-  override fun setLastAwayMessage(objectName: ObjectName, lastAwayMessage: Int)  = Unit 
-  override fun setLastAwayMessageTime(objectName: ObjectName, lastAwayMessageTime: Temporal)  = Unit 
-  override fun setLoginTime(objectName: ObjectName, loginTime: Temporal)  = Unit 
-  override fun setNick(objectName: ObjectName, newNick: String)  = Unit 
-  override fun setRealName(objectName: ObjectName, realName: String)  = Unit 
-  override fun setServer(objectName: ObjectName, server: String)  = Unit 
-  override fun setSuserHost(objectName: ObjectName, suserHost: String)  = Unit 
-  override fun setUser(objectName: ObjectName, user: String)  = Unit 
-  override fun setUserModes(objectName: ObjectName, modes: String)  = Unit 
-  override fun setWhoisServiceReply(objectName: ObjectName, whoisServiceReply: String)  = Unit 
-  override fun updateHostmask(objectName: ObjectName, mask: String)  = Unit 
-  override fun update(objectName: ObjectName, properties: QVariantMap)  = Unit
+  override suspend fun addUserModes(objectName: ObjectName, modes: String)  = Unit 
+  override suspend fun joinChannel(objectName: ObjectName, channelname: String)  = Unit 
+  override suspend fun partChannel(objectName: ObjectName, channelname: String)  = Unit 
+  override suspend fun quit(objectName: ObjectName)  = Unit 
+  override suspend fun removeUserModes(objectName: ObjectName, modes: String)  = Unit 
+  override suspend fun setAccount(objectName: ObjectName, account: String)  = Unit 
+  override suspend fun setAway(objectName: ObjectName, away: Boolean)  = Unit 
+  override suspend fun setAwayMessage(objectName: ObjectName, awayMessage: String)  = Unit 
+  override suspend fun setEncrypted(objectName: ObjectName, encrypted: Boolean)  = Unit 
+  override suspend fun setHost(objectName: ObjectName, host: String)  = Unit 
+  override suspend fun setIdleTime(objectName: ObjectName, idleTime: Temporal)  = Unit 
+  override suspend fun setIrcOperator(objectName: ObjectName, ircOperator: String)  = Unit 
+  override suspend fun setLastAwayMessage(objectName: ObjectName, lastAwayMessage: Int)  = Unit 
+  override suspend fun setLastAwayMessageTime(objectName: ObjectName, lastAwayMessageTime: Temporal)  = Unit 
+  override suspend fun setLoginTime(objectName: ObjectName, loginTime: Temporal)  = Unit 
+  override suspend fun setNick(objectName: ObjectName, newNick: String)  = Unit 
+  override suspend fun setRealName(objectName: ObjectName, realName: String)  = Unit 
+  override suspend fun setServer(objectName: ObjectName, server: String)  = Unit 
+  override suspend fun setSuserHost(objectName: ObjectName, suserHost: String)  = Unit 
+  override suspend fun setUser(objectName: ObjectName, user: String)  = Unit 
+  override suspend fun setUserModes(objectName: ObjectName, modes: String)  = Unit 
+  override suspend fun setWhoisServiceReply(objectName: ObjectName, whoisServiceReply: String)  = Unit 
+  override suspend fun updateHostmask(objectName: ObjectName, mask: String)  = Unit 
+  override suspend fun update(objectName: ObjectName, properties: QVariantMap)  = Unit
 }
diff --git a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/NetworkConfigPersister.kt b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/NetworkConfigPersister.kt
index 255d916207bc6fdb3e8e0720b03a537abd0a095a..088ea7b7be62b08fb5733434e6da5903b2ef5f18 100644
--- a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/NetworkConfigPersister.kt
+++ b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/NetworkConfigPersister.kt
@@ -14,13 +14,13 @@ import de.justjanne.libquassel.protocol.variant.QVariantMap
 import javax.inject.Inject
 
 class NetworkConfigPersister @Inject constructor(): NetworkConfigClientApi {
-  override fun setAutoWhoDelay(delay: Int)  = Unit 
-  override fun setAutoWhoEnabled(enabled: Boolean)  = Unit 
-  override fun setAutoWhoInterval(interval: Int)  = Unit 
-  override fun setAutoWhoNickLimit(limit: Int)  = Unit 
-  override fun setMaxPingCount(count: Int)  = Unit 
-  override fun setPingInterval(interval: Int)  = Unit 
-  override fun setPingTimeoutEnabled(enabled: Boolean)  = Unit 
-  override fun setStandardCtcp(enabled: Boolean)  = Unit 
-  override fun update(properties: QVariantMap)  = Unit
+  override suspend fun setAutoWhoDelay(delay: Int)  = Unit 
+  override suspend fun setAutoWhoEnabled(enabled: Boolean)  = Unit 
+  override suspend fun setAutoWhoInterval(interval: Int)  = Unit 
+  override suspend fun setAutoWhoNickLimit(limit: Int)  = Unit 
+  override suspend fun setMaxPingCount(count: Int)  = Unit 
+  override suspend fun setPingInterval(interval: Int)  = Unit 
+  override suspend fun setPingTimeoutEnabled(enabled: Boolean)  = Unit 
+  override suspend fun setStandardCtcp(enabled: Boolean)  = Unit 
+  override suspend fun update(properties: QVariantMap)  = Unit
 }
diff --git a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/NetworkPersister.kt b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/NetworkPersister.kt
index d51be71e5de3d5554dfb58b024ceb97d52558198..580b61ee435f04f622c5e66dbb0be42df5ce2fc4 100644
--- a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/NetworkPersister.kt
+++ b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/NetworkPersister.kt
@@ -19,42 +19,42 @@ import java.nio.ByteBuffer
 import javax.inject.Inject
 
 class NetworkPersister @Inject constructor(): NetworkClientApi {
-  override fun setNetworkName(objectName: ObjectName, networkName: String)  = Unit 
-  override fun setCurrentServer(objectName: ObjectName, currentServer: String?)  = Unit 
-  override fun setMyNick(objectName: ObjectName, myNick: String?)  = Unit 
-  override fun setLatency(objectName: ObjectName, latency: Int)  = Unit 
-  override fun setCodecForServer(objectName: ObjectName, codecForServer: ByteBuffer)  = Unit 
-  override fun setCodecForEncoding(objectName: ObjectName, codecForEncoding: ByteBuffer)  = Unit 
-  override fun setCodecForDecoding(objectName: ObjectName, codecForDecoding: ByteBuffer)  = Unit 
-  override fun setIdentity(objectName: ObjectName, identityId: IdentityId)  = Unit 
-  override fun setConnected(objectName: ObjectName, isConnected: Boolean)  = Unit 
-  override fun setConnectionState(objectName: ObjectName, connectionState: Int)  = Unit 
-  override fun setUseRandomServer(objectName: ObjectName, useRandomServer: Boolean)  = Unit 
-  override fun setPerform(objectName: ObjectName, perform: QStringList)  = Unit 
-  override fun setSkipCaps(objectName: ObjectName, skipCaps: QStringList)  = Unit 
-  override fun setUseAutoIdentify(objectName: ObjectName, useAutoIdentify: Boolean)  = Unit 
-  override fun setAutoIdentifyService(objectName: ObjectName, autoIdentifyService: String)  = Unit 
-  override fun setAutoIdentifyPassword(objectName: ObjectName, autoIdentifyPassword: String)  = Unit 
-  override fun setUseSasl(objectName: ObjectName, useSasl: Boolean)  = Unit 
-  override fun setSaslAccount(objectName: ObjectName, saslAccount: String)  = Unit 
-  override fun setSaslPassword(objectName: ObjectName, saslPassword: String)  = Unit 
-  override fun setUseAutoReconnect(objectName: ObjectName, useAutoReconnect: Boolean)  = Unit 
-  override fun setAutoReconnectInterval(objectName: ObjectName, autoReconnectInterval: UInt)  = Unit 
-  override fun setAutoReconnectRetries(objectName: ObjectName, autoReconnectRetries: UShort)  = Unit 
-  override fun setUnlimitedReconnectRetries(objectName: ObjectName, unlimitedReconnectRetries: Boolean)  = Unit 
-  override fun setRejoinChannels(objectName: ObjectName, rejoinChannels: Boolean)  = Unit 
-  override fun setUseCustomMessageRate(objectName: ObjectName, useCustomMessageRate: Boolean)  = Unit 
-  override fun setMessageRateBurstSize(objectName: ObjectName, messageRateBurstSize: UInt)  = Unit 
-  override fun setMessageRateDelay(objectName: ObjectName, messageRateDelay: UInt)  = Unit 
-  override fun setUnlimitedMessageRate(objectName: ObjectName, unlimitedMessageRate: Boolean)  = Unit 
-  override fun setServerList(objectName: ObjectName, serverList: QVariantList)  = Unit 
-  override fun addSupport(objectName: ObjectName, param: String, value: String)  = Unit 
-  override fun removeSupport(objectName: ObjectName, param: String)  = Unit 
-  override fun addCap(objectName: ObjectName, capability: String, value: String)  = Unit 
-  override fun acknowledgeCap(objectName: ObjectName, capability: String)  = Unit 
-  override fun removeCap(objectName: ObjectName, capability: String)  = Unit 
-  override fun clearCaps(objectName: ObjectName)  = Unit 
-  override fun addIrcUser(objectName: ObjectName, hostmask: String)  = Unit 
-  override fun addIrcChannel(objectName: ObjectName, channel: String)  = Unit 
-  override fun update(objectName: ObjectName, properties: QVariantMap)  = Unit
+  override suspend fun setNetworkName(objectName: ObjectName, networkName: String)  = Unit 
+  override suspend fun setCurrentServer(objectName: ObjectName, currentServer: String?)  = Unit 
+  override suspend fun setMyNick(objectName: ObjectName, myNick: String?)  = Unit 
+  override suspend fun setLatency(objectName: ObjectName, latency: Int)  = Unit 
+  override suspend fun setCodecForServer(objectName: ObjectName, codecForServer: ByteBuffer)  = Unit 
+  override suspend fun setCodecForEncoding(objectName: ObjectName, codecForEncoding: ByteBuffer)  = Unit 
+  override suspend fun setCodecForDecoding(objectName: ObjectName, codecForDecoding: ByteBuffer)  = Unit 
+  override suspend fun setIdentity(objectName: ObjectName, identityId: IdentityId)  = Unit 
+  override suspend fun setConnected(objectName: ObjectName, isConnected: Boolean)  = Unit 
+  override suspend fun setConnectionState(objectName: ObjectName, connectionState: Int)  = Unit 
+  override suspend fun setUseRandomServer(objectName: ObjectName, useRandomServer: Boolean)  = Unit 
+  override suspend fun setPerform(objectName: ObjectName, perform: QStringList)  = Unit 
+  override suspend fun setSkipCaps(objectName: ObjectName, skipCaps: QStringList)  = Unit 
+  override suspend fun setUseAutoIdentify(objectName: ObjectName, useAutoIdentify: Boolean)  = Unit 
+  override suspend fun setAutoIdentifyService(objectName: ObjectName, autoIdentifyService: String)  = Unit 
+  override suspend fun setAutoIdentifyPassword(objectName: ObjectName, autoIdentifyPassword: String)  = Unit 
+  override suspend fun setUseSasl(objectName: ObjectName, useSasl: Boolean)  = Unit 
+  override suspend fun setSaslAccount(objectName: ObjectName, saslAccount: String)  = Unit 
+  override suspend fun setSaslPassword(objectName: ObjectName, saslPassword: String)  = Unit 
+  override suspend fun setUseAutoReconnect(objectName: ObjectName, useAutoReconnect: Boolean)  = Unit 
+  override suspend fun setAutoReconnectInterval(objectName: ObjectName, autoReconnectInterval: UInt)  = Unit 
+  override suspend fun setAutoReconnectRetries(objectName: ObjectName, autoReconnectRetries: UShort)  = Unit 
+  override suspend fun setUnlimitedReconnectRetries(objectName: ObjectName, unlimitedReconnectRetries: Boolean)  = Unit 
+  override suspend fun setRejoinChannels(objectName: ObjectName, rejoinChannels: Boolean)  = Unit 
+  override suspend fun setUseCustomMessageRate(objectName: ObjectName, useCustomMessageRate: Boolean)  = Unit 
+  override suspend fun setMessageRateBurstSize(objectName: ObjectName, messageRateBurstSize: UInt)  = Unit 
+  override suspend fun setMessageRateDelay(objectName: ObjectName, messageRateDelay: UInt)  = Unit 
+  override suspend fun setUnlimitedMessageRate(objectName: ObjectName, unlimitedMessageRate: Boolean)  = Unit 
+  override suspend fun setServerList(objectName: ObjectName, serverList: QVariantList)  = Unit 
+  override suspend fun addSupport(objectName: ObjectName, param: String, value: String)  = Unit 
+  override suspend fun removeSupport(objectName: ObjectName, param: String)  = Unit 
+  override suspend fun addCap(objectName: ObjectName, capability: String, value: String)  = Unit 
+  override suspend fun acknowledgeCap(objectName: ObjectName, capability: String)  = Unit 
+  override suspend fun removeCap(objectName: ObjectName, capability: String)  = Unit 
+  override suspend fun clearCaps(objectName: ObjectName)  = Unit 
+  override suspend fun addIrcUser(objectName: ObjectName, hostmask: String)  = Unit 
+  override suspend fun addIrcChannel(objectName: ObjectName, channel: String)  = Unit 
+  override suspend fun update(objectName: ObjectName, properties: QVariantMap)  = Unit
 }
diff --git a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/RpcPersister.kt b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/RpcPersister.kt
index b52e82e4576363104b7662184776cb6a4518b508..172ecc97cb49c64f9d75f5e23acbef61090e320f 100644
--- a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/RpcPersister.kt
+++ b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/backend/RpcPersister.kt
@@ -19,14 +19,14 @@ import java.nio.ByteBuffer
 import javax.inject.Inject
 
 class RpcPersister @Inject constructor(): RpcClientApi {
-  override fun objectRenamed(classname: ByteBuffer, newName: String?, oldName: String?)  = Unit 
-  override fun displayMsg(message: Message)  = Unit 
-  override fun displayStatusMsg(net: String?, msg: String?)  = Unit 
-  override fun bufferInfoUpdated(bufferInfo: BufferInfo)  = Unit 
-  override fun identityCreated(identity: QVariantMap)  = Unit 
-  override fun identityRemoved(identityId: IdentityId)  = Unit 
-  override fun networkCreated(networkId: NetworkId)  = Unit 
-  override fun networkRemoved(networkId: NetworkId)  = Unit 
-  override fun passwordChanged(peer: ULong, success: Boolean)  = Unit 
-  override fun disconnectFromCore()  = Unit
+  override suspend fun objectRenamed(classname: ByteBuffer, newName: String?, oldName: String?)  = Unit 
+  override suspend fun displayMsg(message: Message)  = Unit 
+  override suspend fun displayStatusMsg(net: String?, msg: String?)  = Unit 
+  override suspend fun bufferInfoUpdated(bufferInfo: BufferInfo)  = Unit 
+  override suspend fun identityCreated(identity: QVariantMap)  = Unit 
+  override suspend fun identityRemoved(identityId: IdentityId)  = Unit 
+  override suspend fun networkCreated(networkId: NetworkId)  = Unit 
+  override suspend fun networkRemoved(networkId: NetworkId)  = Unit 
+  override suspend fun passwordChanged(peer: ULong, success: Boolean)  = Unit 
+  override suspend fun disconnectFromCore()  = Unit
 }
diff --git a/libquassel-client/src/test/kotlin/de/justjanne/libquassel/client/QuasselApiTest.kt b/libquassel-client/src/test/kotlin/de/justjanne/libquassel/client/QuasselApiTest.kt
index eb3af287b325bf28956001849fd4d2c6fb63a706..369e2fc22b3ba6889a2ddbeb690f9ca6d078dc60 100644
--- a/libquassel-client/src/test/kotlin/de/justjanne/libquassel/client/QuasselApiTest.kt
+++ b/libquassel-client/src/test/kotlin/de/justjanne/libquassel/client/QuasselApiTest.kt
@@ -9,9 +9,12 @@
 
 package de.justjanne.libquassel.client
 
+import androidx.room.Room
+import androidx.sqlite.driver.bundled.BundledSQLiteDriver
 import dagger.Binds
 import dagger.Component
 import dagger.Module
+import dagger.Provides
 import de.justjanne.libquassel.backend.AliasManagerPersister
 import de.justjanne.libquassel.backend.BacklogManagerPersister
 import de.justjanne.libquassel.backend.BufferSyncerPersister
@@ -28,8 +31,26 @@ import de.justjanne.libquassel.backend.IrcUserPersister
 import de.justjanne.libquassel.backend.NetworkConfigPersister
 import de.justjanne.libquassel.backend.NetworkPersister
 import de.justjanne.libquassel.backend.RpcPersister
+import de.justjanne.libquassel.persistence.AliasEntity
+import de.justjanne.libquassel.persistence.AliasRepository
+import de.justjanne.libquassel.persistence.AppDatabase
 import de.justjanne.libquassel.protocol.api.ObjectName
-import de.justjanne.libquassel.protocol.api.client.*
+import de.justjanne.libquassel.protocol.api.client.AliasManagerClientApi
+import de.justjanne.libquassel.protocol.api.client.BacklogManagerClientApi
+import de.justjanne.libquassel.protocol.api.client.BufferSyncerClientApi
+import de.justjanne.libquassel.protocol.api.client.BufferViewConfigClientApi
+import de.justjanne.libquassel.protocol.api.client.BufferViewManagerClientApi
+import de.justjanne.libquassel.protocol.api.client.CertManagerClientApi
+import de.justjanne.libquassel.protocol.api.client.CoreInfoClientApi
+import de.justjanne.libquassel.protocol.api.client.HighlightRuleManagerClientApi
+import de.justjanne.libquassel.protocol.api.client.IdentityClientApi
+import de.justjanne.libquassel.protocol.api.client.IgnoreListManagerClientApi
+import de.justjanne.libquassel.protocol.api.client.IrcChannelClientApi
+import de.justjanne.libquassel.protocol.api.client.IrcListHelperClientApi
+import de.justjanne.libquassel.protocol.api.client.IrcUserClientApi
+import de.justjanne.libquassel.protocol.api.client.NetworkClientApi
+import de.justjanne.libquassel.protocol.api.client.NetworkConfigClientApi
+import de.justjanne.libquassel.protocol.api.client.RpcClientApi
 import de.justjanne.libquassel.protocol.api.dispatcher.ClientDispatcherModule
 import de.justjanne.libquassel.protocol.api.dispatcher.RpcDispatcher
 import de.justjanne.libquassel.protocol.api.dispatcher.SyncHandler
@@ -54,11 +75,19 @@ import de.justjanne.libquassel.protocol.models.types.QtType
 import de.justjanne.libquassel.protocol.variant.QVariantList
 import de.justjanne.libquassel.protocol.variant.QVariant_
 import de.justjanne.libquassel.protocol.variant.qVariant
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.cancelAndJoin
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.collectLatest
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
 import org.junit.jupiter.api.Test
 import javax.inject.Inject
 import javax.inject.Singleton
 import kotlin.test.assertFails
 import kotlin.test.assertFailsWith
+import kotlin.time.Duration.Companion.milliseconds
 
 @Singleton
 class ProxyImpl @Inject constructor() : Proxy {
@@ -92,6 +121,21 @@ interface ClientModule {
   @Binds fun bindProxy(impl: ProxyImpl): Proxy
 }
 
+@Module
+class DatabaseModule {
+  @Provides
+  fun database(): AppDatabase =
+    Room.inMemoryDatabaseBuilder<AppDatabase>()
+      .setDriver(BundledSQLiteDriver())
+      .setQueryCoroutineContext(Dispatchers.IO)
+      .build()
+
+  @Provides
+  fun provideAliasRepository(database: AppDatabase) = database.alias()
+  @Provides
+  fun provideMessageRepository(database: AppDatabase) = database.message()
+}
+
 @Singleton
 class QuasselApiClient @Inject constructor(
   val aliasManager: AliasManagerServerApi,
@@ -109,8 +153,9 @@ class QuasselApiClient @Inject constructor(
 )
 
 @Singleton
-@Component(modules = [ClientModule::class, ClientDispatcherModule::class, ClientProxyModule::class])
+@Component(modules = [ClientModule::class, DatabaseModule::class, ClientDispatcherModule::class, ClientProxyModule::class])
 interface ClientComponent {
+  fun db(): AppDatabase
   fun sync(): SyncHandler
   fun rpc(): RpcDispatcher
   fun api(): QuasselApiClient
@@ -118,7 +163,7 @@ interface ClientComponent {
 
 class QuasselApiTest {
   @Test
-  fun test() {
+  fun test() = runBlocking{
     val client = DaggerClientComponent.builder().build()
     client.sync().invoke(
       "AliasManager",
@@ -148,4 +193,34 @@ class QuasselApiTest {
     client.api().identity.requestUpdate(ObjectName(""), emptyMap())
     println("hi!")
   }
+
+  @Test
+  fun testDb() = runBlocking {
+    val db = Room.inMemoryDatabaseBuilder<AppDatabase>()
+      .setDriver(BundledSQLiteDriver())
+      .setQueryCoroutineContext(Dispatchers.IO)
+      .build()
+
+    val aliasRepo = db.alias()
+    val job = CoroutineScope(Dispatchers.Default).launch {
+      aliasRepo.collectAll().collectLatest {
+        println("alias list changed: $it")
+      }
+    }
+    delay(10.milliseconds)
+    aliasRepo.insert(
+      AliasEntity(0, "foo", "bar"),
+    )
+    delay(10.milliseconds)
+    aliasRepo.insert(
+      AliasEntity(1, "bar", "baz"),
+    )
+    delay(10.milliseconds)
+    aliasRepo.insert(
+      AliasEntity(0, "foo", "foo"),
+      AliasEntity(2, "baz", "foo"),
+    )
+    delay(10.milliseconds)
+    job.cancelAndJoin()
+  }
 }
diff --git a/libquassel-generator/src/main/kotlin/de/justjanne/libquassel/generator/visitors/DispatcherGenerator.kt b/libquassel-generator/src/main/kotlin/de/justjanne/libquassel/generator/visitors/DispatcherGenerator.kt
index 3b944e2d2cd13ec243206e1d96583678e3907938..ed7942ac39f18a8a3022f5089d4f02c2a1755a5d 100644
--- a/libquassel-generator/src/main/kotlin/de/justjanne/libquassel/generator/visitors/DispatcherGenerator.kt
+++ b/libquassel-generator/src/main/kotlin/de/justjanne/libquassel/generator/visitors/DispatcherGenerator.kt
@@ -67,7 +67,7 @@ class DispatcherGenerator : RpcModelVisitor<KotlinModel?> {
             .addAnnotation(TYPENAME_GENERATED)
             .addFunction(
               FunSpec.builder("invoke")
-                .addModifiers(KModifier.OVERRIDE, KModifier.OPERATOR)
+                .addModifiers(KModifier.OVERRIDE, KModifier.OPERATOR, KModifier.SUSPEND)
                 .addAnnotation(TYPENAME_GENERATED)
                 .let {
                   if (model.rpcName.isNotEmpty()) {
diff --git a/libquassel-generator/src/main/kotlin/de/justjanne/libquassel/generator/visitors/ProxyGenerator.kt b/libquassel-generator/src/main/kotlin/de/justjanne/libquassel/generator/visitors/ProxyGenerator.kt
index 81c7ea6ae6ae6e1488a8d18e21497448fa6f69aa..99d6c4aa5331c143fd5677bbad4e9756ecb7aa46 100644
--- a/libquassel-generator/src/main/kotlin/de/justjanne/libquassel/generator/visitors/ProxyGenerator.kt
+++ b/libquassel-generator/src/main/kotlin/de/justjanne/libquassel/generator/visitors/ProxyGenerator.kt
@@ -94,7 +94,7 @@ class AliasManagerClientApiProxy @Inject constructor(
             .addFunctions(
               model.methods.map { method ->
                 FunSpec.builder(method.name)
-                  .addModifiers(KModifier.OVERRIDE)
+                  .addModifiers(KModifier.OVERRIDE, KModifier.SUSPEND)
                   .let {
                     if (!method.static) {
                       it.addParameter(
diff --git a/libquassel-persistence/build.gradle.kts b/libquassel-persistence/build.gradle.kts
new file mode 100644
index 0000000000000000000000000000000000000000..8f96dc516ca45745e0b2fff93eda01dbe7bf30f7
--- /dev/null
+++ b/libquassel-persistence/build.gradle.kts
@@ -0,0 +1,31 @@
+/*
+ * libquassel
+ * Copyright (c) 2024 Janne Mareike Koschinski
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+plugins {
+  id("justjanne.kotlin")
+  id("justjanne.publication")
+}
+
+repositories {
+  google()
+  mavenCentral()
+}
+
+dependencies {
+  api(project(":libquassel-protocol"))
+  api(project(":libquassel-api"))
+
+  implementation(libs.dagger.core)
+  ksp(libs.dagger.compiler)
+
+  implementation(libs.room.runtime)
+  ksp(libs.room.compiler)
+
+  implementation(libs.slf4j)
+}
diff --git a/libquassel-persistence/src/main/kotlin/de/justjanne/libquassel/persistence/AliasEntity.kt b/libquassel-persistence/src/main/kotlin/de/justjanne/libquassel/persistence/AliasEntity.kt
new file mode 100644
index 0000000000000000000000000000000000000000..f5b6224a6b569b67b3b9d65e5cfe8e1f3f9dea38
--- /dev/null
+++ b/libquassel-persistence/src/main/kotlin/de/justjanne/libquassel/persistence/AliasEntity.kt
@@ -0,0 +1,21 @@
+/*
+ * libquassel
+ * Copyright (c) 2025 Janne Mareike Koschinski
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.persistence
+
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+
+@Entity
+data class AliasEntity(
+  @PrimaryKey
+  val id: Int,
+  val name: String,
+  val expansion: String,
+)
diff --git a/libquassel-persistence/src/main/kotlin/de/justjanne/libquassel/persistence/AliasRepository.kt b/libquassel-persistence/src/main/kotlin/de/justjanne/libquassel/persistence/AliasRepository.kt
new file mode 100644
index 0000000000000000000000000000000000000000..73575405c0e2fcedbaf4d3328a728203b585b49c
--- /dev/null
+++ b/libquassel-persistence/src/main/kotlin/de/justjanne/libquassel/persistence/AliasRepository.kt
@@ -0,0 +1,74 @@
+/*
+ * libquassel
+ * Copyright (c) 2024 Janne Mareike Koschinski
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.persistence
+
+import androidx.room.Dao
+import androidx.room.Insert
+import androidx.room.OnConflictStrategy
+import androidx.room.Query
+import androidx.room.Transaction
+import de.justjanne.libquassel.protocol.models.ids.BufferId
+import kotlinx.coroutines.flow.Flow
+
+@Dao
+interface AliasRepository {
+  @Query("SELECT * FROM AliasEntity")
+  suspend fun getAll(): List<AliasEntity>
+
+  @Query("SELECT * FROM AliasEntity")
+  fun collectAll(): Flow<List<AliasEntity>>
+
+  @Insert(onConflict = OnConflictStrategy.REPLACE)
+  suspend fun insert(vararg item: AliasEntity)
+
+  @Query("DELETE FROM AliasEntity")
+  suspend fun clear()
+
+  @Transaction
+  suspend fun sync(data: List<AliasEntity>) {
+    clear()
+    for (item in data) {
+      insert(item)
+    }
+  }
+}
+
+@Dao
+interface MessageRepository {
+  @Query("SELECT * FROM MessageEntity WHERE buffer = :buffer ORDER BY messageId ASC")
+  suspend fun getAll(buffer: BufferId): List<MessageEntity>
+
+  @Query("SELECT * FROM MessageEntity WHERE buffer = :buffer ORDER BY messageId ASC")
+  fun collectAll(buffer: BufferId): Flow<List<MessageEntity>>
+
+  @Query("SELECT * FROM messageentity WHERE buffer = :buffer ORDER BY messageId DESC LIMIT 1")
+  suspend fun getLast(buffer: BufferId): MessageEntity?
+
+  @Query("SELECT * FROM messageentity WHERE buffer = :buffer ORDER BY messageId DESC LIMIT 1")
+  suspend fun collectLast(buffer: BufferId): MessageEntity?
+
+  @Insert(onConflict = OnConflictStrategy.REPLACE)
+  suspend fun insert(vararg item: MessageEntity)
+
+  @Query("DELETE FROM MessageEntity WHERE buffer = :buffer")
+  suspend fun clear(buffer: BufferId)
+
+  @Transaction
+  suspend fun sync(buffer: BufferId, data: List<MessageEntity>) {
+    val newMessages = data.map(MessageEntity::messageId).toSet()
+    val last = getLast(buffer)
+    if (last != null && !newMessages.contains(last.messageId)) {
+      clear(buffer)
+    }
+    for (item in data) {
+      insert(item)
+    }
+  }
+}
diff --git a/libquassel-persistence/src/main/kotlin/de/justjanne/libquassel/persistence/AppDatabase.kt b/libquassel-persistence/src/main/kotlin/de/justjanne/libquassel/persistence/AppDatabase.kt
new file mode 100644
index 0000000000000000000000000000000000000000..dc784cf0e336087f12b7cf28d46f754522c3bd25
--- /dev/null
+++ b/libquassel-persistence/src/main/kotlin/de/justjanne/libquassel/persistence/AppDatabase.kt
@@ -0,0 +1,27 @@
+/*
+ * libquassel
+ * Copyright (c) 2024 Janne Mareike Koschinski
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.persistence
+
+import androidx.room.Database
+import androidx.room.RoomDatabase
+import androidx.room.TypeConverters
+
+@Database(
+  entities = [
+    AliasEntity::class,
+    MessageEntity::class,
+  ],
+  version = 1,
+)
+@TypeConverters(InstantConverter::class)
+abstract class AppDatabase : RoomDatabase() {
+  abstract fun alias(): AliasRepository
+  abstract fun message(): MessageRepository
+}
diff --git a/libquassel-persistence/src/main/kotlin/de/justjanne/libquassel/persistence/InstantConverter.kt b/libquassel-persistence/src/main/kotlin/de/justjanne/libquassel/persistence/InstantConverter.kt
new file mode 100644
index 0000000000000000000000000000000000000000..963f2a106d219018737c004736409fcee457475f
--- /dev/null
+++ b/libquassel-persistence/src/main/kotlin/de/justjanne/libquassel/persistence/InstantConverter.kt
@@ -0,0 +1,25 @@
+/*
+ * libquassel
+ * Copyright (c) 2025 Janne Mareike Koschinski
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.persistence
+
+import androidx.room.TypeConverter
+import org.threeten.bp.Instant
+
+object InstantConverter {
+  @TypeConverter
+  fun fromTimestamp(value: Long): Instant {
+    return Instant.ofEpochMilli(value)
+  }
+
+  @TypeConverter
+  fun toTimestamp(instant: Instant): Long {
+    return instant.toEpochMilli()
+  }
+}
diff --git a/libquassel-persistence/src/main/kotlin/de/justjanne/libquassel/persistence/MessageEntity.kt b/libquassel-persistence/src/main/kotlin/de/justjanne/libquassel/persistence/MessageEntity.kt
new file mode 100644
index 0000000000000000000000000000000000000000..641c98c2fc678551087392b1f1814f3f2d9c217f
--- /dev/null
+++ b/libquassel-persistence/src/main/kotlin/de/justjanne/libquassel/persistence/MessageEntity.kt
@@ -0,0 +1,48 @@
+/*
+ * libquassel
+ * Copyright (c) 2025 Janne Mareike Koschinski
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at https://mozilla.org/MPL/2.0/.
+ */
+
+package de.justjanne.libquassel.persistence
+
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+import de.justjanne.bitflags.toBits
+import de.justjanne.libquassel.protocol.models.Message
+import de.justjanne.libquassel.protocol.models.ids.BufferId
+import de.justjanne.libquassel.protocol.models.ids.MsgId
+import org.threeten.bp.Instant
+
+@Entity
+data class MessageEntity(
+  @PrimaryKey
+  val messageId: MsgId,
+  val time: Instant,
+  val type: Int,
+  val flag: Int,
+  val buffer: BufferId,
+  val sender: String,
+  val senderPrefixes: String,
+  val realName: String,
+  val avatarUrl: String,
+  val content: String,
+) {
+  companion object {
+    fun fromDto(message: Message) = MessageEntity(
+      message.messageId,
+      message.time,
+      message.type.toBits().toInt(),
+      message.flag.toBits().toInt(),
+      message.bufferInfo.bufferId,
+      message.sender,
+      message.senderPrefixes,
+      message.realName,
+      message.avatarUrl,
+      message.content,
+    )
+  }
+}
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 4b191f1d48fdda5ce87ac45a5d4ccf0312b35c92..291dc88e43d4b51c882c8cce6e51bc8ab2dda812 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -15,6 +15,7 @@ include(
   ":libquassel-annotations",
   ":libquassel-api",
   ":libquassel-client",
+  ":libquassel-persistence",
   ":libquassel-generator",
   ":libquassel-irc",
   ":libquassel-protocol"