diff --git a/Example/example-app/.swiftpm/xcode/xcshareddata/xcschemes/MyContactFeature.xcscheme b/Example/example-app/.swiftpm/xcode/xcshareddata/xcschemes/MyContactFeature.xcscheme
deleted file mode 100644
index 60c61fd3b79f6c748a322027d0ca61e8f4e8df28..0000000000000000000000000000000000000000
--- a/Example/example-app/.swiftpm/xcode/xcshareddata/xcschemes/MyContactFeature.xcscheme
+++ /dev/null
@@ -1,78 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
-   LastUpgradeVersion = "1340"
-   version = "1.3">
-   <BuildAction
-      parallelizeBuildables = "YES"
-      buildImplicitDependencies = "YES">
-      <BuildActionEntries>
-         <BuildActionEntry
-            buildForTesting = "YES"
-            buildForRunning = "YES"
-            buildForProfiling = "YES"
-            buildForArchiving = "YES"
-            buildForAnalyzing = "YES">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "MyContactFeature"
-               BuildableName = "MyContactFeature"
-               BlueprintName = "MyContactFeature"
-               ReferencedContainer = "container:">
-            </BuildableReference>
-         </BuildActionEntry>
-      </BuildActionEntries>
-   </BuildAction>
-   <TestAction
-      buildConfiguration = "Debug"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      codeCoverageEnabled = "YES">
-      <Testables>
-         <TestableReference
-            skipped = "NO">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "MyContactFeatureTests"
-               BuildableName = "MyContactFeatureTests"
-               BlueprintName = "MyContactFeatureTests"
-               ReferencedContainer = "container:">
-            </BuildableReference>
-         </TestableReference>
-      </Testables>
-   </TestAction>
-   <LaunchAction
-      buildConfiguration = "Debug"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      launchStyle = "0"
-      useCustomWorkingDirectory = "NO"
-      ignoresPersistentStateOnLaunch = "NO"
-      debugDocumentVersioning = "YES"
-      debugServiceExtension = "internal"
-      allowLocationSimulation = "YES">
-   </LaunchAction>
-   <ProfileAction
-      buildConfiguration = "Release"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      savedToolIdentifier = ""
-      useCustomWorkingDirectory = "NO"
-      debugDocumentVersioning = "YES">
-      <MacroExpansion>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "MyContactFeature"
-            BuildableName = "MyContactFeature"
-            BlueprintName = "MyContactFeature"
-            ReferencedContainer = "container:">
-         </BuildableReference>
-      </MacroExpansion>
-   </ProfileAction>
-   <AnalyzeAction
-      buildConfiguration = "Debug">
-   </AnalyzeAction>
-   <ArchiveAction
-      buildConfiguration = "Release"
-      revealArchiveInOrganizer = "YES">
-   </ArchiveAction>
-</Scheme>
diff --git a/Example/example-app/.swiftpm/xcode/xcshareddata/xcschemes/MyIdentityFeature.xcscheme b/Example/example-app/.swiftpm/xcode/xcshareddata/xcschemes/MyIdentityFeature.xcscheme
deleted file mode 100644
index e69b1d44aa7ba292ef94bb8db602faa9111304f6..0000000000000000000000000000000000000000
--- a/Example/example-app/.swiftpm/xcode/xcshareddata/xcschemes/MyIdentityFeature.xcscheme
+++ /dev/null
@@ -1,78 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
-   LastUpgradeVersion = "1340"
-   version = "1.3">
-   <BuildAction
-      parallelizeBuildables = "YES"
-      buildImplicitDependencies = "YES">
-      <BuildActionEntries>
-         <BuildActionEntry
-            buildForTesting = "YES"
-            buildForRunning = "YES"
-            buildForProfiling = "YES"
-            buildForArchiving = "YES"
-            buildForAnalyzing = "YES">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "MyIdentityFeature"
-               BuildableName = "MyIdentityFeature"
-               BlueprintName = "MyIdentityFeature"
-               ReferencedContainer = "container:">
-            </BuildableReference>
-         </BuildActionEntry>
-      </BuildActionEntries>
-   </BuildAction>
-   <TestAction
-      buildConfiguration = "Debug"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      codeCoverageEnabled = "YES">
-      <Testables>
-         <TestableReference
-            skipped = "NO">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "MyIdentityFeatureTests"
-               BuildableName = "MyIdentityFeatureTests"
-               BlueprintName = "MyIdentityFeatureTests"
-               ReferencedContainer = "container:">
-            </BuildableReference>
-         </TestableReference>
-      </Testables>
-   </TestAction>
-   <LaunchAction
-      buildConfiguration = "Debug"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      launchStyle = "0"
-      useCustomWorkingDirectory = "NO"
-      ignoresPersistentStateOnLaunch = "NO"
-      debugDocumentVersioning = "YES"
-      debugServiceExtension = "internal"
-      allowLocationSimulation = "YES">
-   </LaunchAction>
-   <ProfileAction
-      buildConfiguration = "Release"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      savedToolIdentifier = ""
-      useCustomWorkingDirectory = "NO"
-      debugDocumentVersioning = "YES">
-      <MacroExpansion>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "MyIdentityFeature"
-            BuildableName = "MyIdentityFeature"
-            BlueprintName = "MyIdentityFeature"
-            ReferencedContainer = "container:">
-         </BuildableReference>
-      </MacroExpansion>
-   </ProfileAction>
-   <AnalyzeAction
-      buildConfiguration = "Debug">
-   </AnalyzeAction>
-   <ArchiveAction
-      buildConfiguration = "Release"
-      revealArchiveInOrganizer = "YES">
-   </ArchiveAction>
-</Scheme>
diff --git a/Example/example-app/Package.swift b/Example/example-app/Package.swift
index 6aa4531627631a16dff789a4acbef611711dd361..0c4051afd5c8d97996be45242276539f93b4c88c 100644
--- a/Example/example-app/Package.swift
+++ b/Example/example-app/Package.swift
@@ -1,226 +1,180 @@
 // swift-tools-version: 5.6
-
 import PackageDescription
 
-let swiftSettings: [SwiftSetting] = [
-  .unsafeFlags(
-    [
-      "-Xfrontend",
-      "-debug-time-function-bodies",
-      "-Xfrontend",
-      "-debug-time-expression-type-checking",
-    ],
-    .when(configuration: .debug)
-  ),
-]
+// MARK: - Helpers
 
-let package = Package(
-  name: "example-app",
-  platforms: [
-    .iOS(.v15),
-  ],
-  products: [
-    .library(
-      name: "AppFeature",
-      targets: ["AppFeature"]
-    ),
-    .library(
-      name: "ErrorFeature",
-      targets: ["ErrorFeature"]
-    ),
-    .library(
-      name: "LandingFeature",
-      targets: ["LandingFeature"]
-    ),
-    .library(
-      name: "MyContactFeature",
-      targets: ["MyContactFeature"]
-    ),
-    .library(
-      name: "MyIdentityFeature",
-      targets: ["MyIdentityFeature"]
-    ),
-    .library(
-      name: "SessionFeature",
-      targets: ["SessionFeature"]
-    ),
-  ],
-  dependencies: [
-    .package(path: "../../"), // elixxir-dapps-sdk-swift
-    .package(
-      url: "https://github.com/pointfreeco/swift-composable-architecture.git",
-      .upToNextMajor(from: "0.35.0")
-    ),
-    .package(
-      url: "https://github.com/darrarski/swift-composable-presentation.git",
-      .upToNextMajor(from: "0.5.2")
-    ),
-    .package(
-      url: "https://github.com/kishikawakatsumi/KeychainAccess.git",
-      .upToNextMajor(from: "4.2.2")
-    ),
-  ],
-  targets: [
-    .target(
-      name: "AppFeature",
-      dependencies: [
-        .target(name: "ErrorFeature"),
-        .target(name: "LandingFeature"),
-        .target(name: "MyContactFeature"),
-        .target(name: "MyIdentityFeature"),
-        .target(name: "SessionFeature"),
-        .product(
-          name: "ElixxirDAppsSDK",
-          package: "elixxir-dapps-sdk-swift"
-        ),
-        .product(
-          name: "ComposableArchitecture",
-          package: "swift-composable-architecture"
-        ),
-        .product(
-          name: "ComposablePresentation",
-          package: "swift-composable-presentation"
-        ),
-        .product(
-          name: "KeychainAccess",
-          package: "KeychainAccess"
-        ),
-      ],
-      swiftSettings: swiftSettings
-    ),
-    .testTarget(
-      name: "AppFeatureTests",
-      dependencies: [
-        .target(name: "AppFeature"),
-      ],
-      swiftSettings: swiftSettings
-    ),
-    .target(
-      name: "ErrorFeature",
-      dependencies: [
-        .product(
-          name: "ComposableArchitecture",
-          package: "swift-composable-architecture"
-        ),
-        .product(
-          name: "ElixxirDAppsSDK",
-          package: "elixxir-dapps-sdk-swift"
-        ),
-      ],
-      swiftSettings: swiftSettings
-    ),
-    .testTarget(
-      name: "ErrorFeatureTests",
-      dependencies: [
-        .target(name: "ErrorFeature"),
-      ],
-      swiftSettings: swiftSettings
-    ),
-    .target(
-      name: "LandingFeature",
-      dependencies: [
-        .target(name: "ErrorFeature"),
-        .product(
-          name: "ComposableArchitecture",
-          package: "swift-composable-architecture"
-        ),
-        .product(
-          name: "ComposablePresentation",
-          package: "swift-composable-presentation"
-        ),
-        .product(
-          name: "ElixxirDAppsSDK",
-          package: "elixxir-dapps-sdk-swift"
-        ),
-      ],
-      swiftSettings: swiftSettings
-    ),
-    .testTarget(
-      name: "LandingFeatureTests",
-      dependencies: [
-        .target(name: "LandingFeature"),
-      ],
-      swiftSettings: swiftSettings
-    ),
-    .target(
-      name: "MyContactFeature",
-      dependencies: [
-        .target(name: "ErrorFeature"),
-        .product(
-          name: "ComposableArchitecture",
-          package: "swift-composable-architecture"
-        ),
-        .product(
-          name: "ComposablePresentation",
-          package: "swift-composable-presentation"
-        ),
-        .product(
-          name: "ElixxirDAppsSDK",
-          package: "elixxir-dapps-sdk-swift"
-        ),
-      ],
-      swiftSettings: swiftSettings
-    ),
-    .testTarget(
-      name: "MyContactFeatureTests",
-      dependencies: [
-        .target(name: "MyContactFeature"),
-      ],
-      swiftSettings: swiftSettings
-    ),
-    .target(
-      name: "MyIdentityFeature",
-      dependencies: [
-        .target(name: "ErrorFeature"),
-        .product(
-          name: "ComposableArchitecture",
-          package: "swift-composable-architecture"
-        ),
-        .product(
-          name: "ComposablePresentation",
-          package: "swift-composable-presentation"
-        ),
-        .product(
-          name: "ElixxirDAppsSDK",
-          package: "elixxir-dapps-sdk-swift"
-        ),
-      ],
-      swiftSettings: swiftSettings
-    ),
-    .testTarget(
-      name: "MyIdentityFeatureTests",
-      dependencies: [
-        .target(name: "MyIdentityFeature"),
-      ],
-      swiftSettings: swiftSettings
-    ),
-    .target(
-      name: "SessionFeature",
-      dependencies: [
-        .target(name: "ErrorFeature"),
-        .target(name: "MyContactFeature"),
-        .target(name: "MyIdentityFeature"),
-        .product(
-          name: "ComposableArchitecture",
-          package: "swift-composable-architecture"
-        ),
-        .product(
-          name: "ComposablePresentation",
-          package: "swift-composable-presentation"
-        ),
-        .product(
-          name: "ElixxirDAppsSDK",
-          package: "elixxir-dapps-sdk-swift"
+struct Feature {
+  var product: Product
+  var targets: [Target]
+  var targetDependency: Target.Dependency
+
+  static func library(
+    name: String,
+    dependencies: [Target.Dependency] = [],
+    testDependencies: [Target.Dependency] = [],
+    swiftSettings: [SwiftSetting] = [
+      .unsafeFlags(
+        [
+          "-Xfrontend",
+          "-debug-time-function-bodies",
+          "-Xfrontend",
+          "-debug-time-expression-type-checking",
+        ],
+        .when(configuration: .debug)
+      ),
+    ]
+  ) -> Feature {
+    .init(
+      product: .library(name: name, targets: [name]),
+      targets: [
+        .target(
+          name: name,
+          dependencies: dependencies,
+          swiftSettings: swiftSettings
+        ),
+        .testTarget(
+          name: "\(name)Tests",
+          dependencies: [.target(name: name)] + testDependencies,
+          swiftSettings: swiftSettings
         ),
       ],
-      swiftSettings: swiftSettings
-    ),
-    .testTarget(
-      name: "SessionFeatureTests",
-      dependencies: [
-        .target(name: "SessionFeature"),
-      ],
-      swiftSettings: swiftSettings
-    ),
+      targetDependency: .target(name: name)
+    )
+  }
+}
+
+struct Dependency {
+  var packageDependency: Package.Dependency
+  var targetDependency: Target.Dependency
+
+  static func local(
+    path: String,
+    name: String,
+    package: String
+  ) -> Dependency {
+    .init(
+      packageDependency: .package(path: path),
+      targetDependency: .product(name: name, package: package)
+    )
+  }
+
+  static func external(
+    url: String,
+    version: Range<Version>,
+    name: String,
+    package: String
+  ) -> Dependency {
+    .init(
+      packageDependency: .package(url: url, version),
+      targetDependency: .product(name: name, package: package)
+    )
+  }
+}
+
+// MARK: - Manifest
+
+extension Dependency {
+  static let all: [Dependency] = [
+    .composableArchitecture,
+    .composablePresentation,
+    .elixxirDAppsSDK,
+    .keychainAccess,
+    .xcTestDynamicOverlay,
   ]
+
+  static let composableArchitecture = Dependency.external(
+    url: "https://github.com/pointfreeco/swift-composable-architecture.git",
+    version: .upToNextMajor(from: "0.38.3"),
+    name: "ComposableArchitecture",
+    package: "swift-composable-architecture"
+  )
+
+  static let composablePresentation = Dependency.external(
+    url: "https://github.com/darrarski/swift-composable-presentation.git",
+    version: .upToNextMajor(from: "0.5.2"),
+    name: "ComposablePresentation",
+    package: "swift-composable-presentation"
+  )
+
+  static let elixxirDAppsSDK = Dependency.local(
+    path: "../../",
+    name: "ElixxirDAppsSDK",
+    package: "elixxir-dapps-sdk-swift"
+  )
+
+  static let keychainAccess = Dependency.external(
+    url: "https://github.com/kishikawakatsumi/KeychainAccess.git",
+    version: .upToNextMajor(from: "4.2.2"),
+    name: "KeychainAccess",
+    package: "KeychainAccess"
+  )
+
+  static let xcTestDynamicOverlay = Dependency.external(
+    url: "https://github.com/pointfreeco/xctest-dynamic-overlay.git",
+    version: .upToNextMajor(from: "0.3.3"),
+    name: "XCTestDynamicOverlay",
+    package: "xctest-dynamic-overlay"
+  )
+}
+
+extension Feature {
+  static let all: [Feature] = [
+    .app,
+    .error,
+    .landing,
+    .session,
+  ]
+
+  static let app = Feature.library(
+    name: "AppFeature",
+    dependencies: [
+      Feature.error.targetDependency,
+      Feature.landing.targetDependency,
+      Feature.session.targetDependency,
+      Dependency.composableArchitecture.targetDependency,
+      Dependency.composablePresentation.targetDependency,
+      Dependency.elixxirDAppsSDK.targetDependency,
+      Dependency.keychainAccess.targetDependency,
+      Dependency.xcTestDynamicOverlay.targetDependency,
+    ]
+  )
+
+  static let error = Feature.library(
+    name: "ErrorFeature",
+    dependencies: [
+      Dependency.composableArchitecture.targetDependency,
+      Dependency.elixxirDAppsSDK.targetDependency,
+      Dependency.xcTestDynamicOverlay.targetDependency,
+    ]
+  )
+
+  static let landing = Feature.library(
+    name: "LandingFeature",
+    dependencies: [
+      Feature.error.targetDependency,
+      Dependency.composableArchitecture.targetDependency,
+      Dependency.composablePresentation.targetDependency,
+      Dependency.elixxirDAppsSDK.targetDependency,
+      Dependency.xcTestDynamicOverlay.targetDependency,
+    ]
+  )
+
+  static let session = Feature.library(
+    name: "SessionFeature",
+    dependencies: [
+      Feature.error.targetDependency,
+      Dependency.composableArchitecture.targetDependency,
+      Dependency.composablePresentation.targetDependency,
+      Dependency.elixxirDAppsSDK.targetDependency,
+      Dependency.xcTestDynamicOverlay.targetDependency,
+    ]
+  )
+}
+
+let package = Package(
+  name: "example-app",
+  platforms: [.iOS(.v15)],
+  products: Feature.all.map(\.product),
+  dependencies: Dependency.all.map(\.packageDependency),
+  targets: Feature.all.flatMap(\.targets)
 )
diff --git a/Example/example-app/Sources/AppFeature/App.swift b/Example/example-app/Sources/AppFeature/App.swift
index 65f4728edaf4f763712e3e9ef425e923135ba2ef..2ad3db435adb6e6ee674b09f5d8878cb4d8bea6e 100644
--- a/Example/example-app/Sources/AppFeature/App.swift
+++ b/Example/example-app/Sources/AppFeature/App.swift
@@ -3,8 +3,6 @@ import ComposableArchitecture
 import ElixxirDAppsSDK
 import ErrorFeature
 import LandingFeature
-import MyContactFeature
-import MyIdentityFeature
 import SessionFeature
 import SwiftUI
 
@@ -23,9 +21,7 @@ struct App: SwiftUI.App {
 
 extension AppEnvironment {
   static func live() -> AppEnvironment {
-    let clientSubject = CurrentValueSubject<Client?, Never>(nil)
-    let identitySubject = CurrentValueSubject<Identity?, Never>(nil)
-    let contactSubject = CurrentValueSubject<Data?, Never>(nil)
+    let cmixSubject = CurrentValueSubject<Cmix?, Never>(nil)
     let mainScheduler = DispatchQueue.main.eraseToAnyScheduler()
     let bgScheduler = DispatchQueue(
       label: "xx.network.dApps.ExampleApp.bg",
@@ -34,40 +30,22 @@ extension AppEnvironment {
 
     return AppEnvironment(
       makeId: UUID.init,
-      hasClient: clientSubject.map { $0 != nil }.eraseToAnyPublisher(),
+      hasCmix: { cmixSubject.map { $0 != nil }.eraseToAnyPublisher() },
       mainScheduler: mainScheduler,
       landing: LandingEnvironment(
-        clientStorage: .live(
+        cmixManager: .live(
           passwordStorage: .keychain
         ),
-        setClient: { clientSubject.send($0) },
+        setCmix: { cmixSubject.value = $0 },
         bgScheduler: bgScheduler,
         mainScheduler: mainScheduler,
         error: ErrorEnvironment()
       ),
       session: SessionEnvironment(
-        getClient: { clientSubject.value },
+        getCmix: { cmixSubject.value },
         bgScheduler: bgScheduler,
         mainScheduler: mainScheduler,
-        makeId: UUID.init,
-        error: ErrorEnvironment(),
-        myIdentity: MyIdentityEnvironment(
-          getClient: { clientSubject.value },
-          observeIdentity: { identitySubject.eraseToAnyPublisher() },
-          updateIdentity: { identitySubject.value = $0 },
-          bgScheduler: bgScheduler,
-          mainScheduler: mainScheduler,
-          error: ErrorEnvironment()
-        ),
-        myContact: MyContactEnvironment(
-          getClient: { clientSubject.value },
-          getIdentity: { identitySubject.value },
-          observeContact: { contactSubject.eraseToAnyPublisher() },
-          updateContact: { contactSubject.value = $0 },
-          bgScheduler: bgScheduler,
-          mainScheduler: mainScheduler,
-          error: ErrorEnvironment()
-        )
+        error: ErrorEnvironment()
       )
     )
   }
diff --git a/Example/example-app/Sources/AppFeature/AppFeature.swift b/Example/example-app/Sources/AppFeature/AppFeature.swift
index 347c13b151a70c09e0188a4e3cd5f4ac690d4c08..f9ce028759020d50a8853ebc55aff84530e0a710 100644
--- a/Example/example-app/Sources/AppFeature/AppFeature.swift
+++ b/Example/example-app/Sources/AppFeature/AppFeature.swift
@@ -3,6 +3,7 @@ import ComposableArchitecture
 import ComposablePresentation
 import LandingFeature
 import SessionFeature
+import XCTestDynamicOverlay
 
 struct AppState: Equatable {
   enum Scene: Equatable {
@@ -40,14 +41,14 @@ extension AppState.Scene {
 
 enum AppAction: Equatable {
   case viewDidLoad
-  case clientDidChange(hasClient: Bool)
+  case cmixDidChange(hasCmix: Bool)
   case landing(LandingAction)
   case session(SessionAction)
 }
 
 struct AppEnvironment {
   var makeId: () -> UUID
-  var hasClient: AnyPublisher<Bool, Never>
+  var hasCmix: () -> AnyPublisher<Bool, Never>
   var mainScheduler: AnySchedulerOf<DispatchQueue>
   var landing: LandingEnvironment
   var session: SessionEnvironment
@@ -55,19 +56,18 @@ struct AppEnvironment {
 
 let appReducer = Reducer<AppState, AppAction, AppEnvironment>
 { state, action, env in
+  enum HasCmixEffectId {}
+
   switch action {
   case .viewDidLoad:
-    struct HasClientEffectId: Hashable {
-      var id: UUID
-    }
-    return env.hasClient
+    return env.hasCmix()
       .removeDuplicates()
-      .map(AppAction.clientDidChange(hasClient:))
+      .map(AppAction.cmixDidChange(hasCmix:))
       .receive(on: env.mainScheduler)
       .eraseToEffect()
-      .cancellable(id: HasClientEffectId(id: state.id), cancelInFlight: true)
+      .cancellable(id: HasCmixEffectId.self, cancelInFlight: true)
 
-  case .clientDidChange(let hasClient):
+  case .cmixDidChange(let hasClient):
     if hasClient {
       let sessionState = state.scene.asSession ?? SessionState(id: env.makeId())
       state.scene = .session(sessionState)
@@ -96,14 +96,12 @@ let appReducer = Reducer<AppState, AppAction, AppEnvironment>
   environment: \.session
 )
 
-#if DEBUG
 extension AppEnvironment {
-  static let failing = AppEnvironment(
-    makeId: { fatalError() },
-    hasClient: Empty().eraseToAnyPublisher(),
-    mainScheduler: .failing,
-    landing: .failing,
-    session: .failing
+  static let unimplemented = AppEnvironment(
+    makeId: XCTUnimplemented("\(Self.self).makeId"),
+    hasCmix: XCTUnimplemented("\(Self.self).hasCmix"),
+    mainScheduler: .unimplemented,
+    landing: .unimplemented,
+    session: .unimplemented
   )
 }
-#endif
diff --git a/Example/example-app/Sources/ErrorFeature/ErrorFeature.swift b/Example/example-app/Sources/ErrorFeature/ErrorFeature.swift
index dc7d8b69db96f23837fd62a352dbe8d4f0f2e2f0..eb1671e8424a7db0ee5ccb12c8fef9289d1277da 100644
--- a/Example/example-app/Sources/ErrorFeature/ErrorFeature.swift
+++ b/Example/example-app/Sources/ErrorFeature/ErrorFeature.swift
@@ -1,5 +1,5 @@
 import ComposableArchitecture
-import SwiftUI
+import XCTestDynamicOverlay
 
 public struct ErrorState: Equatable {
   public init(error: NSError) {
@@ -17,8 +17,6 @@ public struct ErrorEnvironment {
 
 public let errorReducer = Reducer<ErrorState, ErrorAction, ErrorEnvironment>.empty
 
-#if DEBUG
 extension ErrorEnvironment {
-  public static let failing = ErrorEnvironment()
+  public static let unimplemented = ErrorEnvironment()
 }
-#endif
diff --git a/Example/example-app/Sources/LandingFeature/LandingFeature.swift b/Example/example-app/Sources/LandingFeature/LandingFeature.swift
index 511b1107b0afed85ddcbf2a9a03c3b99841a055b..f8fa2d9db3a439f112d2b47edd39914d587f1b37 100644
--- a/Example/example-app/Sources/LandingFeature/LandingFeature.swift
+++ b/Example/example-app/Sources/LandingFeature/LandingFeature.swift
@@ -2,58 +2,59 @@ import Combine
 import ComposableArchitecture
 import ElixxirDAppsSDK
 import ErrorFeature
+import XCTestDynamicOverlay
 
 public struct LandingState: Equatable {
   public init(
     id: UUID,
-    hasStoredClient: Bool = false,
-    isMakingClient: Bool = false,
-    isRemovingClient: Bool = false,
+    hasStoredCmix: Bool = false,
+    isMakingCmix: Bool = false,
+    isRemovingCmix: Bool = false,
     error: ErrorState? = nil
   ) {
     self.id = id
-    self.hasStoredClient = hasStoredClient
-    self.isMakingClient = isMakingClient
-    self.isRemovingClient = isRemovingClient
+    self.hasStoredCmix = hasStoredCmix
+    self.isMakingCmix = isMakingCmix
+    self.isRemovingCmix = isRemovingCmix
     self.error = error
   }
 
   var id: UUID
-  var hasStoredClient: Bool
-  var isMakingClient: Bool
-  var isRemovingClient: Bool
+  var hasStoredCmix: Bool
+  var isMakingCmix: Bool
+  var isRemovingCmix: Bool
   var error: ErrorState?
 }
 
 public enum LandingAction: Equatable {
   case viewDidLoad
-  case makeClient
-  case didMakeClient
-  case didFailMakingClient(NSError)
-  case removeStoredClient
-  case didRemoveStoredClient
-  case didFailRemovingStoredClient(NSError)
+  case makeCmix
+  case didMakeCmix
+  case didFailMakingCmix(NSError)
+  case removeStoredCmix
+  case didRemoveStoredCmix
+  case didFailRemovingStoredCmix(NSError)
   case didDismissError
   case error(ErrorAction)
 }
 
 public struct LandingEnvironment {
   public init(
-    clientStorage: ClientStorage,
-    setClient: @escaping (Client) -> Void,
+    cmixManager: CmixManager,
+    setCmix: @escaping (Cmix) -> Void,
     bgScheduler: AnySchedulerOf<DispatchQueue>,
     mainScheduler: AnySchedulerOf<DispatchQueue>,
     error: ErrorEnvironment
   ) {
-    self.clientStorage = clientStorage
-    self.setClient = setClient
+    self.cmixManager = cmixManager
+    self.setCmix = setCmix
     self.bgScheduler = bgScheduler
     self.mainScheduler = mainScheduler
     self.error = error
   }
 
-  public var clientStorage: ClientStorage
-  public var setClient: (Client) -> Void
+  public var cmixManager: CmixManager
+  public var setCmix: (Cmix) -> Void
   public var bgScheduler: AnySchedulerOf<DispatchQueue>
   public var mainScheduler: AnySchedulerOf<DispatchQueue>
   public var error: ErrorEnvironment
@@ -63,60 +64,60 @@ public let landingReducer = Reducer<LandingState, LandingAction, LandingEnvironm
 { state, action, env in
   switch action {
   case .viewDidLoad:
-    state.hasStoredClient = env.clientStorage.hasStoredClient()
+    state.hasStoredCmix = env.cmixManager.hasStorage()
     return .none
 
-  case .makeClient:
-    state.isMakingClient = true
+  case .makeCmix:
+    state.isMakingCmix = true
     return Effect.future { fulfill in
       do {
-        if env.clientStorage.hasStoredClient() {
-          env.setClient(try env.clientStorage.loadClient())
+        if env.cmixManager.hasStorage() {
+          env.setCmix(try env.cmixManager.load())
         } else {
-          env.setClient(try env.clientStorage.createClient())
+          env.setCmix(try env.cmixManager.create())
         }
-        fulfill(.success(.didMakeClient))
+        fulfill(.success(.didMakeCmix))
       } catch {
-        fulfill(.success(.didFailMakingClient(error as NSError)))
+        fulfill(.success(.didFailMakingCmix(error as NSError)))
       }
     }
     .subscribe(on: env.bgScheduler)
     .receive(on: env.mainScheduler)
     .eraseToEffect()
 
-  case .didMakeClient:
-    state.isMakingClient = false
-    state.hasStoredClient = env.clientStorage.hasStoredClient()
+  case .didMakeCmix:
+    state.isMakingCmix = false
+    state.hasStoredCmix = env.cmixManager.hasStorage()
     return .none
 
-  case .didFailMakingClient(let error):
-    state.isMakingClient = false
-    state.hasStoredClient = env.clientStorage.hasStoredClient()
+  case .didFailMakingCmix(let error):
+    state.isMakingCmix = false
+    state.hasStoredCmix = env.cmixManager.hasStorage()
     state.error = ErrorState(error: error)
     return .none
 
-  case .removeStoredClient:
-    state.isRemovingClient = true
+  case .removeStoredCmix:
+    state.isRemovingCmix = true
     return Effect.future { fulfill in
       do {
-        try env.clientStorage.removeClient()
-        fulfill(.success(.didRemoveStoredClient))
+        try env.cmixManager.remove()
+        fulfill(.success(.didRemoveStoredCmix))
       } catch {
-        fulfill(.success(.didFailRemovingStoredClient(error as NSError)))
+        fulfill(.success(.didFailRemovingStoredCmix(error as NSError)))
       }
     }
     .subscribe(on: env.bgScheduler)
     .receive(on: env.mainScheduler)
     .eraseToEffect()
 
-  case .didRemoveStoredClient:
-    state.isRemovingClient = false
-    state.hasStoredClient = env.clientStorage.hasStoredClient()
+  case .didRemoveStoredCmix:
+    state.isRemovingCmix = false
+    state.hasStoredCmix = env.cmixManager.hasStorage()
     return .none
 
-  case .didFailRemovingStoredClient(let error):
-    state.isRemovingClient = false
-    state.hasStoredClient = env.clientStorage.hasStoredClient()
+  case .didFailRemovingStoredCmix(let error):
+    state.isRemovingCmix = false
+    state.hasStoredCmix = env.cmixManager.hasStorage()
     state.error = ErrorState(error: error)
     return .none
 
@@ -133,14 +134,12 @@ public let landingReducer = Reducer<LandingState, LandingAction, LandingEnvironm
   environment: \.error
 )
 
-#if DEBUG
 extension LandingEnvironment {
-  public static let failing = LandingEnvironment(
-    clientStorage: .failing,
-    setClient: { _ in fatalError() },
-    bgScheduler: .failing,
-    mainScheduler: .failing,
-    error: .failing
+  public static let unimplemented = LandingEnvironment(
+    cmixManager: .unimplemented,
+    setCmix: XCTUnimplemented("\(Self.self).setCmix"),
+    bgScheduler: .unimplemented,
+    mainScheduler: .unimplemented,
+    error: .unimplemented
   )
 }
-#endif
diff --git a/Example/example-app/Sources/LandingFeature/LandingView.swift b/Example/example-app/Sources/LandingFeature/LandingView.swift
index 4a45669a3538af966d54876187964d4697a59ee5..f52aeebb80bc75f503060b642ffaf97b9c843f27 100644
--- a/Example/example-app/Sources/LandingFeature/LandingView.swift
+++ b/Example/example-app/Sources/LandingFeature/LandingView.swift
@@ -11,19 +11,19 @@ public struct LandingView: View {
   let store: Store<LandingState, LandingAction>
 
   struct ViewState: Equatable {
-    let hasStoredClient: Bool
-    let isMakingClient: Bool
-    let isRemovingClient: Bool
+    let hasStoredCmix: Bool
+    let isMakingCmix: Bool
+    let isRemovingCmix: Bool
 
     init(state: LandingState) {
-      hasStoredClient = state.hasStoredClient
-      isMakingClient = state.isMakingClient
-      isRemovingClient = state.isRemovingClient
+      hasStoredCmix = state.hasStoredCmix
+      isMakingCmix = state.isMakingCmix
+      isRemovingCmix = state.isRemovingCmix
     }
 
     var isLoading: Bool {
-      isMakingClient ||
-      isRemovingClient
+      isMakingCmix ||
+      isRemovingCmix
     }
   }
 
@@ -31,25 +31,25 @@ public struct LandingView: View {
     WithViewStore(store.scope(state: ViewState.init)) { viewStore in
       Form {
         Button {
-          viewStore.send(.makeClient)
+          viewStore.send(.makeCmix)
         } label: {
           HStack {
-            Text(viewStore.hasStoredClient ? "Load stored client" : "Create new client")
+            Text(viewStore.hasStoredCmix ? "Load stored cMix" : "Create new cMix")
             Spacer()
-            if viewStore.isMakingClient {
+            if viewStore.isMakingCmix {
               ProgressView()
             }
           }
         }
 
-        if viewStore.hasStoredClient {
+        if viewStore.hasStoredCmix {
           Button(role: .destructive) {
-            viewStore.send(.removeStoredClient)
+            viewStore.send(.removeStoredCmix)
           } label: {
             HStack {
-              Text("Remove stored client")
+              Text("Remove stored cMix")
               Spacer()
-              if viewStore.isRemovingClient {
+              if viewStore.isRemovingCmix {
                 ProgressView()
               }
             }
diff --git a/Example/example-app/Sources/MyContactFeature/MyContactFeature.swift b/Example/example-app/Sources/MyContactFeature/MyContactFeature.swift
deleted file mode 100644
index 317b646f1f7b5897f1cd4b4829f41cd8e67fd259..0000000000000000000000000000000000000000
--- a/Example/example-app/Sources/MyContactFeature/MyContactFeature.swift
+++ /dev/null
@@ -1,138 +0,0 @@
-import Combine
-import ComposableArchitecture
-import ComposablePresentation
-import ElixxirDAppsSDK
-import ErrorFeature
-
-public struct MyContactState: Equatable {
-  public init(
-    id: UUID,
-    contact: Data? = nil,
-    isMakingContact: Bool = false,
-    error: ErrorState? = nil
-  ) {
-    self.id = id
-    self.contact = contact
-    self.isMakingContact = isMakingContact
-    self.error = error
-  }
-
-  public var id: UUID
-  public var contact: Data?
-  public var isMakingContact: Bool
-  public var error: ErrorState?
-}
-
-public enum MyContactAction: Equatable {
-  case viewDidLoad
-  case observeMyContact
-  case didUpdateMyContact(Data?)
-  case makeContact
-  case didFinishMakingContact(NSError?)
-  case didDismissError
-  case error(ErrorAction)
-}
-
-public struct MyContactEnvironment {
-  public init(
-    getClient: @escaping () -> Client?,
-    getIdentity: @escaping () -> Identity?,
-    observeContact: @escaping () -> AnyPublisher<Data?, Never>,
-    updateContact: @escaping (Data?) -> Void,
-    bgScheduler: AnySchedulerOf<DispatchQueue>,
-    mainScheduler: AnySchedulerOf<DispatchQueue>,
-    error: ErrorEnvironment
-  ) {
-    self.getClient = getClient
-    self.getIdentity = getIdentity
-    self.observeContact = observeContact
-    self.updateContact = updateContact
-    self.bgScheduler = bgScheduler
-    self.mainScheduler = mainScheduler
-    self.error = error
-  }
-
-  public var getClient: () -> Client?
-  public var getIdentity: () -> Identity?
-  public var observeContact: () -> AnyPublisher<Data?, Never>
-  public var updateContact: (Data?) -> Void
-  public var bgScheduler: AnySchedulerOf<DispatchQueue>
-  public var mainScheduler: AnySchedulerOf<DispatchQueue>
-  public var error: ErrorEnvironment
-}
-
-public let myContactReducer = Reducer<MyContactState, MyContactAction, MyContactEnvironment>
-{ state, action, env in
-  switch action {
-  case .viewDidLoad:
-    return .merge([
-      .init(value: .observeMyContact),
-    ])
-
-  case .observeMyContact:
-    struct EffectId: Hashable {
-      let id: UUID
-    }
-    return env.observeContact()
-      .removeDuplicates()
-      .map(MyContactAction.didUpdateMyContact)
-      .subscribe(on: env.bgScheduler)
-      .receive(on: env.mainScheduler)
-      .eraseToEffect()
-      .cancellable(id: EffectId(id: state.id), cancelInFlight: true)
-
-  case .didUpdateMyContact(let contact):
-    state.contact = contact
-    return .none
-
-  case .makeContact:
-    state.isMakingContact = true
-    return Effect.future { fulfill in
-      guard let identity = env.getIdentity() else {
-        fulfill(.success(.didFinishMakingContact(NoIdentityError() as NSError)))
-        return
-      }
-      do {
-        env.updateContact(try env.getClient()?.makeContactFromIdentity(identity: identity))
-        fulfill(.success(.didFinishMakingContact(nil)))
-      } catch {
-        fulfill(.success(.didFinishMakingContact(error as NSError)))
-      }
-    }
-    .subscribe(on: env.bgScheduler)
-    .receive(on: env.mainScheduler)
-    .eraseToEffect()
-
-  case .didFinishMakingContact(let error):
-    state.isMakingContact = false
-    if let error = error {
-      state.error = ErrorState(error: error)
-    }
-    return .none
-
-  case .didDismissError:
-    state.error = nil
-    return .none
-
-  case .error(_):
-    return .none
-  }
-}
-
-public struct NoIdentityError: Error, LocalizedError {
-  public init() {}
-}
-
-#if DEBUG
-extension MyContactEnvironment {
-  public static let failing = MyContactEnvironment(
-    getClient: { fatalError() },
-    getIdentity: { fatalError() },
-    observeContact: { fatalError() },
-    updateContact: { _ in fatalError() },
-    bgScheduler: .failing,
-    mainScheduler: .failing,
-    error: .failing
-  )
-}
-#endif
diff --git a/Example/example-app/Sources/MyContactFeature/MyContactView.swift b/Example/example-app/Sources/MyContactFeature/MyContactView.swift
deleted file mode 100644
index 88f9d4b8fa84272d7ef3695fed506410d4010aa1..0000000000000000000000000000000000000000
--- a/Example/example-app/Sources/MyContactFeature/MyContactView.swift
+++ /dev/null
@@ -1,90 +0,0 @@
-import ComposableArchitecture
-import ComposablePresentation
-import ElixxirDAppsSDK
-import ErrorFeature
-import SwiftUI
-
-public struct MyContactView: View {
-  public init(store: Store<MyContactState, MyContactAction>) {
-    self.store = store
-  }
-
-  let store: Store<MyContactState, MyContactAction>
-
-  struct ViewState: Equatable {
-    let contact: Data?
-    let isMakingContact: Bool
-
-    init(state: MyContactState) {
-      contact = state.contact
-      isMakingContact = state.isMakingContact
-    }
-
-    var isLoading: Bool {
-      isMakingContact
-    }
-  }
-
-  public var body: some View {
-    WithViewStore(store.scope(state: ViewState.init)) { viewStore in
-      Form {
-        Section {
-          Text(string(for: viewStore.contact))
-            .textSelection(.enabled)
-        }
-
-        Section {
-          Button {
-            viewStore.send(.makeContact)
-          } label: {
-            HStack {
-              Text("Make contact from identity")
-              Spacer()
-              if viewStore.isMakingContact {
-                ProgressView()
-              }
-            }
-          }
-        }
-        .disabled(viewStore.isLoading)
-      }
-      .navigationTitle("My contact")
-      .navigationBarBackButtonHidden(viewStore.isLoading)
-      .task {
-        viewStore.send(.viewDidLoad)
-      }
-      .sheet(
-        store.scope(
-          state: \.error,
-          action: MyContactAction.error
-        ),
-        onDismiss: {
-          viewStore.send(.didDismissError)
-        },
-        content: ErrorView.init(store:)
-      )
-    }
-  }
-
-  func string(for contact: Data?) -> String {
-    guard let contact = contact else {
-      return "No contact"
-    }
-    return String(data: contact, encoding: .utf8) ?? "Decoding error"
-  }
-}
-
-#if DEBUG
-public struct MyContactView_Previews: PreviewProvider {
-  public static var previews: some View {
-    NavigationView {
-      MyContactView(store: .init(
-        initialState: .init(id: UUID()),
-        reducer: .empty,
-        environment: ()
-      ))
-    }
-    .navigationViewStyle(.stack)
-  }
-}
-#endif
diff --git a/Example/example-app/Sources/MyIdentityFeature/MyIdentityFeature.swift b/Example/example-app/Sources/MyIdentityFeature/MyIdentityFeature.swift
deleted file mode 100644
index df4559d5cb56cb3f47c0ad79c57bbe5c0296a3bb..0000000000000000000000000000000000000000
--- a/Example/example-app/Sources/MyIdentityFeature/MyIdentityFeature.swift
+++ /dev/null
@@ -1,129 +0,0 @@
-import Combine
-import ComposableArchitecture
-import ComposablePresentation
-import ElixxirDAppsSDK
-import ErrorFeature
-
-public struct MyIdentityState: Equatable {
-  public init(
-    id: UUID,
-    identity: Identity? = nil,
-    isMakingIdentity: Bool = false,
-    error: ErrorState? = nil
-  ) {
-    self.id = id
-    self.isMakingIdentity = isMakingIdentity
-    self.error = error
-  }
-
-  public var id: UUID
-  public var identity: Identity?
-  public var isMakingIdentity: Bool
-  public var error: ErrorState?
-}
-
-public enum MyIdentityAction: Equatable {
-  case viewDidLoad
-  case observeMyIdentity
-  case didUpdateMyIdentity(Identity?)
-  case makeIdentity
-  case didFinishMakingIdentity(NSError?)
-  case didDismissError
-  case error(ErrorAction)
-}
-
-public struct MyIdentityEnvironment {
-  public init(
-    getClient: @escaping () -> Client?,
-    observeIdentity: @escaping () -> AnyPublisher<Identity?, Never>,
-    updateIdentity: @escaping (Identity?) -> Void,
-    bgScheduler: AnySchedulerOf<DispatchQueue>,
-    mainScheduler: AnySchedulerOf<DispatchQueue>,
-    error: ErrorEnvironment
-  ) {
-    self.getClient = getClient
-    self.observeIdentity = observeIdentity
-    self.updateIdentity = updateIdentity
-    self.bgScheduler = bgScheduler
-    self.mainScheduler = mainScheduler
-    self.error = error
-  }
-
-  public var getClient: () -> Client?
-  public var observeIdentity: () -> AnyPublisher<Identity?, Never>
-  public var updateIdentity: (Identity?) -> Void
-  public var bgScheduler: AnySchedulerOf<DispatchQueue>
-  public var mainScheduler: AnySchedulerOf<DispatchQueue>
-  public var error: ErrorEnvironment
-}
-
-public let myIdentityReducer = Reducer<MyIdentityState, MyIdentityAction, MyIdentityEnvironment>
-{ state, action, env in
-  switch action {
-  case .viewDidLoad:
-    return .merge([
-      .init(value: .observeMyIdentity),
-    ])
-
-  case .observeMyIdentity:
-    struct EffectId: Hashable {
-      let id: UUID
-    }
-    return env.observeIdentity()
-      .removeDuplicates()
-      .map(MyIdentityAction.didUpdateMyIdentity)
-      .subscribe(on: env.bgScheduler)
-      .receive(on: env.mainScheduler)
-      .eraseToEffect()
-      .cancellable(id: EffectId(id: state.id), cancelInFlight: true)
-
-  case .didUpdateMyIdentity(let identity):
-    state.identity = identity
-    return .none
-
-  case .makeIdentity:
-    state.isMakingIdentity = true
-    return Effect.future { fulfill in
-      do {
-        env.updateIdentity(try env.getClient()?.makeIdentity())
-        fulfill(.success(.didFinishMakingIdentity(nil)))
-      } catch {
-        fulfill(.success(.didFinishMakingIdentity(error as NSError)))
-      }
-    }
-    .subscribe(on: env.bgScheduler)
-    .receive(on: env.mainScheduler)
-    .eraseToEffect()
-
-  case .didDismissError:
-    state.error = nil
-    return .none
-
-  case .didFinishMakingIdentity(let error):
-    state.isMakingIdentity = false
-    if let error = error {
-      state.error = ErrorState(error: error)
-    }
-    return .none
-  }
-}
-.presenting(
-  errorReducer,
-  state: .keyPath(\.error),
-  id: .keyPath(\.?.error),
-  action: /MyIdentityAction.error,
-  environment: \.error
-)
-
-#if DEBUG
-extension MyIdentityEnvironment {
-  public static let failing = MyIdentityEnvironment(
-    getClient: { fatalError() },
-    observeIdentity: { fatalError() },
-    updateIdentity: { _ in fatalError() },
-    bgScheduler: .failing,
-    mainScheduler: .failing,
-    error: .failing
-  )
-}
-#endif
diff --git a/Example/example-app/Sources/MyIdentityFeature/MyIdentityView.swift b/Example/example-app/Sources/MyIdentityFeature/MyIdentityView.swift
deleted file mode 100644
index 61e09c1355755a7f1955e91ad7054d78f3689f5a..0000000000000000000000000000000000000000
--- a/Example/example-app/Sources/MyIdentityFeature/MyIdentityView.swift
+++ /dev/null
@@ -1,97 +0,0 @@
-import ComposableArchitecture
-import ComposablePresentation
-import ElixxirDAppsSDK
-import ErrorFeature
-import SwiftUI
-
-public struct MyIdentityView: View {
-  public init(store: Store<MyIdentityState, MyIdentityAction>) {
-    self.store = store
-  }
-
-  let store: Store<MyIdentityState, MyIdentityAction>
-
-  struct ViewState: Equatable {
-    let identity: Identity?
-    let isMakingIdentity: Bool
-
-    init(state: MyIdentityState) {
-      identity = state.identity
-      isMakingIdentity = state.isMakingIdentity
-    }
-
-    var isLoading: Bool {
-      isMakingIdentity
-    }
-  }
-
-  public var body: some View {
-    WithViewStore(store.scope(state: ViewState.init)) { viewStore in
-      Form {
-        Section {
-          Text(string(for: viewStore.identity))
-            .textSelection(.enabled)
-        }
-
-        Section {
-          Button {
-            viewStore.send(.makeIdentity)
-          } label: {
-            HStack {
-              Text("Make new identity")
-              Spacer()
-              if viewStore.isMakingIdentity {
-                ProgressView()
-              }
-            }
-          }
-        }
-        .disabled(viewStore.isLoading)
-      }
-      .navigationTitle("My identity")
-      .navigationBarBackButtonHidden(viewStore.isLoading)
-      .task {
-        viewStore.send(.viewDidLoad)
-      }
-      .sheet(
-        store.scope(
-          state: \.error,
-          action: MyIdentityAction.error
-        ),
-        onDismiss: {
-          viewStore.send(.didDismissError)
-        },
-        content: ErrorView.init(store:)
-      )
-    }
-  }
-
-  func string(for identity: Identity?) -> String {
-    guard let identity = identity else {
-      return "No identity"
-    }
-    let encoder = JSONEncoder()
-    encoder.outputFormatting = .prettyPrinted
-    do {
-      let data = try encoder.encode(identity)
-      return String(data: data, encoding: .utf8) ?? "Decoding error"
-    } catch {
-      return "Decoding error: \(error)"
-    }
-  }
-}
-
-#if DEBUG
-public struct MyIdentityView_Previews: PreviewProvider {
-  public static var previews: some View {
-    NavigationView {
-      MyIdentityView(store: .init(
-        initialState: .init(id: UUID()),
-        reducer: .empty,
-        environment: ()
-      ))
-    }
-    .navigationViewStyle(.stack)
-  }
-}
-#endif
diff --git a/Example/example-app/Sources/SessionFeature/NetworkFollowerStatusView.swift b/Example/example-app/Sources/SessionFeature/NetworkFollowerStatusView.swift
index 5d1ba1dee39fba281819f0865cfaecd73bae6038..dbb06c4f6646859cbfe4e1a5b05343d68e10f2a6 100644
--- a/Example/example-app/Sources/SessionFeature/NetworkFollowerStatusView.swift
+++ b/Example/example-app/Sources/SessionFeature/NetworkFollowerStatusView.swift
@@ -9,9 +9,6 @@ struct NetworkFollowerStatusView: View {
     case .stopped:
       Label("Stopped", systemImage: "stop.fill")
 
-    case .starting:
-      Label("Starting...", systemImage: "play")
-
     case .running:
       Label("Running", systemImage: "play.fill")
 
@@ -32,7 +29,6 @@ struct NetworkFollowerStatusView_Previews: PreviewProvider {
   static var previews: some View {
     Group {
       NetworkFollowerStatusView(status: .stopped)
-      NetworkFollowerStatusView(status: .starting)
       NetworkFollowerStatusView(status: .running)
       NetworkFollowerStatusView(status: .stopping)
       NetworkFollowerStatusView(status: .unknown(code: -1))
diff --git a/Example/example-app/Sources/SessionFeature/SessionFeature.swift b/Example/example-app/Sources/SessionFeature/SessionFeature.swift
index 5b1005a9a632e62978cc8a66294566e2f1ba4069..a5bd6f9cb07099ea08483bed50941b371566f59f 100644
--- a/Example/example-app/Sources/SessionFeature/SessionFeature.swift
+++ b/Example/example-app/Sources/SessionFeature/SessionFeature.swift
@@ -2,32 +2,25 @@ import Combine
 import ComposableArchitecture
 import ElixxirDAppsSDK
 import ErrorFeature
-import MyContactFeature
-import MyIdentityFeature
+import XCTestDynamicOverlay
 
 public struct SessionState: Equatable {
   public init(
     id: UUID,
     networkFollowerStatus: NetworkFollowerStatus? = nil,
     isNetworkHealthy: Bool? = nil,
-    error: ErrorState? = nil,
-    myIdentity: MyIdentityState? = nil,
-    myContact: MyContactState? = nil
+    error: ErrorState? = nil
   ) {
     self.id = id
     self.networkFollowerStatus = networkFollowerStatus
     self.isNetworkHealthy = isNetworkHealthy
     self.error = error
-    self.myIdentity = myIdentity
-    self.myContact = myContact
   }
 
   public var id: UUID
   public var networkFollowerStatus: NetworkFollowerStatus?
   public var isNetworkHealthy: Bool?
   public var error: ErrorState?
-  public var myIdentity: MyIdentityState?
-  public var myContact: MyContactState?
 }
 
 public enum SessionAction: Equatable {
@@ -39,41 +32,26 @@ public enum SessionAction: Equatable {
   case monitorNetworkHealth(Bool)
   case didUpdateNetworkHealth(Bool?)
   case didDismissError
-  case presentMyIdentity
-  case didDismissMyIdentity
-  case presentMyContact
-  case didDismissMyContact
   case error(ErrorAction)
-  case myIdentity(MyIdentityAction)
-  case myContact(MyContactAction)
 }
 
 public struct SessionEnvironment {
   public init(
-    getClient: @escaping () -> Client?,
+    getCmix: @escaping () -> Cmix?,
     bgScheduler: AnySchedulerOf<DispatchQueue>,
     mainScheduler: AnySchedulerOf<DispatchQueue>,
-    makeId: @escaping () -> UUID,
-    error: ErrorEnvironment,
-    myIdentity: MyIdentityEnvironment,
-    myContact: MyContactEnvironment
+    error: ErrorEnvironment
   ) {
-    self.getClient = getClient
+    self.getCmix = getCmix
     self.bgScheduler = bgScheduler
     self.mainScheduler = mainScheduler
-    self.makeId = makeId
     self.error = error
-    self.myIdentity = myIdentity
-    self.myContact = myContact
   }
 
-  public var getClient: () -> Client?
+  public var getCmix: () -> Cmix?
   public var bgScheduler: AnySchedulerOf<DispatchQueue>
   public var mainScheduler: AnySchedulerOf<DispatchQueue>
-  public var makeId: () -> UUID
   public var error: ErrorEnvironment
-  public var myIdentity: MyIdentityEnvironment
-  public var myContact: MyContactEnvironment
 }
 
 public let sessionReducer = Reducer<SessionState, SessionAction, SessionEnvironment>
@@ -87,7 +65,7 @@ public let sessionReducer = Reducer<SessionState, SessionAction, SessionEnvironm
 
   case .updateNetworkFollowerStatus:
     return Effect.future { fulfill in
-      let status = env.getClient()?.networkFollower.status()
+      let status = env.getCmix()?.networkFollowerStatus()
       fulfill(.success(.didUpdateNetworkFollowerStatus(status)))
     }
     .subscribe(on: env.bgScheduler)
@@ -99,18 +77,17 @@ public let sessionReducer = Reducer<SessionState, SessionAction, SessionEnvironm
     return .none
 
   case .runNetworkFollower(let start):
-    state.networkFollowerStatus = start ? .starting : .stopping
     return Effect.run { subscriber in
       do {
         if start {
-          try env.getClient()?.networkFollower.start(timeoutMS: 30_000)
+          try env.getCmix()?.startNetworkFollower(timeoutMS: 30_000)
         } else {
-          try env.getClient()?.networkFollower.stop()
+          try env.getCmix()?.stopNetworkFollower()
         }
       } catch {
         subscriber.send(.networkFollowerDidFail(error as NSError))
       }
-      let status = env.getClient()?.networkFollower.status()
+      let status = env.getCmix()?.networkFollowerStatus()
       subscriber.send(.didUpdateNetworkFollowerStatus(status))
       subscriber.send(completion: .finished)
       return AnyCancellable {}
@@ -130,9 +107,10 @@ public let sessionReducer = Reducer<SessionState, SessionAction, SessionEnvironm
     let effectId = MonitorEffectId(id: state.id)
     if start {
       return Effect.run { subscriber in
-        var cancellable = env.getClient()?.monitorNetworkHealth { isHealthy in
+        let callback = HealthCallback { isHealthy in
           subscriber.send(.didUpdateNetworkHealth(isHealthy))
         }
+        let cancellable = env.getCmix()?.addHealthCallback(callback)
         return AnyCancellable {
           cancellable?.cancel()
         }
@@ -155,27 +133,7 @@ public let sessionReducer = Reducer<SessionState, SessionAction, SessionEnvironm
     state.error = nil
     return .none
 
-  case .presentMyIdentity:
-    if state.myIdentity == nil {
-      state.myIdentity = MyIdentityState(id: env.makeId())
-    }
-    return .none
-
-  case .didDismissMyIdentity:
-    state.myIdentity = nil
-    return .none
-
-  case .presentMyContact:
-    if state.myContact == nil {
-      state.myContact = MyContactState(id: env.makeId())
-    }
-    return .none
-
-  case .didDismissMyContact:
-    state.myContact = nil
-    return .none
-
-  case .error(_), .myIdentity(_), .myContact(_):
+  case .error(_):
     return .none
   }
 }
@@ -186,31 +144,12 @@ public let sessionReducer = Reducer<SessionState, SessionAction, SessionEnvironm
   action: /SessionAction.error,
   environment: \.error
 )
-.presenting(
-  myIdentityReducer,
-  state: .keyPath(\.myIdentity),
-  id: .keyPath(\.?.id),
-  action: /SessionAction.myIdentity,
-  environment: \.myIdentity
-)
-.presenting(
-  myContactReducer,
-  state: .keyPath(\.myContact),
-  id: .keyPath(\.?.id),
-  action: /SessionAction.myContact,
-  environment: \.myContact
-)
 
-#if DEBUG
 extension SessionEnvironment {
-  public static let failing = SessionEnvironment(
-    getClient: { .failing },
-    bgScheduler: .failing,
-    mainScheduler: .failing,
-    makeId: { fatalError() },
-    error: .failing,
-    myIdentity: .failing,
-    myContact: .failing
+  public static let unimplemented = SessionEnvironment(
+    getCmix: XCTUnimplemented("\(Self.self).getCmix"),
+    bgScheduler: .unimplemented,
+    mainScheduler: .unimplemented,
+    error: .unimplemented
   )
 }
-#endif
diff --git a/Example/example-app/Sources/SessionFeature/SessionView.swift b/Example/example-app/Sources/SessionFeature/SessionView.swift
index ea14d91ff94358572a9462647044186b3c47ab6a..395cfcb160067fedc31ec3ddd5200aa6960864e2 100644
--- a/Example/example-app/Sources/SessionFeature/SessionView.swift
+++ b/Example/example-app/Sources/SessionFeature/SessionView.swift
@@ -2,8 +2,6 @@ import ComposableArchitecture
 import ComposablePresentation
 import ElixxirDAppsSDK
 import ErrorFeature
-import MyContactFeature
-import MyIdentityFeature
 import SwiftUI
 
 public struct SessionView: View {
@@ -51,28 +49,6 @@ public struct SessionView: View {
         } header: {
           Text("Network health")
         }
-
-        Section {
-          Button {
-            viewStore.send(.presentMyIdentity)
-          } label: {
-            HStack {
-              Text("My identity")
-              Spacer()
-              Image(systemName: "chevron.forward")
-            }
-          }
-
-          Button {
-            viewStore.send(.presentMyContact)
-          } label: {
-            HStack {
-              Text("My contact")
-              Spacer()
-              Image(systemName: "chevron.forward")
-            }
-          }
-        }
       }
       .navigationTitle("Session")
       .task {
@@ -88,30 +64,6 @@ public struct SessionView: View {
         },
         content: ErrorView.init(store:)
       )
-      .background(
-        NavigationLinkWithStore(
-          store.scope(
-            state: \.myIdentity,
-            action: SessionAction.myIdentity
-          ),
-          onDeactivate: {
-            viewStore.send(.didDismissMyIdentity)
-          },
-          destination: MyIdentityView.init(store:)
-        )
-      )
-      .background(
-        NavigationLinkWithStore(
-          store.scope(
-            state: \.myContact,
-            action: SessionAction.myContact
-          ),
-          onDeactivate: {
-            viewStore.send(.didDismissMyContact)
-          },
-          destination: MyContactView.init(store:)
-        )
-      )
     }
   }
 }
diff --git a/Example/example-app/Tests/AppFeatureTests/AppFeatureTests.swift b/Example/example-app/Tests/AppFeatureTests/AppFeatureTests.swift
index ce5891ed1d1e147abdca7390420e2888e82321a5..24abccd89477d96029c36a768a735d5f3bc59828 100644
--- a/Example/example-app/Tests/AppFeatureTests/AppFeatureTests.swift
+++ b/Example/example-app/Tests/AppFeatureTests/AppFeatureTests.swift
@@ -8,45 +8,44 @@ import XCTest
 final class AppFeatureTests: XCTestCase {
   func testViewDidLoad() throws {
     let newId = UUID()
-    let hasClient = PassthroughSubject<Bool, Never>()
+    let hasCmix = PassthroughSubject<Bool, Never>()
     let mainScheduler = DispatchQueue.test
 
-    var env = AppEnvironment.failing
-    env.makeId = { newId }
-    env.hasClient = hasClient.eraseToAnyPublisher()
-    env.mainScheduler = mainScheduler.eraseToAnyScheduler()
-
     let store = TestStore(
       initialState: AppState(),
       reducer: appReducer,
-      environment: env
+      environment: .unimplemented
     )
 
+    store.environment.makeId = { newId }
+    store.environment.hasCmix = { hasCmix.eraseToAnyPublisher() }
+    store.environment.mainScheduler = mainScheduler.eraseToAnyScheduler()
+
     store.send(.viewDidLoad)
 
-    hasClient.send(false)
+    hasCmix.send(false)
     mainScheduler.advance()
 
-    store.receive(.clientDidChange(hasClient: false))
+    store.receive(.cmixDidChange(hasCmix: false))
 
-    hasClient.send(true)
+    hasCmix.send(true)
     mainScheduler.advance()
 
-    store.receive(.clientDidChange(hasClient: true)) {
+    store.receive(.cmixDidChange(hasCmix: true)) {
       $0.scene = .session(SessionState(id: newId))
     }
 
-    hasClient.send(true)
+    hasCmix.send(true)
     mainScheduler.advance()
 
-    hasClient.send(false)
+    hasCmix.send(false)
     mainScheduler.advance()
 
-    store.receive(.clientDidChange(hasClient: false)) {
+    store.receive(.cmixDidChange(hasCmix: false)) {
       $0.scene = .landing(LandingState(id: newId))
     }
 
-    hasClient.send(completion: .finished)
+    hasCmix.send(completion: .finished)
     mainScheduler.advance()
   }
 }
diff --git a/Example/example-app/Tests/LandingFeatureTests/LandingFeatureTests.swift b/Example/example-app/Tests/LandingFeatureTests/LandingFeatureTests.swift
index c5b56f988cd96cf0f8a8c9e03ab2afad9ef885cc..cb52fb7b3b50c0e1cf39d8e6af5e509c1988686b 100644
--- a/Example/example-app/Tests/LandingFeatureTests/LandingFeatureTests.swift
+++ b/Example/example-app/Tests/LandingFeatureTests/LandingFeatureTests.swift
@@ -5,183 +5,177 @@ import XCTest
 
 final class LandingFeatureTests: XCTestCase {
   func testViewDidLoad() throws {
-    var env = LandingEnvironment.failing
-    env.clientStorage.hasStoredClient = { true }
-
     let store = TestStore(
       initialState: LandingState(id: UUID()),
       reducer: landingReducer,
-      environment: env
+      environment: .unimplemented
     )
 
+    store.environment.cmixManager.hasStorage.run = { true }
+
     store.send(.viewDidLoad) {
-      $0.hasStoredClient = true
+      $0.hasStoredCmix = true
     }
   }
 
-  func testCreateClient() {
-    var hasStoredClient = false
-    var didSetClient = false
+  func testCreateCmix() {
+    var hasStoredCmix = false
+    var didSetCmix = false
     let bgScheduler = DispatchQueue.test
     let mainScheduler = DispatchQueue.test
 
-    var env = LandingEnvironment.failing
-    env.clientStorage.hasStoredClient = { hasStoredClient }
-    env.clientStorage.createClient = { .failing }
-    env.setClient = { _ in didSetClient = true }
-    env.bgScheduler = bgScheduler.eraseToAnyScheduler()
-    env.mainScheduler = mainScheduler.eraseToAnyScheduler()
-
     let store = TestStore(
       initialState: LandingState(id: UUID()),
       reducer: landingReducer,
-      environment: env
+      environment: .unimplemented
     )
 
-    store.send(.makeClient) {
-      $0.isMakingClient = true
+    store.environment.cmixManager.hasStorage.run = { hasStoredCmix }
+    store.environment.cmixManager.create.run = { .unimplemented }
+    store.environment.setCmix = { _ in didSetCmix = true }
+    store.environment.bgScheduler = bgScheduler.eraseToAnyScheduler()
+    store.environment.mainScheduler = mainScheduler.eraseToAnyScheduler()
+
+    store.send(.makeCmix) {
+      $0.isMakingCmix = true
     }
 
     bgScheduler.advance()
 
-    XCTAssertTrue(didSetClient)
+    XCTAssertTrue(didSetCmix)
 
-    hasStoredClient = true
+    hasStoredCmix = true
     mainScheduler.advance()
 
-    store.receive(.didMakeClient) {
-      $0.isMakingClient = false
-      $0.hasStoredClient = true
+    store.receive(.didMakeCmix) {
+      $0.isMakingCmix = false
+      $0.hasStoredCmix = true
     }
   }
 
-  func testLoadStoredClient() {
-    var didSetClient = false
+  func testLoadStoredCmix() {
+    var didSetCmix = false
     let bgScheduler = DispatchQueue.test
     let mainScheduler = DispatchQueue.test
 
-    var env = LandingEnvironment.failing
-    env.clientStorage.hasStoredClient = { true }
-    env.clientStorage.loadClient = { .failing }
-    env.setClient = { _ in didSetClient = true }
-    env.bgScheduler = bgScheduler.eraseToAnyScheduler()
-    env.mainScheduler = mainScheduler.eraseToAnyScheduler()
-
     let store = TestStore(
       initialState: LandingState(id: UUID()),
       reducer: landingReducer,
-      environment: env
+      environment: .unimplemented
     )
 
-    store.send(.makeClient) {
-      $0.isMakingClient = true
+    store.environment.cmixManager.hasStorage.run = { true }
+    store.environment.cmixManager.load.run = { .unimplemented }
+    store.environment.setCmix = { _ in didSetCmix = true }
+    store.environment.bgScheduler = bgScheduler.eraseToAnyScheduler()
+    store.environment.mainScheduler = mainScheduler.eraseToAnyScheduler()
+
+    store.send(.makeCmix) {
+      $0.isMakingCmix = true
     }
 
     bgScheduler.advance()
 
-    XCTAssertTrue(didSetClient)
+    XCTAssertTrue(didSetCmix)
 
     mainScheduler.advance()
 
-    store.receive(.didMakeClient) {
-      $0.isMakingClient = false
-      $0.hasStoredClient = true
+    store.receive(.didMakeCmix) {
+      $0.isMakingCmix = false
+      $0.hasStoredCmix = true
     }
   }
 
-  func testMakeClientFailure() {
+  func testMakeCmixFailure() {
     let error = NSError(domain: "test", code: 1234)
     let bgScheduler = DispatchQueue.test
     let mainScheduler = DispatchQueue.test
 
-    var env = LandingEnvironment.failing
-    env.clientStorage.hasStoredClient = { false }
-    env.clientStorage.createClient = { throw error }
-    env.bgScheduler = bgScheduler.eraseToAnyScheduler()
-    env.mainScheduler = mainScheduler.eraseToAnyScheduler()
-
     let store = TestStore(
       initialState: LandingState(id: UUID()),
       reducer: landingReducer,
-      environment: env
+      environment: .unimplemented
     )
 
-    store.send(.makeClient) {
-      $0.isMakingClient = true
+    store.environment.cmixManager.hasStorage.run = { false }
+    store.environment.cmixManager.create.run = { throw error }
+    store.environment.bgScheduler = bgScheduler.eraseToAnyScheduler()
+    store.environment.mainScheduler = mainScheduler.eraseToAnyScheduler()
+
+    store.send(.makeCmix) {
+      $0.isMakingCmix = true
     }
 
     bgScheduler.advance()
     mainScheduler.advance()
 
-    store.receive(.didFailMakingClient(error)) {
-      $0.isMakingClient = false
-      $0.hasStoredClient = false
+    store.receive(.didFailMakingCmix(error)) {
+      $0.isMakingCmix = false
+      $0.hasStoredCmix = false
       $0.error = ErrorState(error: error)
     }
   }
 
-  func testRemoveStoredClient() {
-    var hasStoredClient = true
-    var didRemoveClient = false
+  func testRemoveStoredCmix() {
+    var hasStoredCmix = true
+    var didRemoveCmix = false
     let bgScheduler = DispatchQueue.test
     let mainScheduler = DispatchQueue.test
 
-    var env = LandingEnvironment.failing
-    env.clientStorage.hasStoredClient = { hasStoredClient }
-    env.clientStorage.removeClient = { didRemoveClient = true }
-    env.bgScheduler = bgScheduler.eraseToAnyScheduler()
-    env.mainScheduler = mainScheduler.eraseToAnyScheduler()
-
     let store = TestStore(
       initialState: LandingState(id: UUID()),
       reducer: landingReducer,
-      environment: env
+      environment: .unimplemented
     )
 
-    store.send(.removeStoredClient) {
-      $0.isRemovingClient = true
+    store.environment.cmixManager.hasStorage.run = { hasStoredCmix }
+    store.environment.cmixManager.remove.run = { didRemoveCmix = true }
+    store.environment.bgScheduler = bgScheduler.eraseToAnyScheduler()
+    store.environment.mainScheduler = mainScheduler.eraseToAnyScheduler()
+
+    store.send(.removeStoredCmix) {
+      $0.isRemovingCmix = true
     }
 
     bgScheduler.advance()
 
-    XCTAssertTrue(didRemoveClient)
+    XCTAssertTrue(didRemoveCmix)
 
-    hasStoredClient = false
+    hasStoredCmix = false
     mainScheduler.advance()
 
-    store.receive(.didRemoveStoredClient) {
-      $0.isRemovingClient = false
-      $0.hasStoredClient = false
+    store.receive(.didRemoveStoredCmix) {
+      $0.isRemovingCmix = false
+      $0.hasStoredCmix = false
     }
   }
 
-  func testRemoveStoredClientFailure() {
+  func testRemoveStoredCmixFailure() {
     let error = NSError(domain: "test", code: 1234)
     let bgScheduler = DispatchQueue.test
     let mainScheduler = DispatchQueue.test
 
-    var env = LandingEnvironment.failing
-    env.clientStorage.hasStoredClient = { true }
-    env.clientStorage.removeClient = { throw error }
-    env.bgScheduler = bgScheduler.eraseToAnyScheduler()
-    env.mainScheduler = mainScheduler.eraseToAnyScheduler()
-
     let store = TestStore(
       initialState: LandingState(id: UUID()),
       reducer: landingReducer,
-      environment: env
+      environment: .unimplemented
     )
 
-    store.send(.removeStoredClient) {
-      $0.isRemovingClient = true
+    store.environment.cmixManager.hasStorage.run = { true }
+    store.environment.cmixManager.remove.run = { throw error }
+    store.environment.bgScheduler = bgScheduler.eraseToAnyScheduler()
+    store.environment.mainScheduler = mainScheduler.eraseToAnyScheduler()
+
+    store.send(.removeStoredCmix) {
+      $0.isRemovingCmix = true
     }
 
     bgScheduler.advance()
     mainScheduler.advance()
 
-    store.receive(.didFailRemovingStoredClient(error)) {
-      $0.isRemovingClient = false
-      $0.hasStoredClient = true
+    store.receive(.didFailRemovingStoredCmix(error)) {
+      $0.isRemovingCmix = false
+      $0.hasStoredCmix = true
       $0.error = ErrorState(error: error)
     }
   }
diff --git a/Example/example-app/Tests/MyContactFeatureTests/MyContactFeatureTests.swift b/Example/example-app/Tests/MyContactFeatureTests/MyContactFeatureTests.swift
deleted file mode 100644
index 862be08da221c884a14875b3ceb86010788073f4..0000000000000000000000000000000000000000
--- a/Example/example-app/Tests/MyContactFeatureTests/MyContactFeatureTests.swift
+++ /dev/null
@@ -1,174 +0,0 @@
-import Combine
-import ComposableArchitecture
-import CustomDump
-import ElixxirDAppsSDK
-import ErrorFeature
-import XCTest
-@testable import MyContactFeature
-
-final class MyContactFeatureTests: XCTestCase {
-  func testViewDidLoad() {
-    let myContactSubject = PassthroughSubject<Data?, Never>()
-    let bgScheduler = DispatchQueue.test
-    let mainScheduler = DispatchQueue.test
-
-    var env = MyContactEnvironment.failing
-    env.observeContact = { myContactSubject.eraseToAnyPublisher() }
-    env.bgScheduler = bgScheduler.eraseToAnyScheduler()
-    env.mainScheduler = mainScheduler.eraseToAnyScheduler()
-
-    let store = TestStore(
-      initialState: MyContactState(id: UUID()),
-      reducer: myContactReducer,
-      environment: env
-    )
-
-    store.send(.viewDidLoad)
-    store.receive(.observeMyContact)
-
-    bgScheduler.advance()
-    let contact = "\(Int.random(in: 100...999))".data(using: .utf8)!
-    myContactSubject.send(contact)
-    mainScheduler.advance()
-
-    store.receive(.didUpdateMyContact(contact)) {
-      $0.contact = contact
-    }
-
-    myContactSubject.send(nil)
-    mainScheduler.advance()
-
-    store.receive(.didUpdateMyContact(nil)) {
-      $0.contact = nil
-    }
-
-    myContactSubject.send(completion: .finished)
-    mainScheduler.advance()
-  }
-
-  func testMakeContact() {
-    let identity = Identity.stub()
-    let newContact = "\(Int.random(in: 100...999))".data(using: .utf8)!
-    var didMakeContactFromIdentity = [Identity]()
-    var didUpdateContact = [Data?]()
-    let bgScheduler = DispatchQueue.test
-    let mainScheduler = DispatchQueue.test
-
-    var env = MyContactEnvironment.failing
-    env.getClient = {
-      var client = Client.failing
-      client.makeContactFromIdentity.get = { identity in
-        didMakeContactFromIdentity.append(identity)
-        return newContact
-      }
-      return client
-    }
-    env.updateContact = { didUpdateContact.append($0) }
-    env.getIdentity = { identity }
-    env.bgScheduler = bgScheduler.eraseToAnyScheduler()
-    env.mainScheduler = mainScheduler.eraseToAnyScheduler()
-
-    let store = TestStore(
-      initialState: MyContactState(id: UUID()),
-      reducer: myContactReducer,
-      environment: env
-    )
-
-    store.send(.makeContact) {
-      $0.isMakingContact = true
-    }
-
-    bgScheduler.advance()
-
-    XCTAssertNoDifference(didMakeContactFromIdentity, [identity])
-    XCTAssertNoDifference(didUpdateContact, [newContact])
-
-    mainScheduler.advance()
-
-    store.receive(.didFinishMakingContact(nil)) {
-      $0.isMakingContact = false
-    }
-  }
-
-  func testMakeContactWithoutIdentity() {
-    let error = NoIdentityError() as NSError
-    let bgScheduler = DispatchQueue.test
-    let mainScheduler = DispatchQueue.test
-
-    var env = MyContactEnvironment.failing
-    env.getIdentity = { nil }
-    env.bgScheduler = bgScheduler.eraseToAnyScheduler()
-    env.mainScheduler = mainScheduler.eraseToAnyScheduler()
-
-    let store = TestStore(
-      initialState: MyContactState(id: UUID()),
-      reducer: myContactReducer,
-      environment: env
-    )
-
-    store.send(.makeContact) {
-      $0.isMakingContact = true
-    }
-
-    bgScheduler.advance()
-    mainScheduler.advance()
-
-    store.receive(.didFinishMakingContact(error)) {
-      $0.isMakingContact = false
-      $0.error = ErrorState(error: error)
-    }
-
-    store.send(.didDismissError) {
-      $0.error = nil
-    }
-  }
-
-  func testMakeContactFailure() {
-    let error = NSError(domain: "test", code: 1234)
-    let bgScheduler = DispatchQueue.test
-    let mainScheduler = DispatchQueue.test
-
-    var env = MyContactEnvironment.failing
-    env.getClient = {
-      var client = Client.failing
-      client.makeContactFromIdentity.get = { _ in throw error }
-      return client
-    }
-    env.getIdentity = { .stub() }
-    env.bgScheduler = bgScheduler.eraseToAnyScheduler()
-    env.mainScheduler = mainScheduler.eraseToAnyScheduler()
-
-    let store = TestStore(
-      initialState: MyContactState(id: UUID()),
-      reducer: myContactReducer,
-      environment: env
-    )
-
-    store.send(.makeContact) {
-      $0.isMakingContact = true
-    }
-
-    bgScheduler.advance()
-    mainScheduler.advance()
-
-    store.receive(.didFinishMakingContact(error)) {
-      $0.isMakingContact = false
-      $0.error = ErrorState(error: error)
-    }
-
-    store.send(.didDismissError) {
-      $0.error = nil
-    }
-  }
-}
-
-private extension Identity {
-  static func stub() -> Identity {
-    Identity(
-      id: "\(Int.random(in: 100...999))".data(using: .utf8)!,
-      rsaPrivatePem: "\(Int.random(in: 100...999))".data(using: .utf8)!,
-      salt: "\(Int.random(in: 100...999))".data(using: .utf8)!,
-      dhKeyPrivate: "\(Int.random(in: 100...999))".data(using: .utf8)!
-    )
-  }
-}
diff --git a/Example/example-app/Tests/MyIdentityFeatureTests/MyIdentityFeatureTests.swift b/Example/example-app/Tests/MyIdentityFeatureTests/MyIdentityFeatureTests.swift
deleted file mode 100644
index b426cc0fbd26c49bc14b462db938b1eb27afb712..0000000000000000000000000000000000000000
--- a/Example/example-app/Tests/MyIdentityFeatureTests/MyIdentityFeatureTests.swift
+++ /dev/null
@@ -1,133 +0,0 @@
-import Combine
-import ComposableArchitecture
-import CustomDump
-import ElixxirDAppsSDK
-import ErrorFeature
-import XCTest
-@testable import MyIdentityFeature
-
-final class MyIdentityFeatureTests: XCTestCase {
-  func testViewDidLoad() {
-    let myIdentitySubject = PassthroughSubject<Identity?, Never>()
-    let bgScheduler = DispatchQueue.test
-    let mainScheduler = DispatchQueue.test
-
-    var env = MyIdentityEnvironment.failing
-    env.observeIdentity = { myIdentitySubject.eraseToAnyPublisher() }
-    env.bgScheduler = bgScheduler.eraseToAnyScheduler()
-    env.mainScheduler = mainScheduler.eraseToAnyScheduler()
-
-    let store = TestStore(
-      initialState: MyIdentityState(id: UUID()),
-      reducer: myIdentityReducer,
-      environment: env
-    )
-
-    store.send(.viewDidLoad)
-    store.receive(.observeMyIdentity)
-
-    bgScheduler.advance()
-    let identity = Identity.stub()
-    myIdentitySubject.send(identity)
-    mainScheduler.advance()
-
-    store.receive(.didUpdateMyIdentity(identity)) {
-      $0.identity = identity
-    }
-
-    myIdentitySubject.send(nil)
-    mainScheduler.advance()
-
-    store.receive(.didUpdateMyIdentity(nil)) {
-      $0.identity = nil
-    }
-
-    myIdentitySubject.send(completion: .finished)
-    mainScheduler.advance()
-  }
-
-  func testMakeIdentity() {
-    let newIdentity = Identity.stub()
-    var didUpdateIdentity = [Identity?]()
-    let bgScheduler = DispatchQueue.test
-    let mainScheduler = DispatchQueue.test
-
-    var env = MyIdentityEnvironment.failing
-    env.getClient = {
-      var client = Client.failing
-      client.makeIdentity.make = { newIdentity }
-      return client
-    }
-    env.updateIdentity = { didUpdateIdentity.append($0) }
-    env.bgScheduler = bgScheduler.eraseToAnyScheduler()
-    env.mainScheduler = mainScheduler.eraseToAnyScheduler()
-
-    let store = TestStore(
-      initialState: MyIdentityState(id: UUID()),
-      reducer: myIdentityReducer,
-      environment: env
-    )
-
-    store.send(.makeIdentity) {
-      $0.isMakingIdentity = true
-    }
-
-    bgScheduler.advance()
-
-    XCTAssertNoDifference(didUpdateIdentity, [newIdentity])
-
-    mainScheduler.advance()
-
-    store.receive(.didFinishMakingIdentity(nil)) {
-      $0.isMakingIdentity = false
-    }
-  }
-
-  func testMakeIdentityFailure() {
-    let error = NSError(domain: "test", code: 1234)
-    let bgScheduler = DispatchQueue.test
-    let mainScheduler = DispatchQueue.test
-
-    var env = MyIdentityEnvironment.failing
-    env.getClient = {
-      var client = Client.failing
-      client.makeIdentity.make = { throw error }
-      return client
-    }
-    env.bgScheduler = bgScheduler.eraseToAnyScheduler()
-    env.mainScheduler = mainScheduler.eraseToAnyScheduler()
-
-    let store = TestStore(
-      initialState: MyIdentityState(id: UUID()),
-      reducer: myIdentityReducer,
-      environment: env
-    )
-
-    store.send(.makeIdentity) {
-      $0.isMakingIdentity = true
-    }
-
-    bgScheduler.advance()
-    mainScheduler.advance()
-
-    store.receive(.didFinishMakingIdentity(error)) {
-      $0.isMakingIdentity = false
-      $0.error = ErrorState(error: error)
-    }
-
-    store.send(.didDismissError) {
-      $0.error = nil
-    }
-  }
-}
-
-private extension Identity {
-  static func stub() -> Identity {
-    Identity(
-      id: "\(Int.random(in: 100...999))".data(using: .utf8)!,
-      rsaPrivatePem: "\(Int.random(in: 100...999))".data(using: .utf8)!,
-      salt: "\(Int.random(in: 100...999))".data(using: .utf8)!,
-      dhKeyPrivate: "\(Int.random(in: 100...999))".data(using: .utf8)!
-    )
-  }
-}
diff --git a/Example/example-app/Tests/SessionFeatureTests/SessionFeatureTests.swift b/Example/example-app/Tests/SessionFeatureTests/SessionFeatureTests.swift
index 5c1aa3babd922cf042c0df855604dceeae7c36f7..2b3250c6b0b2db94c409cdf60804da306b12b4b4 100644
--- a/Example/example-app/Tests/SessionFeatureTests/SessionFeatureTests.swift
+++ b/Example/example-app/Tests/SessionFeatureTests/SessionFeatureTests.swift
@@ -1,8 +1,6 @@
 import ComposableArchitecture
 import ElixxirDAppsSDK
 import ErrorFeature
-import MyContactFeature
-import MyIdentityFeature
 import XCTest
 @testable import SessionFeature
 
@@ -11,31 +9,30 @@ final class SessionFeatureTests: XCTestCase {
     var networkFollowerStatus: NetworkFollowerStatus!
     var didStartMonitoringNetworkHealth = 0
     var didStopMonitoringNetworkHealth = 0
-    var networkHealthCallback: ((Bool) -> Void)!
+    var networkHealthCallback: HealthCallback!
     let bgScheduler = DispatchQueue.test
     let mainScheduler = DispatchQueue.test
 
-    var env = SessionEnvironment.failing
-    env.getClient = {
-      var client = Client.failing
-      client.networkFollower.status.status = { networkFollowerStatus }
-      client.monitorNetworkHealth.listen = { callback in
+    let store = TestStore(
+      initialState: SessionState(id: UUID()),
+      reducer: sessionReducer,
+      environment: .unimplemented
+    )
+
+    store.environment.getCmix = {
+      var cmix = Cmix.unimplemented
+      cmix.networkFollowerStatus.run = { networkFollowerStatus }
+      cmix.addHealthCallback.run = { callback in
         networkHealthCallback = callback
         didStartMonitoringNetworkHealth += 1
         return Cancellable {
           didStopMonitoringNetworkHealth += 1
         }
       }
-      return client
+      return cmix
     }
-    env.bgScheduler = bgScheduler.eraseToAnyScheduler()
-    env.mainScheduler = mainScheduler.eraseToAnyScheduler()
-
-    let store = TestStore(
-      initialState: SessionState(id: UUID()),
-      reducer: sessionReducer,
-      environment: env
-    )
+    store.environment.bgScheduler = bgScheduler.eraseToAnyScheduler()
+    store.environment.mainScheduler = mainScheduler.eraseToAnyScheduler()
 
     store.send(.viewDidLoad)
 
@@ -53,7 +50,7 @@ final class SessionFeatureTests: XCTestCase {
     XCTAssertEqual(didStartMonitoringNetworkHealth, 1)
     XCTAssertEqual(didStopMonitoringNetworkHealth, 0)
 
-    networkHealthCallback(true)
+    networkHealthCallback.handle(true)
     bgScheduler.advance()
     mainScheduler.advance()
 
@@ -77,35 +74,30 @@ final class SessionFeatureTests: XCTestCase {
     let bgScheduler = DispatchQueue.test
     let mainScheduler = DispatchQueue.test
 
-    var env = SessionEnvironment.failing
-    env.getClient = {
-      var client = Client.failing
-      client.networkFollower.status.status = {
-        networkFollowerStatus
-      }
-      client.networkFollower.start.start = {
+    let store = TestStore(
+      initialState: SessionState(id: UUID()),
+      reducer: sessionReducer,
+      environment: .unimplemented
+    )
+
+    store.environment.getCmix = {
+      var cmix = Cmix.unimplemented
+      cmix.networkFollowerStatus.run = { networkFollowerStatus }
+      cmix.startNetworkFollower.run = {
         didStartNetworkFollowerWithTimeout.append($0)
         if let error = networkFollowerStartError {
           throw error
         }
       }
-      client.networkFollower.stop.stop = {
+      cmix.stopNetworkFollower.run = {
         didStopNetworkFollower += 1
       }
-      return client
+      return cmix
     }
-    env.bgScheduler = bgScheduler.eraseToAnyScheduler()
-    env.mainScheduler = mainScheduler.eraseToAnyScheduler()
+    store.environment.bgScheduler = bgScheduler.eraseToAnyScheduler()
+    store.environment.mainScheduler = mainScheduler.eraseToAnyScheduler()
 
-    let store = TestStore(
-      initialState: SessionState(id: UUID()),
-      reducer: sessionReducer,
-      environment: env
-    )
-
-    store.send(.runNetworkFollower(true)) {
-      $0.networkFollowerStatus = .starting
-    }
+    store.send(.runNetworkFollower(true))
 
     networkFollowerStatus = .running
     bgScheduler.advance()
@@ -118,9 +110,7 @@ final class SessionFeatureTests: XCTestCase {
       $0.networkFollowerStatus = .running
     }
 
-    store.send(.runNetworkFollower(false)) {
-      $0.networkFollowerStatus = .stopping
-    }
+    store.send(.runNetworkFollower(false))
 
     networkFollowerStatus = .stopped
     bgScheduler.advance()
@@ -133,9 +123,7 @@ final class SessionFeatureTests: XCTestCase {
       $0.networkFollowerStatus = .stopped
     }
 
-    store.send(.runNetworkFollower(true)) {
-      $0.networkFollowerStatus = .starting
-    }
+    store.send(.runNetworkFollower(true))
 
     networkFollowerStartError = NSError(domain: "test", code: 1234)
     networkFollowerStatus = .stopped
@@ -149,54 +137,10 @@ final class SessionFeatureTests: XCTestCase {
       $0.error = ErrorState(error: networkFollowerStartError!)
     }
 
-    store.receive(.didUpdateNetworkFollowerStatus(.stopped)) {
-      $0.networkFollowerStatus = .stopped
-    }
+    store.receive(.didUpdateNetworkFollowerStatus(.stopped))
 
     store.send(.didDismissError) {
       $0.error = nil
     }
   }
-
-  func testPresentingMyIdentity() {
-    let newId = UUID()
-
-    var env = SessionEnvironment.failing
-    env.makeId = { newId }
-
-    let store = TestStore(
-      initialState: SessionState(id: UUID()),
-      reducer: sessionReducer,
-      environment: env
-    )
-
-    store.send(.presentMyIdentity) {
-      $0.myIdentity = MyIdentityState(id: newId)
-    }
-
-    store.send(.didDismissMyIdentity) {
-      $0.myIdentity = nil
-    }
-  }
-
-  func testPresentingMyContact() {
-    let newId = UUID()
-
-    var env = SessionEnvironment.failing
-    env.makeId = { newId }
-
-    let store = TestStore(
-      initialState: SessionState(id: UUID()),
-      reducer: sessionReducer,
-      environment: env
-    )
-
-    store.send(.presentMyContact) {
-      $0.myContact = MyContactState(id: newId)
-    }
-
-    store.send(.didDismissMyContact) {
-      $0.myContact = nil
-    }
-  }
 }