Repository: 7mind/izumi
Pull request #942 (2020-03-13 15:21:57)

Feature/bio3 2

codecov-io: # [Codecov](https://codecov.io/gh/7mind/izumi/pull/942?src=pr&el=h1) Report
> Merging [#942](https://codecov.io/gh/7mind/izumi/pull/942?src=pr&el=desc) into [develop](https://codecov.io/gh/7mind/izumi/commit/132db37b5ae60f791baf45cea32a8f880b36fa9a?src=pr&el=desc) will **decrease** coverage by `0.55%`.
> The diff coverage is `10.16%`.

[![Impacted file tree graph](https://codecov.io/gh/7mind/izumi/pull/942/graphs/tree.svg?width=650&token=77pa3UU1Je&height=150&src=pr)](https://codecov.io/gh/7mind/izumi/pull/942?src=pr&el=tree)

```diff
@@             Coverage Diff             @@
##           develop     #942      +/-   ##
===========================================
- Coverage    58.21%   57.65%   -0.56%     
===========================================
  Files          352      366      +14     
  Lines         7658     7732      +74     
  Branches       476      450      -26     
===========================================
  Hits          4458     4458              
- Misses        3200     3274      +74
```


| [Impacted Files](https://codecov.io/gh/7mind/izumi/pull/942?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [...in/scala/izumi/distage/model/effect/DIEffect.scala](https://codecov.io/gh/7mind/izumi/pull/942/diff?src=pr&el=tree#diff-ZGlzdGFnZS9kaXN0YWdlLWNvcmUtYXBpL3NyYy9tYWluL3NjYWxhL2l6dW1pL2Rpc3RhZ2UvbW9kZWwvZWZmZWN0L0RJRWZmZWN0LnNjYWxh) | `84.37% <ø> (ø)` | :arrow_up: |
| [...umi/distage/effect/modules/ZIODIEffectModule.scala](https://codecov.io/gh/7mind/izumi/pull/942/diff?src=pr&el=tree#diff-ZGlzdGFnZS9kaXN0YWdlLWZyYW1ld29yay9zcmMvbWFpbi9zY2FsYS9penVtaS9kaXN0YWdlL2VmZmVjdC9tb2R1bGVzL1pJT0RJRWZmZWN0TW9kdWxlLnNjYWxh) | `100% <ø> (ø)` | :arrow_up: |
| [...scala/izumi/functional/bio/syntax/BIO3Syntax.scala](https://codecov.io/gh/7mind/izumi/pull/942/diff?src=pr&el=tree#diff-ZnVuZGFtZW50YWxzL2Z1bmRhbWVudGFscy1iaW8vc3JjL21haW4vc2NhbGEvaXp1bWkvZnVuY3Rpb25hbC9iaW8vc3ludGF4L0JJTzNTeW50YXguc2NhbGE=) | `0% <0%> (ø)` | |
| [...izumi/functional/bio/instances/BIOPrimitives.scala](https://codecov.io/gh/7mind/izumi/pull/942/diff?src=pr&el=tree#diff-ZnVuZGFtZW50YWxzL2Z1bmRhbWVudGFscy1iaW8vc3JjL21haW4vc2NhbGEvaXp1bWkvZnVuY3Rpb25hbC9iaW8vaW5zdGFuY2VzL0JJT1ByaW1pdGl2ZXMuc2NhbGE=) | `14.28% <0%> (ø)` | |
| [...zumi/functional/bio/instances/BIOMonadError3.scala](https://codecov.io/gh/7mind/izumi/pull/942/diff?src=pr&el=tree#diff-ZnVuZGFtZW50YWxzL2Z1bmRhbWVudGFscy1iaW8vc3JjL21haW4vc2NhbGEvaXp1bWkvZnVuY3Rpb25hbC9iaW8vaW5zdGFuY2VzL0JJT01vbmFkRXJyb3IzLnNjYWxh) | `0% <0%> (ø)` | |
| [...ala/izumi/functional/bio/impl/BIOTemporalZio.scala](https://codecov.io/gh/7mind/izumi/pull/942/diff?src=pr&el=tree#diff-ZnVuZGFtZW50YWxzL2Z1bmRhbWVudGFscy1iaW8vc3JjL21haW4vc2NhbGEvaXp1bWkvZnVuY3Rpb25hbC9iaW8vaW1wbC9CSU9UZW1wb3JhbFppby5zY2FsYQ==) | `0% <0%> (ø)` | |
| [...a/izumi/functional/bio/instances/BIOBracket3.scala](https://codecov.io/gh/7mind/izumi/pull/942/diff?src=pr&el=tree#diff-ZnVuZGFtZW50YWxzL2Z1bmRhbWVudGFscy1iaW8vc3JjL21haW4vc2NhbGEvaXp1bWkvZnVuY3Rpb25hbC9iaW8vaW5zdGFuY2VzL0JJT0JyYWNrZXQzLnNjYWxh) | `0% <0%> (ø)` | |
| [...ala/izumi/functional/bio/instances/BIOError3.scala](https://codecov.io/gh/7mind/izumi/pull/942/diff?src=pr&el=tree#diff-ZnVuZGFtZW50YWxzL2Z1bmRhbWVudGFscy1iaW8vc3JjL21haW4vc2NhbGEvaXp1bWkvZnVuY3Rpb25hbC9iaW8vaW5zdGFuY2VzL0JJT0Vycm9yMy5zY2FsYQ==) | `0% <0%> (ø)` | |
| [...ala/izumi/functional/bio/instances/BIOPanic3.scala](https://codecov.io/gh/7mind/izumi/pull/942/diff?src=pr&el=tree#diff-ZnVuZGFtZW50YWxzL2Z1bmRhbWVudGFscy1iaW8vc3JjL21haW4vc2NhbGEvaXp1bWkvZnVuY3Rpb25hbC9iaW8vaW5zdGFuY2VzL0JJT1BhbmljMy5zY2FsYQ==) | `0% <0%> (ø)` | |
| [...src/main/scala/izumi/functional/bio/BIOFiber.scala](https://codecov.io/gh/7mind/izumi/pull/942/diff?src=pr&el=tree#diff-ZnVuZGFtZW50YWxzL2Z1bmRhbWVudGFscy1iaW8vc3JjL21haW4vc2NhbGEvaXp1bWkvZnVuY3Rpb25hbC9iaW8vQklPRmliZXIuc2NhbGE=) | `0% <0%> (ø)` | :arrow_up: |
| ... and [28 more](https://codecov.io/gh/7mind/izumi/pull/942/diff?src=pr&el=tree-more) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/7mind/izumi/pull/942?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/7mind/izumi/pull/942?src=pr&el=footer). Last update [132db37...ee120c8](https://codecov.io/gh/7mind/izumi/pull/942?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/build.sbt b/build.sbt
index 5b274fdd7..b43b2a8e6 100644
--- a/build.sbt
+++ b/build.sbt
@@ -90,7 +90,6 @@ lazy val `fundamentals-collections` = project.in(file("fundamentals/fundamentals
       )
       case (_, _) => Seq.empty
     } },
-    scalacOptions += "-P:silencer:globalFilters=inside.of.package.objects",
     scalaVersion := crossScalaVersions.value.head,
     crossScalaVersions := Seq(
       "2.12.10",
@@ -199,7 +198,6 @@ lazy val `fundamentals-platform` = project.in(file("fundamentals/fundamentals-pl
       )
       case (_, _) => Seq.empty
     } },
-    scalacOptions += "-P:silencer:globalFilters=inside.of.package.objects",
     scalaVersion := crossScalaVersions.value.head,
     crossScalaVersions := Seq(
       "2.12.10",
@@ -295,7 +293,6 @@ lazy val `fundamentals-functional` = project.in(file("fundamentals/fundamentals-
       )
       case (_, _) => Seq.empty
     } },
-    scalacOptions += "-P:silencer:globalFilters=inside.of.package.objects",
     scalaVersion := crossScalaVersions.value.head,
     crossScalaVersions := Seq(
       "2.12.10",
@@ -402,7 +399,6 @@ lazy val `fundamentals-thirdparty-boopickle-shaded` = project.in(file("fundament
       )
       case (_, _) => Seq.empty
     } },
-    scalacOptions += "-P:silencer:globalFilters=inside.of.package.objects",
     scalaVersion := crossScalaVersions.value.head,
     crossScalaVersions := Seq(
       "2.12.10",
@@ -504,7 +500,6 @@ lazy val `fundamentals-reflection` = project.in(file("fundamentals/fundamentals-
       )
       case (_, _) => Seq.empty
     } },
-    scalacOptions += "-P:silencer:globalFilters=inside.of.package.objects",
     scalaVersion := crossScalaVersions.value.head,
     crossScalaVersions := Seq(
       "2.12.10",
@@ -603,7 +598,6 @@ lazy val `fundamentals-bio` = project.in(file("fundamentals/fundamentals-bio"))
       )
       case (_, _) => Seq.empty
     } },
-    scalacOptions += "-P:silencer:globalFilters=inside.of.package.objects",
     scalaVersion := crossScalaVersions.value.head,
     crossScalaVersions := Seq(
       "2.12.10",
@@ -709,7 +703,6 @@ lazy val `fundamentals-json-circe` = project.in(file("fundamentals/fundamentals-
       )
       case (_, _) => Seq.empty
     } },
-    scalacOptions += "-P:silencer:globalFilters=inside.of.package.objects",
     scalaVersion := crossScalaVersions.value.head,
     crossScalaVersions := Seq(
       "2.12.10",
@@ -815,7 +808,6 @@ lazy val `distage-core-api` = project.in(file("distage/distage-core-api"))
       )
       case (_, _) => Seq.empty
     } },
-    scalacOptions += "-P:silencer:globalFilters=inside.of.package.objects",
     scalaVersion := crossScalaVersions.value.head,
     crossScalaVersions := Seq(
       "2.12.10",
@@ -914,7 +906,6 @@ lazy val `distage-core-proxy-cglib` = project.in(file("distage/distage-core-prox
       )
       case (_, _) => Seq.empty
     } },
-    scalacOptions += "-P:silencer:globalFilters=inside.of.package.objects",
     scalaVersion := crossScalaVersions.value.head,
     crossScalaVersions := Seq(
       "2.12.10",
@@ -1013,7 +1004,6 @@ lazy val `distage-core` = project.in(file("distage/distage-core"))
       )
       case (_, _) => Seq.empty
     } },
-    scalacOptions += "-P:silencer:globalFilters=inside.of.package.objects",
     scalaVersion := crossScalaVersions.value.head,
     crossScalaVersions := Seq(
       "2.12.10",
@@ -1115,7 +1105,6 @@ lazy val `distage-extension-config` = project.in(file("distage/distage-extension
       )
       case (_, _) => Seq.empty
     } },
-    scalacOptions += "-P:silencer:globalFilters=inside.of.package.objects",
     scalaVersion := crossScalaVersions.value.head,
     crossScalaVersions := Seq(
       "2.12.10",
@@ -1217,7 +1206,6 @@ lazy val `distage-extension-plugins` = project.in(file("distage/distage-extensio
       )
       case (_, _) => Seq.empty
     } },
-    scalacOptions += "-P:silencer:globalFilters=inside.of.package.objects",
     scalaVersion := crossScalaVersions.value.head,
     crossScalaVersions := Seq(
       "2.12.10",
@@ -1318,7 +1306,6 @@ lazy val `distage-extension-logstage` = project.in(file("distage/distage-extensi
       )
       case (_, _) => Seq.empty
     } },
-    scalacOptions += "-P:silencer:globalFilters=inside.of.package.objects",
     scalaVersion := crossScalaVersions.value.head,
     crossScalaVersions := Seq(
       "2.12.10",
@@ -1416,7 +1403,6 @@ lazy val `distage-framework-api` = project.in(file("distage/distage-framework-ap
       )
       case (_, _) => Seq.empty
     } },
-    scalacOptions += "-P:silencer:globalFilters=inside.of.package.objects",
     scalaVersion := crossScalaVersions.value.head,
     crossScalaVersions := Seq(
       "2.12.10",
@@ -1523,7 +1509,6 @@ lazy val `distage-framework` = project.in(file("distage/distage-framework"))
       )
       case (_, _) => Seq.empty
     } },
-    scalacOptions += "-P:silencer:globalFilters=inside.of.package.objects",
     scalaVersion := crossScalaVersions.value.head,
     crossScalaVersions := Seq(
       "2.12.10",
@@ -1629,7 +1614,6 @@ lazy val `distage-framework-docker` = project.in(file("distage/distage-framework
       )
       case (_, _) => Seq.empty
     } },
-    scalacOptions += "-P:silencer:globalFilters=inside.of.package.objects",
     scalaVersion := crossScalaVersions.value.head,
     crossScalaVersions := Seq(
       "2.12.10",
@@ -1733,7 +1717,6 @@ lazy val `distage-testkit-core` = project.in(file("distage/distage-testkit-core"
       )
       case (_, _) => Seq.empty
     } },
-    scalacOptions += "-P:silencer:globalFilters=inside.of.package.objects",
     scalaVersion := crossScalaVersions.value.head,
     crossScalaVersions := Seq(
       "2.12.10",
@@ -1838,7 +1821,6 @@ lazy val `distage-testkit-scalatest` = project.in(file("distage/distage-testkit-
       )
       case (_, _) => Seq.empty
     } },
-    scalacOptions += "-P:silencer:globalFilters=inside.of.package.objects",
     scalaVersion := crossScalaVersions.value.head,
     crossScalaVersions := Seq(
       "2.12.10",
@@ -1943,7 +1925,6 @@ lazy val `logstage-core` = project.in(file("logstage/logstage-core"))
       )
       case (_, _) => Seq.empty
     } },
-    scalacOptions += "-P:silencer:globalFilters=inside.of.package.objects",
     scalaVersion := crossScalaVersions.value.head,
     crossScalaVersions := Seq(
       "2.12.10",
@@ -2042,7 +2023,6 @@ lazy val `logstage-rendering-circe` = project.in(file("logstage/logstage-renderi
       )
       case (_, _) => Seq.empty
     } },
-    scalacOptions += "-P:silencer:globalFilters=inside.of.package.objects",
     scalaVersion := crossScalaVersions.value.head,
     crossScalaVersions := Seq(
       "2.12.10",
@@ -2144,7 +2124,6 @@ lazy val `logstage-adapter-slf4j` = project.in(file("logstage/logstage-adapter-s
       )
       case (_, _) => Seq.empty
     } },
-    scalacOptions += "-P:silencer:globalFilters=inside.of.package.objects",
     scalaVersion := crossScalaVersions.value.head,
     crossScalaVersions := Seq(
       "2.12.10",
@@ -2245,7 +2224,6 @@ lazy val `logstage-sink-slf4j` = project.in(file("logstage/logstage-sink-slf4j")
       )
       case (_, _) => Seq.empty
     } },
-    scalacOptions += "-P:silencer:globalFilters=inside.of.package.objects",
     scalaVersion := crossScalaVersions.value.head,
     crossScalaVersions := Seq(
       "2.12.10",
@@ -2420,7 +2398,6 @@ lazy val `microsite` = project.in(file("doc/microsite"))
       )
       case (_, _) => Seq.empty
     } },
-    scalacOptions += "-P:silencer:globalFilters=inside.of.package.objects",
     scalaVersion := crossScalaVersions.value.head,
     crossScalaVersions := Seq(
       "2.12.10",
@@ -2518,7 +2495,6 @@ lazy val `sbt-izumi-deps` = project.in(file("sbt-plugins/sbt-izumi-deps"))
       )
       case (_, _) => Seq.empty
     } },
-    scalacOptions += "-P:silencer:globalFilters=inside.of.package.objects",
     scalaVersion := crossScalaVersions.value.head,
     crossScalaVersions := Seq(
       "2.12.10"
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/effect/DIEffect.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/effect/DIEffect.scala
index acd81e411..62778ed0a 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/effect/DIEffect.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/effect/DIEffect.scala
@@ -115,7 +115,7 @@ object DIEffect extends LowPriorityDIEffectInstances {
         F.bracket(acquire = suspendF(acquire))(release = release(_).orTerminate)(use = use)
       }
       override def bracketCase[A, B](acquire: => F[E, A])(release: (A, Option[E]) => F[E, Unit])(use: A => F[E, B]): F[E, B] = {
-        F.bracketCase[Throwable, A, B](acquire = suspendF(acquire))(release = {
+        F.bracketCase[Any, Throwable, A, B](acquire = suspendF(acquire))(release = {
           case (a, exit) => exit match {
             case BIOExit.Success(_) => release(a, None).orTerminate
             case failure: BIOExit.Failure[E] => release(a, Some(failure.toThrowable)).orTerminate
diff --git a/distage/distage-framework-docker/src/main/scala/izumi/distage/docker/DockerContainer.scala b/distage/distage-framework-docker/src/main/scala/izumi/distage/docker/DockerContainer.scala
index f8d6b1460..948e1e68b 100644
--- a/distage/distage-framework-docker/src/main/scala/izumi/distage/docker/DockerContainer.scala
+++ b/distage/distage-framework-docker/src/main/scala/izumi/distage/docker/DockerContainer.scala
@@ -65,6 +65,7 @@ object ContainerDef {
 final case class DockerContainer[Tag](
   id: Docker.ContainerId,
   name: String,
+  hostName: String,
   ports: Map[Docker.DockerPort, Seq[ServicePort]],
   containerConfig: Docker.ContainerConfig[Tag],
   clientConfig: ClientConfig,
@@ -219,6 +220,7 @@ object DockerContainer {
               containerConfig = config,
               clientConfig = clientw.clientConfig,
               availablePorts = Map.empty,
+              hostName = inspection.getConfig.getHostName
             )
             await(unverified)
           case None =>
@@ -269,6 +271,7 @@ object DockerContainer {
           client.startContainerCmd(res.getId).exec()
 
           val inspection = client.inspectContainerCmd(res.getId).exec()
+          val hostName = inspection.getConfig.getHostName
           val maybeMappedPorts = mapContainerPorts(inspection)
 
           maybeMappedPorts match {
@@ -276,7 +279,7 @@ object DockerContainer {
               throw new RuntimeException(s"Created container from `${config.image}` with ${res.getId -> "id"}, but ports are missing: $value!")
 
             case Right(mappedPorts) =>
-              val container = DockerContainer[T](ContainerId(res.getId), inspection.getName, mappedPorts, config, clientw.clientConfig, Map.empty)
+              val container = DockerContainer[T](ContainerId(res.getId), inspection.getName, hostName, mappedPorts, config, clientw.clientConfig, Map.empty)
               logger.debug(s"Created $container from ${config.image}...")
 
               if (config.networks.nonEmpty) {
diff --git a/distage/distage-framework-docker/src/main/scala/izumi/distage/docker/examples/CassandraDocker.scala b/distage/distage-framework-docker/src/main/scala/izumi/distage/docker/examples/CassandraDocker.scala
new file mode 100644
index 000000000..32a3bc15e
--- /dev/null
+++ b/distage/distage-framework-docker/src/main/scala/izumi/distage/docker/examples/CassandraDocker.scala
@@ -0,0 +1,23 @@
+package izumi.distage.docker.examples
+
+import izumi.distage.docker.ContainerDef
+import izumi.distage.docker.Docker.{ContainerConfig, DockerPort}
+import izumi.distage.model.definition.ModuleDef
+import izumi.fundamentals.reflection.Tags.TagK
+
+object CassandraDocker extends ContainerDef {
+  val primaryPort: DockerPort = DockerPort.TCP(9042)
+
+  override def config: Config = {
+    ContainerConfig(
+      image = "cassandra:3.11.6",
+      ports = Seq(primaryPort)
+    )
+  }
+}
+
+class CassandraDockerModule[F[_]: TagK] extends ModuleDef {
+  make[CassandraDocker.Container].fromResource {
+    CassandraDocker.make[F]
+  }
+}
diff --git a/distage/distage-framework-docker/src/main/scala/izumi/distage/docker/examples/KafkaDocker.scala b/distage/distage-framework-docker/src/main/scala/izumi/distage/docker/examples/KafkaDocker.scala
new file mode 100644
index 000000000..33b929d3c
--- /dev/null
+++ b/distage/distage-framework-docker/src/main/scala/izumi/distage/docker/examples/KafkaDocker.scala
@@ -0,0 +1,29 @@
+package izumi.distage.docker.examples
+
+import distage.{ModuleDef, TagK}
+import izumi.distage.docker.Docker.{ContainerConfig, DockerPort}
+import izumi.distage.docker.{ContainerDef, DockerClientWrapper, DockerContainer}
+import izumi.distage.model.effect.{DIEffect, DIEffectAsync}
+import izumi.logstage.api.IzLogger
+
+object KafkaDocker extends ContainerDef {
+  val primaryPort: DockerPort.TCP = DockerPort.TCP(9092)
+  override def config: Config = {
+    ContainerConfig(
+      image = "wurstmeister/kafka:2.12-2.4.1",
+      ports = Seq(primaryPort),
+      env = Map(
+        "KAFKA_ADVERTISED_HOST_NAME" -> "127.0.0.1"
+      ),
+      networks = Seq(ZookeeperDocker.zookeeperNetwork),
+    )
+  }
+}
+
+class KafkaDockerModule[F[_]: TagK] extends ModuleDef {
+  make[KafkaDocker.Container].fromResource {
+    (zookeeperDocker: ZookeeperDocker.Container, wr: DockerClientWrapper[F], log: IzLogger, eff: DIEffect[F], effAsync: DIEffectAsync[F]) =>
+      val zkEnv = KafkaDocker.config.env ++ Map("KAFKA_ZOOKEEPER_CONNECT" -> s"${zookeeperDocker.hostName}:2181")
+      new DockerContainer.Resource[F, KafkaDocker.Tag](KafkaDocker.config.copy(env = zkEnv), wr, log)(eff, effAsync)
+  }
+}
diff --git a/distage/distage-framework-docker/src/main/scala/izumi/distage/docker/examples/ZookkeeperDocker.scala b/distage/distage-framework-docker/src/main/scala/izumi/distage/docker/examples/ZookkeeperDocker.scala
new file mode 100644
index 000000000..096fc0ee2
--- /dev/null
+++ b/distage/distage-framework-docker/src/main/scala/izumi/distage/docker/examples/ZookkeeperDocker.scala
@@ -0,0 +1,22 @@
+package izumi.distage.docker.examples
+
+import distage.{ModuleDef, TagK}
+import izumi.distage.docker.ContainerDef
+import izumi.distage.docker.Docker.{ContainerConfig, ContainerNetwork, DockerPort}
+
+object ZookeeperDocker extends ContainerDef {
+  val zookeeperNetwork: ContainerNetwork = ContainerNetwork("zookeeper-network")
+  override def config: Config = {
+    ContainerConfig(
+      image = "zookeeper:3.4.14",
+      ports = Seq(DockerPort.TCP(2181), DockerPort.TCP(2888), DockerPort.TCP(3888)),
+      networks = Seq(zookeeperNetwork),
+    )
+  }
+}
+
+class ZookeeperDockerModule[F[_]: TagK] extends ModuleDef {
+  make[ZookeeperDocker.Container].fromResource {
+    ZookeeperDocker.make[F]
+  }
+}
diff --git a/distage/distage-framework/src/main/scala/izumi/distage/effect/modules/ZIODIEffectModule.scala b/distage/distage-framework/src/main/scala/izumi/distage/effect/modules/ZIODIEffectModule.scala
index 12113fa43..5211b127a 100644
--- a/distage/distage-framework/src/main/scala/izumi/distage/effect/modules/ZIODIEffectModule.scala
+++ b/distage/distage-framework/src/main/scala/izumi/distage/effect/modules/ZIODIEffectModule.scala
@@ -8,8 +8,8 @@ import izumi.distage.model.effect._
 import izumi.functional.bio.BIORunner.{FailureHandler, ZIORunner}
 import izumi.functional.bio._
 import izumi.logstage.api.IzLogger
-import zio.IO
 import zio.internal.tracing.TracingConfig
+import zio.{IO, ZIO}
 
 import scala.concurrent.ExecutionContext
 
@@ -23,26 +23,54 @@ trait ZIODIEffectModule extends ModuleDef {
 
   make[ExecutionContext].named("zio.cpu").from(ExecutionContext.fromExecutor(_: ThreadPoolExecutor @Id("zio.cpu")))
   make[ExecutionContext].named("zio.io").from(ExecutionContext.fromExecutor(_: ThreadPoolExecutor @Id("zio.io")))
-  make[ThreadPoolExecutor].named("zio.cpu")
-    .fromResource { () =>
+  make[ThreadPoolExecutor].named("zio.cpu").fromResource {
+    () =>
       val coresOr2 = Runtime.getRuntime.availableProcessors() max 2
       DIResource.fromExecutorService(Executors.newFixedThreadPool(coresOr2).asInstanceOf[ThreadPoolExecutor])
-    }
-  make[ThreadPoolExecutor].named("zio.io")
-    .fromResource { () =>
+  }
+  make[ThreadPoolExecutor].named("zio.io").fromResource {
+    () =>
       DIResource.fromExecutorService(Executors.newCachedThreadPool().asInstanceOf[ThreadPoolExecutor])
-    }
+  }
 
-  make[BlockingIO[IO]].from {
+  make[BlockingIO3[ZIO]].from {
     blockingPool: ThreadPoolExecutor @Id("zio.io") =>
-      BlockingIOInstances.BlockingZIOFromThreadPool[Any](blockingPool)
+      BlockingIOInstances.BlockingZIOFromThreadPool(blockingPool)
+  }
+  make[BlockingIO[IO]].from {
+    implicit b: BlockingIO3[ZIO] =>
+      implicitly[BlockingIO[IO]]
   }
 
   addImplicit[BIOTransZio[IO]]
+  addImplicit[BIOFork3[ZIO]]
   addImplicit[BIOFork[IO]]
+  addImplicit[SyncSafe3[ZIO]]
   addImplicit[SyncSafe2[IO]]
+  addImplicit[BIOPrimitives3[ZIO]]
   addImplicit[BIOPrimitives[IO]]
 
+  addImplicit[BIOFunctor3[ZIO]]
+  addImplicit[BIOBifunctor3[ZIO]]
+  addImplicit[BIOApplicative3[ZIO]]
+  addImplicit[BIOGuarantee3[ZIO]]
+  addImplicit[BIOError3[ZIO]]
+  addImplicit[BIOMonad3[ZIO]]
+  addImplicit[BIOMonadError3[ZIO]]
+  addImplicit[BIOBracket3[ZIO]]
+  addImplicit[BIOPanic3[ZIO]]
+  addImplicit[BIO3[ZIO]]
+  addImplicit[BIOAsync3[ZIO]]
+  make[BIOTemporal3[ZIO]].from {
+    implicit r: zio.clock.Clock =>
+      implicitly[BIOTemporal3[ZIO]]
+  }
+  addImplicit[BIOAsk[ZIO]]
+  addImplicit[BIOMonadAsk[ZIO]]
+  addImplicit[BIOLocal[ZIO]]
+  addImplicit[BIOProfunctor[ZIO]]
+  addImplicit[BIOArrow[ZIO]]
+
   addImplicit[BIOFunctor[IO]]
   addImplicit[BIOBifunctor[IO]]
   addImplicit[BIOApplicative[IO]]
@@ -55,7 +83,8 @@ trait ZIODIEffectModule extends ModuleDef {
   addImplicit[BIO[IO]]
   addImplicit[BIOAsync[IO]]
   make[BIOTemporal[IO]].from {
-    r: zio.clock.Clock => BIOTemporalInstances.BIOTemporalZio[Any](r)
+    implicit r: zio.clock.Clock =>
+      implicitly[BIOTemporal[IO]]
   }
 
   make[zio.clock.Clock].from(zio.Has(zio.clock.Clock.Service.live))
@@ -75,10 +104,7 @@ trait ZIODIEffectModule extends ModuleDef {
       }
   }
   make[ZIORunner].from {
-    (cpuPool: ThreadPoolExecutor @Id("zio.cpu"),
-     handler: FailureHandler,
-     tracingConfig: TracingConfig,
-    ) =>
+    (cpuPool: ThreadPoolExecutor @Id("zio.cpu"), handler: FailureHandler, tracingConfig: TracingConfig) =>
       BIORunner.createZIO(
         cpuPool = cpuPool,
         handler = handler,
diff --git a/fundamentals/fundamentals-bio/.jvm/src/main/scala/izumi/functional/bio/BlockingIO3.scala b/fundamentals/fundamentals-bio/.jvm/src/main/scala/izumi/functional/bio/BlockingIO3.scala
index 14a643453..a1a9cd3b5 100644
--- a/fundamentals/fundamentals-bio/.jvm/src/main/scala/izumi/functional/bio/BlockingIO3.scala
+++ b/fundamentals/fundamentals-bio/.jvm/src/main/scala/izumi/functional/bio/BlockingIO3.scala
@@ -22,19 +22,14 @@ trait BlockingIO3[F[-_, +_, +_]] extends BlockingIOInstances {
     * **/
   def syncInterruptibleBlocking[A](f: => A): F[Any, Throwable, A]
 }
-
 object BlockingIO3 {
   def apply[F[-_, +_, +_]: BlockingIO3]: BlockingIO3[F] = implicitly
 }
 
 private[bio] sealed trait BlockingIOInstances
 object BlockingIOInstances extends LowPriorityBlockingIOInstances {
-  // FIXME: bad encoding for lifting to 2-parameters...
-  def BlockingZIOFromThreadPool[R](blockingPool: ThreadPoolExecutor): BlockingIO[ZIO[R, +?, +?]] = {
-    convert3To2(BlockingZIO3FromThreadPool(blockingPool))
-  }
 
-  def BlockingZIO3FromThreadPool(blockingPool: ThreadPoolExecutor): BlockingIO3[ZIO] = {
+  def BlockingZIOFromThreadPool(blockingPool: ThreadPoolExecutor): BlockingIO3[ZIO] = {
     val executor = Executor.fromThreadPoolExecutor(_ => Int.MaxValue)(blockingPool)
     val blocking: Blocking.Service = new Blocking.Service {
       override val blockingExecutor: Executor = executor
diff --git a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIO3.scala b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIO3.scala
new file mode 100644
index 000000000..3ba6621d1
--- /dev/null
+++ b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIO3.scala
@@ -0,0 +1,27 @@
+package izumi.functional.bio
+
+import scala.util.Try
+
+trait BIO3[F[-_, +_, +_]] extends BIOPanic3[F] {
+  final type Or[+E, +A] = F[Any, E, A]
+  final type Just[+A] = F[Any, Nothing, A]
+
+  def syncThrowable[A](effect: => A): F[Any, Throwable, A]
+  def sync[A](effect: => A): F[Any, Nothing, A]
+
+  @inline final def apply[A](effect: => A): F[Any, Throwable, A] = syncThrowable(effect)
+
+  def suspend[R, A](effect: => F[R, Throwable, A]): F[R, Throwable, A] = flatten(syncThrowable(effect))
+
+  // defaults
+  override def fromEither[E, A](effect: => Either[E, A]): F[Any, E, A] = flatMap(sync(effect)) {
+    case Left(e) => fail(e): F[Any, E, A]
+    case Right(v) => pure(v): F[Any, E, A]
+  }
+  override def fromOption[E, A](errorOnNone: => E)(effect: => Option[A]): F[Any, E, A] = {
+    flatMap(sync(effect))(e => fromEither(e.toRight(errorOnNone)))
+  }
+  override def fromTry[A](effect: => Try[A]): F[Any, Throwable, A] = {
+    syncThrowable(effect.get)
+  }
+}
diff --git a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOApplicative3.scala b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOApplicative3.scala
new file mode 100644
index 000000000..3b84ce5f6
--- /dev/null
+++ b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOApplicative3.scala
@@ -0,0 +1,30 @@
+package izumi.functional.bio
+
+trait BIOApplicative3[F[-_, +_, +_]] extends BIOBifunctor3[F] {
+  def pure[A](a: A): F[Any, Nothing, A]
+
+  /** execute two operations in order, map their results */
+  def map2[R, E, A, B, C](firstOp: F[R, E, A], secondOp: => F[R, E, B])(f: (A, B) => C): F[R, E, C]
+
+  /** execute two operations in order, return result of second operation */
+  def *>[R, E, A, B](firstOp: F[R, E, A], secondOp: => F[R, E, B]): F[R, E, B]
+
+  /** execute two operations in order, same as `*>`, but return result of first operation */
+  def <*[R, E, A, B](firstOp: F[R, E, A], secondOp: => F[R, E, B]): F[R, E, A]
+
+  def traverse[R, E, A, B](l: Iterable[A])(f: A => F[R, E, B]): F[R, E, List[B]]
+
+  @inline final def forever[R, E, A](r: F[R, E, A]): F[R, E, Nothing] = *>(r, forever(r))
+  def traverse_[R, E, A](l: Iterable[A])(f: A => F[R, E, Unit]): F[R, E, Unit] = void(traverse(l)(f))
+  def sequence[R, E, A, B](l: Iterable[F[R, E, A]]): F[R, E, List[A]] = traverse(l)(identity)
+  def sequence_[R, E](l: Iterable[F[R, E, Unit]]): F[R, E, Unit] = void(traverse(l)(identity))
+
+  final val unit: F[Any, Nothing, Unit] = pure(())
+  @inline final def traverse[R, E, A, B](o: Option[A])(f: A => F[R, E, B]): F[R, E, Option[B]] = o match {
+    case Some(a) => map(f(a))(Some(_))
+    case None => pure(None)
+  }
+  @inline final def when[R, E](cond: Boolean)(ifTrue: F[R, E, Unit]): F[R, E, Unit] = if (cond) ifTrue else unit
+  @inline final def unless[R, E](cond: Boolean)(ifFalse: F[R, E, Unit]): F[R, E, Unit] = if (cond) unit else ifFalse
+  @inline final def ifThenElse[R, E, A](cond: Boolean)(ifTrue: F[R, E, A], ifFalse: F[R, E, A]): F[R, E, A] = if (cond) ifTrue else ifFalse
+}
diff --git a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOArrow.scala b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOArrow.scala
new file mode 100644
index 000000000..17d2aba5a
--- /dev/null
+++ b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOArrow.scala
@@ -0,0 +1,7 @@
+package izumi.functional.bio
+
+trait BIOArrow[FR[-_, +_, +_]] extends BIOProfunctor[FR] {
+  def askWith[R, A](f: R => A): FR[R, Nothing, A]
+  def andThen[R, R1, E, A](f: FR[R, E, R1], g: FR[R1, E, A]): FR[R, E, A]
+  def asking[R, E, A](f: FR[R, E, A]): FR[R, E, (A, R)]
+}
diff --git a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOArrowChoice.scala b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOArrowChoice.scala
new file mode 100644
index 000000000..e0e464b08
--- /dev/null
+++ b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOArrowChoice.scala
@@ -0,0 +1,8 @@
+package izumi.functional.bio
+
+trait BIOArrowChoice[FR[-_, +_, +_]] extends BIOArrow[FR] {
+  def choose[R1, R2, E, A, B](f: FR[R1, E, A], g: FR[R2, E, B]): FR[Either[R1, R2], E, Either[A, B]]
+
+  // defaults
+  def choice[R1, R2, E, A](f: FR[R1, E, A], g: FR[R2, E, A]): FR[Either[R1, R2], E, A] = dimap(choose(f, g))(identity[Either[R1, R2]])(_.merge)
+}
diff --git a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOAsk.scala b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOAsk.scala
new file mode 100644
index 000000000..fd2c7549d
--- /dev/null
+++ b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOAsk.scala
@@ -0,0 +1,18 @@
+package izumi.functional.bio
+
+import izumi.functional.bio.PredefinedHelper.Predefined
+import izumi.functional.bio.impl.BIOAsyncZio
+import zio.ZIO
+
+trait BIOAsk[FR[-_, +_, +_]] extends BIOAskInstances with PredefinedHelper {
+  val InnerF: BIOApplicative3[FR]
+  def ask[R]: FR[R, Nothing, R]
+
+  // defaults
+  def askWith[R, A](f: R => A): FR[R, Nothing, A] = InnerF.map[R, Nothing, R, A](ask)(f)
+}
+
+private[bio] sealed trait BIOAskInstances
+object BIOAskInstances {
+  @inline implicit final def BIOLocalZio: Predefined.Of[BIOLocal[ZIO]] = Predefined(BIOAsyncZio)
+}
diff --git a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOAsync3.scala b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOAsync3.scala
new file mode 100644
index 000000000..0699a3bf3
--- /dev/null
+++ b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOAsync3.scala
@@ -0,0 +1,35 @@
+package izumi.functional.bio
+
+import java.util.concurrent.CompletionStage
+
+import scala.concurrent.{ExecutionContext, Future}
+
+trait BIOAsync3[F[-_, +_, +_]] extends BIO3[F] {
+  final type Canceler = F[Any, Nothing, Unit]
+
+  def async[E, A](register: (Either[E, A] => Unit) => Unit): F[Any, E, A]
+  def asyncF[R, E, A](register: (Either[E, A] => Unit) => F[R, E, Unit]): F[R, E, A]
+  def asyncCancelable[E, A](register: (Either[E, A] => Unit) => Canceler): F[Any, E, A]
+
+  def fromFuture[A](mkFuture: ExecutionContext => Future[A]): F[Any, Throwable, A]
+  def fromFutureJava[A](javaFuture: => CompletionStage[A]): F[Any, Throwable, A]
+
+  def yieldNow: F[Any, Nothing, Unit]
+
+  /** Race two actions, the winner is the first action to TERMINATE, whether by success or failure */
+  def race[R, E, A](r1: F[R, E, A], r2: F[R, E, A]): F[R, E, A]
+  def racePair[R, E, A, B](fa: F[R, E, A], fb: F[R, E, B]): F[R, E, Either[(A, BIOFiber3[F, E, B]), (BIOFiber3[F, E, A], B)]]
+
+  def parTraverseN[R, E, A, B](maxConcurrent: Int)(l: Iterable[A])(f: A => F[R, E, B]): F[R, E, List[B]]
+  def parTraverse[R, E, A, B](l: Iterable[A])(f: A => F[R, E, B]): F[R, E, List[B]]
+
+  def uninterruptible[R, E, A](r: F[R, E, A]): F[R, E, A]
+
+  // defaults
+  def never: F[Any, Nothing, Nothing] = async(_ => ())
+
+  def parTraverse_[R, E, A, B](l: Iterable[A])(f: A => F[R, E, B]): F[R, E, Unit] = void(parTraverse(l)(f))
+  def parTraverseN_[R, E, A, B](maxConcurrent: Int)(l: Iterable[A])(f: A => F[R, E, B]): F[R, E, Unit] = void(parTraverseN(maxConcurrent)(l)(f))
+
+  @inline final def fromFuture[A](mkFuture: => Future[A]): F[Any, Throwable, A] = fromFuture(_ => mkFuture)
+}
diff --git a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOBifunctor3.scala b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOBifunctor3.scala
new file mode 100644
index 000000000..27b19824d
--- /dev/null
+++ b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOBifunctor3.scala
@@ -0,0 +1,10 @@
+package izumi.functional.bio
+
+trait BIOBifunctor3[F[-_, +_, +_]] extends BIOFunctor3[F] {
+  def bimap[R, E, A, E2, A2](r: F[R, E, A])(f: E => E2, g: A => A2): F[R, E2, A2]
+  def leftMap[R, E, A, E2](r: F[R, E, A])(f: E => E2): F[R, E2, A] = bimap(r)(f, identity)
+
+  @inline final def widenError[R, E, A, E1](r: F[R, E, A])(implicit @deprecated("unused", "") ev: E <:< E1): F[R, E1, A] = r.asInstanceOf[F[R, E1, A]]
+  @inline final def widenBoth[R, E, A, E1, A1](r: F[R, E, A])(implicit @deprecated("unused", "") ev: E <:< E1, @deprecated("unused", "") ev2: A <:< A1): F[R, E1, A1] =
+    r.asInstanceOf[F[R, E1, A1]]
+}
diff --git a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOBracket3.scala b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOBracket3.scala
new file mode 100644
index 000000000..a994300e6
--- /dev/null
+++ b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOBracket3.scala
@@ -0,0 +1,14 @@
+package izumi.functional.bio
+
+trait BIOBracket3[F[-_, +_, +_]] extends BIOMonadError3[F] {
+  def bracketCase[R, E, A, B](acquire: F[R, E, A])(release: (A, BIOExit[E, B]) => F[R, Nothing, Unit])(use: A => F[R, E, B]): F[R, E, B]
+
+  def bracket[R, E, A, B](acquire: F[R, E, A])(release: A => F[R, Nothing, Unit])(use: A => F[R, E, B]): F[R, E, B] = {
+    bracketCase[R, E, A, B](acquire)((a, _) => release(a))(use)
+  }
+
+  // defaults
+  override def guarantee[R, E, A](f: F[R, E, A], cleanup: F[R, Nothing, Unit]): F[R, E, A] = {
+    bracket[R, E, Unit, A](unit)(_ => cleanup)(_ => f)
+  }
+}
diff --git a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOCatsConversions.scala b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOCatsConversions.scala
index 2190f0c8d..54c92c4c1 100644
--- a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOCatsConversions.scala
+++ b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOCatsConversions.scala
@@ -3,6 +3,8 @@ package izumi.functional.bio
 import cats.Eval
 import cats.effect.{CancelToken, Concurrent, ExitCase, Fiber}
 import izumi.functional.bio.BIOCatsConversions._
+import izumi.functional.bio.BIOFiber._
+import izumi.functional.bio.SpecificityHelper.{S1, S10, S2, S3, S4, S5, S6, S7, S8, S9}
 
 import scala.util.Either
 
@@ -19,7 +21,7 @@ import scala.util.Either
   * }}}
   */
 trait BIOCatsConversions extends BIOCatsConversions1 {
-  @inline implicit final def BIOToFunctor[F[_, +_], E](implicit F0: BIOFunctor[F]): cats.Functor[F[E, ?]] with S1 = new BIOCatsFunctor[F, E] {
+  @inline implicit final def BIOToFunctor[F[+_, +_], E](implicit F0: BIOFunctor[F]): cats.Functor[F[E, ?]] with S1 = new BIOCatsFunctor[F, E] {
     override val F: BIOFunctor[F] = F0
   }
 }
@@ -34,9 +36,10 @@ trait BIOCatsConversions2 extends BIOCatsConversions3 {
   }
 }
 trait BIOCatsConversions3 extends BIOCatsConversions4 {
-  @inline implicit final def BIOToApplicativeError[F[+_, +_], E](implicit F0: BIOError[F]): cats.ApplicativeError[F[E, ?], E] with S4 = new BIOCatsApplicativeError[F, E] {
-    override val F: BIOError[F] = F0
-  }
+  @inline implicit final def BIOToApplicativeError[F[+_, +_], E](implicit F0: BIOError[F]): cats.ApplicativeError[F[E, ?], E] with S4 =
+    new BIOCatsApplicativeError[F, E] {
+      override val F: BIOError[F] = F0
+    }
 }
 trait BIOCatsConversions4 extends BIOCatsConversions5 {
   @inline implicit final def BIOToMonad[F[+_, +_], E](implicit F: BIOMonad[F]): cats.Monad[F[E, ?]] with S5 = new BIOCatsMonad[F, E](F)
@@ -54,29 +57,16 @@ trait BIOCatsConversions8 extends BIOCatsConversions9 {
   @inline implicit final def BIOAsyncToAsync[F[+_, +_]](implicit F: BIOAsync[F]): cats.effect.Async[F[Throwable, ?]] with S9 = new BIOCatsAsync[F](F)
 }
 trait BIOCatsConversions9 {
-  @inline implicit final def BIOAsyncForkToConcurrent[F[+_, +_]](implicit @deprecated("unused","unused") ev: BIOFunctor[F], F: BIOAsync[F], Fork: BIOFork[F]): cats.effect.Concurrent[F[Throwable, ?]] with S10 = new BIOCatsConcurrent[F](F, Fork)
+  @inline implicit final def BIOAsyncForkToConcurrent[F[+_, +_]](
+    implicit @deprecated("unused", "unused") ev: BIOFunctor[F],
+    F: BIOAsync[F],
+    Fork: BIOFork[F]
+  ): cats.effect.Concurrent[F[Throwable, ?]] with S10 = new BIOCatsConcurrent[F](F, Fork)
 }
 
-/**
-  * Just packaging conversions into implicit priority traits is not enough,
-  * scalac also has a rule that the most specific return type wins, for some reason. /_\
-  * 2.13 seems to overweigh this rule compared to 2.12
-  * So we "disjoin" the types from each other such that they're not "related", by *checks notes*... mixing some empty traits in
-  */
-private[bio] sealed trait S1 extends Any
-private[bio] sealed trait S2 extends Any
-private[bio] sealed trait S3 extends Any
-private[bio] sealed trait S4 extends Any
-private[bio] sealed trait S5 extends Any
-private[bio] sealed trait S6 extends Any
-private[bio] sealed trait S7 extends Any
-private[bio] sealed trait S8 extends Any
-private[bio] sealed trait S9 extends Any
-private[bio] sealed trait S10 extends Any
-
 object BIOCatsConversions {
 
-  trait BIOCatsFunctor[F[_, +_], E] extends cats.Functor[F[E, ?]] with S1 with S2 with S3 with S4 with S5 with S6 with S7 with S8 with S9 with S10 {
+  trait BIOCatsFunctor[F[+_, +_], E] extends cats.Functor[F[E, ?]] with S1 with S2 with S3 with S4 with S5 with S6 with S7 with S8 with S9 with S10 {
     def F: BIOFunctor[F]
 
     @inline override final def map[A, B](fa: F[E, A])(f: A => B): F[E, B] = F.map(fa)(f)
@@ -127,18 +117,25 @@ object BIOCatsConversions {
     }
   }
 
-  class BIOCatsMonadError[F[+_, +_], E](override val F: BIOMonadError[F]) extends BIOCatsMonad[F, E](F) with BIOCatsApplicativeError[F, E] with cats.MonadError[F[E, ?], E]
+  class BIOCatsMonadError[F[+_, +_], E](override val F: BIOMonadError[F])
+    extends BIOCatsMonad[F, E](F)
+    with BIOCatsApplicativeError[F, E]
+    with cats.MonadError[F[E, ?], E]
 
   class BIOCatsBracket[F[+_, +_]](override val F: BIOPanic[F]) extends BIOCatsMonadError[F, Throwable](F) with cats.effect.Bracket[F[Throwable, ?], Throwable] {
 
-    @inline override final def bracketCase[A, B](acquire: F[Throwable, A])(use: A => F[Throwable, B])(release: (A, ExitCase[Throwable]) => F[Throwable, Unit]): F[Throwable, B] = {
-      F.bracketCase[Throwable, A, B](acquire)(
-        (a, e) => F.orTerminate {
-          release(a, e match {
-            case BIOExit.Success(_) => ExitCase.Completed
-            case value: BIOExit.Failure[Throwable] => ExitCase.Error(value.toThrowable)
-          })
-        })(use)
+    @inline override final def bracketCase[A, B](
+      acquire: F[Throwable, A]
+    )(use: A => F[Throwable, B])(release: (A, ExitCase[Throwable]) => F[Throwable, Unit]): F[Throwable, B] = {
+      F.bracketCase[Any, Throwable, A, B](acquire)(
+        (a, e) =>
+          F.orTerminate {
+            release(a, e match {
+              case BIOExit.Success(_) => ExitCase.Completed
+              case value: BIOExit.Failure[Throwable] => ExitCase.Error(value.toThrowable)
+            })
+          }
+      )(use)
     }
 
     @inline override final def bracket[A, B](acquire: F[Throwable, A])(use: A => F[Throwable, B])(release: A => F[Throwable, Unit]): F[Throwable, B] = {
@@ -154,7 +151,8 @@ object BIOCatsConversions {
   class BIOCatsAsync[F[+_, +_]](override val F: BIOAsync[F]) extends BIOCatsSync[F](F) with cats.effect.Async[F[Throwable, ?]] {
     @inline override final def async[A](k: (Either[Throwable, A] => Unit) => Unit): F[Throwable, A] = F.async(k)
     @inline override final def asyncF[A](k: (Either[Throwable, A] => Unit) => F[Throwable, Unit]): F[Throwable, A] = F.asyncF(k)
-    @inline override def liftIO[A](ioa: cats.effect.IO[A]): F[Throwable, A] = Concurrent.liftIO(ioa)(new BIOCatsConcurrent[F](F, null)) // Concurrent.liftIO uses only F.cancelable, not fork
+    @inline override def liftIO[A](ioa: cats.effect.IO[A]): F[Throwable, A] =
+      Concurrent.liftIO(ioa)(new BIOCatsConcurrent[F](F, null)) // Concurrent.liftIO uses only F.cancelable, not fork
     @inline override final def never[A]: F[Throwable, A] = F.never
   }
 
@@ -162,7 +160,10 @@ object BIOCatsConversions {
     @inline override final def start[A](fa: F[Throwable, A]): F[Throwable, Fiber[F[Throwable, *], A]] = {
       F.map(Fork.fork(fa))(_.toCats(F))
     }
-    @inline override final def racePair[A, B](fa: F[Throwable, A], fb: F[Throwable, B]): F[Throwable, Either[(A, Fiber[F[Throwable, *], B]), (Fiber[F[Throwable, *], A], B)]] = {
+    @inline override final def racePair[A, B](
+      fa: F[Throwable, A],
+      fb: F[Throwable, B]
+    ): F[Throwable, Either[(A, Fiber[F[Throwable, *], B]), (Fiber[F[Throwable, *], A], B)]] = {
       F.map(F.racePair(fa, fb)) {
         case Left((a, f)) => Left((a, f.toCats(F)))
         case Right((f, b)) => Right((f.toCats(F), b))
diff --git a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOError3.scala b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOError3.scala
new file mode 100644
index 000000000..48382cd93
--- /dev/null
+++ b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOError3.scala
@@ -0,0 +1,20 @@
+package izumi.functional.bio
+
+import scala.util.Try
+
+trait BIOError3[F[-_, +_, +_]] extends BIOGuarantee3[F] {
+  def fail[E](v: => E): F[Any, E, Nothing]
+  def catchAll[R, E, A, E2, A2 >: A](r: F[R, E, A])(f: E => F[R, E2, A2]): F[R, E2, A2]
+  def catchSome[R, E, A, E2 >: E, A2 >: A](r: F[R, E, A])(f: PartialFunction[E, F[R, E2, A2]]): F[R, E2, A2]
+
+  def fromEither[E, V](effect: => Either[E, V]): F[Any, E, V]
+  def fromOption[E, A](errorOnNone: => E)(effect: => Option[A]): F[Any, E, A]
+  def fromTry[A](effect: => Try[A]): F[Any, Throwable, A]
+
+  def redeemPure[R, E, A, B](r: F[R, E, A])(err: E => B, succ: A => B): F[R, Nothing, B] = catchAll(map(r)(succ))(e => pure(err(e)))
+  def tapError[R, E, A, E1 >: E](r: F[R, E, A])(f: E => F[R, E1, Unit]): F[R, E1, A] = catchAll(r)(e => *>(f(e), fail(e)))
+  def attempt[R, E, A](r: F[R, E, A]): F[R, Nothing, Either[E, A]] = redeemPure(r)(Left(_), Right(_))
+
+  // defaults
+  override def bimap[R, E, A, E2, B](r: F[R, E, A])(f: E => E2, g: A => B): F[R, E2, B] = catchAll(map(r)(g))(e => fail(f(e)))
+}
diff --git a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOFiber.scala b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOFiber.scala
index f35f425c4..11c64d6ba 100644
--- a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOFiber.scala
+++ b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOFiber.scala
@@ -1,26 +1,30 @@
 package izumi.functional.bio
 
 import izumi.functional.bio.BIOExit.ZIOExit
-import zio.{Fiber, ZIO}
+import zio.{Fiber, IO, ZIO}
 
-trait BIOFiber[F[+_, +_], +E, +A] {
-  def join: F[E, A]
-  def observe: F[Nothing, BIOExit[E, A]]
-  def interrupt: F[Nothing, BIOExit[E, A]]
+trait BIOFiber3[F[-_, +_, +_], +E, +A] {
+  def join: F[Any, E, A]
+  def observe: F[Any, Nothing, BIOExit[E, A]]
+  def interrupt: F[Any, Nothing, BIOExit[E, A]]
 }
 
-object BIOFiber {
-  def fromZIO[R, E, A](f: Fiber[E, A]): BIOFiber[ZIO[R, +?, +?], E, A] =
-    new BIOFiber[ZIO[R, +?, +?], E, A] {
-      override val join: ZIO[R, E, A] = f.join
-      override val observe: ZIO[R, Nothing, BIOExit[E, A]] = f.await.map(ZIOExit.toBIOExit[E, A])
-      override def interrupt: ZIO[R, Nothing, BIOExit[E, A]] = f.interrupt.map(ZIOExit.toBIOExit[E, A])
+object BIOFiber3 {
+  def fromZIO[E, A](f: Fiber[E, A]): BIOFiber3[ZIO, E, A] =
+    new BIOFiber3[ZIO, E, A] {
+      override val join: IO[E, A] = f.join
+      override val observe: IO[Nothing, BIOExit[E, A]] = f.await.map(ZIOExit.toBIOExit[E, A])
+      override def interrupt: IO[Nothing, BIOExit[E, A]] = f.interrupt.map(ZIOExit.toBIOExit[E, A])
     }
 
-  implicit final class ToCats[F[+_, +_], A](private val bioFiber: BIOFiber[F, Throwable, A]) extends AnyVal {
-    def toCats(implicit F: BIOFunctor[F]): cats.effect.Fiber[F[Throwable, ?], A] = new cats.effect.Fiber[F[Throwable, ?], A] {
-      override def cancel: F[Throwable, Unit] = F.void(bioFiber.interrupt)
-      override def join: F[Throwable, A] = bioFiber.join
+  implicit final class ToCats[FR[-_, +_, +_], A](private val bioFiber: BIOFiber3[FR, Throwable, A]) extends AnyVal {
+    def toCats(implicit F: BIOFunctor3[FR]): cats.effect.Fiber[FR[Any, Throwable, ?], A] = new cats.effect.Fiber[FR[Any, Throwable, ?], A] {
+      override def cancel: FR[Any, Throwable, Unit] = F.void(bioFiber.interrupt)
+      override def join: FR[Any, Throwable, A] = bioFiber.join
     }
   }
 }
+
+object BIOFiber {
+  @inline def fromZIO[E, A](f: Fiber[E, A]): BIOFiber3[ZIO, E, A] = BIOFiber3.fromZIO(f)
+}
diff --git a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOFork3.scala b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOFork3.scala
new file mode 100644
index 000000000..fd3f60de3
--- /dev/null
+++ b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOFork3.scala
@@ -0,0 +1,25 @@
+package izumi.functional.bio
+
+import zio.ZIO
+
+trait BIOFork3[F[-_, +_, +_]] extends BIOForkInstances {
+  def fork[R, E, A](f: F[R, E, A]): F[R, Nothing, BIOFiber3[F, E, A]]
+}
+
+private[bio] sealed trait BIOForkInstances
+object BIOForkInstances extends LowPriorityBIOForkInstances {
+  implicit object BIOForkZio extends BIOFork3[ZIO] {
+    override def fork[R, E, A](f: ZIO[R, E, A]): ZIO[R, Nothing, BIOFiber3[ZIO, E, A]] =
+      f
+      // FIXME: ZIO Bug / feature (interruption inheritance) breaks behavior in bracket/DIResource
+      //  unless wrapped in `interruptible`
+      //  see: https://github.com/zio/zio/issues/945
+      .interruptible
+        .forkDaemon
+        .map(BIOFiber.fromZIO)
+  }
+}
+
+sealed trait LowPriorityBIOForkInstances {
+  @inline implicit final def BIOFork3To2[FR[-_, +_, +_], R](implicit BIOFork3: BIOFork3[FR]): BIOFork[FR[R, +?, +?]] = convert3To2(BIOFork3)
+}
diff --git a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOFunctor3.scala b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOFunctor3.scala
new file mode 100644
index 000000000..433ce9dfa
--- /dev/null
+++ b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOFunctor3.scala
@@ -0,0 +1,57 @@
+package izumi.functional.bio
+
+import cats.data.Kleisli
+import izumi.functional.bio.DivergenceHelper.{Divergent, Nondivergent}
+import izumi.functional.bio.PredefinedHelper.{NotPredefined, Predefined}
+import izumi.functional.bio.SpecificityHelper.{S1, S2, S3}
+import izumi.functional.bio.impl.BIOAsyncZio
+import zio.ZIO
+
+import scala.language.implicitConversions
+
+trait BIOFunctor3[F[-_, +_, +_]] extends BIOFunctorInstances with DivergenceHelper with PredefinedHelper {
+  def map[R, E, A, B](r: F[R, E, A])(f: A => B): F[R, E, B]
+
+  def as[R, E, A, B](r: F[R, E, A])(v: => B): F[R, E, B] = map(r)(_ => v)
+  def void[R, E, A](r: F[R, E, A]): F[R, E, Unit] = map(r)(_ => ())
+  @inline final def widen[R, E, A, A1](r: F[R, E, A])(implicit @deprecated("unused", "") ev: A <:< A1): F[R, E, A1] = r.asInstanceOf[F[R, E, A1]]
+}
+
+private[bio] sealed trait BIOFunctorInstances
+object BIOFunctorInstances extends BIOFunctorInstancesLowPriority1 {
+  @inline implicit final def BIOConvertFromBIOMonadAsk[FR[-_, +_, +_]](implicit BIOMonadAsk: NotPredefined.Of[BIOMonadAsk[FR]]): BIOMonad3[FR] with S1 = S1(BIOMonadAsk.InnerF)
+
+  @inline implicit final def AttachBIOAsk[FR[-_, +_, +_]](@deprecated("unused", "") self: BIOFunctor3[FR])(implicit BIOAsk: BIOAsk[FR]): BIOAsk.type = BIOAsk
+  @inline implicit final def AttachBIOPrimitives3[FR[-_, +_, +_]](@deprecated("unused", "") self: BIOFunctor3[FR])(implicit BIOPrimitives: BIOPrimitives3[FR]): BIOPrimitives.type = BIOPrimitives
+  @inline implicit final def AttachBIOFork3[FR[-_, +_, +_]](@deprecated("unused", "") self: BIOFunctor3[FR])(implicit BIOFork: BIOFork3[FR]): BIOFork.type = BIOFork
+  @inline implicit final def AttachBlockingIO3[FR[-_, +_, +_]](@deprecated("unused", "") self: BIOFunctor3[FR])(implicit BlockingIO: BlockingIO3[FR]): BlockingIO.type = BlockingIO
+
+  implicit final class KleisliSyntaxAttached[FR[-_, +_, +_]](private val FR0: BIOFunctor3[FR]) extends AnyVal {
+    @inline def fromKleisli[R, E, A](k: Kleisli[FR[Any, E, ?], R, A])(implicit FR: BIOMonadAsk[FR]): FR[R, E, A] = FR.fromKleisli(k)
+    @inline def toKleisli[R, E, A](fr: FR[R, E, A])(implicit FR: BIOLocal[FR]): Kleisli[FR[Any, E, ?], R, A] = FR.toKleisli(fr)
+  }
+}
+
+sealed trait BIOFunctorInstancesLowPriority1 extends BIOFunctorInstancesLowPriority2 {
+  @inline implicit final def BIOConvertFromBIOAsk[FR[-_, +_, +_]](implicit BIOAsk: NotPredefined.Of[BIOAsk[FR]]): BIOApplicative3[FR] with S2 = S2(BIOAsk.InnerF)
+}
+
+sealed trait BIOFunctorInstancesLowPriority2 extends BIOFunctorInstancesLowPriority3 {
+  @inline implicit final def BIOConvertFromBIOProfunctor[FR[-_, +_, +_]](implicit BIOProfunctor: NotPredefined.Of[BIOProfunctor[FR]]): BIOFunctor3[FR] with S3 = S3(BIOProfunctor.InnerF)
+
+  @inline implicit final def AttachBIOProfunctor[FR[-_, +_, +_]](@deprecated("unused", "") self: BIOFunctor3[FR])(implicit BIOProfunctor: BIOProfunctor[FR]): BIOProfunctor.type = BIOProfunctor
+}
+
+sealed trait BIOFunctorInstancesLowPriority3 {
+  // place ZIO instance at the root of the hierarchy, so that it's visible when summoning any class in hierarchy
+  @inline implicit final def BIOZIO: Predefined.Of[BIOAsync3[ZIO]] = Predefined(BIOAsyncZio)
+//  @inline implicit final def BIOZIOR[R]: BIOAsync[ZIO[R, +?, +?]] = convert3To2(BIOAsyncZio)
+
+  @inline implicit final def BIOConvert3To2[C[_[-_, +_, +_]], FR[-_, +_, +_], R0](
+    implicit BIOFunctor3: C[FR] with BIOFunctor3[FR] {
+      type Divergence = Nondivergent
+    }
+  ): C[Lambda[(`-R`, `+E`, `+A`) => FR[R0, E, A]]] with BIOFunctor[FR[R0, +?, +?]] {
+    type Divergence = Divergent
+  } = BIOFunctor3.asInstanceOf[C[Lambda[(`-R`, `+E`, `+A`) => FR[R0, E, A]]] with BIOFunctor[FR[R0, +?, +?]] { type Divergence = Divergent }]
+}
diff --git a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOGuarantee3.scala b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOGuarantee3.scala
new file mode 100644
index 000000000..510d63f9c
--- /dev/null
+++ b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOGuarantee3.scala
@@ -0,0 +1,5 @@
+package izumi.functional.bio
+
+trait BIOGuarantee3[F[-_, +_, +_]] extends BIOApplicative3[F] {
+  def guarantee[R, E, A](f: F[R, E, A], cleanup: F[R, Nothing, Unit]): F[R, E, A]
+}
diff --git a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOLocal.scala b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOLocal.scala
new file mode 100644
index 000000000..d4e52182b
--- /dev/null
+++ b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOLocal.scala
@@ -0,0 +1,23 @@
+package izumi.functional.bio
+
+import cats.data.Kleisli
+
+trait BIOLocal[FR[-_, +_, +_]] extends BIOMonadAsk[FR] with BIOArrowChoice[FR] with BIOLocalInstances {
+  override val InnerF: BIOMonad3[FR]
+
+  def provide[R, E, A](fr: FR[R, E, A])(env: => R): FR[Any, E, A] = contramap(fr)((_: Any) => env)
+
+  // defaults
+  override def dimap[R1, E, A1, R2, A2](fab: FR[R1, E, A1])(f: R2 => R1)(g: A1 => A2): FR[R2, E, A2] = InnerF.map(contramap(fab)(f))(g)
+  override def choose[RL, RR, E, AL, AR](f: FR[RL, E, AL], g: FR[RR, E, AR]): FR[Either[RL, RR], E, Either[AL, AR]] = access {
+    case Left(a)  => InnerF.map(provide(f)(a))(Left(_))
+    case Right(b) => InnerF.map(provide(g)(b))(Right(_)): FR[Either[RL, RR], E, Either[AL, AR]]
+  }
+}
+
+private[bio] sealed trait BIOLocalInstances
+object BIOLocalInstances {
+  implicit final class ToKleisliSyntaxLocal[FR[-_, +_, +_]](private val FR: BIOLocal[FR]) extends AnyVal {
+    @inline final def toKleisli[R, E, A](fr: FR[R, E, A]): Kleisli[FR[Any, E, ?], R, A] = Kleisli(FR.provide(fr)(_))
+  }
+}
diff --git a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOMonad3.scala b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOMonad3.scala
new file mode 100644
index 000000000..00ab43ee3
--- /dev/null
+++ b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOMonad3.scala
@@ -0,0 +1,23 @@
+package izumi.functional.bio
+
+trait BIOMonad3[F[-_, +_, +_]] extends BIOApplicative3[F] {
+  def flatMap[R, E, A, R2 <: R, E2 >: E, B](r: F[R, E, A])(f: A => F[R2, E2, B]): F[R2, E2, B]
+  def flatten[R, E, A](r: F[R, E, F[R, E, A]]): F[R, E, A] = flatMap(r)(identity)
+
+  def tap[R, E, A, R2 <: R, E2 >: E](r: F[R, E, A])(f: A => F[R2, E2, Unit]): F[R2, E2, A] = flatMap[R, E, A, R2, E2, A](r)(a => as(f(a))(a))
+  @inline final def when[R, E, E1](cond: F[R, E, Boolean])(ifTrue: F[R, E1, Unit])(implicit ev: E <:< E1): F[R, E1, Unit] = {
+    ifThenElse(cond)(ifTrue, unit)
+  }
+  @inline final def unless[R, E, E1](cond: F[R, E, Boolean])(ifFalse: F[R, E1, Unit])(implicit ev: E <:< E1): F[R, E1, Unit] = {
+    ifThenElse(cond)(unit, ifFalse)
+  }
+  @inline final def ifThenElse[R, E, E1, A](cond: F[R, E, Boolean])(ifTrue: F[R, E1, A], ifFalse: F[R, E1, A])(implicit ev: E <:< E1): F[R, E1, A] = {
+    flatMap(widenError(cond)(ev))(if (_) ifTrue else ifFalse)
+  }
+
+  // defaults
+  override def map[R, E, A, B](r: F[R, E, A])(f: A => B): F[R, E, B] = flatMap(r)(a => pure(f(a)))
+  override def *>[R, E, A, B](f: F[R, E, A], next: => F[R, E, B]): F[R, E, B] = flatMap(f)(_ => next)
+  override def <*[R, E, A, B](f: F[R, E, A], next: => F[R, E, B]): F[R, E, A] = flatMap(f)(a => map(next)(_ => a))
+  override def map2[R, E, A, B, C](r1: F[R, E, A], r2: => F[R, E, B])(f: (A, B) => C): F[R, E, C] = flatMap(r1)(a => map(r2)(b => f(a, b)))
+}
diff --git a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOMonadAsk.scala b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOMonadAsk.scala
new file mode 100644
index 000000000..3cb506917
--- /dev/null
+++ b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOMonadAsk.scala
@@ -0,0 +1,15 @@
+package izumi.functional.bio
+
+import cats.data.Kleisli
+
+trait BIOMonadAsk[FR[-_, +_, +_]] extends BIOAsk[FR] with BIOMonadAskSyntax {
+  override val InnerF: BIOMonad3[FR]
+  def access[R, E, A](f: R => FR[R, E, A]): FR[R, E, A]
+}
+
+private[bio] sealed trait BIOMonadAskSyntax
+object BIOMonadAskSyntax {
+  implicit final class KleisliSyntaxMonadAsk[FR[-_, +_, +_]](private val FR: BIOMonadAsk[FR]) extends AnyVal {
+    @inline def fromKleisli[R, E, A](k: Kleisli[FR[Any, E, ?], R, A]): FR[R, E, A] = FR.access(k.run)
+  }
+}
diff --git a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOMonadError3.scala b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOMonadError3.scala
new file mode 100644
index 000000000..1b84a3807
--- /dev/null
+++ b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOMonadError3.scala
@@ -0,0 +1,28 @@
+package izumi.functional.bio
+
+trait BIOMonadError3[F[-_, +_, +_]] extends BIOError3[F] with BIOMonad3[F] {
+  def redeem[R, E, A, E2, B](r: F[R, E, A])(err: E => F[R, E2, B], succ: A => F[R, E2, B]): F[R, E2, B] = {
+    flatMap(attempt(r))(_.fold(err, succ))
+  }
+
+  def flip[R, E, A](r: F[R, E, A]): F[R, A, E] = {
+    redeem(r)(pure, fail(_))
+  }
+  def leftFlatMap[R, E, A, E2](r: F[R, E, A])(f: E => F[R, Nothing, E2]): F[R, E2, A] = {
+    redeem(r)(e => flatMap(f(e))(fail(_)), pure)
+  }
+  def tapBoth[R, E, A, E2 >: E](r: F[R, E, A])(err: E => F[R, E2, Unit], succ: A => F[R, E2, Unit]): F[R, E2, A] = {
+    tap(tapError[R, E, A, E2](r)(err))(succ)
+  }
+  /** for-comprehensions sugar:
+    *
+    * {{{
+    *   for {
+    *    (1, 2) <- F.pure((2, 1))
+    *   } yield ()
+    * }}}
+    */
+  def withFilter[R, E, A](r: F[R, E, A])(predicate: A => Boolean)(implicit ev: NoSuchElementException <:< E): F[R, E, A] = {
+    flatMap(r)(a => if (predicate(a)) pure(a) else fail(new NoSuchElementException("The value doesn't satisfy the predicate")))
+  }
+}
diff --git a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOPanic3.scala b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOPanic3.scala
new file mode 100644
index 000000000..cc6fc81e2
--- /dev/null
+++ b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOPanic3.scala
@@ -0,0 +1,17 @@
+package izumi.functional.bio
+
+import cats.~>
+
+trait BIOPanic3[F[-_, +_, +_]] extends BIOBracket3[F] with BIOPanicSyntax {
+  def terminate(v: => Throwable): F[Any, Nothing, Nothing]
+  def sandbox[R, E, A](r: F[R, E, A]): F[R, BIOExit.Failure[E], A]
+
+  @inline final def orTerminate[R, A](r: F[R, Throwable, A]): F[R, Nothing, A] = catchAll(r)(terminate(_))
+}
+
+private[bio] sealed trait BIOPanicSyntax
+object BIOPanicSyntax {
+  implicit final class BIOPanicOrTerminateK[F[-_, +_, +_]](private val F: BIOPanic3[F]) extends AnyVal {
+    def orTerminateK[R]: F[R, Throwable, ?] ~> F[R, Nothing, ?] = Lambda[F[R, Throwable, ?] ~> F[R, Nothing, ?]](f => F.orTerminate(f))
+  }
+}
diff --git a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOPrimitives.scala b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOPrimitives.scala
index 129e56234..c1ddfdb35 100644
--- a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOPrimitives.scala
+++ b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOPrimitives.scala
@@ -9,19 +9,20 @@ trait BIOPrimitives[F[+_, +_]] extends BIOPrimitivesInstances {
   def mkPromise[E, A]: F[Nothing, BIOPromise[F, E, A]]
   def mkSemaphore(permits: Long): F[Nothing, BIOSemaphore[F]]
 }
+object BIOPrimitives {
+  def apply[F[+_, +_]: BIOPrimitives]: BIOPrimitives[F] = implicitly
+}
 
 private[bio] sealed trait BIOPrimitivesInstances
 object BIOPrimitivesInstances {
-  implicit val zioPrimitives: BIOPrimitives[IO] = {
-    new BIOPrimitives[IO] {
-      override def mkRef[A](a: A): IO[Nothing, BIORef[IO, A]]                = Ref.make(a).map(BIORef.fromZIO)
-      override def mkLatch: IO[Nothing, BIOPromise[IO, Nothing, Unit]]       = mkPromise[Nothing, Unit]
-      override def mkPromise[E, A]: IO[Nothing, BIOPromise[IO, E, A]]        = Promise.make[E, A].map(BIOPromise.fromZIO)
-      override def mkSemaphore(permits: Long): IO[Nothing, BIOSemaphore[IO]] = {
-        Semaphore[Task](permits)(catz.BIOAsyncForkToConcurrent)
-          .map(BIOSemaphore.fromCats[IO])
-          .orTerminate
-      }
+  implicit val BIOPrimitivesZio: BIOPrimitives[IO] = new BIOPrimitives[IO] {
+    override def mkRef[A](a: A): IO[Nothing, BIORef[IO, A]] = Ref.make(a).map(BIORef.fromZIO)
+    override def mkLatch: IO[Nothing, BIOPromise[IO, Nothing, Unit]] = mkPromise[Nothing, Unit]
+    override def mkPromise[E, A]: IO[Nothing, BIOPromise[IO, E, A]] = Promise.make[E, A].map(BIOPromise.fromZIO)
+    override def mkSemaphore(permits: Long): IO[Nothing, BIOSemaphore[IO]] = {
+      Semaphore[Task](permits)(catz.BIOAsyncForkToConcurrent[IO])
+        .map(BIOSemaphore.fromCats[IO])
+        .orTerminate
     }
   }
 }
diff --git a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOProfunctor.scala b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOProfunctor.scala
new file mode 100644
index 000000000..8748c12cf
--- /dev/null
+++ b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOProfunctor.scala
@@ -0,0 +1,19 @@
+package izumi.functional.bio
+
+import izumi.functional.bio.PredefinedHelper.Predefined
+import izumi.functional.bio.impl.BIOAsyncZio
+import zio.ZIO
+
+trait BIOProfunctor[FR[-_, +_, +_]] extends BIOProfunctorInstances with PredefinedHelper {
+  val InnerF: BIOFunctor3[FR]
+
+  def dimap[R1, E, A1, R2, A2](fra: FR[R1, E, A1])(fr: R2 => R1)(fa: A1 => A2): FR[R2, E, A2]
+
+  // defaults
+  def contramap[R, E, A, R0](fr: FR[R, E, A])(f: R0 => R): FR[R0, E, A] = dimap(fr)(f)(identity)
+}
+
+private[bio] sealed trait BIOProfunctorInstances
+object BIOProfunctorInstances {
+  @inline implicit final def BIOArrowChoiceZIO: Predefined.Of[BIOArrowChoice[ZIO]] = Predefined(BIOAsyncZio)
+}
diff --git a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOTemporal3.scala b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOTemporal3.scala
new file mode 100644
index 000000000..8120e9957
--- /dev/null
+++ b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOTemporal3.scala
@@ -0,0 +1,39 @@
+package izumi.functional.bio
+
+import izumi.functional.bio.impl.BIOTemporalZio
+import zio.ZIO
+
+import scala.concurrent.duration.{Duration, FiniteDuration}
+
+trait BIOTemporal3[F[-_, +_, +_]] extends BIOAsync3[F] with BIOTemporalInstances {
+  def sleep(duration: Duration): F[Any, Nothing, Unit]
+  def timeout[R, E, A](r: F[R, E, A])(duration: Duration): F[R, E, Option[A]]
+  def retryOrElse[R, A, E, A2 >: A, E2](r: F[R, E, A])(duration: FiniteDuration, orElse: => F[R, E2, A2]): F[R, E2, A2]
+
+  @inline final def repeatUntil[R, E, A](action: F[R, E, Option[A]])(onTimeout: => E, sleep: FiniteDuration, maxAttempts: Int): F[R, E, A] = {
+    def go(n: Int): F[R, E, A] = {
+      flatMap(action) {
+        case Some(value) =>
+          pure(value)
+        case None =>
+          if (n <= maxAttempts) {
+            *>(this.sleep(sleep), go(n + 1))
+          } else {
+            fail(onTimeout)
+          }
+      }
+    }
+
+    go(0)
+  }
+}
+
+private[bio] sealed trait BIOTemporalInstances
+object BIOTemporalInstances /*extends LowPriorityBIOTemporalInstances */{
+  @inline implicit final def BIOTemporal3Zio(implicit clockService: zio.clock.Clock): BIOTemporal3[ZIO] = new BIOTemporalZio(clockService)
+//  @inline implicit final def BIOTemporalZio[R](implicit clockService: zio.clock.Clock): BIOTemporal[ZIO[R, +?, +?]] = convert3To2(BIOTemporalInstances.BIOTemporal3Zio)
+}
+
+//sealed trait LowPriorityBIOTemporalInstances {
+//  @inline implicit final def BIOTemporal3To2[FR[-_, +_, +_], R](implicit BIOTemporal3: BIOTemporal3[FR]): BIOTemporal[FR[R, +?, +?]] = convert3To2(BIOTemporal3)
+//}
diff --git a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/DivergenceHelper.scala b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/DivergenceHelper.scala
new file mode 100644
index 000000000..49a96000b
--- /dev/null
+++ b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/DivergenceHelper.scala
@@ -0,0 +1,11 @@
+package izumi.functional.bio
+
+import izumi.functional.bio.DivergenceHelper.Nondivergent
+
+trait DivergenceHelper {
+  type Divergence = Nondivergent
+}
+object DivergenceHelper {
+  type Divergent
+  type Nondivergent
+}
diff --git a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/PredefinedHelper.scala b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/PredefinedHelper.scala
new file mode 100644
index 000000000..eefe4f9dd
--- /dev/null
+++ b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/PredefinedHelper.scala
@@ -0,0 +1,19 @@
+package izumi.functional.bio
+
+import izumi.functional.bio.PredefinedHelper.NotPredefined
+
+trait PredefinedHelper {
+  type IsPredefined = NotPredefined
+}
+object PredefinedHelper {
+  type Predefined
+  type NotPredefined
+
+  object Predefined {
+    type Of[A] = A { type IsPredefined = Predefined}
+    @inline def apply[A <: PredefinedHelper, A1 >: A](a: A): Predefined.Of[A1] = a.asInstanceOf[Predefined.Of[A1]]
+  }
+  object NotPredefined {
+    type Of[A] = A { type IsPredefined = NotPredefined }
+  }
+}
diff --git a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/SpecificityHelper.scala b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/SpecificityHelper.scala
new file mode 100644
index 000000000..cf545fa8d
--- /dev/null
+++ b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/SpecificityHelper.scala
@@ -0,0 +1,23 @@
+package izumi.functional.bio
+
+/**
+  * Just packaging conversions into implicit priority traits is not enough,
+  * scalac also has a rule that the most specific return type wins, for some reason. /_\
+  * 2.13 seems to overweigh this rule compared to 2.12
+  * So we "disjoin" the types from each other such that they're not "related", by *checks notes*... mixing some empty traits in
+  */
+private[bio] object SpecificityHelper {
+  private[bio] trait S1 extends Any
+  private[bio] trait S2 extends Any
+  private[bio] trait S3 extends Any
+  private[bio] trait S4 extends Any
+  private[bio] trait S5 extends Any
+  private[bio] trait S6 extends Any
+  private[bio] trait S7 extends Any
+  private[bio] trait S8 extends Any
+  private[bio] trait S9 extends Any
+  private[bio] trait S10 extends Any
+  @inline private[bio] def S1[A, A1 >: A](a: A): A1 with S1 = a.asInstanceOf[A1 with S1]
+  @inline private[bio] def S2[A, A1 >: A](a: A): A1 with S2 = a.asInstanceOf[A1 with S2]
+  @inline private[bio] def S3[A, A1 >: A](a: A): A1 with S3 = a.asInstanceOf[A1 with S3]
+}
diff --git a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/impl/BIOAsyncZio.scala b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/impl/BIOAsyncZio.scala
new file mode 100644
index 000000000..ae33b2fe5
--- /dev/null
+++ b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/impl/BIOAsyncZio.scala
@@ -0,0 +1,136 @@
+package izumi.functional.bio.impl
+
+import java.util.concurrent.CompletionStage
+
+import izumi.functional.bio.BIOExit.ZIOExit
+import izumi.functional.bio.{BIOAsync3, BIOExit, BIOFiber, BIOFiber3, BIOLocal, BIOMonad3, __PlatformSpecific}
+import zio.ZIO.ZIOWithFilterOps
+import zio.internal.ZIOSucceedNow
+import zio.{NeedsEnv, ZIO}
+
+import scala.concurrent.{ExecutionContext, Future}
+import scala.util.Try
+
+object BIOAsyncZio extends BIOAsyncZio
+
+class BIOAsyncZio extends BIOAsync3[ZIO] with BIOLocal[ZIO] {
+  @inline override final def pure[A](a: A): ZIO[Any, Nothing, A] = ZIOSucceedNow(a)
+  @inline override final def sync[A](effect: => A): ZIO[Any, Nothing, A] = ZIO.effectTotal(effect)
+  @inline override final def syncThrowable[A](effect: => A): ZIO[Any, Throwable, A] = ZIO.effect(effect)
+  @inline override final def suspend[R, A](effect: => ZIO[R, Throwable, A]): ZIO[R, Throwable, A] = ZIO.effectSuspend(effect)
+
+  @inline override final def fail[E](v: => E): ZIO[Any, E, Nothing] = ZIO.fail(v)
+  @inline override final def terminate(v: => Throwable): ZIO[Any, Nothing, Nothing] = ZIO.die(v)
+
+  @inline override final def fromEither[L, R0](v: => Either[L, R0]): ZIO[Any, L, R0] = ZIO.fromEither(v)
+  @inline override final def fromTry[A](effect: => Try[A]): ZIO[Any, Throwable, A] = ZIO.fromTry(effect)
+
+  @inline override final def void[R, E, A](r: ZIO[R, E, A]): ZIO[R, E, Unit] = r.unit
+  @inline override final def map[R, E, A, B](r: ZIO[R, E, A])(f: A => B): ZIO[R, E, B] = r.map(f)
+  @inline override final def as[R, E, A, B](r: ZIO[R, E, A])(v: => B): ZIO[R, E, B] = r.as(v)
+
+  @inline override final def tapError[R, E, A, E1 >: E](r: ZIO[R, E, A])(f: E => ZIO[R, E1, Unit]): ZIO[R, E1, A] = r.tapError(f)
+  @inline override final def leftMap[R, E, A, E2](r: ZIO[R, E, A])(f: E => E2): ZIO[R, E2, A] = r.mapError(f)
+  @inline override final def leftFlatMap[R, E, A, E2](r: ZIO[R, E, A])(f: E => ZIO[R, Nothing, E2]): ZIO[R, E2, A] = r.flatMapError(f)
+  @inline override final def flip[R, E, A](r: ZIO[R, E, A]): ZIO[R, A, E] = r.flip
+  @inline override final def bimap[R, E, A, E2, B](r: ZIO[R, E, A])(f: E => E2, g: A => B): ZIO[R, E2, B] = r.bimap(f, g)
+
+  @inline override final def flatMap[R, E, A, R1 <: R, E1 >: E, B](r: ZIO[R, E, A])(f0: A => ZIO[R1, E1, B]): ZIO[R1, E1, B] = r.flatMap(f0)
+  @inline override final def tap[R, E, A, R1 <: R, E2 >: E](r: ZIO[R, E, A])(f: A => ZIO[R1, E2, Unit]): ZIO[R1, E2, A] = r.tap(f)
+  @inline override final def tapBoth[R, E, A, E2 >: E](r: ZIO[R, E, A])(err: E => ZIO[R, E2, Unit], succ: A => ZIO[R, E2, Unit]): ZIO[R, E2, A] = r.tapBoth(err, succ)
+  @inline override final def flatten[R, E, A](r: ZIO[R, E, ZIO[R, E, A]]): ZIO[R, E, A] = ZIO.flatten(r)
+  @inline override final def *>[R, E, A, B](f: ZIO[R, E, A], next: => ZIO[R, E, B]): ZIO[R, E, B] = f *> next
+  @inline override final def <*[R, E, A, B](f: ZIO[R, E, A], next: => ZIO[R, E, B]): ZIO[R, E, A] =  f <* next
+  @inline override final def map2[R, E, A, B, C](r1: ZIO[R, E, A], r2: => ZIO[R, E, B])(f: (A, B) => C): ZIO[R, E, C] = r1.zipWith(r2)(f)
+
+  @inline override final def redeem[R, E, A, E2, B](r: ZIO[R, E, A])(err: E => ZIO[R, E2, B], succ: A => ZIO[R, E2, B]): ZIO[R, E2, B] = r.foldM(err, succ)
+  @inline override final def catchAll[R, E, A, E2, A2 >: A](r: ZIO[R, E, A])(f: E => ZIO[R, E2, A2]): ZIO[R, E2, A2] = r.catchAll(f)
+  @inline override final def catchSome[R, E, A, E2 >: E, A2 >: A](r: ZIO[R, E, A])(f: PartialFunction[E, ZIO[R, E2, A2]]): ZIO[R, E2, A2] = r.catchSome(f)
+  @inline override final def withFilter[R, E, A](r: ZIO[R, E, A])(predicate: A => Boolean)(implicit ev: NoSuchElementException <:< E): ZIO[R, E, A] =
+    new ZIOWithFilterOps(r).withFilter(predicate)(ev)
+
+  @inline override final def guarantee[R, E, A](f: ZIO[R, E, A], cleanup: ZIO[R, Nothing, Unit]): ZIO[R, E, A] = f.ensuring(cleanup)
+  @inline override final def attempt[R, E, A](r: ZIO[R, E, A]): ZIO[R, Nothing, Either[E, A]] = r.either
+  @inline override final def redeemPure[R, E, A, B](r: ZIO[R, E, A])(err: E => B, succ: A => B): ZIO[R, Nothing, B] = r.fold(err, succ)
+
+  @inline override final def bracket[R, E, A, B](acquire: ZIO[R, E, A])(release: A => ZIO[R, Nothing, Unit])(use: A => ZIO[R, E, B]): ZIO[R, E, B] = {
+    ZIO.bracket(acquire)(release)(use)
+  }
+
+  @inline override final def bracketCase[R, E, A, B](acquire: ZIO[R, E, A])(release: (A, BIOExit[E, B]) => ZIO[R, Nothing, Unit])(use: A => ZIO[R, E, B]): ZIO[R, E, B] = {
+    ZIO.bracketExit[R, E, A, B](acquire, { case (a, exit) => release(a, ZIOExit.toBIOExit(exit)) }, use)
+  }
+
+  @inline override final def traverse[R, E, A, B](l: Iterable[A])(f: A => ZIO[R, E, B]): ZIO[R, E, List[B]] = ZIO.foreach(l)(f)
+  @inline override final def sequence[R, E, A, B](l: Iterable[ZIO[R, E, A]]): ZIO[R, E, List[A]] = ZIO.collectAll(l)
+  @inline override final def traverse_[R, E, A](l: Iterable[A])(f: A => ZIO[R, E, Unit]): ZIO[R, E, Unit] = ZIO.foreach_(l)(f)
+  @inline override final def sequence_[R, E](l: Iterable[ZIO[R, E, Unit]]): ZIO[R, E, Unit] = ZIO.foreach_(l)(identity)
+
+  @inline override final def sandbox[R, E, A](r: ZIO[R, E, A]): ZIO[R, BIOExit.Failure[E], A] = r.sandbox.mapError(ZIOExit.toBIOExit[E])
+
+  // BIOAsync
+
+  @inline override final def yieldNow: ZIO[Any, Nothing, Unit] = ZIO.yieldNow
+  @inline override final def never: ZIO[Any, Nothing, Nothing] = ZIO.never
+
+  @inline override final def race[R, E, A](r1: ZIO[R, E, A], r2: ZIO[R, E, A]): ZIO[R, E, A] = r1.interruptible.raceFirst(r2.interruptible)
+
+  @inline override final def racePair[R, E, A, B](
+    r1: ZIO[R, E, A],
+    r2: ZIO[R, E, B]
+  ): ZIO[R, E, Either[(A, BIOFiber3[ZIO, E, B]), (BIOFiber3[ZIO, E, A], B)]] = {
+    (r1.interruptible raceWith r2.interruptible)(
+      { case (l, f) => l.fold(f.interrupt *> ZIO.halt(_), ZIOSucceedNow).map(lv => Left((lv, BIOFiber.fromZIO(f)))) },
+      { case (r, f) => r.fold(f.interrupt *> ZIO.halt(_), ZIOSucceedNow).map(rv => Right((BIOFiber.fromZIO(f), rv))) }
+    )
+  }
+
+  @inline override final def async[E, A](register: (Either[E, A] => Unit) => Unit): ZIO[Any, E, A] = {
+    ZIO.effectAsync(cb => register(cb apply _.fold(ZIO.fail(_), ZIOSucceedNow)))
+  }
+
+  @inline override final def asyncF[R, E, A](register: (Either[E, A] => Unit) => ZIO[R, E, Unit]): ZIO[R, E, A] = {
+    ZIO.effectAsyncM(cb => register(cb apply _.fold(ZIO.fail(_), ZIOSucceedNow)))
+  }
+
+  @inline override final def asyncCancelable[E, A](register: (Either[E, A] => Unit) => Canceler): ZIO[Any, E, A] = {
+    ZIO.effectAsyncInterrupt[Any, E, A] {
+      cb =>
+        val canceler = register(cb apply _.fold(ZIO.fail(_), ZIOSucceedNow))
+        Left(canceler)
+    }
+  }
+
+  @inline override final def fromFuture[A](mkFuture: ExecutionContext => Future[A]): ZIO[Any, Throwable, A] = {
+    ZIO.fromFuture(mkFuture)
+  }
+
+  @inline override final def fromFutureJava[A](javaFuture: => CompletionStage[A]): ZIO[Any, Throwable, A] = {
+    __PlatformSpecific.fromFutureJava(javaFuture)
+  }
+
+  @inline override final def uninterruptible[R, E, A](r: ZIO[R, E, A]): ZIO[R, E, A] = r.uninterruptible
+
+  @inline override final def parTraverseN[R, E, A, B](maxConcurrent: Int)(l: Iterable[A])(f: A => ZIO[R, E, B]): ZIO[R, E, List[B]] = ZIO.foreachParN(maxConcurrent)(l)(f(_).interruptible)
+  @inline override final def parTraverseN_[R, E, A, B](maxConcurrent: Int)(l: Iterable[A])(f: A => ZIO[R, E, B]): ZIO[R, E, Unit] = ZIO.foreachParN_(maxConcurrent)(l)(f(_).interruptible)
+  @inline override final def parTraverse[R, E, A, B](l: Iterable[A])(f: A => ZIO[R, E, B]): ZIO[R, E, List[B]] = ZIO.foreachPar(l)(f(_).interruptible)
+  @inline override final def parTraverse_[R, E, A, B](l: Iterable[A])(f: A => ZIO[R, E, B]): ZIO[R, E, Unit] = ZIO.foreachPar_(l)(f(_).interruptible)
+
+  @inline override final val InnerF: BIOMonad3[ZIO] = this
+
+  @inline override final def ask[R]: ZIO[R, Nothing, R] = ZIO.environment
+  @inline override final def askWith[R, A](f: R => A): ZIO[R, Nothing, A] = ZIO.access(f)
+
+  @inline override final def provide[R, E, A](fr: ZIO[R, E, A])(r: => R): ZIO[Any, E, A] = fr.provide(r)(NeedsEnv)
+  @inline override final def contramap[R, E, A, R0](fr: ZIO[R, E, A])(f: R0 => R): ZIO[R0, E, A] = fr.provideSome(f)(NeedsEnv)
+
+  @inline override final def access[R, E, A](f: R => ZIO[R, E, A]): ZIO[R, E, A] = ZIO.accessM(f)
+
+  @inline override final def dimap[R1, E, A1, R2, A2](fab: ZIO[R1, E, A1])(f: R2 => R1)(g: A1 => A2): ZIO[R2, E, A2] = fab.provideSome(f).map(g)
+
+  @inline override final def andThen[R, R1, E, A](f: ZIO[R, E, R1], g: ZIO[R1, E, A]): ZIO[R, E, A] = f >>> g
+  @inline override final def asking[R, E, A](f: ZIO[R, E, A]): ZIO[R, E, (A, R)] = f.onFirst
+
+  @inline override final def choice[RL, RR, E, A](f: ZIO[RL, E, A], g: ZIO[RR, E, A]): ZIO[Either[RL, RR], E, A] =  (f +++ g).map(_.merge)
+  @inline override final def choose[RL, RR, E, AL, AR](f: ZIO[RL, E, AL], g: ZIO[RR, E, AR]): ZIO[Either[RL, RR], E, Either[AL, AR]] = f +++ g
+}
diff --git a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/impl/BIOTemporalZio.scala b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/impl/BIOTemporalZio.scala
new file mode 100644
index 000000000..3232a45c1
--- /dev/null
+++ b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/impl/BIOTemporalZio.scala
@@ -0,0 +1,29 @@
+package izumi.functional.bio.impl
+
+import izumi.functional.bio.BIOTemporal3
+import zio.clock.Clock
+import zio.duration.Duration.fromScala
+import zio.{Schedule, ZIO}
+
+import scala.concurrent.duration.{Duration, FiniteDuration}
+
+class BIOTemporalZio(private val clock: Clock) extends BIOAsyncZio with BIOTemporal3[ZIO] {
+  @inline override final def sleep(duration: Duration): ZIO[Any, Nothing, Unit] = {
+    ZIO.sleep(fromScala(duration)).provide(clock)
+  }
+
+  @inline override final def retryOrElse[R, A, E, A2 >: A, E2](r: ZIO[R, E, A])(duration: FiniteDuration, orElse: => ZIO[R, E2, A2]): ZIO[R, E2, A2] =
+    ZIO.accessM {
+      env =>
+        val zioDuration = Schedule.duration(fromScala(duration))
+
+        r.provide(env)
+          .retryOrElse(zioDuration, (_: Any, _: Any) => orElse.provide(env))
+          .provide(clock)
+    }
+
+  @inline override final def timeout[R, E, A](r: ZIO[R, E, A])(duration: Duration): ZIO[R, E, Option[A]] = {
+    ZIO.accessM[R](e => race(r.provide(e).map(Some(_)).interruptible, sleep(duration).as(None).interruptible))
+  }
+
+}
diff --git a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/impl/BIOZio.scala b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/impl/BIOZio.scala
deleted file mode 100644
index d71babbbd..000000000
--- a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/impl/BIOZio.scala
+++ /dev/null
@@ -1,140 +0,0 @@
-package izumi.functional.bio.impl
-
-import java.util.concurrent.CompletionStage
-
-import izumi.functional.bio.BIOExit.ZIOExit
-import izumi.functional.bio.{BIOAsync, BIOExit, BIOFiber, BIOTemporal, __PlatformSpecific}
-import zio.ZIO.ZIOWithFilterOps
-import zio.clock.Clock
-import zio.internal.ZIOSucceedNow
-import zio.duration.Duration.fromScala
-import zio.{Schedule, ZIO}
-
-import scala.concurrent.duration.{Duration, FiniteDuration}
-import scala.concurrent.{ExecutionContext, Future}
-import scala.util.Try
-
-object BIOZio extends BIOZio[Any]
-
-class BIOZio[R] extends BIOAsync[ZIO[R, +?, +?]] {
-  private[this] final type IO[+E, +A] = ZIO[R, E, A]
-
-  @inline override final def pure[A](a: A): IO[Nothing, A] = ZIOSucceedNow(a)
-  @inline override final def sync[A](effect: => A): IO[Nothing, A] = ZIO.effectTotal(effect)
-  @inline override final def syncThrowable[A](effect: => A): IO[Throwable, A] = ZIO.effect(effect)
-  @inline override final def suspend[A](effect: => IO[Throwable, A]): IO[Throwable, A] = ZIO.effectSuspend(effect)
-
-  @inline override final def fail[E](v: => E): IO[E, Nothing] = ZIO.fail(v)
-  @inline override final def terminate(v: => Throwable): IO[Nothing, Nothing] = ZIO.die(v)
-
-  @inline override final def fromEither[L, R0](v: => Either[L, R0]): IO[L, R0] = ZIO.fromEither(v)
-  @inline override final def fromTry[A](effect: => Try[A]): IO[Throwable, A] = ZIO.fromTry(effect)
-
-  @inline override final def void[E, A](r: IO[E, A]): IO[E, Unit] = r.unit
-  @inline override final def map[E, A, B](r: IO[E, A])(f: A => B): IO[E, B] = r.map(f)
-  @inline override final def as[E, A, B](r: IO[E, A])(v: => B): IO[E, B] = r.as(v)
-
-  @inline override final def tapError[E, A, E1 >: E](r: IO[E, A])(f: E => IO[E1, Unit]): IO[E1, A] = r.tapError(f)
-  @inline override final def leftMap[E, A, E2](r: IO[E, A])(f: E => E2): IO[E2, A] = r.mapError(f)
-  @inline override final def leftFlatMap[E, A, E2](r: IO[E, A])(f: E => IO[Nothing, E2]): IO[E2, A] = r.flatMapError(f)
-  @inline override final def flip[E, A](r: IO[E, A]): IO[A, E] = r.flip
-  @inline override final def bimap[E, A, E2, B](r: IO[E, A])(f: E => E2, g: A => B): IO[E2, B] = r.bimap(f, g)
-
-  @inline override final def flatMap[E, A, E1 >: E, B](r: IO[E, A])(f0: A => IO[E1, B]): IO[E1, B] = r.flatMap(f0)
-  @inline override final def tap[E, A, E2 >: E](r: IO[E, A])(f: A => IO[E2, Unit]): IO[E2, A] = r.tap(f)
-  @inline override final def tapBoth[E, A, E2 >: E](r: IO[E, A])(err: E => IO[E2, Unit], succ: A => IO[E2, Unit]): IO[E2, A] = r.tapBoth(err, succ)
-  @inline override final def flatten[E, A](r: IO[E, IO[E, A]]): IO[E, A] = ZIO.flatten(r)
-  @inline override final def *>[E, A, B](f: IO[E, A], next: => IO[E, B]): IO[E, B] = f *> next
-  @inline override final def <*[E, A, B](f: IO[E, A], next: => IO[E, B]): IO[E, A] = f <* next
-  @inline override final def map2[E, A, B, C](r1: IO[E, A], r2: => IO[E, B])(f: (A, B) => C): IO[E, C] = r1.zipWith(r2)(f)
-
-  @inline override final def redeem[E, A, E2, B](r: IO[E, A])(err: E => IO[E2, B], succ: A => IO[E2, B]): IO[E2, B] = r.foldM(err, succ)
-  @inline override final def catchAll[E, A, E2, A2 >: A](r: IO[E, A])(f: E => IO[E2, A2]): IO[E2, A2] = r.catchAll(f)
-  @inline override final def catchSome[E, A, E2 >: E, A2 >: A](r: ZIO[R, E, A])(f: PartialFunction[E, ZIO[R, E2, A2]]): ZIO[R, E2, A2] = r.catchSome(f)
-  @inline override final def withFilter[E, A](r: IO[E, A])(predicate: A => Boolean)(implicit ev: NoSuchElementException <:< E): IO[E, A] =
-    new ZIOWithFilterOps(r).withFilter(predicate)(ev)
-
-  @inline override final def guarantee[E, A](f: IO[E, A])(cleanup: IO[Nothing, Unit]): IO[E, A] = f.ensuring(cleanup)
-  @inline override final def attempt[E, A](r: IO[E, A]): IO[Nothing, Either[E, A]] = r.either
-  @inline override final def redeemPure[E, A, B](r: IO[E, A])(err: E => B, succ: A => B): IO[Nothing, B] = r.fold(err, succ)
-
-  @inline override final def bracket[E, A, B](acquire: IO[E, A])(release: A => IO[Nothing, Unit])(use: A => IO[E, B]): IO[E, B] = {
-    ZIO.bracket(acquire)(release)(use)
-  }
-
-  @inline override final def bracketCase[E, A, B](acquire: IO[E, A])(release: (A, BIOExit[E, B]) => IO[Nothing, Unit])(use: A => IO[E, B]): IO[E, B] = {
-    ZIO.bracketExit[R, E, A, B](acquire, { case (a, exit) => release(a, ZIOExit.toBIOExit(exit)) }, use)
-  }
-
-  @inline override final def traverse[E, A, B](l: Iterable[A])(f: A => IO[E, B]): IO[E, List[B]] = ZIO.foreach(l)(f)
-  @inline override final def sequence[E, A, B](l: Iterable[IO[E, A]]): IO[E, List[A]] = ZIO.collectAll(l)
-  @inline override final def traverse_[E, A](l: Iterable[A])(f: A => IO[E, Unit]): IO[E, Unit] = ZIO.foreach_(l)(f)
-  @inline override final def sequence_[E](l: Iterable[IO[E, Unit]]): IO[E, Unit] = ZIO.foreach_(l)(identity)
-
-  @inline override final def sandbox[E, A](r: IO[E, A]): IO[BIOExit.Failure[E], A] = r.sandbox.mapError(ZIOExit.toBIOExit[E])
-
-  // BIOAsync
-
-  @inline override final def yieldNow: IO[Nothing, Unit] = ZIO.yieldNow
-  @inline override final def never: IO[Nothing, Nothing] = ZIO.never
-
-  @inline override final def race[E, A](r1: IO[E, A], r2: IO[E, A]): IO[E, A] = r1.interruptible.raceFirst(r2.interruptible)
-
-  @inline override final def racePair[E, A, B](r1: IO[E, A], r2: IO[E, B]): IO[E, Either[(A, BIOFiber[ZIO[R, +?, +?], E, B]), (BIOFiber[ZIO[R, +?, +?], E, A], B)]] = {
-    (r1.interruptible raceWith r2.interruptible)(
-      { case (l, f) => l.fold(f.interrupt *> ZIO.halt(_), ZIOSucceedNow).map(lv => Left((lv, BIOFiber.fromZIO(f)))) },
-      { case (r, f) => r.fold(f.interrupt *> ZIO.halt(_), ZIOSucceedNow).map(rv => Right((BIOFiber.fromZIO(f), rv))) }
-    )
-  }
-
-  @inline override final def async[E, A](register: (Either[E, A] => Unit) => Unit): IO[E, A] = {
-    ZIO.effectAsync(cb => register(cb apply _.fold(ZIO.fail(_), ZIOSucceedNow)))
-  }
-
-  @inline override final def asyncF[E, A](register: (Either[E, A] => Unit) => ZIO[R, E, Unit]): ZIO[R, E, A] = {
-    ZIO.effectAsyncM(cb => register(cb apply _.fold(ZIO.fail(_), ZIOSucceedNow)))
-  }
-
-  @inline override final def asyncCancelable[E, A](register: (Either[E, A] => Unit) => Canceler): IO[E, A] = {
-    ZIO.effectAsyncInterrupt[R, E, A] {
-      cb =>
-        val canceler = register(cb apply _.fold(ZIO.fail(_), ZIOSucceedNow))
-        Left(canceler)
-    }
-  }
-
-  @inline override final def fromFuture[A](mkFuture: ExecutionContext => Future[A]): IO[Throwable, A] = {
-    ZIO.fromFuture(mkFuture)
-  }
-
-  @inline override final def fromFutureJava[A](javaFuture: => CompletionStage[A]): IO[Throwable, A] = {
-    __PlatformSpecific.fromFutureJava(javaFuture)
-  }
-
-  @inline override final def uninterruptible[E, A](r: IO[E, A]): IO[E, A] = r.uninterruptible
-
-  @inline override final def parTraverseN[E, A, B](maxConcurrent: Int)(l: Iterable[A])(f: A => IO[E, B]): IO[E, List[B]] = ZIO.foreachParN(maxConcurrent)(l)(f(_).interruptible)
-  @inline override final def parTraverseN_[E, A, B](maxConcurrent: Int)(l: Iterable[A])(f: A => ZIO[R, E, B]): ZIO[R, E, Unit] = ZIO.foreachParN_(maxConcurrent)(l)(f(_).interruptible)
-  @inline override final def parTraverse[E, A, B](l: Iterable[A])(f: A => ZIO[R, E, B]): ZIO[R, E, List[B]] = ZIO.foreachPar(l)(f(_).interruptible)
-  @inline override final def parTraverse_[E, A, B](l: Iterable[A])(f: A => ZIO[R, E, B]): ZIO[R, E, Unit] = ZIO.foreachPar_(l)(f(_).interruptible)
-}
-
-class BIOTemporalZio[R](private val clock: Clock) extends BIOZio[R] with BIOTemporal[ZIO[R, +?, +?]] {
-  @inline override final def sleep(duration: Duration): ZIO[R, Nothing, Unit] = {
-    ZIO.sleep(fromScala(duration)).provide(clock)
-  }
-
-  @inline override final def retryOrElse[A, E, A2 >: A, E2](r: ZIO[R, E, A])(duration: FiniteDuration, orElse: => ZIO[R, E2, A2]): ZIO[R, E2, A2] =
-    ZIO.accessM { env =>
-      val zioDuration = Schedule.duration(fromScala(duration))
-
-      r.provide(env)
-        .retryOrElse(zioDuration, (_: Any, _: Any) => orElse.provide(env))
-        .provide(clock)
-    }
-
-  @inline override final def timeout[E, A](r: ZIO[R, E, A])(duration: Duration): ZIO[R, E, Option[A]] = {
-    ZIO.accessM[R](e => race(r.provide(e).map(Some(_)).interruptible, sleep(duration).as(None).interruptible))
-  }
-
-}
diff --git a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/impl/MiniBIO.scala b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/impl/MiniBIO.scala
index cb53a960f..94053f5a4 100644
--- a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/impl/MiniBIO.scala
+++ b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/impl/MiniBIO.scala
@@ -33,9 +33,9 @@ sealed trait MiniBIO[+E, +A] {
   final def run(): BIOExit[E, A] = {
 
     final class Catcher[E0, A0, E1, B](
-                                        val recover: BIOExit.Failure[E0] => MiniBIO[E1, B]
-                                      , f: A0 => MiniBIO[E1, B]
-                                      ) extends (A0 => MiniBIO[E1, B]) {
+      val recover: BIOExit.Failure[E0] => MiniBIO[E1, B],
+      f: A0 => MiniBIO[E1, B]
+    ) extends (A0 => MiniBIO[E1, B]) {
       override def apply(a: A0): MiniBIO[E1, B] = f(a)
     }
 
@@ -48,18 +48,20 @@ sealed trait MiniBIO[+E, +A] {
         runner(io, new Catcher(err, succ) :: stack)
 
       case MiniBIO.Sync(a) =>
-        val exit = try { a() } catch {
-          case t: Throwable =>
-            BIOExit.Termination(t, Trace.empty)
-        }
+        val exit =
+          try { a() } catch {
+            case t: Throwable =>
+              BIOExit.Termination(t, Trace.empty)
+          }
         exit match {
           case BIOExit.Success(value) =>
             stack match {
               case flatMap :: stackRest =>
-                val nextIO = try { flatMap(value) } catch {
-                  case t: Throwable =>
-                    Fail.terminate(t)
-                }
+                val nextIO =
+                  try { flatMap(value) } catch {
+                    case t: Throwable =>
+                      Fail.terminate(t)
+                  }
                 runner(nextIO, stackRest)
 
               case Nil =>
@@ -70,10 +72,12 @@ sealed trait MiniBIO[+E, +A] {
             runner(Fail.halt(failure), stack)
         }
       case MiniBIO.Fail(e) =>
-        val err = try e() catch {
-          case t: Throwable =>
-            BIOExit.Termination(t, Trace.empty)
-        }
+        val err =
+          try e()
+          catch {
+            case t: Throwable =>
+              BIOExit.Termination(t, Trace.empty)
+          }
         val catcher = stack.dropWhile(!_.isInstanceOf[Catcher[_, _, _, _]])
         catcher match {
           case value :: stackRest =>
@@ -89,7 +93,6 @@ sealed trait MiniBIO[+E, +A] {
 }
 
 object MiniBIO {
-
   object autoRun {
     implicit def autoRunAlways[A](f: MiniBIO[Throwable, A]): A = f.run() match {
       case BIOExit.Success(value) =>
@@ -112,49 +115,52 @@ object MiniBIO {
 
   implicit val BIOMiniBIO: BIO[MiniBIO] with BlockingIO[MiniBIO] = new BIO[MiniBIO] with BlockingIO[MiniBIO] {
     override def pure[A](a: A): MiniBIO[Nothing, A] = sync(a)
-    override def flatMap[E, A, E1 >: E, B](r: MiniBIO[E, A])(f: A => MiniBIO[E1, B]): MiniBIO[E1, B] = FlatMap(r, f)
+    override def flatMap[R, E, A, R1 <: R, E1 >: E, B](r: MiniBIO[E, A])(f: A => MiniBIO[E1, B]): MiniBIO[E1, B] = FlatMap(r, f)
     override def fail[E](v: => E): MiniBIO[E, Nothing] = Fail(() => BIOExit.Error(v, Trace.empty))
     override def terminate(v: => Throwable): MiniBIO[Nothing, Nothing] = Fail.terminate(v)
 
     override def syncThrowable[A](effect: => A): MiniBIO[Throwable, A] = Sync {
-      () => try { BIOExit.Success(effect) } catch { case e: Throwable => BIOExit.Error(e, Trace.empty) }
+      () =>
+        try { BIOExit.Success(effect) } catch { case e: Throwable => BIOExit.Error(e, Trace.empty) }
     }
     override def sync[A](effect: => A): MiniBIO[Nothing, A] = Sync(() => BIOExit.Success(effect))
 
-    override def redeem[E, A, E2, B](r: MiniBIO[E, A])(err: E => MiniBIO[E2, B], succ: A => MiniBIO[E2, B]): MiniBIO[E2, B] = {
+    override def redeem[R, E, A, E2, B](r: MiniBIO[E, A])(err: E => MiniBIO[E2, B], succ: A => MiniBIO[E2, B]): MiniBIO[E2, B] = {
       Redeem[E, A, E2, B](r, {
         case BIOExit.Termination(t, e, c) => Fail.halt(BIOExit.Termination(t, e, c))
         case BIOExit.Error(e, _) => err(e)
       }, succ)
     }
 
-    override def catchAll[E, A, E2, A2 >: A](r: MiniBIO[E, A])(f: E => MiniBIO[E2, A2]): MiniBIO[E2, A2] = redeem(r)(f, pure)
+    override def catchAll[R, E, A, E2, A2 >: A](r: MiniBIO[E, A])(f: E => MiniBIO[E2, A2]): MiniBIO[E2, A2] = redeem(r)(f, pure)
 
-    override def catchSome[E, A, E2 >: E, A2 >: A](r: MiniBIO[E, A])(f: PartialFunction[E, MiniBIO[E2, A2]]): MiniBIO[E2, A2] = {
+    override def catchSome[R, E, A, E2 >: E, A2 >: A](r: MiniBIO[E, A])(f: PartialFunction[E, MiniBIO[E2, A2]]): MiniBIO[E2, A2] = {
       Redeem[E, A, E2, A2](r, {
         case BIOExit.Termination(t, e, c) => Fail.halt(BIOExit.Termination(t, e, c))
-        case exit@BIOExit.Error(e, _) => f.applyOrElse(e, (_: E) => Fail.halt(exit))
+        case exit @ BIOExit.Error(e, _) => f.applyOrElse(e, (_: E) => Fail.halt(exit))
       }, pure)
     }
 
-    override def bracketCase[E, A, B](acquire: MiniBIO[E, A])(release: (A, BIOExit[E, B]) => MiniBIO[Nothing, Unit])(use: A => MiniBIO[E, B]): MiniBIO[E, B] = {
+    override def bracketCase[R, E, A, B](acquire: MiniBIO[E, A])(release: (A, BIOExit[E, B]) => MiniBIO[Nothing, Unit])(use: A => MiniBIO[E, B]): MiniBIO[E, B] = {
       // does not propagate error in release in case `use` fails, propagates only error from `use`
-      flatMap(acquire)(a =>
-        Redeem[E, B, E, B](
-          io = use(a)
-        , err = e => Redeem[Nothing, Unit, E, Nothing](release(a, e), err = _ => Fail(() => e), succ = _ => Fail(() => e))
-        , succ = v => map(release(a, BIOExit.Success(v)))(_ => v)
-        )
+      flatMap(acquire)(
+        a =>
+          Redeem[E, B, E, B](
+            io = use(a),
+            err = e => Redeem[Nothing, Unit, E, Nothing](release(a, e), err = _ => Fail(() => e), succ = _ => Fail(() => e)),
+            succ = v => map(release(a, BIOExit.Success(v)))(_ => v)
+          )
       )
     }
 
-    override def sandbox[E, A](r: MiniBIO[E, A]): MiniBIO[BIOExit.Failure[E], A] = {
+    override def sandbox[R, E, A](r: MiniBIO[E, A]): MiniBIO[BIOExit.Failure[E], A] = {
       Redeem[E, A, BIOExit.Failure[E], A](r, e => fail(e), pure)
     }
 
-    override def traverse[E, A, B](l: Iterable[A])(f: A => MiniBIO[E, B]): MiniBIO[E, List[B]] = {
-      val x = l.foldLeft(pure(Nil): MiniBIO[E, List[B]]) { (acc, a) =>
-        flatMap(acc)(list => map(f(a))(_ :: list))
+    override def traverse[R, E, A, B](l: Iterable[A])(f: A => MiniBIO[E, B]): MiniBIO[E, List[B]] = {
+      val x = l.foldLeft(pure(Nil): MiniBIO[E, List[B]]) {
+        (acc, a) =>
+          flatMap(acc)(list => map(f(a))(_ :: list))
       }
       map(x)(_.reverse)
     }
diff --git a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/package.scala b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/package.scala
index d99dfaf22..0cf68d2a5 100644
--- a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/package.scala
+++ b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/package.scala
@@ -1,18 +1,9 @@
 package izumi.functional
 
-import java.util.concurrent.CompletionStage
-
-import cats.~>
-import izumi.functional.bio.impl.{BIOTemporalZio, BIOZio}
+import izumi.functional.bio.syntax.{BIO3Syntax, BIOSyntax}
 import izumi.functional.mono.{Clock, Entropy, SyncSafe}
-import zio.ZIO
-
-import scala.concurrent.duration.{Duration, FiniteDuration}
-import scala.concurrent.{ExecutionContext, Future}
-import scala.language.implicitConversions
-import scala.util.Try
 
-package object bio extends BIOSyntax {
+package object bio extends BIO3Syntax with BIOSyntax {
 
   /**
     * A convenient dependent summoner for BIO* hierarchy.
@@ -25,299 +16,79 @@ package object bio extends BIOSyntax {
     * }}}
     *
     */
-  @inline override final def F[F[+_, +_]](implicit F: BIOFunctor[F]): F.type = F
+  @inline override final def F[FR[-_, +_, +_]](implicit FR: BIOFunctor3[FR]): FR.type = FR
 
   /**
     * NOTE: The left type parameter is not forced to be covariant
     * because [[BIOFunctor]] does not yet expose any operations
     * on it.
     **/
-  trait BIOFunctor[F[_, +_]] extends BIOFunctorInstances {
-    def map[E, A, B](r: F[E, A])(f: A => B): F[E, B]
-
-    def as[E, A, B](r: F[E, A])(v: => B): F[E, B] = map(r)(_ => v)
-    def void[E, A](r: F[E, A]): F[E, Unit] = map(r)(_ => ())
-    @inline final def widen[E, A, A1](r: F[E, A])(implicit @deprecated("unused", "") ev: A <:< A1): F[E, A1] = r.asInstanceOf[F[E, A1]]
-  }
-
-  private[bio] sealed trait BIOFunctorInstances
-  object BIOFunctorInstances {
-    // place ZIO instance at the root of the hierarchy, so that it's visible when summoning any class in hierarchy
-    @inline implicit final def BIOZIO[R]: BIOZio[R] = BIOZio.asInstanceOf[BIOZio[R]]
-
-    @inline implicit final def AttachBIOPrimitives[F[+_, +_]](@deprecated("unused", "") self: BIOFunctor[F])(implicit BIOPrimitives: BIOPrimitives[F]): BIOPrimitives.type = BIOPrimitives
-
-    @inline implicit final def AttachBIOFork[F[+_, +_]](@deprecated("unused", "") self: BIOFunctor[F])(implicit BIOFork: BIOFork[F]): BIOFork.type = BIOFork
-    @inline implicit final def AttachBIOFork3[F[-_, +_, +_]](@deprecated("unused", "") self: BIOFunctor[F[Any, +?, +?]])(implicit BIOFork: BIOFork3[F]): BIOFork.type = BIOFork
-
-    @inline implicit final def AttachBlockingIO[F[+_, +_]](@deprecated("unused", "") self: BIOFunctor[F])(implicit BlockingIO: BlockingIO[F]): BlockingIO.type = BlockingIO
-    @inline implicit final def AttachBlockingIO3[F[-_, +_, +_]](@deprecated("unused", "") self: BIOFunctor[F[Any, +?, +?]])(implicit BlockingIO: BlockingIO3[F]): BlockingIO.type = BlockingIO
-  }
-
-  trait BIOBifunctor[F[+_, +_]] extends BIOFunctor[F] {
-    def bimap[E, A, E2, A2](r: F[E, A])(f: E => E2, g: A => A2): F[E2, A2]
-    def leftMap[E, A, E2](r: F[E, A])(f: E => E2): F[E2, A] = bimap(r)(f, identity)
-
-    @inline final def widenError[E, A, E1](r: F[E, A])(implicit @deprecated("unused","") ev: E <:< E1): F[E1, A] = r.asInstanceOf[F[E1, A]]
-    @inline final def widenBoth[E, A, E1, A1](r: F[E, A])(implicit @deprecated("unused","") ev: E <:< E1, @deprecated("unused", "") ev2: A <:< A1): F[E1, A1] = r.asInstanceOf[F[E1, A1]]
-  }
-
-  trait BIOApplicative[F[+_, +_]] extends BIOBifunctor[F] {
-    def pure[A](a: A): F[Nothing, A]
-
-    /** execute two operations in order, map their results */
-    def map2[E, A, B, C](firstOp: F[E, A], secondOp: => F[E, B])(f: (A, B) => C): F[E, C]
-
-    /** execute two operations in order, return result of second operation */
-    def *>[E, A, B](firstOp: F[E, A], secondOp: => F[E, B]): F[E, B]
-
-    /** execute two operations in order, same as `*>`, but return result of first operation */
-    def <*[E, A, B](firstOp: F[E, A], secondOp: => F[E, B]): F[E, A]
-
-    def traverse[E, A, B](l: Iterable[A])(f: A => F[E, B]): F[E, List[B]]
+  type BIOFunctor[F[+_, +_]] = BIOFunctor3[Lambda[(`-R`, `+E`, `+A`) => F[E, A]]]
 
-    @inline final def forever[E, A](r: F[E, A]): F[E, Nothing] = *>(r, forever(r))
-    def traverse_[E, A](l: Iterable[A])(f: A => F[E, Unit]): F[E, Unit] = void(traverse(l)(f))
-    def sequence[E, A, B](l: Iterable[F[E, A]]): F[E, List[A]] = traverse(l)(identity)
-    def sequence_[E](l: Iterable[F[E, Unit]]): F[E, Unit] = void(traverse(l)(identity))
+  type BIOBifunctor[F[+_, +_]] = BIOBifunctor3[Lambda[(`-R`, `+E`, `+A`) => F[E, A]]]
 
-    final val unit: F[Nothing, Unit] = pure(())
-    @inline final def traverse[E, A, B](o: Option[A])(f: A => F[E, B]): F[E, Option[B]] = o match {
-      case Some(a) => map(f(a))(Some(_))
-      case None => pure(None)
-    }
-    @inline final def when[E](cond: Boolean)(ifTrue: F[E, Unit]): F[E, Unit] = if (cond) ifTrue else unit
-    @inline final def unless[E](cond: Boolean)(ifFalse: F[E, Unit]): F[E, Unit] = if (cond) unit else ifFalse
-    @inline final def ifThenElse[E, A](cond: Boolean)(ifTrue: F[E, A], ifFalse: F[E, A]): F[E, A] = if (cond) ifTrue else ifFalse
-  }
-
-  trait BIOGuarantee[F[+_, +_]] extends BIOApplicative[F] {
-    def guarantee[E, A](f: F[E, A])(cleanup: F[Nothing, Unit]): F[E, A]
-  }
+  type BIOApplicative[F[+_, +_]] = BIOApplicative3[Lambda[(`-R`, `+E`, `+A`) => F[E, A]]]
 
-  trait BIOError[F[+_, +_]] extends BIOGuarantee[F] {
-    def fail[E](v: => E): F[E, Nothing]
-    def catchAll[E, A, E2, A2 >: A](r: F[E, A])(f: E => F[E2, A2]): F[E2, A2]
-    def catchSome[E, A, E2 >: E, A2 >: A](r: F[E, A])(f: PartialFunction[E, F[E2, A2]]): F[E2, A2]
+  type BIOGuarantee[F[+_, +_]] = BIOGuarantee3[Lambda[(`-R`, `+E`, `+A`) => F[E, A]]]
 
-    def fromEither[E, V](effect: => Either[E, V]): F[E, V]
-    def fromOption[E, A](errorOnNone: => E)(effect: => Option[A]): F[E, A]
-    def fromTry[A](effect: => Try[A]): F[Throwable, A]
+  type BIOError[F[+_, +_]] = BIOError3[Lambda[(`-R`, `+E`, `+A`) => F[E, A]]]
 
-    def redeemPure[E, A, B](r: F[E, A])(err: E => B, succ: A => B): F[Nothing, B] = catchAll(map(r)(succ))(e => pure(err(e)))
-    def tapError[E, A, E1 >: E](r: F[E, A])(f: E => F[E1, Unit]): F[E1, A] = catchAll(r)(e => *>(f(e), fail(e)))
-    def attempt[E, A](r: F[E, A]): F[Nothing, Either[E, A]] = redeemPure(r)(Left(_), Right(_))
-
-    // defaults
-    override def bimap[E, A, E2, B](r: F[E, A])(f: E => E2, g: A => B): F[E2, B] = catchAll(map(r)(g))(e => fail(f(e)))
-  }
+  type BIOMonad[F[+_, +_]] = BIOMonad3[Lambda[(`-R`, `+E`, `+A`) => F[E, A]]]
 
-  trait BIOMonad[F[+_, +_]] extends BIOApplicative[F] {
-    def flatMap[E, A, E2 >: E, B](r: F[E, A])(f: A => F[E2, B]): F[E2, B]
-    def flatten[E, A](r: F[E, F[E, A]]): F[E, A] = flatMap(r)(identity)
+  type BIOMonadError[F[+_, +_]] = BIOMonadError3[Lambda[(`-R`, `+E`, `+A`) => F[E, A]]]
 
-    def tap[E, A, E2 >: E](r: F[E, A])(f: A => F[E2, Unit]): F[E2, A] = flatMap[E, A, E2, A](r)(a => as(f(a))(a))
-    @inline final def when[E, E1](cond: F[E, Boolean])(ifTrue: F[E1, Unit])(implicit ev: E <:< E1): F[E1, Unit] = {
-      ifThenElse(cond)(ifTrue, unit)
-    }
-    @inline final def unless[E, E1](cond: F[E, Boolean])(ifFalse: F[E1, Unit])(implicit ev: E <:< E1): F[E1, Unit] = {
-      ifThenElse(cond)(unit, ifFalse)
-    }
-    @inline final def ifThenElse[E, E1, A](cond: F[E, Boolean])(ifTrue: F[E1, A], ifFalse: F[E1, A])(implicit ev: E <:< E1): F[E1, A] = {
-      flatMap(widenError(cond)(ev))(if (_) ifTrue else ifFalse)
-    }
+  type BIOBracket[F[+_, +_]] = BIOBracket3[Lambda[(`-R`, `+E`, `+A`) => F[E, A]]]
 
-    // defaults
-    override def map[E, A, B](r: F[E, A])(f: A => B): F[E, B] = flatMap(r)(a => pure(f(a)))
-    override def *>[E, A, B](f: F[E, A], next: => F[E, B]): F[E, B] = flatMap(f)(_ => next)
-    override def <*[E, A, B](f: F[E, A], next: => F[E, B]): F[E, A] = flatMap(f)(a => map(next)(_ => a))
-    override def map2[E, A, B, C](r1: F[E, A], r2: => F[E, B])(f: (A, B) => C): F[E, C] = flatMap(r1)(a => map(r2)(b => f(a, b)))
-  }
-
-  trait BIOMonadError[F[+_, +_]] extends BIOError[F] with BIOMonad[F] {
-    def redeem[E, A, E2, B](r: F[E, A])(err: E => F[E2, B], succ: A => F[E2, B]): F[E2, B] = {
-      flatMap(attempt(r))(_.fold(err, succ))
-    }
-
-    def flip[E, A](r: F[E, A]): F[A, E] = {
-      redeem(r)(pure, fail(_))
-    }
-    def leftFlatMap[E, A, E2](r: F[E, A])(f: E => F[Nothing, E2]): F[E2, A] = {
-      redeem(r)(e => flatMap(f(e))(fail(_)), pure)
-    }
-    def tapBoth[E, A, E2 >: E](r: F[E, A])(err: E => F[E2, Unit], succ: A => F[E2, Unit]): F[E2, A] = {
-      tap(tapError[E, A, E2](r)(err))(succ)
-    }
-    /** for-comprehensions sugar:
-      *
-      * {{{
-      *   for {
-      *    (1, 2) <- F.pure((2, 1))
-      *   } yield ()
-      * }}}
-      */
-    def withFilter[E, A](r: F[E, A])(predicate: A => Boolean)(implicit ev: NoSuchElementException <:< E): F[E, A] = {
-      flatMap(r)(a => if (predicate(a)) pure(a) else fail(new NoSuchElementException("The value doesn't satisfy the predicate")))
-    }
-  }
+  type BIOPanic[F[+_, +_]] = BIOPanic3[Lambda[(`-R`, `+E`, `+A`) => F[E, A]]]
 
-  trait BIOBracket[F[+_, +_]] extends BIOMonadError[F] {
-    def bracketCase[E, A, B](acquire: F[E, A])(release: (A, BIOExit[E, B]) => F[Nothing, Unit])(use: A => F[E, B]): F[E, B]
-
-    def bracket[E, A, B](acquire: F[E, A])(release: A => F[Nothing, Unit])(use: A => F[E, B]): F[E, B] = {
-      bracketCase[E, A, B](acquire)((a, _) => release(a))(use)
-    }
-
-    // defaults
-    override def guarantee[E, A](f: F[E, A])(cleanup: F[Nothing, Unit]): F[E, A] = {
-      bracket(unit)(_ => cleanup)(_ => f)
-    }
-  }
-
-  trait BIOPanic[F[+_, +_]] extends BIOBracket[F] with BIOPanicSyntax {
-    def terminate(v: => Throwable): F[Nothing, Nothing]
-    def sandbox[E, A](r: F[E, A]): F[BIOExit.Failure[E], A]
-
-    @inline final def orTerminate[A](r: F[Throwable, A]): F[Nothing, A] = catchAll(r)(terminate(_))
-  }
-
-  private[bio] sealed trait BIOPanicSyntax
-  object BIOPanicSyntax {
-    implicit final class BIOPanicOrTerminateK[F[+_, +_]](private val F: BIOPanic[F]) extends AnyVal {
-      def orTerminateK: F[Throwable, ?] ~> F[Nothing, ?] = Lambda[F[Throwable, ?] ~> F[Nothing, ?]](F.orTerminate(_))
-    }
-  }
+  type BIO[F[+_, +_]] = BIO3[Lambda[(`-R`, `+E`, `+A`) => F[E, A]]]
 
-  trait BIO[F[+_, +_]] extends BIOPanic[F] {
-    final type Or[+E, +A] = F[E, A]
-    final type Just[+A] = F[Nothing, A]
+  type BIOAsync[F[+_, +_]] = BIOAsync3[Lambda[(`-R`, `+E`, `+A`) => F[E, A]]]
 
-    def syncThrowable[A](effect: => A): F[Throwable, A]
-    def sync[A](effect: => A): F[Nothing, A]
-
-    @inline final def apply[A](effect: => A): F[Throwable, A] = syncThrowable(effect)
-
-    def suspend[A](effect: => F[Throwable, A]): F[Throwable, A] = flatten(syncThrowable(effect))
-
-    // defaults
-    override def fromEither[E, A](effect: => Either[E, A]): F[E, A] = flatMap(sync(effect)) {
-      case Left(e) => fail(e): F[E, A]
-      case Right(v) => pure(v): F[E, A]
-    }
-    override def fromOption[E, A](errorOnNone: => E)(effect: => Option[A]): F[E, A] = {
-      flatMap(sync(effect))(e => fromEither(e.toRight(errorOnNone)))
-    }
-    override def fromTry[A](effect: => Try[A]): F[Throwable, A] = {
-      syncThrowable(effect.get)
-    }
-  }
-
-  trait BIOAsync[F[+_, +_]] extends BIO[F] {
-    final type Canceler = F[Nothing, Unit]
-
-    def async[E, A](register: (Either[E, A] => Unit) => Unit): F[E, A]
-    def asyncF[E, A](register: (Either[E, A] => Unit) => F[E, Unit]): F[E, A]
-    def asyncCancelable[E, A](register: (Either[E, A] => Unit) => Canceler): F[E, A]
-
-    def fromFuture[A](mkFuture: ExecutionContext => Future[A]): F[Throwable, A]
-    def fromFutureJava[A](javaFuture: => CompletionStage[A]): F[Throwable, A]
-
-    def yieldNow: F[Nothing, Unit]
-
-    /** Race two actions, the winner is the first action to TERMINATE, whether by success or failure */
-    def race[E, A](r1: F[E, A], r2: F[E, A]): F[E, A]
-    def racePair[E, A, B](fa: F[E, A], fb: F[E, B]): F[E, Either[(A, BIOFiber[F, E, B]), (BIOFiber[F, E, A], B)]]
-
-    def parTraverseN[E, A, B](maxConcurrent: Int)(l: Iterable[A])(f: A => F[E, B]): F[E, List[B]]
-    def parTraverse[E, A, B](l: Iterable[A])(f: A => F[E, B]): F[E, List[B]]
-
-    def uninterruptible[E, A](r: F[E, A]): F[E, A]
-
-    // defaults
-    def never: F[Nothing, Nothing] = async(_ => ())
-
-    def parTraverse_[E, A, B](l: Iterable[A])(f: A => F[E, B]): F[E, Unit] = void(parTraverse(l)(f))
-    def parTraverseN_[E, A, B](maxConcurrent: Int)(l: Iterable[A])(f: A => F[E, B]): F[E, Unit] = void(parTraverseN(maxConcurrent)(l)(f))
-
-    @inline final def fromFuture[A](mkFuture: => Future[A]): F[Throwable, A] = fromFuture(_ => mkFuture)
-  }
-
-  trait BIOTemporal[F[+_, +_]] extends BIOAsync[F] with BIOTemporalInstances {
-    def sleep(duration: Duration): F[Nothing, Unit]
-    def timeout[E, A](r: F[E, A])(duration: Duration): F[E, Option[A]]
-    def retryOrElse[A, E, A2 >: A, E2](r: F[E, A])(duration: FiniteDuration, orElse: => F[E2, A2]): F[E2, A2]
-
-    @inline final def repeatUntil[E, A](action: F[E, Option[A]])(onTimeout: => E, sleep: FiniteDuration, maxAttempts: Int): F[E, A] = {
-      def go(n: Int): F[E, A] = {
-        flatMap(action) {
-          case Some(value) =>
-            pure(value)
-          case None =>
-            if (n <= maxAttempts) {
-              *>(this.sleep(sleep), go(n + 1))
-            } else {
-              fail(onTimeout)
-            }
-        }
-      }
-
-      go(0)
-    }
-  }
-
-  private[bio] sealed trait BIOTemporalInstances
-  object BIOTemporalInstances {
-    implicit def BIOTemporalZio[R](implicit clockService: zio.clock.Clock): BIOTemporal[ZIO[R, +?, +?]] = new BIOTemporalZio[R](clockService)
-  }
-
-  trait BIOFork3[F[-_, +_, +_]] extends BIOForkInstances {
-    def fork[R, E, A](f: F[R, E, A]): F[R, Nothing, BIOFiber[F[Any, +?, +?], E, A]]
-  }
-
-  private[bio] sealed trait BIOForkInstances
-  object BIOForkInstances extends LowPriorityBIOForkInstances {
-    implicit val BIOForkZio: BIOFork3[ZIO] = new BIOFork3[ZIO] {
-      override def fork[R, E, A](f: ZIO[R, E, A]): ZIO[R, Nothing, BIOFiber[ZIO[Any, +?, +?], E, A]] =
-        f
-          // FIXME: ZIO Bug / feature (interruption inheritance) breaks behavior in bracket/DIResource
-          //  unless wrapped in `interruptible`
-          //  see: https://github.com/zio/zio/issues/945
-          .interruptible
-          .forkDaemon
-          .map(BIOFiber.fromZIO)
-    }
-  }
-  sealed trait LowPriorityBIOForkInstances {
-    @inline implicit final def BIOFork3To2[FR[-_, +_, +_], R](implicit BIOFork3: BIOFork3[FR]): BIOFork[FR[R, +?, +?]] = convert3To2(BIOFork3)
-  }
+  type BIOTemporal[F[+_, +_]] = BIOTemporal3[Lambda[(`-R`, `+E`, `+A`) => F[E, A]]]
 
+  type BIOFork[F[+_, +_]] = BIOFork3[Lambda[(`-R`, `+E`, `+A`) => F[E, A]]]
   type BIOLatch[F[+_, +_]] = BIOPromise[F, Nothing, Unit]
+  type BIOFiber[F[+_, +_], +E, +A] = BIOFiber3[Lambda[(`-R`, `+E`, `+A`) => F[E, A]], E, A]
 
-  type BIOFork[F[+_, +_]] = BIOFork3[Lambda[(`-R`, `+E`, `+A`) => F[E, A]]]
   type BlockingIO[F[+_, +_]] = BlockingIO3[Lambda[(`-R`, `+E`, `+A`) => F[E, A]]]
   object BlockingIO {
     def apply[F[+_, +_]: BlockingIO]: BlockingIO[F] = implicitly
   }
 
   type BIOPrimitives3[F[-_, +_, +_]] = BIOPrimitives[F[Any, +?, +?]]
+  object BIOPrimitives3 {
+    def apply[F[-_, +_, +_]: BIOPrimitives3]: BIOPrimitives3[F] = implicitly
+  }
 
   type SyncSafe2[F[_, _]] = SyncSafe[F[Nothing, ?]]
   object SyncSafe2 {
     def apply[F[_, _]: SyncSafe2]: SyncSafe2[F] = implicitly
   }
+  type SyncSafe3[F[_, _, _]] = SyncSafe[F[Any, Nothing, ?]]
+  object SyncSafe3 {
+    def apply[F[_, _, _]: SyncSafe3]: SyncSafe3[F] = implicitly
+  }
 
   type Clock2[F[_, _]] = Clock[F[Nothing, ?]]
   object Clock2 {
     def apply[F[_, _]: Clock2]: Clock2[F] = implicitly
   }
+  type Clock3[F[_, _, _]] = Clock[F[Any, Nothing, ?]]
+  object Clock3 {
+    def apply[F[_, _, _]: Clock3]: Clock3[F] = implicitly
+  }
 
   type Entropy2[F[_, _]] = Entropy[F[Nothing, ?]]
   object Entropy2 {
     def apply[F[_, _]: Entropy2]: Entropy2[F] = implicitly
   }
+  type Entropy3[F[_, _, _]] = Entropy[F[Any, Nothing, ?]]
+  object Entropy3 {
+    def apply[F[_, _, _]: Entropy3]: Entropy3[F] = implicitly
+  }
 
   @inline private[bio] final def convert3To2[C[_[-_, +_, +_]], FR[-_, +_, +_], R](instance: C[FR]): C[Lambda[(`-R0`, `+E`, `+A`) => FR[R, E, A]]] = {
     instance.asInstanceOf[C[Lambda[(`-R0`, `+E`, `+A`) => FR[R, E, A]]]]
   }
-
 }
diff --git a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/syntax/BIO3Syntax.scala b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/syntax/BIO3Syntax.scala
new file mode 100644
index 000000000..4d030b066
--- /dev/null
+++ b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/syntax/BIO3Syntax.scala
@@ -0,0 +1,282 @@
+package izumi.functional.bio.syntax
+
+import cats.data.Kleisli
+import izumi.functional.bio.syntax.BIO3Syntax.BIO3ImplicitPuns
+import izumi.functional.bio.{BIO3, BIOApplicative3, BIOArrow, BIOArrowChoice, BIOAsk, BIOAsync3, BIOBifunctor3, BIOBracket3, BIOError3, BIOExit, BIOFiber3, BIOFork3, BIOFunctor3, BIOGuarantee3, BIOLocal, BIOMonad3, BIOMonadError3, BIOPanic3, BIOProfunctor, BIOTemporal3}
+
+import scala.concurrent.duration.{Duration, FiniteDuration}
+import scala.language.implicitConversions
+
+trait BIO3Syntax extends BIO3ImplicitPuns {
+  /**
+    * A convenient dependent summoner for BIO* hierarchy.
+    * Auto-narrows to the most powerful available class:
+    *
+    * {{{
+    *   def y[F[+_, +_]: BIOTemporal] = {
+    *     F.timeout(5.seconds)(F.forever(F.unit))
+    *   }
+    * }}}
+    *
+    */
+  def F[FR[-_, +_, +_]](implicit FR: BIOFunctor3[FR]): FR.type = FR
+}
+
+object BIO3Syntax {
+
+  class BIOFunctor3Ops[+FR[-_, +_, +_], -R, +E, +A](protected[this] val r: FR[R, E, A])(implicit protected[this] val F: BIOFunctor3[FR]) {
+    @inline final def map[B](f: A => B): FR[R, E, B] = F.map(r)(f)
+
+    @inline final def as[B](b: => B): FR[R, E, B] = F.map(r)(_ => b)
+    @inline final def void: FR[R, E, Unit] = F.void(r)
+    @inline final def widen[A1](implicit @deprecated("unused", "") ev: A <:< A1): FR[R, E, A1] = r.asInstanceOf[FR[R, E, A1]]
+  }
+
+  class BIOBifunctor3Ops[+FR[-_, +_, +_], -R, +E, +A](override protected[this] val r: FR[R, E, A])(implicit override protected[this] val F: BIOBifunctor3[FR])
+    extends BIOFunctor3Ops(r) {
+    @inline final def leftMap[E2](f: E => E2): FR[R, E2, A] = F.leftMap(r)(f)
+    @inline final def bimap[E2, B](f: E => E2, g: A => B): FR[R, E2, B] = F.bimap(r)(f, g)
+
+    @inline final def widenError[E1](implicit @deprecated("unused", "") ev: E <:< E1): FR[R, E1, A] = r.asInstanceOf[FR[R, E1, A]]
+    @inline final def widenBoth[E1, A1](implicit @deprecated("unused", "") ev: E <:< E1, @deprecated("unused", "") ev2: A <:< A1): FR[R, E1, A1] =
+      r.asInstanceOf[FR[R, E1, A1]]
+  }
+
+  class BIOApplicative3Ops[FR[-_, +_, +_], -R, +E, +A](override protected[this] val r: FR[R, E, A])(implicit override protected[this] val F: BIOApplicative3[FR])
+    extends BIOBifunctor3Ops(r) {
+
+    /** execute two operations in order, return result of second operation */
+    @inline final def *>[R1 <: R, E1 >: E, B](f0: => FR[R1, E1, B]): FR[R1, E1, B] = F.*>(r, f0)
+
+    /** execute two operations in order, same as `*>`, but return result of first operation */
+    @inline final def <*[R1 <: R, E1 >: E, B](f0: => FR[R1, E1, B]): FR[R1, E1, A] = F.<*(r, f0)
+
+    /** execute two operations in order, return result of both operations */
+    @inline final def zip[R1 <: R, E1 >: E, B, C](r2: => FR[R1, E1, B]): FR[R1, E1, (A, B)] = F.map2(r, r2)(_ -> _)
+
+    /** execute two operations in order, map their results */
+    @inline final def map2[R1 <: R, E1 >: E, B, C](r2: => FR[R1, E1, B])(f: (A, B) => C): FR[R1, E1, C] = F.map2(r, r2)(f)
+
+    @inline final def forever: FR[R, E, Nothing] = F.forever(r)
+  }
+
+  class BIOGuarantee3Ops[FR[-_, +_, +_], -R, +E, +A](override protected[this] val r: FR[R, E, A])(implicit override protected[this] val F: BIOGuarantee3[FR])
+    extends BIOApplicative3Ops(r) {
+    @inline final def guarantee[R1 <: R](cleanup: FR[R1, Nothing, Unit]): FR[R1, E, A] = F.guarantee(r, cleanup)
+  }
+
+  final class BIOMonad3Ops[FR[-_, +_, +_], -R, +E, +A](override protected[this] val r: FR[R, E, A])(implicit override protected[this] val F: BIOMonad3[FR])
+    extends BIOApplicative3Ops(r) {
+    @inline final def flatMap[R1 <: R, E1 >: E, B](f0: A => FR[R1, E1, B]): FR[R1, E1, B] = F.flatMap[R, E, A, R1, E1, B](r)(f0)
+    @inline final def tap[R1 <: R, E1 >: E, B](f0: A => FR[R1, E1, Unit]): FR[R1, E1, A] = F.flatMap[R, E, A, R1, E1, A](r)(a => F.map(f0(a))(_ => a))
+
+    @inline final def flatten[R1 <: R, E1 >: E, A1](implicit ev: A <:< FR[R1, E1, A1]): FR[R1, E1, A1] = F.flatten(F.widen(r))
+  }
+
+  class BIOError3Ops[FR[-_, +_, +_], -R, +E, +A](override protected[this] val r: FR[R, E, A])(implicit override protected[this] val F: BIOError3[FR])
+    extends BIOGuarantee3Ops(r) {
+    @inline final def catchAll[R1 <: R, E2, A2 >: A](h: E => FR[R1, E2, A2]): FR[R1, E2, A2] = F.catchAll[R1, E, A, E2, A2](r)(h)
+    @inline final def catchSome[R1 <: R, E2 >: E, A2 >: A](h: PartialFunction[E, FR[R1, E2, A2]]): FR[R1, E2, A2] = F.catchSome[R1, E, A, E2, A2](r)(h)
+
+    @inline final def redeemPure[B](err: E => B, succ: A => B): FR[R, Nothing, B] = F.redeemPure(r)(err, succ)
+
+    @inline final def tapError[R1 <: R, E1 >: E](f: E => FR[R1, E1, Unit]): FR[R1, E1, A] = F.tapError[R1, E, A, E1](r)(f)
+
+    @inline final def attempt: FR[R, Nothing, Either[E, A]] = F.attempt(r)
+  }
+
+  class BIOMonadError3Ops[FR[-_, +_, +_], -R, +E, +A](override protected[this] val r: FR[R, E, A])(implicit override protected[this] val F: BIOMonadError3[FR])
+    extends BIOError3Ops(r) {
+    @inline final def flatMap[R1 <: R, E1 >: E, B](f0: A => FR[R1, E1, B]): FR[R1, E1, B] = F.flatMap[R, E, A, R1, E1, B](r)(f0)
+    @inline final def tap[R1 <: R, E1 >: E, B](f0: A => FR[R1, E1, Unit]): FR[R1, E1, A] = F.flatMap[R, E, A, R1, E1, A](r)(a => F.map(f0(a))(_ => a))
+
+    @inline final def flatten[R1 <: R, E1 >: E, A1](implicit ev: A <:< FR[R1, E1, A1]): FR[R1, E1, A1] = F.flatten(F.widen(r))
+
+    @inline final def redeem[R1 <: R, E2, B](err: E => FR[R1, E2, B], succ: A => FR[R1, E2, B]): FR[R1, E2, B] = F.redeem[R1, E, A, E2, B](r)(err, succ)
+
+    @inline final def leftFlatMap[R1 <: R, E2](f: E => FR[R1, Nothing, E2]): FR[R1, E2, A] = F.leftFlatMap[R1, E, A, E2](r)(f)
+    @inline final def flip: FR[R, A, E] = F.flip(r)
+
+    @inline final def tapBoth[R1 <: R, E1 >: E, E2 >: E1](err: E => FR[R1, E1, Unit])(succ: A => FR[R1, E2, Unit]): FR[R1, E2, A] = F.tapBoth[R1, E, A, E2](r)(err, succ)
+
+    @inline final def fromEither[R1 <: R, E1 >: E, A1](implicit ev: A <:< Either[E1, A1]): FR[R1, E1, A1] = F.flatMap[R, E, A, R1, E1, A1](r)(F.fromEither[E1, A1](_))
+    @inline final def fromOption[R1 <: R, E1 >: E, A1](errorOnNone: => E1)(implicit ev1: A <:< Option[A1]): FR[R1, E1, A1] =
+      F.flatMap[R, E, A, R1, E1, A1](r)(F.fromOption(errorOnNone)(_))
+
+    /** for-comprehensions sugar:
+      *
+      * {{{
+      *   for {
+      *    (1, 2) <- F.pure((2, 1))
+      *   } yield ()
+      * }}}
+      */
+    @inline final def withFilter[E1 >: E](predicate: A => Boolean)(implicit ev: NoSuchElementException <:< E1): FR[R, E1, A] = F.withFilter[R, E1, A](r)(predicate)
+  }
+
+  class BIOBracket3Ops[FR[-_, +_, +_], -R, +E, +A](override protected[this] val r: FR[R, E, A])(implicit override protected[this] val F: BIOBracket3[FR])
+    extends BIOMonadError3Ops(r) {
+    @inline final def bracket[R1 <: R, E1 >: E, B](release: A => FR[R1, Nothing, Unit])(use: A => FR[R1, E1, B]): FR[R1, E1, B] =
+      F.bracket(r: FR[R1, E1, A])(release)(use)
+  }
+
+  class BIOPanic3Ops[FR[-_, +_, +_], -R, +E, +A](override protected[this] val r: FR[R, E, A])(implicit override protected[this] val F: BIOPanic3[FR])
+    extends BIOBracket3Ops(r) {
+    @inline final def sandbox: FR[R, BIOExit.Failure[E], A] = F.sandbox(r)
+    @inline final def sandboxBIOExit: FR[R, Nothing, BIOExit[E, A]] = F.redeemPure(F.sandbox(r))(identity, BIOExit.Success(_))
+
+    /**
+      * Catch all _defects_ in this effect and convert them to Throwable
+      * Example:
+      *
+      * {{{
+      *   BIO[FR].pure(1)
+      *     .map(_ => ???)
+      *     .sandboxThrowable
+      *     .catchAll(_ => BIO(println("Caught error!")))
+      * }}}
+      *
+      */
+    @inline final def sandboxToThrowable(implicit ev: E <:< Throwable): FR[R, Throwable, A] =
+      F.leftMap(F.sandbox(r))(_.toThrowable)
+
+    /** Convert Throwable typed error into a defect */
+    @inline final def orTerminate(implicit ev: E <:< Throwable): FR[R, Nothing, A] = F.catchAll(r)(F.terminate(_))
+  }
+
+  class BIO3Ops[FR[-_, +_, +_], -R, +E, +A](override protected[this] val r: FR[R, E, A])(implicit override protected[this] val F: BIO3[FR]) extends BIOPanic3Ops(r) {
+    @inline final def bracketAuto[R1 <: R, E1 >: E, B](use: A => FR[R1, E1, B])(implicit ev: A <:< AutoCloseable): FR[R1, E1, B] =
+      F.bracket[R1, E1, A, B](r)(c => F.sync(c.close()))(use)
+  }
+
+  class BIOAsync3Ops[FR[-_, +_, +_], -R, +E, +A](override protected[this] val r: FR[R, E, A])(implicit override protected[this] val F: BIOAsync3[FR]) extends BIO3Ops(r) {
+    @inline final def race[R1 <: R, E1 >: E, A1 >: A](that: FR[R1, E1, A1]): FR[R1, E1, A1] = F.race(r, that)
+  }
+
+  final class BIOTemporal3Ops[FR[-_, +_, +_], -R, +E, +A](override protected[this] val r: FR[R, E, A])(implicit override protected[this] val F: BIOTemporal3[FR])
+    extends BIOAsync3Ops(r) {
+    @inline final def retryOrElse[R1 <: R, A2 >: A, E2](duration: FiniteDuration, orElse: => FR[R1, E2, A2]): FR[R1, E2, A2] = F.retryOrElse[R1, A, E, A2, E2](r)(duration, orElse)
+    @inline final def repeatUntil[E2 >: E, A2](onTimeout: => E2, sleep: FiniteDuration, maxAttempts: Int)(implicit ev: A <:< Option[A2]): FR[R, E2, A2] =
+      F.repeatUntil[R, E2, A2](new BIOFunctor3Ops(r)(F).widen)(onTimeout, sleep, maxAttempts)
+
+    @inline final def timeout(duration: Duration): FR[R, E, Option[A]] = F.timeout(r)(duration)
+    @inline final def timeoutFail[E1 >: E](e: E1)(duration: Duration): FR[R, E1, A] =
+      F.flatMap(timeout(duration): FR[R, E1, Option[A]])(_.fold[FR[R, E1, A]](F.fail(e))(F.pure))
+  }
+
+  final class BIOFork3Ops[FR[-_, +_, +_], -R, +E, +A](private val r: FR[R, E, A])(implicit private val F: BIOFork3[FR]) {
+    @inline final def fork: FR[R, Nothing, BIOFiber3[FR, E, A]] = F.fork(r)
+  }
+
+  class BIOProfunctorOps[+FR[-_, +_, +_], -R, +E, +A](protected[this] val r: FR[R, E, A])(implicit protected[this] val F: BIOProfunctor[FR]) {
+    @inline final def dimap[R1, A1](f: R1 => R)(g: A => A1): FR[R1, E, A1] = F.dimap(r)(f)(g)
+  }
+
+  class BIOArrowOps[FR[-_, +_, +_], -R, +E, +A](override protected[this] val r: FR[R, E, A])(implicit override protected[this] val F: BIOArrow[FR]) extends BIOProfunctorOps(r) {
+    @inline final def andThen[E1 >: E, A1](g: FR[A, E1, A1]): FR[R, E1, A1] = F.andThen(r, g)
+    @inline final def compose[E1 >: E, R1](g: FR[R1, E1, R]): FR[R1, E1, A] = F.andThen(g, r)
+  }
+
+  class BIOArrowChoiceOps[FR[-_, +_, +_], -R, +E, +A](override protected[this] val r: FR[R, E, A])(implicit override protected[this] val F: BIOArrowChoice[FR]) extends BIOArrowOps(r) {
+    @inline final def choice[R1 <: R, E1 >: E, A1 >: A, R2](g: FR[R2, E1, A1]): FR[Either[R1, R2], E1, A1] = F.choice(r, g)
+    @inline final def choose[R1 <: R, E1 >: E, R2, A1](g: FR[R2, E1, A1]): FR[Either[R1, R2], E1, Either[A, A1]] = F.choose(r, g)
+  }
+
+  final class BIOLocalOps[FR[-_, +_, +_], -R, +E, +A](protected[this] override val r: FR[R, E, A])(implicit override protected[this] val F: BIOLocal[FR]) extends BIOArrowChoiceOps(r) {
+    @inline final def provide(env: => R): FR[Any, E, A]= F.provide(r)(env)
+    @inline final def contramap[R0 <: R](f: R0 => R): FR[R0, E, A]= F.contramap(r)(f)
+  }
+
+  final class BIOLocalOpsKleisliSyntax[FR[-_, +_, +_], R, E, A](private val r: FR[R, E, A])(implicit private val F: BIOLocal[FR]) {
+    @inline final def toKleisli: Kleisli[FR[Any, E, ?], R, A] = F.toKleisli(r)
+  }
+
+  trait BIO3ImplicitPuns extends BIO3ImplicitPuns1 {
+    @inline implicit final def BIOTemporal3[FR[-_, +_, +_]: BIOTemporal3, R, E, A](self: FR[R, E, A]): BIO3Syntax.BIOTemporal3Ops[FR, R, E, A] = new BIO3Syntax.BIOTemporal3Ops[FR, R, E, A](self)
+    @inline final def BIOTemporal3[FR[-_, +_, +_]: BIOTemporal3]: BIOTemporal3[FR] = implicitly
+
+    @inline implicit final def BIOFork3[FR[-_, +_, +_]: BIOFork3, R, E, A](self: FR[R, E, A]): BIO3Syntax.BIOFork3Ops[FR, R, E, A] = new BIO3Syntax.BIOFork3Ops[FR, R, E, A](self)
+    @inline final def BIOFork3[FR[-_, +_, +_]: BIOFork3]: BIOFork3[FR] = implicitly
+
+    @inline implicit final def BIOLocal[FR[-_, +_, +_]: BIOLocal, R, E, A](self: FR[R, E, A]): BIO3Syntax.BIOLocalOps[FR, R, E, A] = new BIO3Syntax.BIOLocalOps[FR, R, E, A](self)
+    @inline implicit final def BIOLocal[FR[-_, +_, +_]: BIOMonad3, R, E, A](self: FR[R, E, A]): BIO3Syntax.BIOMonad3Ops[FR, R, E, A] = new BIO3Syntax.BIOMonad3Ops[FR, R, E, A](self)
+    @inline implicit final def BIOLocal[FR[-_, +_, +_]: BIOLocal, R, E, A](self: FR[R, E, A])(implicit d1: DummyImplicit): BIO3Syntax.BIOLocalOpsKleisliSyntax[FR, R, E, A] = new BIO3Syntax.BIOLocalOpsKleisliSyntax[FR, R, E, A](self)
+    @inline final def BIOLocal[FR[-_, +_, +_]: BIOLocal]: BIOLocal[FR] = implicitly
+  }
+  trait BIO3ImplicitPuns1 extends BIO3ImplicitPuns2 {
+    @inline implicit final def BIOAsync3[FR[-_, +_, +_]: BIOAsync3, R, E, A](self: FR[R, E, A]): BIO3Syntax.BIOAsync3Ops[FR, R, E, A] = new BIO3Syntax.BIOAsync3Ops[FR, R, E, A](self)
+    @inline final def BIOAsync3[FR[-_, +_, +_]: BIOAsync3]: BIOAsync3[FR] = implicitly
+
+    @inline implicit final def BIOArrowChoice[FR[-_, +_, +_]: BIOArrowChoice, R, E, A](self: FR[R, E, A]): BIO3Syntax.BIOArrowChoiceOps[FR, R, E, A] = new BIO3Syntax.BIOArrowChoiceOps[FR, R, E, A](self)
+    @inline implicit final def BIOArrowChoice[FR[-_, +_, +_]: BIOFunctor3, R, E, A](self: FR[R, E, A]): BIO3Syntax.BIOFunctor3Ops[FR, R, E, A] = new BIO3Syntax.BIOFunctor3Ops[FR, R, E, A](self)
+    @inline final def BIOArrowChoice[FR[-_, +_, +_]: BIOArrowChoice]: BIOArrowChoice[FR] = implicitly
+  }
+  trait BIO3ImplicitPuns2 extends BIO3ImplicitPuns3 {
+    @inline implicit final def BIO3[FR[-_, +_, +_]: BIO3, R, E, A](self: FR[R, E, A]): BIO3Syntax.BIO3Ops[FR, R, E, A] = new BIO3Syntax.BIO3Ops[FR, R, E, A](self)
+    /**
+      * Shorthand for [[BIO3#syncThrowable]]
+      *
+      * {{{
+      *   BIO(println("Hello world!"))
+      * }}}
+      */
+    @inline final def BIO3[FR[-_, +_, +_], A](effect: => A)(implicit F: BIO3[FR]): FR[Any, Throwable, A] = F.syncThrowable(effect)
+    @inline final def BIO3[FR[-_, +_, +_]: BIO3]: BIO3[FR] = implicitly
+
+    @inline implicit final def BIOArrow[FR[-_, +_, +_]: BIOArrow, R, E, A](self: FR[R, E, A]): BIO3Syntax.BIOArrowOps[FR, R, E, A] = new BIO3Syntax.BIOArrowOps[FR, R, E, A](self)
+    @inline implicit final def BIOArrow[FR[-_, +_, +_]: BIOFunctor3, R, E, A](self: FR[R, E, A]): BIO3Syntax.BIOFunctor3Ops[FR, R, E, A] = new BIO3Syntax.BIOFunctor3Ops[FR, R, E, A](self)
+    @inline final def BIOArrow[FR[-_, +_, +_]: BIOArrow]: BIOArrow[FR] = implicitly
+  }
+  trait BIO3ImplicitPuns3 extends BIO3ImplicitPuns4 {
+    @inline implicit final def BIOPanic3[FR[-_, +_, +_]: BIOPanic3, R, E, A](self: FR[R, E, A]): BIO3Syntax.BIOPanic3Ops[FR, R, E, A] = new BIO3Syntax.BIOPanic3Ops[FR, R, E, A](self)
+    @inline final def BIOPanic3[FR[-_, +_, +_]: BIOPanic3]: BIOPanic3[FR] = implicitly
+
+    @inline implicit final def BIOProfunctor[FR[-_, +_, +_]: BIOProfunctor, R, E, A](self: FR[R, E, A]): BIO3Syntax.BIOProfunctorOps[FR, R, E, A] = new BIO3Syntax.BIOProfunctorOps[FR, R, E, A](self)
+    @inline implicit final def BIOProfunctor[FR[-_, +_, +_]: BIOFunctor3, R, E, A](self: FR[R, E, A]): BIO3Syntax.BIOFunctor3Ops[FR, R, E, A] = new BIO3Syntax.BIOFunctor3Ops[FR, R, E, A](self)
+    @inline final def BIOProfunctor[FR[-_, +_, +_]: BIOProfunctor]: BIOProfunctor[FR] = implicitly
+
+  }
+  trait BIO3ImplicitPuns4 extends BIO3ImplicitPuns5 {
+    @inline implicit final def BIOBracket3[FR[-_, +_, +_]: BIOBracket3, R, E, A](self: FR[R, E, A]): BIO3Syntax.BIOBracket3Ops[FR, R, E, A] = new BIO3Syntax.BIOBracket3Ops[FR, R, E, A](self)
+    @inline final def BIOBracket3[FR[-_, +_, +_]: BIOBracket3]: BIOBracket3[FR] = implicitly
+
+    @inline implicit final def BIOAsk[FR[-_, +_, +_]: BIOApplicative3, R, E, A](self: FR[R, E, A]): BIO3Syntax.BIOApplicative3Ops[FR, R, E, A] = new BIO3Syntax.BIOApplicative3Ops[FR, R, E, A](self)
+    @inline final def BIOAsk[FR[-_, +_, +_]: BIOAsk]: BIOAsk[FR] = implicitly
+  }
+  trait BIO3ImplicitPuns5 extends BIO3ImplicitPuns6 {
+    @inline implicit final def BIOMonadError3[FR[-_, +_, +_]: BIOMonadError3, R, E, A](self: FR[R, E, A]): BIO3Syntax.BIOMonadError3Ops[FR, R, E, A] =
+      new BIO3Syntax.BIOMonadError3Ops[FR, R, E, A](self)
+    @inline final def BIOMonadError3[FR[-_, +_, +_]: BIOMonadError3]: BIOMonadError3[FR] = implicitly
+  }
+  trait BIO3ImplicitPuns6 extends BIO3ImplicitPuns7 {
+    @inline implicit final def BIOError3[FR[-_, +_, +_]: BIOError3, R, E, A](self: FR[R, E, A]): BIO3Syntax.BIOError3Ops[FR, R, E, A] =
+      new BIO3Syntax.BIOError3Ops[FR, R, E, A](self)
+    @inline final def BIOError3[FR[-_, +_, +_]: BIOError3]: BIOError3[FR] = implicitly
+  }
+  trait BIO3ImplicitPuns7 extends BIO3ImplicitPuns8 {
+    @inline implicit final def BIOGuarantee3[FR[-_, +_, +_]: BIOGuarantee3, R, E, A](self: FR[R, E, A]): BIO3Syntax.BIOGuarantee3Ops[FR, R, E, A] =
+      new BIO3Syntax.BIOGuarantee3Ops[FR, R, E, A](self)
+    @inline final def BIOGuarantee3[FR[-_, +_, +_]: BIOGuarantee3]: BIOGuarantee3[FR] = implicitly
+  }
+  trait BIO3ImplicitPuns8 extends BIO3ImplicitPuns9 {
+    @inline implicit final def BIOMonad3[FR[-_, +_, +_]: BIOMonad3, R, E, A](self: FR[R, E, A]): BIO3Syntax.BIOMonad3Ops[FR, R, E, A] =
+      new BIO3Syntax.BIOMonad3Ops[FR, R, E, A](self)
+    @inline final def BIOMonad3[FR[-_, +_, +_]: BIOMonad3]: BIOMonad3[FR] = implicitly
+  }
+  trait BIO3ImplicitPuns9 extends BIO3ImplicitPuns10 {
+    @inline implicit final def BIOApplicative3[FR[-_, +_, +_]: BIOApplicative3, R, E, A](self: FR[R, E, A]): BIO3Syntax.BIOApplicative3Ops[FR, R, E, A] =
+      new BIO3Syntax.BIOApplicative3Ops[FR, R, E, A](self)
+    @inline final def BIOApplicative3[FR[-_, +_, +_]: BIOApplicative3]: BIOApplicative3[FR] = implicitly
+  }
+  trait BIO3ImplicitPuns10 extends BIO3ImplicitPuns11 {
+    @inline implicit final def BIOBifunctor3[FR[-_, +_, +_]: BIOBifunctor3, R, E, A](self: FR[R, E, A]): BIO3Syntax.BIOBifunctor3Ops[FR, R, E, A] =
+      new BIO3Syntax.BIOBifunctor3Ops[FR, R, E, A](self)
+    @inline final def BIOBifunctor3[FR[-_, +_, +_]: BIOBifunctor3]: BIOBifunctor3[FR] = implicitly
+  }
+  trait BIO3ImplicitPuns11 {
+    @inline implicit final def BIOFunctor3[FR[-_, +_, +_]: BIOFunctor3, R, E, A](self: FR[R, E, A]): BIO3Syntax.BIOFunctor3Ops[FR, R, E, A] =
+      new BIO3Syntax.BIOFunctor3Ops[FR, R, E, A](self)
+    @inline final def BIOFunctor3[FR[-_, +_, +_]: BIOFunctor3]: BIOFunctor3[FR] = implicitly
+  }
+
+}
diff --git a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOSyntax.scala b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/syntax/BIOSyntax.scala
similarity index 66%
rename from fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOSyntax.scala
rename to fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/syntax/BIOSyntax.scala
index 022541707..ef5e4e3cd 100644
--- a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/BIOSyntax.scala
+++ b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/syntax/BIOSyntax.scala
@@ -1,28 +1,17 @@
-package izumi.functional.bio
+package izumi.functional.bio.syntax
 
-import izumi.functional.bio.BIOSyntax.BIOImplicitPuns
+import izumi.functional.bio._
+import izumi.functional.bio.syntax.BIOSyntax.BIOImplicitPuns
 
+import scala.annotation.unchecked.uncheckedVariance
 import scala.concurrent.duration.{Duration, FiniteDuration}
 import scala.language.implicitConversions
 
-trait BIOSyntax extends BIOImplicitPuns {
-  /**
-    * A convenient dependent summoner for BIO* hierarchy.
-    * Auto-narrows to the most powerful available class:
-    *
-    * {{{
-    *   def y[F[+_, +_]: BIOTemporal] = {
-    *     F.timeout(5.seconds)(F.forever(F.unit))
-    *   }
-    * }}}
-    *
-    */
-  def F[F[+_, +_]](implicit F: BIOFunctor[F]): F.type = F
-}
+trait BIOSyntax extends BIOImplicitPuns
 
 object BIOSyntax {
 
-  class BIOFunctorOps[F[_, + _], E, A](protected[this] val r: F[E, A])(implicit protected[this] val F: BIOFunctor[F]) {
+  class BIOFunctorOps[+F[+_, +_], E, +A](protected[this] val r: F[E, A])(implicit protected[this] val F: BIOFunctor[F]) {
     @inline final def map[B](f: A => B): F[E, B] = F.map(r)(f)
 
     @inline final def as[B](b: => B): F[E, B] = F.map(r)(_ => b)
@@ -30,15 +19,15 @@ object BIOSyntax {
     @inline final def widen[A1](implicit @deprecated("unused","") ev: A <:< A1): F[E, A1] = r.asInstanceOf[F[E, A1]]
   }
 
-  class BIOBifunctorOps[F[+_, +_], E, A](override protected[this] val r: F[E, A])(implicit override protected[this] val F: BIOBifunctor[F]) extends BIOFunctorOps(r) {
+  class BIOBifunctorOps[+F[+_, +_], +E, +A](override protected[this] val r: F[E, A])(implicit override protected[this] val F: BIOBifunctor[F]) extends BIOFunctorOps[F, E @uncheckedVariance, A](r) {
     @inline final def leftMap[E2](f: E => E2): F[E2, A] = F.leftMap(r)(f)
     @inline final def bimap[E2, B](f: E => E2, g: A => B): F[E2, B] = F.bimap(r)(f, g)
 
-    @inline final def widenError[E1](implicit @deprecated("unused","") ev: E <:< E1): F[E1, A] = r.asInstanceOf[F[E1, A]]
-    @inline final def widenBoth[E1, A1](implicit @deprecated("unused","") ev: E <:< E1, @deprecated("unused", "") ev2: A <:< A1): F[E1, A1] = r.asInstanceOf[F[E1, A1]]
+    @inline final def widenError[E1 >: E]: F[E1, A] = r
+    @inline final def widenBoth[E1 >: E, A1](implicit @deprecated("unused","") ev2: A <:< A1): F[E1, A1] = r.asInstanceOf[F[E1, A1]]
   }
 
-  class BIOApplicativeOps[F[+_, +_], E, A](override protected[this] val r: F[E, A])(implicit override protected[this] val F: BIOApplicative[F]) extends BIOBifunctorOps(r) {
+  class BIOApplicativeOps[F[+_, +_], +E, +A](override protected[this] val r: F[E, A])(implicit override protected[this] val F: BIOApplicative[F]) extends BIOBifunctorOps(r) {
 
     /** execute two operations in order, return result of second operation */
     @inline final def *>[E1 >: E, B](f0: => F[E1, B]): F[E1, B] = F.*>(r, f0)
@@ -55,43 +44,43 @@ object BIOSyntax {
     @inline final def forever: F[E, Nothing] = F.forever(r)
   }
 
-  class BIOGuaranteeOps[F[+_, +_], E, A](override protected[this] val r: F[E, A])(implicit override protected[this] val F: BIOGuarantee[F]) extends BIOApplicativeOps(r) {
-    @inline final def guarantee(cleanup: F[Nothing, Unit]): F[E, A] = F.guarantee(r)(cleanup)
+  class BIOGuaranteeOps[F[+_, +_], +E, +A](override protected[this] val r: F[E, A])(implicit override protected[this] val F: BIOGuarantee[F]) extends BIOApplicativeOps(r) {
+    @inline final def guarantee(cleanup: F[Nothing, Unit]): F[E, A] = F.guarantee(r, cleanup)
   }
 
-  final class BIOMonadOps[F[+_, +_], E, A](override protected[this] val r: F[E, A])(implicit override protected[this] val F: BIOMonad[F]) extends BIOApplicativeOps(r) {
-    @inline final def flatMap[E1 >: E, B](f0: A => F[E1, B]): F[E1, B] = F.flatMap[E, A, E1, B](r)(f0)
-    @inline final def tap[E1 >: E, B](f0: A => F[E1, Unit]): F[E1, A] = F.flatMap[E, A, E1, A](r)(a => F.map(f0(a))(_ => a))
+  final class BIOMonadOps[F[+_, +_], +E, +A](override protected[this] val r: F[E, A])(implicit override protected[this] val F: BIOMonad[F]) extends BIOApplicativeOps(r) {
+    @inline final def flatMap[E1 >: E, B](f0: A => F[E1, B]): F[E1, B] = F.flatMap[Any, E, A, Any, E1, B](r)(f0)
+    @inline final def tap[E1 >: E, B](f0: A => F[E1, Unit]): F[E1, A] = F.flatMap[Any, E, A, Any, E1, A](r)(a => F.map(f0(a))(_ => a))
 
     @inline final def flatten[E1 >: E, A1](implicit ev: A <:< F[E1, A1]): F[E1, A1] = F.flatten(r.widen)
   }
 
-  class BIOErrorOps[F[+_, +_], E, A](override protected[this] val r: F[E, A])(implicit override protected[this] val F: BIOError[F]) extends BIOGuaranteeOps(r) {
-    @inline final def catchAll[E2, A2 >: A](h: E => F[E2, A2]): F[E2, A2] = F.catchAll[E, A, E2, A2](r)(h)
-    @inline final def catchSome[E2 >: E, A2 >: A](h: PartialFunction[E, F[E2, A2]]): F[E2, A2] = F.catchSome[E, A, E2, A2](r)(h)
+  class BIOErrorOps[F[+_, +_], +E, +A](override protected[this] val r: F[E, A])(implicit override protected[this] val F: BIOError[F]) extends BIOGuaranteeOps(r) {
+    @inline final def catchAll[E2, A2 >: A](h: E => F[E2, A2]): F[E2, A2] = F.catchAll[Any, E, A, E2, A2](r)(h)
+    @inline final def catchSome[E2 >: E, A2 >: A](h: PartialFunction[E, F[E2, A2]]): F[E2, A2] = F.catchSome[Any, E, A, E2, A2](r)(h)
 
     @inline final def redeemPure[B](err: E => B, succ: A => B): F[Nothing, B] = F.redeemPure(r)(err, succ)
 
-    @inline final def tapError[E1 >: E](f: E => F[E1, Unit]): F[E1, A] = F.tapError[E, A, E1](r)(f)
+    @inline final def tapError[E1 >: E](f: E => F[E1, Unit]): F[E1, A] = F.tapError[Any, E, A, E1](r)(f)
 
     @inline final def attempt: F[Nothing, Either[E, A]] = F.attempt(r)
   }
 
-  class BIOMonadErrorOps[F[+_, +_], E, A](override protected[this] val r: F[E, A])(implicit override protected[this] val F: BIOMonadError[F]) extends BIOErrorOps(r) {
-    @inline final def flatMap[E1 >: E, B](f0: A => F[E1, B]): F[E1, B] = F.flatMap[E, A, E1, B](r)(f0)
-    @inline final def tap[E1 >: E, B](f0: A => F[E1, Unit]): F[E1, A] = F.flatMap[E, A, E1, A](r)(a => F.map(f0(a))(_ => a))
+  class BIOMonadErrorOps[F[+_, +_], +E, +A](override protected[this] val r: F[E, A])(implicit override protected[this] val F: BIOMonadError[F]) extends BIOErrorOps(r) {
+    @inline final def flatMap[E1 >: E, B](f0: A => F[E1, B]): F[E1, B] = F.flatMap[Any, E, A, Any, E1, B](r)(f0)
+    @inline final def tap[E1 >: E, B](f0: A => F[E1, Unit]): F[E1, A] = F.flatMap[Any, E, A, Any, E1, A](r)(a => F.map(f0(a))(_ => a))
 
     @inline final def flatten[E1 >: E, A1](implicit ev: A <:< F[E1, A1]): F[E1, A1] = F.flatten(r.widen)
 
-    @inline final def redeem[E2, B](err: E => F[E2, B], succ: A => F[E2, B]): F[E2, B] = F.redeem[E, A, E2, B](r)(err, succ)
+    @inline final def redeem[E2, B](err: E => F[E2, B], succ: A => F[E2, B]): F[E2, B] = F.redeem[Any, E, A, E2, B](r)(err, succ)
 
     @inline final def leftFlatMap[E2](f: E => F[Nothing, E2]): F[E2, A] = F.leftFlatMap(r)(f)
     @inline final def flip: F[A, E] = F.flip(r)
 
-    @inline final def tapBoth[E1 >: E, E2 >: E1](err: E => F[E1, Unit])(succ: A => F[E2, Unit]): F[E2, A] = F.tapBoth[E, A, E2](r)(err, succ)
+    @inline final def tapBoth[E1 >: E, E2 >: E1](err: E => F[E1, Unit])(succ: A => F[E2, Unit]): F[E2, A] = F.tapBoth[Any, E, A, E2](r)(err, succ)
 
-    @inline final def fromEither[E1 >: E, A1](implicit ev: A <:< Either[E1, A1]): F[E1, A1] = F.flatMap[E, A, E1, A1](r)(F.fromEither[E1, A1](_))
-    @inline final def fromOption[E1 >: E, A1](errorOnNone: => E1)(implicit ev1: A <:< Option[A1]): F[E1, A1] = F.flatMap[E, A, E1, A1](r)(F.fromOption(errorOnNone)(_))
+    @inline final def fromEither[E1 >: E, A1](implicit ev: A <:< Either[E1, A1]): F[E1, A1] = F.flatMap[Any, E, A, Any, E1, A1](r)(F.fromEither[E1, A1](_))
+    @inline final def fromOption[E1 >: E, A1](errorOnNone: => E1)(implicit ev1: A <:< Option[A1]): F[E1, A1] = F.flatMap[Any, E, A, Any, E1, A1](r)(F.fromOption(errorOnNone)(_))
 
     /** for-comprehensions sugar:
       *
@@ -101,15 +90,15 @@ object BIOSyntax {
       *   } yield ()
       * }}}
       */
-    @inline final def withFilter[E1 >: E](predicate: A => Boolean)(implicit ev: NoSuchElementException <:< E1): F[E1, A] = F.withFilter[E1, A](r)(predicate)
+    @inline final def withFilter[E1 >: E](predicate: A => Boolean)(implicit ev: NoSuchElementException <:< E1): F[E1, A] = F.withFilter[Any, E1, A](r)(predicate)
   }
 
-  class BIOBracketOps[F[+_, +_], E, A](override protected[this] val r: F[E, A])(implicit override protected[this] val F: BIOBracket[F]) extends BIOMonadErrorOps(r) {
+  class BIOBracketOps[F[+_, +_], +E, +A](override protected[this] val r: F[E, A])(implicit override protected[this] val F: BIOBracket[F]) extends BIOMonadErrorOps(r) {
     @inline final def bracket[E1 >: E, B](release: A => F[Nothing, Unit])(use: A => F[E1, B]): F[E1, B] =
       F.bracket(r: F[E1, A])(release)(use)
   }
 
-  class BIOPanicOps[F[+_, +_], E, A](override protected[this] val r: F[E, A])(implicit override protected[this] val F: BIOPanic[F]) extends BIOBracketOps(r) {
+  class BIOPanicOps[F[+_, +_], +E, +A](override protected[this] val r: F[E, A])(implicit override protected[this] val F: BIOPanic[F]) extends BIOBracketOps(r) {
     @inline final def sandbox: F[BIOExit.Failure[E], A] = F.sandbox(r)
     @inline final def sandboxBIOExit: F[Nothing, BIOExit[E, A]] = F.redeemPure(F.sandbox(r))(identity, BIOExit.Success(_))
 
@@ -132,45 +121,35 @@ object BIOSyntax {
     @inline final def orTerminate(implicit ev: E <:< Throwable): F[Nothing, A] = F.catchAll(r)(F.terminate(_))
   }
 
-  class BIOOps[F[+_, +_], E, A](override protected[this] val r: F[E, A])(implicit override protected[this] val F: BIO[F]) extends BIOPanicOps(r) {
+  class BIOOps[F[+_, +_], +E, +A](override protected[this] val r: F[E, A])(implicit override protected[this] val F: BIO[F]) extends BIOPanicOps(r) {
     @inline final def bracketAuto[E1 >: E, B](use: A => F[E1, B])(implicit ev: A <:< AutoCloseable): F[E1, B] =
-      F.bracket[E1, A, B](r)(c => F.sync(c.close()))(use)
+      F.bracket[Any, E1, A, B](r)(c => F.sync(c.close()))(use)
   }
 
-  class BIOAsyncOps[F[+_, +_], E, A](override protected[this] val r: F[E, A])(implicit override protected[this] val F: BIOAsync[F]) extends BIOOps(r) {
+  class BIOAsyncOps[F[+_, +_], +E, +A](override protected[this] val r: F[E, A])(implicit override protected[this] val F: BIOAsync[F]) extends BIOOps(r) {
     @inline final def race[E1 >: E, A1 >: A](that: F[E1, A1]): F[E1, A1] = F.race(r, that)
   }
 
-  final class BIOTemporalOps[F[+_, +_], E, A](override protected[this] val r: F[E, A])(implicit override protected[this] val F: BIOTemporal[F]) extends BIOAsyncOps(r) {
-    @inline final def retryOrElse[A2 >: A, E2](duration: FiniteDuration, orElse: => F[E2, A2]): F[E2, A2] = F.retryOrElse[A, E, A2, E2](r)(duration, orElse)
+  final class BIOTemporalOps[F[+_, +_], +E, +A](override protected[this] val r: F[E, A])(implicit override protected[this] val F: BIOTemporal[F]) extends BIOAsyncOps(r) {
+    @inline final def retryOrElse[A2 >: A, E2](duration: FiniteDuration, orElse: => F[E2, A2]): F[E2, A2] = F.retryOrElse[Any, A, E, A2, E2](r)(duration, orElse)
     @inline final def repeatUntil[E2 >: E, A2](onTimeout: => E2, sleep: FiniteDuration, maxAttempts: Int)(implicit ev: A <:< Option[A2]): F[E2, A2] =
-      F.repeatUntil[E2, A2](new BIOFunctorOps(r)(F).widen)(onTimeout, sleep, maxAttempts)
+      F.repeatUntil[Any, E2, A2](new BIOFunctorOps(r)(F).widen)(onTimeout, sleep, maxAttempts)
 
     @inline final def timeout(duration: Duration): F[E, Option[A]] = F.timeout(r)(duration)
     @inline final def timeoutFail[E1 >: E](e: E1)(duration: Duration): F[E1, A] =
       F.flatMap(timeout(duration): F[E1, Option[A]])(_.fold[F[E1, A]](F.fail(e))(F.pure))
-
   }
 
-  final class BIOForkOps[F[+_, +_], E, A](private val r: F[E, A])(implicit private val F: BIOFork[F]) {
+  final class BIOForkOps[F[+_, +_], +E, +A](private val r: F[E, A])(implicit private val F: BIOFork[F]) {
     @inline final def fork: F[Nothing, BIOFiber[F, E, A]] = F.fork(r)
   }
 
-  final class BIOFork3Ops[F[-_, +_, +_], R, E, A](private val r: F[R, E, A])(implicit private val F: BIOFork3[F]) {
-    @inline final def fork: F[R, Nothing, BIOFiber[F[Any, +?, +?], E, A]] = F.fork(r)
-  }
-
   trait BIOImplicitPuns extends BIOImplicitPuns1 {
     @inline implicit final def BIOTemporal[F[+_, +_]: BIOTemporal, E, A](self: F[E, A]): BIOSyntax.BIOTemporalOps[F, E, A] = new BIOSyntax.BIOTemporalOps[F, E, A](self)
     @inline final def BIOTemporal[F[+_, +_]: BIOTemporal]: BIOTemporal[F] = implicitly
 
     @inline implicit final def BIOFork[F[+_, +_]: BIOFork, E, A](self: F[E, A]): BIOSyntax.BIOForkOps[F, E, A] = new BIOSyntax.BIOForkOps[F, E, A](self)
     @inline final def BIOFork[F[+_, +_]: BIOFork]: BIOFork[F] = implicitly
-
-    @inline implicit final def BIOFork3[F[-_, +_, +_]: BIOFork3, R, E, A](self: F[R, E, A]): BIOSyntax.BIOFork3Ops[F, R, E, A] = new BIOSyntax.BIOFork3Ops[F, R, E, A](self)
-    @inline final def BIOFork3[F[-_, +_, +_]: BIOFork3]: BIOFork3[F] = implicitly
-
-    @inline final def BIOPrimitives[F[+_, +_]: BIOPrimitives]: BIOPrimitives[F] = implicitly
   }
   trait BIOImplicitPuns1 extends BIOImplicitPuns2 {
     @inline implicit final def BIOAsync[F[+_, +_]: BIOAsync, E, A](self: F[E, A]): BIOSyntax.BIOAsyncOps[F, E, A] = new BIOSyntax.BIOAsyncOps[F, E, A](self)
@@ -221,8 +200,8 @@ object BIOSyntax {
     @inline final def BIOBifunctor[F[+_, +_]: BIOBifunctor]: BIOBifunctor[F] = implicitly
   }
   trait BIOImplicitPuns11 {
-    @inline implicit final def BIOFunctor[F[_, + _]: BIOFunctor, E, A](self: F[E, A]): BIOSyntax.BIOFunctorOps[F, E, A] = new BIOSyntax.BIOFunctorOps[F, E, A](self)
-    @inline final def BIOFunctor[F[_, +_]: BIOFunctor]: BIOFunctor[F] = implicitly
+    @inline implicit final def BIOFunctor[F[+_, +_]: BIOFunctor, E, A](self: F[E, A]): BIOSyntax.BIOFunctorOps[F, E, A] = new BIOSyntax.BIOFunctorOps[F, E, A](self)
+    @inline final def BIOFunctor[F[+_, +_]: BIOFunctor]: BIOFunctor[F] = implicitly
   }
 
 }
diff --git a/project/Deps.sc b/project/Deps.sc
index d0804374d..5e1adef5b 100644
--- a/project/Deps.sc
+++ b/project/Deps.sc
@@ -145,8 +145,8 @@ object Izumi {
   object Targets {
     // switch order to use 2.13 in IDEA
     val targetScala = Seq(scala212, scala213)
+//    val targetScala = Seq(scala213, scala212)
     val targetScalaWith211 = Seq(scala212, scala213, scala211)
-    //    val targetScala = Seq(scala213, scala212)
     private val jvmPlatform = PlatformEnv(
       platform = Platform.Jvm,
       language = targetScala,
@@ -260,7 +260,6 @@ object Izumi {
           ),
           SettingKey.Default := Const.EmptySeq
         ),
-        "scalacOptions" += "-P:silencer:globalFilters=inside.of.package.objects"
       )
 
     }


Test patch:
diff --git a/distage/distage-framework-docker/src/test/scala/izumi/distage/testkit/docker/DistageTestDockerBIO.scala b/distage/distage-framework-docker/src/test/scala/izumi/distage/testkit/docker/DistageTestDockerBIO.scala
index 861d324ba..d205206a9 100644
--- a/distage/distage-framework-docker/src/test/scala/izumi/distage/testkit/docker/DistageTestDockerBIO.scala
+++ b/distage/distage-framework-docker/src/test/scala/izumi/distage/testkit/docker/DistageTestDockerBIO.scala
@@ -15,14 +15,14 @@ final class DistageTestDockerBIO extends DistageBIOSpecScalatest[IO] {
       "support docker resources" in {
         service: PgSvcExample =>
           for {
-            _ <- IO(println(s"ports/1: pg=${service.pg} ddb=${service.ddb} "))
+            _ <- IO(println(s"ports/1: pg=${service.pg} ddb=${service.ddb} kafka=${service.kafka} cs=${service.cs}"))
           } yield ()
       }
 
       "support memoization" in {
         service: PgSvcExample =>
           for {
-            _ <- IO(println(s"ports/2: pg=${service.pg} ddb=${service.ddb} "))
+            _ <- IO(println(s"ports/2: pg=${service.pg} ddb=${service.ddb} kafka=${service.kafka} cs=${service.cs}"))
           } yield ()
       }
     }
diff --git a/distage/distage-framework-docker/src/test/scala/izumi/distage/testkit/docker/fixtures/DockerPlugin.scala b/distage/distage-framework-docker/src/test/scala/izumi/distage/testkit/docker/fixtures/DockerPlugin.scala
index 60712a206..cad54024a 100644
--- a/distage/distage-framework-docker/src/test/scala/izumi/distage/testkit/docker/fixtures/DockerPlugin.scala
+++ b/distage/distage-framework-docker/src/test/scala/izumi/distage/testkit/docker/fixtures/DockerPlugin.scala
@@ -1,39 +1,52 @@
 package izumi.distage.testkit.docker.fixtures
 
 import distage.config.ConfigModuleDef
-import izumi.distage.model.definition.Id
-import izumi.distage.model.definition.StandardAxis.Env
-import izumi.distage.effect.modules.{CatsDIEffectModule, ZIODIEffectModule}
-import izumi.distage.plugins.PluginDef
 import izumi.distage.docker.Docker.AvailablePort
-import izumi.distage.docker.examples.{DynamoDocker, PostgresDocker}
+import izumi.distage.docker.examples._
 import izumi.distage.docker.modules.DockerContainerModule
+import izumi.distage.effect.modules.{CatsDIEffectModule, ZIODIEffectModule}
 import izumi.distage.framework.model.IntegrationCheck
+import izumi.distage.model.definition.Id
+import izumi.distage.model.definition.StandardAxis.Env
+import izumi.distage.plugins.PluginDef
 import izumi.fundamentals.platform.integration.{PortCheck, ResourceCheck}
 import zio.Task
 
 class PgSvcExample(
-                    val pg: AvailablePort @Id("pg"),
-                    val ddb: AvailablePort @Id("ddb"),
-                  ) extends IntegrationCheck {
+  val pg: AvailablePort @Id("pg"),
+  val ddb: AvailablePort @Id("ddb"),
+  val kafka: AvailablePort @Id("kafka"),
+  val cs: AvailablePort @Id("cs"),
+) extends IntegrationCheck {
   override def resourcesAvailable(): ResourceCheck = {
     new PortCheck(10).checkPort(pg.hostV4, pg.port)
   }
 }
 
-object MonadPlugin extends PluginDef
-  with CatsDIEffectModule
-  with ZIODIEffectModule
+object MonadPlugin extends PluginDef with CatsDIEffectModule with ZIODIEffectModule
 
 object DockerPlugin extends DockerContainerModule[Task] with PluginDef {
   make[DynamoDocker.Container].fromResource {
     DynamoDocker.make[Task]
   }
 
+  include(new CassandraDockerModule[Task])
+  include(new ZookeeperDockerModule[Task])
+  include(new KafkaDockerModule[Task])
+
+  make[AvailablePort].named("cs").tagged(Env.Test).from {
+    cs: CassandraDocker.Container =>
+      cs.availablePorts(CassandraDocker.primaryPort).head
+  }
+
+  make[AvailablePort].named("kafka").tagged(Env.Test).from {
+    kafka: KafkaDocker.Container =>
+      kafka.availablePorts(KafkaDocker.primaryPort).head
+  }
+
   // this container will start once `DynamoContainer` is up and running
   make[PostgresDocker.Container].fromResource {
-    PostgresDocker.make[Task]
-      .dependOnDocker(DynamoDocker)
+    PostgresDocker.make[Task].dependOnDocker(DynamoDocker)
   }
 
   // these lines are for test scope
diff --git a/fundamentals/fundamentals-bio/.jvm/src/test/scala/izumi/functional/bio/test/BlockingIOSyntaxTest.scala b/fundamentals/fundamentals-bio/.jvm/src/test/scala/izumi/functional/bio/test/BlockingIOSyntaxTest.scala
index a03bd8205..eeb6f90ac 100644
--- a/fundamentals/fundamentals-bio/.jvm/src/test/scala/izumi/functional/bio/test/BlockingIOSyntaxTest.scala
+++ b/fundamentals/fundamentals-bio/.jvm/src/test/scala/izumi/functional/bio/test/BlockingIOSyntaxTest.scala
@@ -1,10 +1,9 @@
 package izumi.functional.bio.test
 
-import izumi.functional.bio.{BIOFunctor, BlockingIO, BlockingIO3, BlockingIOInstances, F}
-import izumi.fundamentals.bio.test.masking.BIOMonad3
+import izumi.functional.bio.{BIOFunctor, BIOMonad3, BlockingIO, BlockingIO3, BlockingIOInstances, F}
 import org.scalatest.wordspec.AnyWordSpec
-import zio.{Has, ZIO}
 import zio.blocking.Blocking
+import zio.{Has, ZIO}
 
 class BlockingIOSyntaxTest extends AnyWordSpec {
 
@@ -16,8 +15,9 @@ class BlockingIOSyntaxTest extends AnyWordSpec {
   }
   val _: ZIO[Blocking, Throwable, Int] = {
     implicit val blocking: Blocking = Has(Blocking.Service.live)
-    `attach BlockingIO methods to a trifunctor BIO`[BlockingIOInstances.ZIOWithBlocking]
+    `attach BlockingIO methods to a trifunctor BIO`[ZIO]
     `attach BlockingIO methods to a bifunctor BIO`[zio.IO]
+    `attach BlockingIO methods to a bifunctor BIO`[BlockingIOInstances.ZIOWithBlocking[Any, +?, +?]]
   }
 
   "BlockingIO.apply is callable" in {
diff --git a/fundamentals/fundamentals-bio/src/test/scala/izumi/fundamentals/bio/test/BIOSyntaxTest.scala b/fundamentals/fundamentals-bio/src/test/scala/izumi/fundamentals/bio/test/BIOSyntaxTest.scala
index 8634e7acf..b58acd3e4 100644
--- a/fundamentals/fundamentals-bio/src/test/scala/izumi/fundamentals/bio/test/BIOSyntaxTest.scala
+++ b/fundamentals/fundamentals-bio/src/test/scala/izumi/fundamentals/bio/test/BIOSyntaxTest.scala
@@ -1,21 +1,10 @@
 package izumi.fundamentals.bio.test
 
-import izumi.functional.bio.{BIO, BIOFunctor, BIOMonad, BIOMonadError, BIOPrimitives, BIOTemporal, F}
-import izumi.fundamentals.bio.test.masking._
+import izumi.functional.bio.{BIO, BIOArrow, BIOAsk, BIOFork, BIOFork3, BIOFunctor, BIOFunctor3, BIOLocal, BIOMonad, BIOMonad3, BIOMonadAsk, BIOMonadError, BIOPrimitives, BIOPrimitives3, BIOProfunctor, BIOTemporal, F}
 import org.scalatest.wordspec.AnyWordSpec
 
 import scala.concurrent.duration._
 
-object masking {
-  import izumi.functional.bio.{BIOFork, BIOFork3, BIOPrimitives3}
-
-  type Primitives[F[+_, +_]] = BIOPrimitives[F]
-  type Fork[F[+_, +_]] = BIOFork[F]
-  type Fork3[F[-_, +_, +_]] = BIOFork3[F]
-  type BIOMonad3[F[-_, +_, +_]] = BIOMonad[F[Any, +?, +?]]
-  type Primitives3[F[-_, +_, +_]] = BIOPrimitives3[F]
-}
-
 class BIOSyntaxTest extends AnyWordSpec {
 
   "BIO.apply is callable" in {
@@ -67,30 +56,94 @@ class BIOSyntaxTest extends AnyWordSpec {
     x[zio.IO]
   }
 
-  "F summoner examples" in {
+  "F / FR summoners examples" in {
     def x[F[+_, +_]: BIOMonad] = {
       F.when(false)(F.unit)
     }
     def y[F[+_, +_]: BIOTemporal] = {
-      F.timeout(F.forever(F.unit))(5.seconds)
+      F.timeout(F.forever(F.unit))(5.seconds) *>
+      F.map(z[F])(_ => ())
     }
     def z[F[+_, +_]: BIOFunctor]: F[Nothing, Unit] = {
       F.map(z[F])(_ => ())
     }
-    def `attach BIOPrimitives & BIOFork methods even when they aren't imported`[F[+_, +_]: BIOMonad: Primitives: Fork]: F[Nothing, Int] = {
+    def `attach BIOPrimitives & BIOFork methods even when they aren't imported`[F[+_, +_]: BIOMonad: BIOPrimitives: BIOFork]: F[Nothing, Int] = {
       F.fork[Any, Nothing, Int] {
-        F.mkRef(4).flatMap(r => r.update(_ + 5) *> r.get.map(_ - 1))
-      }.flatMap(_.join)
+          F.mkRef(4).flatMap(r => r.update(_ + 5) *> r.get.map(_ - 1))
+        }.flatMap(_.join) *>
+      F.mkRef(4).flatMap(r => r.update(_ + 5) *> r.get.map(_ - 1)).fork.flatMap(_.join)
     }
-    def `attach BIOPrimitives & BIOFork3 methods to a trifunctor BIO even when not imported`[F[-_, +_, +_]: BIOMonad3: Primitives3: Fork3]: F[Any, Nothing, Int] = {
-      F.fork(F.mkRef(4).flatMap(r => r.update(_ + 5) *> r.get.map(_ - 1))).flatMap(_.join)
+    def `attach BIOPrimitives & BIOFork3 methods to a trifunctor BIO even when not imported`[FR[-_, +_, +_]: BIOMonad3: BIOPrimitives3: BIOFork3]
+      : FR[Nothing, Nothing, Int] = {
+      F.fork(F.mkRef(4).flatMap(r => r.update(_ + 5) *> r.get.map(_ - 1))).flatMap(_.join) *>
+      F.mkRef(4).flatMap(r => r.update(_ + 5) *> r.get.map(_ - 1)).fork.flatMap(_.join)
     }
     lazy val _ = (
-      x,
+      x[zio.IO],
       y[zio.IO](_: BIOTemporal[zio.IO]),
-      z,
+      z[zio.IO],
       `attach BIOPrimitives & BIOFork methods even when they aren't imported`[zio.IO],
       `attach BIOPrimitives & BIOFork3 methods to a trifunctor BIO even when not imported`[zio.ZIO],
     )
   }
+
+  "FR: Local/Ask summoners examples" in {
+    def x[FR[-_, +_, +_]: BIOMonad3: BIOAsk] = {
+      F.unit *> F.ask[Int].map {
+        _: Int =>
+          true
+      } *>
+      F.unit *> F.askWith {
+        _: Int =>
+          true
+      }
+    }
+    def onlyMonadAsk[FR[-_, +_, +_]: BIOMonadAsk]: FR[Int, Nothing, Unit] = {
+      F.unit <* F.askWith {
+        _: Int =>
+          true
+      }
+    }
+    def onlyAsk[FR[-_, +_, +_]: BIOAsk]: FR[Int, Nothing, Unit] = {
+      F.askWith {
+        _: Int =>
+          true
+      } *> F.unit
+    }
+    def y[FR[-_, +_, +_]: BIOLocal]: FR[Any, Throwable, Unit] = {
+      F.fromKleisli {
+        F.askWith {
+          _: Int =>
+            ()
+        }.toKleisli
+      }.provide(4)
+    }
+    def arrowAsk[FR[-_, +_, +_]: BIOArrow: BIOAsk]: FR[String, Throwable, Int] = {
+      F.askWith {
+        _: Int =>
+          ()
+      }.dimap {
+        _: String =>
+          4
+      }(_ => 1)
+    }
+    def profunctorOnly[FR[-_, +_, +_]: BIOProfunctor]: FR[String, Throwable, Int] = {
+      F.contramap( ??? : FR[Unit, Throwable, Int] ) {
+        _: Int =>
+          ()
+      }.dimap {
+        _: String =>
+          4
+      }(_ => 1)
+        .map(_ + 2)
+    }
+    lazy val _ = (
+      x[zio.ZIO],
+      onlyMonadAsk[zio.ZIO],
+      onlyAsk[zio.ZIO],
+      y[zio.ZIO],
+      arrowAsk[zio.ZIO],
+      profunctorOnly[zio.ZIO],
+    )
+  }
 }