diff --git a/app/src/main/java/de/justjanne/quasseldroid/QuasseldroidRouter.kt b/app/src/main/java/de/justjanne/quasseldroid/QuasseldroidRouter.kt
index 424550bc32c7e9f6f55783574acb867a08219297..8ed54ebf19f9547fc96105e95099c4c78f9bf00c 100644
--- a/app/src/main/java/de/justjanne/quasseldroid/QuasseldroidRouter.kt
+++ b/app/src/main/java/de/justjanne/quasseldroid/QuasseldroidRouter.kt
@@ -1,21 +1,47 @@
 package de.justjanne.quasseldroid
 
+import androidx.compose.material.Text
 import androidx.compose.runtime.Composable
+import androidx.navigation.NavType
 import androidx.navigation.compose.NavHost
 import androidx.navigation.compose.composable
 import androidx.navigation.compose.rememberNavController
+import androidx.navigation.navArgument
 import de.justjanne.quasseldroid.service.QuasselBackend
-import de.justjanne.quasseldroid.ui.CoreInfoRoute
-import de.justjanne.quasseldroid.ui.HomeView
-import de.justjanne.quasseldroid.ui.LoginRoute
+import de.justjanne.quasseldroid.ui.routes.CoreInfoRoute
+import de.justjanne.quasseldroid.ui.routes.HomeRoute
+import de.justjanne.quasseldroid.ui.routes.LoginRoute
 
 @Composable
 fun QuasseldroidRouter(backend: QuasselBackend) {
   val navController = rememberNavController()
 
   NavHost(navController = navController, startDestination = "login") {
-    composable("login") { LoginRoute(backend, navController) }
-    composable("home") { HomeView(backend, navController) }
-    composable("coreInfo") { CoreInfoRoute(backend, navController) }
+    composable("login") {
+      LoginRoute(backend, navController)
+    }
+    composable("home") {
+      HomeRoute(backend, navController)
+    }
+
+    composable(
+      "buffer/{bufferId}",
+      listOf(navArgument("bufferId") { type = NavType.IntType })
+    ) {
+      Text("Buffer ${it.arguments?.getInt("bufferId")}")
+    }
+    composable("bufferViewConfigs") {
+      Text("List of BufferViewConfigs")
+    }
+    composable(
+      "bufferViewConfigs/{bufferViewConfigId}",
+      listOf(navArgument("bufferViewConfigId") { type = NavType.IntType })
+    ) {
+      Text("BufferViewConfig ${it.arguments?.getInt("bufferViewConfigId")}")
+    }
+
+    composable("coreInfo") {
+      CoreInfoRoute(backend, navController)
+    }
   }
 }
diff --git a/app/src/main/java/de/justjanne/quasseldroid/messages/MessageBuffer.kt b/app/src/main/java/de/justjanne/quasseldroid/messages/MessageBuffer.kt
new file mode 100644
index 0000000000000000000000000000000000000000..6df763cceae4c48b0c18bb4523bf3f9daeec6ea0
--- /dev/null
+++ b/app/src/main/java/de/justjanne/quasseldroid/messages/MessageBuffer.kt
@@ -0,0 +1,12 @@
+package de.justjanne.quasseldroid.messages
+
+import de.justjanne.libquassel.protocol.models.Message
+
+data class MessageBuffer(
+  /**
+   * Whether the chronologically latest message for a given buffer id is in the buffer.
+   * If yes, new messages that arrive for this buffer should be appened to the end.
+   */
+  val atEnd: Boolean,
+  val messages: List<Message>
+)
diff --git a/app/src/main/java/de/justjanne/quasseldroid/messages/MessageStore.kt b/app/src/main/java/de/justjanne/quasseldroid/messages/MessageStore.kt
new file mode 100644
index 0000000000000000000000000000000000000000..c9f670522e200b15c25cdb7a9327831f020f9807
--- /dev/null
+++ b/app/src/main/java/de/justjanne/quasseldroid/messages/MessageStore.kt
@@ -0,0 +1,100 @@
+package de.justjanne.quasseldroid.messages
+
+import de.justjanne.libquassel.client.syncables.ClientBacklogManager
+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.util.StateHolder
+import de.justjanne.libquassel.protocol.variant.into
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.async
+import kotlinx.coroutines.awaitAll
+import kotlinx.coroutines.cancelAndJoin
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.update
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
+import java.io.Closeable
+
+class MessageStore(
+  incoming: Flow<Message>,
+  private val backlogManager: ClientBacklogManager
+) : Closeable, StateHolder<Map<BufferId, MessageBuffer>> {
+  private val state = MutableStateFlow(mapOf<BufferId, MessageBuffer>())
+  override fun state() = state.value
+  override fun flow() = state
+
+  private val scope = CoroutineScope(Dispatchers.IO)
+  private val disposable = incoming.onEach { message ->
+    val bufferId = message.bufferInfo.bufferId
+    state.update { messages ->
+      val buffer = messages[bufferId] ?: MessageBuffer(true, emptyList())
+      if (buffer.atEnd) {
+        messages + Pair(bufferId, buffer.copy(messages = buffer.messages + message))
+      } else {
+        messages
+      }
+    }
+  }.launchIn(scope)
+
+  fun loadAround(bufferId: BufferId, messageId: MsgId) {
+    scope.launch {
+      state.update { messages ->
+        val (before, after) = listOf(
+          async { backlogManager.backlog(bufferId, messageId) },
+          async { backlogManager.backlogForward(bufferId, messageId) },
+        ).awaitAll()
+
+        val updated = MessageBuffer(
+          atEnd = false,
+          messages = (before + after)
+            .mapNotNull { it.into<Message>() }
+            .sortedBy { it.messageId }
+        )
+        messages + Pair(bufferId, updated)
+      }
+    }
+  }
+
+  fun loadBefore(bufferId: BufferId) {
+    scope.launch {
+      state.update { messages ->
+        val buffer = messages[bufferId] ?: MessageBuffer(true, emptyList())
+        val messageId = buffer.messages.firstOrNull()?.messageId ?: MsgId(-1)
+        val data = backlogManager.backlog(bufferId, messageId)
+          .mapNotNull { it.into<Message>() }
+        val updated = buffer.copy(
+          messages = (buffer.messages + data)
+            .sortedBy { it.messageId }
+        )
+        messages + Pair(bufferId, updated)
+      }
+    }
+  }
+
+  fun loadAfter(bufferId: BufferId) {
+    scope.launch {
+      state.update { messages ->
+        val buffer = messages[bufferId] ?: MessageBuffer(true, emptyList())
+        val messageId = buffer.messages.lastOrNull()?.messageId ?: MsgId(-1)
+        val data = backlogManager.backlogForward(bufferId, messageId)
+          .mapNotNull { it.into<Message>() }
+        val updated = buffer.copy(
+          messages = (buffer.messages + data)
+            .sortedBy { it.messageId }
+        )
+        messages + Pair(bufferId, updated)
+      }
+    }
+  }
+
+  override fun close() {
+    runBlocking {
+      disposable.cancelAndJoin()
+    }
+  }
+}
diff --git a/app/src/main/java/de/justjanne/quasseldroid/service/ClientSessionWrapper.kt b/app/src/main/java/de/justjanne/quasseldroid/service/ClientSessionWrapper.kt
new file mode 100644
index 0000000000000000000000000000000000000000..a52a88fb688d4f23b726be9c2c42cd5c553addb6
--- /dev/null
+++ b/app/src/main/java/de/justjanne/quasseldroid/service/ClientSessionWrapper.kt
@@ -0,0 +1,9 @@
+package de.justjanne.quasseldroid.service
+
+import de.justjanne.libquassel.client.session.ClientSession
+import de.justjanne.quasseldroid.messages.MessageStore
+
+data class ClientSessionWrapper(
+    val session: ClientSession,
+    val messages: MessageStore
+)
diff --git a/app/src/main/java/de/justjanne/quasseldroid/service/QuasselBackend.kt b/app/src/main/java/de/justjanne/quasseldroid/service/QuasselBackend.kt
index 5d8ebb5b0c6caba48b744e146e101da168777f08..6f2edb9d05f631263254dbbed2981a155e6e7ce7 100644
--- a/app/src/main/java/de/justjanne/quasseldroid/service/QuasselBackend.kt
+++ b/app/src/main/java/de/justjanne/quasseldroid/service/QuasselBackend.kt
@@ -15,7 +15,7 @@ import de.justjanne.quasseldroid.util.lifecycle.LifecycleStatus
 import kotlinx.coroutines.flow.MutableStateFlow
 
 class QuasselBackend : DefaultContextualLifecycleObserver(), ServiceConnection,
-  StateHolder<ClientSession?> {
+  StateHolder<ClientSessionWrapper?> {
   private var connectionData: ConnectionData? = null
 
   override fun flow() = state.flatMap()
diff --git a/app/src/main/java/de/justjanne/quasseldroid/service/QuasselBinder.kt b/app/src/main/java/de/justjanne/quasseldroid/service/QuasselBinder.kt
index db890aef00a95a7a0c526d37815565a7208cea01..993619d8cf654e533fe933a8d400491877881dfe 100644
--- a/app/src/main/java/de/justjanne/quasseldroid/service/QuasselBinder.kt
+++ b/app/src/main/java/de/justjanne/quasseldroid/service/QuasselBinder.kt
@@ -6,8 +6,8 @@ import de.justjanne.libquassel.protocol.util.StateHolder
 import kotlinx.coroutines.flow.StateFlow
 
 class QuasselBinder(
-  private val state: StateFlow<ClientSession?>
-) : Binder(), StateHolder<ClientSession?> {
+  private val state: StateFlow<ClientSessionWrapper?>
+) : Binder(), StateHolder<ClientSessionWrapper?> {
   constructor(runner: QuasselRunner) : this(runner.flow())
 
   override fun flow() = state
diff --git a/app/src/main/java/de/justjanne/quasseldroid/service/QuasselRunner.kt b/app/src/main/java/de/justjanne/quasseldroid/service/QuasselRunner.kt
index e8d8ca7c540af6ea5f22a1bab74d2810c0331c60..93512a477f82ef4eb28f1238accddebb359181e1 100644
--- a/app/src/main/java/de/justjanne/quasseldroid/service/QuasselRunner.kt
+++ b/app/src/main/java/de/justjanne/quasseldroid/service/QuasselRunner.kt
@@ -8,6 +8,7 @@ import de.justjanne.libquassel.protocol.connection.ProtocolVersion
 import de.justjanne.libquassel.protocol.features.FeatureSet
 import de.justjanne.libquassel.protocol.io.CoroutineChannel
 import de.justjanne.libquassel.protocol.util.StateHolder
+import de.justjanne.quasseldroid.messages.MessageStore
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
@@ -20,16 +21,16 @@ import javax.net.ssl.SSLContext
 class QuasselRunner(
   private val address: InetSocketAddress,
   private val auth: Pair<String, String>
-) : Thread("Quassel Runner"), Closeable, StateHolder<ClientSession?> {
+) : Thread("Quassel Runner"), Closeable, StateHolder<ClientSessionWrapper?> {
   private val channel = CoroutineChannel()
 
-  override fun state(): ClientSession? = state.value
-  override fun flow(): StateFlow<ClientSession?> = state
+  override fun state(): ClientSessionWrapper? = state.value
+  override fun flow(): StateFlow<ClientSessionWrapper?> = state
 
-  private val state = MutableStateFlow<ClientSession?>(null)
+  private val state = MutableStateFlow<ClientSessionWrapper?>(null)
 
   init {
-      start()
+    start()
   }
 
   override fun run() {
@@ -49,7 +50,14 @@ class QuasselRunner(
           )
         ),
         SSLContext.getDefault()
-      ).also { state.value = it }
+      )
+      state.value = ClientSessionWrapper(
+        session,
+        messages = MessageStore(
+          session.rpcHandler.messages(),
+          session.backlogManager
+        )
+      )
       session.handshakeHandler.init(
         "Quasseltest v0.1",
         "2022-02-24",
diff --git a/app/src/main/java/de/justjanne/quasseldroid/ui/ConnectedClientCard.kt b/app/src/main/java/de/justjanne/quasseldroid/ui/components/ConnectedClientCard.kt
similarity index 97%
rename from app/src/main/java/de/justjanne/quasseldroid/ui/ConnectedClientCard.kt
rename to app/src/main/java/de/justjanne/quasseldroid/ui/components/ConnectedClientCard.kt
index 314956f18bc1301450ad9fc64e1f4b5d7674ea07..66af09a56424ec699d8bf4be34758115702b306a 100644
--- a/app/src/main/java/de/justjanne/quasseldroid/ui/ConnectedClientCard.kt
+++ b/app/src/main/java/de/justjanne/quasseldroid/ui/components/ConnectedClientCard.kt
@@ -1,4 +1,4 @@
-package de.justjanne.quasseldroid.ui
+package de.justjanne.quasseldroid.ui.components
 
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.Row
diff --git a/app/src/main/java/de/justjanne/quasseldroid/ui/CoreInfoView.kt b/app/src/main/java/de/justjanne/quasseldroid/ui/components/CoreInfoView.kt
similarity index 97%
rename from app/src/main/java/de/justjanne/quasseldroid/ui/CoreInfoView.kt
rename to app/src/main/java/de/justjanne/quasseldroid/ui/components/CoreInfoView.kt
index 90b99fc45f1bab33dfae89f54ee5bd6419781864..c25cdce54c448f33da3ae384d1bd2992745bff55 100644
--- a/app/src/main/java/de/justjanne/quasseldroid/ui/CoreInfoView.kt
+++ b/app/src/main/java/de/justjanne/quasseldroid/ui/components/CoreInfoView.kt
@@ -1,4 +1,4 @@
-package de.justjanne.quasseldroid.ui
+package de.justjanne.quasseldroid.ui.components
 
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.padding
diff --git a/app/src/main/java/de/justjanne/quasseldroid/ui/LoginView.kt b/app/src/main/java/de/justjanne/quasseldroid/ui/components/LoginView.kt
similarity index 90%
rename from app/src/main/java/de/justjanne/quasseldroid/ui/LoginView.kt
rename to app/src/main/java/de/justjanne/quasseldroid/ui/components/LoginView.kt
index bd1388dcfcb8eb1b0e1997fdd4cb8dbed371756b..2c1e30c759b8997ff616f266758815e2c5c484bd 100644
--- a/app/src/main/java/de/justjanne/quasseldroid/ui/LoginView.kt
+++ b/app/src/main/java/de/justjanne/quasseldroid/ui/components/LoginView.kt
@@ -1,4 +1,4 @@
-package de.justjanne.quasseldroid.ui
+package de.justjanne.quasseldroid.ui.components
 
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.fillMaxWidth
@@ -15,28 +15,15 @@ import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.saveable.rememberSaveable
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.focus.FocusDirection
-import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.platform.LocalFocusManager
 import androidx.compose.ui.text.input.ImeAction
 import androidx.compose.ui.text.input.TextFieldValue
 import androidx.compose.ui.tooling.preview.Preview
 import androidx.compose.ui.unit.dp
-import androidx.navigation.NavController
 import de.justjanne.quasseldroid.service.ConnectionData
-import de.justjanne.quasseldroid.service.QuasselBackend
 import de.justjanne.quasseldroid.util.TextFieldValueSaver
 import java.net.InetSocketAddress
 
-@Composable
-fun LoginRoute(backend: QuasselBackend, navController: NavController) {
-  val context = LocalContext.current
-  LoginView(onLogin = {
-    if (backend.login(context, it)) {
-      navController.navigate("home")
-    }
-  })
-}
-
 @Preview(name = "Login", showBackground = true)
 @Composable
 fun LoginView(onLogin: (ConnectionData) -> Unit = {}) {
diff --git a/app/src/main/java/de/justjanne/quasseldroid/ui/PasswordTextField.kt b/app/src/main/java/de/justjanne/quasseldroid/ui/components/PasswordTextField.kt
similarity index 98%
rename from app/src/main/java/de/justjanne/quasseldroid/ui/PasswordTextField.kt
rename to app/src/main/java/de/justjanne/quasseldroid/ui/components/PasswordTextField.kt
index a4741b39b654f8aaa378c9d90035c4e25ef5552a..978fa20da8d9c03a52d60d96360d3247d42fda05 100644
--- a/app/src/main/java/de/justjanne/quasseldroid/ui/PasswordTextField.kt
+++ b/app/src/main/java/de/justjanne/quasseldroid/ui/components/PasswordTextField.kt
@@ -1,4 +1,4 @@
-package de.justjanne.quasseldroid.ui
+package de.justjanne.quasseldroid.ui.components
 
 import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.text.KeyboardActions
diff --git a/app/src/main/java/de/justjanne/quasseldroid/ui/CoreInfoRoute.kt b/app/src/main/java/de/justjanne/quasseldroid/ui/routes/CoreInfoRoute.kt
similarity index 87%
rename from app/src/main/java/de/justjanne/quasseldroid/ui/CoreInfoRoute.kt
rename to app/src/main/java/de/justjanne/quasseldroid/ui/routes/CoreInfoRoute.kt
index c509d7c7d97f58bc3e009b914040d2ae701c6539..cc17d865f7f54618ed6d0b1641cd00cb26a5df69 100644
--- a/app/src/main/java/de/justjanne/quasseldroid/ui/CoreInfoRoute.kt
+++ b/app/src/main/java/de/justjanne/quasseldroid/ui/routes/CoreInfoRoute.kt
@@ -1,4 +1,4 @@
-package de.justjanne.quasseldroid.ui
+package de.justjanne.quasseldroid.ui.routes
 
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.padding
@@ -10,6 +10,7 @@ import androidx.compose.ui.unit.dp
 import androidx.navigation.NavController
 import de.justjanne.libquassel.protocol.util.flatMap
 import de.justjanne.quasseldroid.service.QuasselBackend
+import de.justjanne.quasseldroid.ui.components.CoreInfoView
 import de.justjanne.quasseldroid.util.mapNullable
 import de.justjanne.quasseldroid.util.rememberFlow
 
@@ -17,6 +18,7 @@ import de.justjanne.quasseldroid.util.rememberFlow
 fun CoreInfoRoute(backend: QuasselBackend, navController: NavController) {
   val coreInfo = rememberFlow(null) {
     backend.flow()
+      .mapNullable { it.session }
       .flatMap()
       .mapNullable { it.coreInfo }
       .flatMap()
diff --git a/app/src/main/java/de/justjanne/quasseldroid/ui/HomeView.kt b/app/src/main/java/de/justjanne/quasseldroid/ui/routes/HomeRoute.kt
similarity index 85%
rename from app/src/main/java/de/justjanne/quasseldroid/ui/HomeView.kt
rename to app/src/main/java/de/justjanne/quasseldroid/ui/routes/HomeRoute.kt
index e139fb4901cc9462226ea3db62926055b7c1686e..165d193baa37d58b625e4c92afc7b9f694ce1f5a 100644
--- a/app/src/main/java/de/justjanne/quasseldroid/ui/HomeView.kt
+++ b/app/src/main/java/de/justjanne/quasseldroid/ui/routes/HomeRoute.kt
@@ -1,4 +1,4 @@
-package de.justjanne.quasseldroid.ui
+package de.justjanne.quasseldroid.ui.routes
 
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.Row
@@ -7,11 +7,8 @@ import androidx.compose.foundation.lazy.items
 import androidx.compose.material.Button
 import androidx.compose.material.Text
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.saveable.rememberSaveable
 import androidx.compose.ui.platform.LocalContext
 import androidx.navigation.NavController
-import de.justjanne.libquassel.protocol.models.ids.BufferId
 import de.justjanne.libquassel.protocol.syncables.state.BufferViewConfigState
 import de.justjanne.libquassel.protocol.util.combineLatest
 import de.justjanne.libquassel.protocol.util.flatMap
@@ -20,11 +17,15 @@ import de.justjanne.quasseldroid.util.mapNullable
 import de.justjanne.quasseldroid.util.rememberFlow
 
 @Composable
-fun HomeView(backend: QuasselBackend, navController: NavController) {
-  val session = rememberFlow(null) { backend.flow() }
+fun HomeRoute(backend: QuasselBackend, navController: NavController) {
+  val session = rememberFlow(null) {
+    backend.flow()
+      .mapNullable { it.session }
+  }
 
   val bufferViewConfigs: List<BufferViewConfigState> = rememberFlow(emptyList()) {
     backend.flow()
+      .mapNullable { it.session }
       .flatMap()
       .mapNullable { it.bufferViewManager }
       .flatMap()
@@ -34,6 +35,7 @@ fun HomeView(backend: QuasselBackend, navController: NavController) {
 
   val initStatus = rememberFlow(null) {
     backend.flow()
+      .mapNullable { it.session }
       .mapNullable { it.baseInitHandler }
       .flatMap()
   }
diff --git a/app/src/main/java/de/justjanne/quasseldroid/ui/routes/LoginRoute.kt b/app/src/main/java/de/justjanne/quasseldroid/ui/routes/LoginRoute.kt
new file mode 100644
index 0000000000000000000000000000000000000000..789c050790c866e07f4230e71779dcaf485ce233
--- /dev/null
+++ b/app/src/main/java/de/justjanne/quasseldroid/ui/routes/LoginRoute.kt
@@ -0,0 +1,17 @@
+package de.justjanne.quasseldroid.ui.routes
+
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.platform.LocalContext
+import androidx.navigation.NavController
+import de.justjanne.quasseldroid.service.QuasselBackend
+import de.justjanne.quasseldroid.ui.components.LoginView
+
+@Composable
+fun LoginRoute(backend: QuasselBackend, navController: NavController) {
+  val context = LocalContext.current
+    LoginView(onLogin = {
+        if (backend.login(context, it)) {
+            navController.navigate("home")
+        }
+    })
+}
diff --git a/gradle/convention/src/main/kotlin/justjanne.kotlin.android.gradle.kts b/gradle/convention/src/main/kotlin/justjanne.kotlin.android.gradle.kts
index fc84b973d233756575149499bfcf9c589c712729..bb75c465bca06b8ede38082676fde791b72fc062 100644
--- a/gradle/convention/src/main/kotlin/justjanne.kotlin.android.gradle.kts
+++ b/gradle/convention/src/main/kotlin/justjanne.kotlin.android.gradle.kts
@@ -1,3 +1,5 @@
+import gradle.kotlin.dsl.accessors._9f9f63157b527b37420ecbe9e569524a.implementation
+import gradle.kotlin.dsl.accessors._9f9f63157b527b37420ecbe9e569524a.testImplementation
 import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 
 plugins {
@@ -8,7 +10,10 @@ plugins {
 }
 
 dependencies {
-  "implementation"("org.jetbrains.kotlin:kotlin-stdlib:1.6.10")
+  implementation("org.jetbrains.kotlin:kotlin-stdlib:1.6.10")
+  implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0")
+  implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0")
+  testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.0")
 }
 
 tasks.withType<KotlinCompile> {
diff --git a/gradle/convention/src/main/kotlin/justjanne.kotlin.gradle.kts b/gradle/convention/src/main/kotlin/justjanne.kotlin.gradle.kts
index 39b8cf9c07cfaec8bb2085d7055cce183abe7266..04838711e0b75c7dcca6bbf3ccee950be7bfa082 100644
--- a/gradle/convention/src/main/kotlin/justjanne.kotlin.gradle.kts
+++ b/gradle/convention/src/main/kotlin/justjanne.kotlin.gradle.kts
@@ -10,6 +10,8 @@ plugins {
 
 dependencies {
   implementation("org.jetbrains.kotlin:kotlin-stdlib:1.6.10")
+  implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0")
+  testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.0")
 }
 
 tasks.withType<KotlinCompile> {
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index fdcd6bae8a0f3e64a481b7984b916c8d1b6650ea..bdf9f59c73e752c7596b8641ed88c76b6210893a 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -1,5 +1,5 @@
 [versions]
-libquassel = "0.8.1"
+libquassel = "0.9.0"
 androidx-activity = "1.4.0"
 androidx-appcompat = "1.4.1"
 androidx-compose = "1.1.1"