diff --git a/Examples/xx-messenger/Sources/AppFeature/AppEnvironment+Live.swift b/Examples/xx-messenger/Sources/AppFeature/AppEnvironment+Live.swift
index 34d9f80675fd106a479ea9707c193ab810344222..cd5d752e89186c7c417cc5696ccf2e1a1367b57e 100644
--- a/Examples/xx-messenger/Sources/AppFeature/AppEnvironment+Live.swift
+++ b/Examples/xx-messenger/Sources/AppFeature/AppEnvironment+Live.swift
@@ -4,6 +4,7 @@ import ChatFeature
 import CheckContactAuthFeature
 import ConfirmRequestFeature
 import ContactFeature
+import ContactLookupFeature
 import ContactsFeature
 import Foundation
 import HomeFeature
@@ -38,7 +39,11 @@ extension AppEnvironment {
       mainQueue: mainQueue,
       bgQueue: bgQueue,
       lookup: {
-        ContactLookupEnvironment()
+        ContactLookupEnvironment(
+          messenger: messenger,
+          mainQueue: mainQueue,
+          bgQueue: bgQueue
+        )
       },
       sendRequest: {
         SendRequestEnvironment(
diff --git a/Examples/xx-messenger/Sources/ContactLookupFeature/ContactLookupFeature.swift b/Examples/xx-messenger/Sources/ContactLookupFeature/ContactLookupFeature.swift
index 7fd2fc8e893fa9dd62b0934b2030ada99c2ed94d..82a775dd574227f7e95d09f29cbd1a02cd4fd08a 100644
--- a/Examples/xx-messenger/Sources/ContactLookupFeature/ContactLookupFeature.swift
+++ b/Examples/xx-messenger/Sources/ContactLookupFeature/ContactLookupFeature.swift
@@ -1,46 +1,81 @@
 import ComposableArchitecture
 import Foundation
 import XCTestDynamicOverlay
+import XXClient
+import XXMessengerClient
 
 public struct ContactLookupState: Equatable {
   public init(
     id: Data,
-    isLookingUp: Bool = false
+    isLookingUp: Bool = false,
+    failure: String? = nil
   ) {
     self.id = id
     self.isLookingUp = isLookingUp
+    self.failure = failure
   }
 
   public var id: Data
   public var isLookingUp: Bool
+  public var failure: String?
 }
 
 public enum ContactLookupAction: Equatable {
-  case task
-  case cancelTask
   case lookupTapped
+  case didLookup(XXClient.Contact)
+  case didFail(NSError)
 }
 
 public struct ContactLookupEnvironment {
-  public init() {}
+  public init(
+    messenger: Messenger,
+    mainQueue: AnySchedulerOf<DispatchQueue>,
+    bgQueue: AnySchedulerOf<DispatchQueue>
+  ) {
+    self.messenger = messenger
+    self.mainQueue = mainQueue
+    self.bgQueue = bgQueue
+  }
+
+  public var messenger: Messenger
+  public var mainQueue: AnySchedulerOf<DispatchQueue>
+  public var bgQueue: AnySchedulerOf<DispatchQueue>
 }
 
 #if DEBUG
 extension ContactLookupEnvironment {
-  public static let unimplemented = ContactLookupEnvironment()
+  public static let unimplemented = ContactLookupEnvironment(
+    messenger: .unimplemented,
+    mainQueue: .unimplemented,
+    bgQueue: .unimplemented
+  )
 }
 #endif
 
 public let contactLookupReducer = Reducer<ContactLookupState, ContactLookupAction, ContactLookupEnvironment>
 { state, action, env in
   switch action {
-  case .task:
-    return .none
+  case .lookupTapped:
+    state.isLookingUp = true
+    return Effect.result { [state] in
+      do {
+        let contact = try env.messenger.lookupContact(id: state.id)
+        return .success(.didLookup(contact))
+      } catch {
+        return .success(.didFail(error as NSError))
+      }
+    }
+    .subscribe(on: env.bgQueue)
+    .receive(on: env.mainQueue)
+    .eraseToEffect()
 
-  case .cancelTask:
+  case .didLookup(_):
+    state.isLookingUp = false
     return .none
 
-  case .lookupTapped:
+  case .didFail(let error):
+    state.failure = error.localizedDescription
+    state.isLookingUp = false
     return .none
   }
 }
diff --git a/Examples/xx-messenger/Sources/ContactLookupFeature/ContactLookupView.swift b/Examples/xx-messenger/Sources/ContactLookupFeature/ContactLookupView.swift
index 1d1e02085ac84f849318dcf1b6548c5ee9cc4da4..a8bcd339a287e4ee003a37a673f1cc498b68bc99 100644
--- a/Examples/xx-messenger/Sources/ContactLookupFeature/ContactLookupView.swift
+++ b/Examples/xx-messenger/Sources/ContactLookupFeature/ContactLookupView.swift
@@ -45,9 +45,6 @@ public struct ContactLookupView: View {
         }
       }
       .navigationTitle("Lookup")
-      .task {
-        await viewStore.send(.task).finish()
-      }
     }
   }
 }
diff --git a/Examples/xx-messenger/Tests/ContactLookupFeatureTests/ContactLookupFeatureTests.swift b/Examples/xx-messenger/Tests/ContactLookupFeatureTests/ContactLookupFeatureTests.swift
index 70847105030548fc33490bc567bb0cc0e57b2224..34ecabc362be0541b52517d1885bffe5c8a18303 100644
--- a/Examples/xx-messenger/Tests/ContactLookupFeatureTests/ContactLookupFeatureTests.swift
+++ b/Examples/xx-messenger/Tests/ContactLookupFeatureTests/ContactLookupFeatureTests.swift
@@ -1,31 +1,57 @@
 import ComposableArchitecture
 import XCTest
+import XXClient
 @testable import ContactLookupFeature
 
 final class ContactLookupFeatureTests: XCTestCase {
-  func testTask() {
+  func testLookup() {
+    let id: Data = "1234".data(using: .utf8)!
+    var didLookupId: [Data] = []
+    let lookedUpContact = Contact.unimplemented("123data".data(using: .utf8)!)
+
     let store = TestStore(
-      initialState: ContactLookupState(
-        id: "1234".data(using: .utf8)!
-      ),
+      initialState: ContactLookupState(id: id),
       reducer: contactLookupReducer,
       environment: .unimplemented
     )
+    store.environment.mainQueue = .immediate
+    store.environment.bgQueue = .immediate
+    store.environment.messenger.lookupContact.run = { id in
+      didLookupId.append(id)
+      return lookedUpContact
+    }
+
+    store.send(.lookupTapped) {
+      $0.isLookingUp = true
+    }
 
-    store.send(.task)
+    XCTAssertEqual(didLookupId, [id])
 
-    store.send(.cancelTask)
+    store.receive(.didLookup(lookedUpContact)) {
+      $0.isLookingUp = false
+    }
   }
 
-  func testLookup() {
+  func testLookupFailure() {
+    let id: Data = "1234".data(using: .utf8)!
+    let failure = NSError(domain: "test", code: 0)
+
     let store = TestStore(
-      initialState: ContactLookupState(
-        id: "1234".data(using: .utf8)!
-      ),
+      initialState: ContactLookupState(id: id),
       reducer: contactLookupReducer,
       environment: .unimplemented
     )
+    store.environment.mainQueue = .immediate
+    store.environment.bgQueue = .immediate
+    store.environment.messenger.lookupContact.run = { _ in throw failure }
+
+    store.send(.lookupTapped) {
+      $0.isLookingUp = true
+    }
 
-    store.send(.lookupTapped)
+    store.receive(.didFail(failure)) {
+      $0.failure = failure.localizedDescription
+      $0.isLookingUp = false
+    }
   }
 }