diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,21 @@
 # Revision history for dep-t
 
+## 0.6.5
+
+* Deprecated `Constructor`, `fixEnv` and the `Accum-` counterparts from `Dep.Env`.
+  
+  Created new versions in `Dep.Constructor`. The new versions are newtypes, not
+  type aliases.
+
+  Users trying to migrate should hide the old `Dep.Env` versions when importing
+  the module.
+
+  > import Dep.Env hiding (AccumConstructor, Constructor, accumConstructor, constructor, fixEnv, fixEnvAccum)
+
+* Deprecated the `Dep` type family from `Dep.Has`.
+
+* Shifted `DepT`-specific parts of the readme to `Control.Monad.Dep`.
+
 ## 0.6.4
 
 * Added AccumConstructor, a generalization of Constructor that threads a
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,259 +1,61 @@
 # dep-t
 
-This package provides various helpers for the "record-of-functions" style of structuring Haskell applications. The guiding idea is that record-of-functions is a form of dependency injection, and the that the environment which contains the functions is akin to an [`ApplicationContext`](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/ApplicationContext.html) in object-oriented frameworks like [Java Spring](https://docs.spring.io/spring-framework/docs/current/reference/html/).
-
-If every dependency knew about the concrete environment, that would increase coupling. The solution is to use `Has`-style classes so that each dependency knows only about those parts of the environment which it needs to function, and nothing more. Those `Has`-style classes can be tailor-made, but the package also provides a generic one. 
-
-*Very* loosely speaking, `Has`-style constraints correspond to injected member variables in object-oriented frameworks.
-
-[![dep-t.png](https://i.postimg.cc/2j0qqkmJ/dep-t.png)](https://postimg.cc/V5bspcJB)
-
-- __Dep.Has__ contains a generic `Has` typeclass for locating dependencies in an environment. It can be useful independently of `ReaderT`, `DepT` or any monad transformer.
-- __Dep.Env__ complements __Dep.Has__, adding helpers for building environments of records.
-- __Dep.Tagged__ is a helper for disambiguating dependencies in __Dep.Env__ environments.
-- __Control.Monad.Dep__ contains the `DepT` monad transformer, a variant of `ReaderT`.
-- __Control.Monad.Dep.Class__ is an extension of `MonadReader`, useful to program against both `ReaderT` and `DepT`.
-
-## The DepT transformer
-
-`DepT` is a
-[ReaderT](http://hackage.haskell.org/package/mtl-2.2.2/docs/Control-Monad-Reader.html)-like
-monad transformer for dependency injection.
-
-The difference with `ReaderT` is that `DepT` takes an enviroment whose type is
-parameterized by `DepT` itself.
-
-### Rationale
-
-To perform dependency injection in Haskell, a common solution is to build a
-record of functions and pass it to the program logic using some variant of
-[`ReaderT`](http://hackage.haskell.org/package/mtl-2.2.2/docs/Control-Monad-Reader.html).
-
-To avoid becoming tied to a concrete reader environment, let's define some
-auxiliary typeclasses that extract functions from a generic environment:
-
-    type HasLogger :: (Type -> Type) -> Type -> Constraint
-    class HasLogger d e | e -> d where
-      logger :: e -> String -> d ()
-
-    type HasRepository :: (Type -> Type) -> Type -> Constraint
-    class HasRepository d e | e -> d where
-      repository :: e -> Int -> d ()
-
-We see that the type `e` of the environment determines the monad `d` on which
-the effects take place.
-
-Here's a monomorphic environment record with functions that have effects in `IO`:
-
-    type EnvIO :: Type
-    data EnvIO = EnvIO
-      { _loggerIO :: String -> IO (),
-        _repositoryIO :: Int -> IO ()
-      }
-
-    instance HasLogger IO EnvIO where
-      logger = _loggerIO
-
-    instance HasRepository IO EnvIO where
-      repository = _repositoryIO
-
-[Record-of-functions-in-IO](https://www.fpcomplete.com/blog/2017/06/readert-design-pattern/) is a simple technique which works well in many
-situations. There are even [specialized
-libraries](http://hackage.haskell.org/package/rio) that support it.
-
-Here's a function which can get its dependencies from the monomorphic
-environment:
-
-    mkControllerIO :: (HasLogger IO e, HasRepository IO e) => Int -> ReaderT e IO String
-    mkControllerIO x = do
-      e <- ask
-      liftIO $ logger e "I'm going to insert in the db!"
-      liftIO $ repository e x
-      return "view"
-
-That's all and well, but there are two issues that bug me:
-
-- We might want to write code that is innocent of `IO` and polymorphic over the
-  monad, to ensure that the program logic can't do some unexpected missile
-  launch, or to allow testing our app in a "pure" way. 
-
-- What if the repository function needs access to the logger, too? The
-  repository lives in the environment record, but isn't aware of it. That means
-  it can't use the `HasLogger` typeclass for easy and convenient dependency
-  injection. Why privilege the controller in such a way?
-
-  In a sufficiently complex app, the diverse functions that comprise it will be
-  organized in a big
-  [DAG](https://en.wikipedia.org/wiki/Directed_acyclic_graph) of dependencies.
-  And it would be nice if all the functions taking part in dependency injection
-  were treated uniformly; if all of them had access to (some view of) the
-  environment record.
-
-To tackle these issues, we begin by giving the controller a more general signature:
-
-    mkControllerIO :: (HasLogger IO e, HasRepository IO e, MonadIO m, MonadReader e m) => Int -> m String
-
-Now the function can work in other reader-like monads besides `ReaderT`.
-
-Let's go one step further, and abstract away the `IO`, so that functions in the
-record can have effects in other monads:
-
-    mkController :: (HasLogger d e, HasRepository d e, LiftDep d m, MonadReader e m) => Int -> m String
-    mkController x = do
-      e <- ask
-      liftD $ logger e "I'm going to insert in the db!"
-      liftD $ repository e x
-      return "view"
-
-Now both the signature and the implementation have changed:
-
-- There's a new type variable `d`, the monad in which functions taken from the
-  environment `e` have their effects.
-
-- `MonadIO` has been replaced by `LiftDep` from `Control.Monad.Dep.Class`, a
-  constraint that says we can lift `d` effects into `m` (though it could still
-  make sense to require `MonadIO m` for effects not originating in the
-  environment).
-
-- Uses of `liftIO` have been replaced by `liftD`.
-
-If all those constraints prove annoying to write, there's a convenient shorthand using the `MonadDep` type family:
-
-    mkController :: MonadDep [HasLogger, HasRepository] d e m => Int -> m String
-
-The new, more polymorphic `mkController` function can replace the original `mkControllerIO`:
-
-    mkControllerIO' :: (HasLogger IO e, HasRepository IO e) => Int -> ReaderT e IO String
-    mkControllerIO' = mkController
-
-Now let's focus on the environment record. We'll parameterize its type by a
-monad: 
-
-    type Env :: (Type -> Type) -> Type
-    data Env m = Env
-      { _logger :: String -> m (),
-        _repository :: Int -> m (),
-        _controller :: Int -> m String
-      }
-
-    instance HasLogger m (Env m) where
-      logger = _logger
-
-    instance HasRepository m (Env m) where
-      repository = _repository
-
-Notice that the controller function is now part of the environment. No
-favorites here!
-
-The following implementation of the logger function has no dependencies besides
-`MonadIO`:
-
-    mkStdoutLogger :: MonadIO m => String -> m ()
-    mkStdoutLogger msg = liftIO (putStrLn msg)
-
-But look at this implementation of the repository function. It gets hold of the
-logger through `HasLogger`, just as the controller did:
-
-    mkStdoutRepository :: (MonadDep '[HasLogger] d e m, MonadIO m) => Int -> m ()
-    mkStdoutRepository entity = do
-      e <- ask
-      liftD $ logger e "I'm going to write the entity!"
-      liftIO $ print entity
-
-It's about time we choose a concrete monad and assemble an environment record:
-
-    envIO :: Env (DepT Env IO)
-    envIO =
-      let _logger = mkStdoutLogger
-          _repository = mkStdoutRepository
-          _controller = mkController
-       in Env {_logger,  _repository, _controller}
-
-Not very complicated, except... what is that weird `DepT Env IO` doing there in
-the signature? 
-
-Well, that's the whole reason this library exists. For dependency injection to
-work for *all* functions, `Env` needs to be parameterized with a monad that
-provides that same `Env` environment. And trying to use a `ReaderT (Env
-something) IO` to parameterize `Env` won't fly; you'll get weird "infinite
-type" kind of errors. So I created the `DepT` newtype over `ReaderT` to mollify
-the compiler.
-
-`DepT` has `MonadReader` and `LiftDep` instances, so the effects of
-`mkController` can take place on it.
-
-### So how do we invoke the controller now?
-
-I suggest something like
-
-    runDepT (do e <- ask; _controller e 7) envIO 
-
-or 
-
-    (do e <- ask; _controller e 7) `runDepT` envIO 
-
-The companion package
-[dep-t-advice](http://hackage.haskell.org/package/dep-t-advice) has some more
-functions for running `DepT` computations.
-
-### How to avoid using "ask" and "liftD" before invoking a dependency?
-
-One possible workaround (at the cost of more boilerplate) is to define helper
-functions like:  
-
-    loggerD :: MonadDep '[HasLogger] d e m => String -> m ()
-    loggerD msg = asks logger >>= \f -> liftD $ f msg
-
-Which you can invoke like this:
-
-    usesLoggerD :: MonadDep [HasLogger, HasRepository] d e m => Int -> m String
-    usesLoggerD i = do
-      loggerD "I'm calling the logger!"
-      return "foo"
-
-Though perhaps this isn't worth the hassle.
-
-### How to use "pure fakes" during testing?
-
-The [test suite](./test/tests.hs) has an example of using a `Writer` monad for
-collecting the outputs of functions working as ["test
-doubles"](https://martinfowler.com/bliki/TestDouble.html).
+This package provides various helpers for the "record-of-functions" style of
+structuring Haskell applications. 
 
-### How to make a function "see" a different evironment from the one seen by its dependencies?
+A record that groups related functions is considered a component. Hypothetical example:
 
-Sometimes we want a function in the environment to see a slightly different
-record from the record seen by the other functions, and in particular from the
-record seen by its own dependencies. 
+```
+data Repository m = Repository
+  { findById :: ResourceId -> m Resource,
+    save :: Resource -> m ()
+  } 
+```
 
-For example, the function might have a `HasLogger` constraint but we don't want
-it to use the default `HasLogger` instance of the environment.
+The record type is the component's "interface". A component's "implementation" is
+defined by a constructor function that returns a value of the record type.
 
-The companion package
-[dep-t-advice](http://hackage.haskell.org/package/dep-t-advice) provides a
-`deceive` function that allows for this.
+When starting up, applications build a dependency injection environment
+which contains all the required components. And components read their *own* dependencies
+from the DI environment. The DI environment is akin to an
+[`ApplicationContext`](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/ApplicationContext.html)
+in object-oriented frameworks like [Java
+Spring](https://docs.spring.io/spring-framework/docs/current/reference/html/).
 
-### How to add AOP-ish "aspects" to functions in an environment?
+If components knew about the *concrete* DI environment, that would increase
+coupling. Everything would depend on everything else. To avoid that, we resort
+to `Has`-style typeclasses so that each constructor function knows only about the
+parts of the environment that it needs, and nothing more. Those `Has`-style classes can
+be tailor-made, but this package also provides a generic one. 
 
-The companion package
-[dep-t-advice](http://hackage.haskell.org/package/dep-t-advice) provides a
-general method of extending the behaviour of `DepT`-effectful functions, in a
-way reminiscent of aspect-oriented programming.
+Hypothetical example of constructor function:
 
-### What if I don't want to use DepT, or any other monad transformer for that matter?
+```
+makeRepository :: (Has Logger m deps, Has SomeOtherDep m deps) => deps -> Repository m
+```
 
-Check out the function `fixEnv` in module `Dep.Env`, which
-provides a transformer-less way to perform dependency injection, based on
-knot-tying.
+*Very* loosely speaking, `Has`-style constraints correspond to [injected
+constructor arguments](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-constructor-injection) in object-oriented DI frameworks.
 
-That method requires an environment parameterized by _two_ type constructors:
-one that wraps each field, and another that works as the effect monad for the
-components.
+## Module structure
 
-### DepT caveats
+```mermaid
+  graph TD;
+      Dep.Env-->Dep.Has;
+      Dep.Constructor-->Dep.Env;
+      Dep.Tagged;
+      Control.Monad.Dep.Class-->Control.Monad.Reader;
+      Control.Monad.Dep-->Control.Monad.Reader;
+      Control.Monad.Dep-->Control.Monad.Dep.Class;
+```
 
-The structure of the `DepT` type might be prone to trigger a [known infelicity
-of the GHC
-simplifier](https://twitter.com/DiazCarrete/status/1350116413445439493).
+- __Dep.Has__ provides a generic `Has` typeclass for locating dependencies in an
+environment. Usually, component implementations import this module.
+- __Dep.Env__ complements __Dep.Has__ with helpers for building dependency injection environments. Usually, only the [composition root](https://stackoverflow.com/questions/6277771/what-is-a-composition-root-in-the-context-of-dependency-injection) of the application imports this module.
+- __Dep.Tagged__ is a helper for disambiguating dependencies in __Dep.Env__ environments.
+- __Dep.Constructor__ enables fixpoint-based dependency injection in __Dep.Env__ environments.
+- __Control.Monad.Dep__ provides the `DepT` monad transformer, a variant of `ReaderT`. You either want to use this or __Dep.Constructor__ in your composition root, but not both.
+- __Control.Monad.Dep.Class__ is an extension of `MonadReader`, useful to program against both `ReaderT` and `DepT`.
 
 ## Links
 
diff --git a/dep-t.cabal b/dep-t.cabal
--- a/dep-t.cabal
+++ b/dep-t.cabal
@@ -1,7 +1,7 @@
 cabal-version:       3.0
 
 name:                dep-t
-version:             0.6.4.0
+version:             0.6.5.0
 synopsis:            Dependency injection for records-of-functions.
 description:         Put all your functions in the environment record! Let all
                      your functions read from the environment record! No favorites!
@@ -28,6 +28,7 @@
   import: common
   exposed-modules:     Dep.Has
                        Dep.Env
+                       Dep.Constructor
                        Dep.Tagged
                        Control.Monad.Dep
                        Control.Monad.Dep.Class
diff --git a/lib/Control/Monad/Dep.hs b/lib/Control/Monad/Dep.hs
--- a/lib/Control/Monad/Dep.hs
+++ b/lib/Control/Monad/Dep.hs
@@ -11,15 +11,18 @@
 {-# LANGUAGE KindSignatures #-}
 
 -- |
---    This module provides 'DepT', a monad transformer similar to 'ReaderT'.
---
---    The difference is that the environment of 'DepT' must be parameterized by
---    @DepT@'s own monad stack.
+-- This module provides 'DepT', a monad transformer similar to 'ReaderT'.
 --
---    There's a function 'withDepT' which is analogous to 'withReaderT'.
---    There's no analogue of 'mapReaderT' however. 
+-- The difference with 'ReaderT' is that 'DepT' takes an enviroment whose type is
+-- parameterized by 'DepT' itself.
 module Control.Monad.Dep
   ( 
+    -- * Motivation 
+    -- $motivation
+
+    -- ** Caveats
+    -- $caveats
+    
     -- * The DepT transformer
     DepT (DepT),
     runDepT,
@@ -55,6 +58,211 @@
 import Data.Coerce
 import Data.Functor.Constant
 
+-- $motivation
+--
+-- Dependency injection.
+--
+-- To perform dependency injection in Haskell, a common solution is to build a
+-- record of functions and pass it to the program logic using some variant of
+-- 'ReaderT'.
+-- 
+-- To avoid becoming tied to a concrete reader environment, let's define some
+-- auxiliary typeclasses that extract functions from a generic environment:
+--
+-- @
+-- type HasLogger :: (Type -> Type) -> Type -> Constraint
+-- class HasLogger d e | e -> d where
+--   logger :: e -> String -> d ()
+-- 
+-- type HasRepository :: (Type -> Type) -> Type -> Constraint
+-- class HasRepository d e | e -> d where
+--   repository :: e -> Int -> d ()
+-- @
+-- 
+-- We see that the type `e` of the environment determines the monad `d` on which
+-- the effects take place.
+-- 
+-- Here's a monomorphic environment record with functions that have effects in `IO`:
+-- 
+-- @
+-- type EnvIO :: Type
+-- data EnvIO = EnvIO
+--   { _loggerIO :: String -> IO (),
+--     _repositoryIO :: Int -> IO ()
+--   }
+-- 
+-- instance HasLogger IO EnvIO where
+--   logger = _loggerIO
+-- 
+-- instance HasRepository IO EnvIO where
+--   repository = _repositoryIO
+-- @
+-- 
+-- [Record-of-functions-in-IO](https://www.fpcomplete.com/blog/2017/06/readert-design-pattern/) is a simple technique which works well in many
+-- situations. There are even [specialized
+-- libraries](http://hackage.haskell.org/package/rio) that support it.
+-- 
+-- Here's a function which can get its dependencies from the monomorphic
+-- environment:
+-- 
+-- @
+-- mkControllerIO :: (HasLogger IO e, HasRepository IO e) => Int -> ReaderT e IO String
+-- mkControllerIO x = do
+--   e <- ask
+--   liftIO $ logger e "I'm going to insert in the db!"
+--   liftIO $ repository e x
+--   return "view"
+-- @
+-- 
+-- That's all and well, but there are two issues that bug me:
+-- 
+-- - We might want to write code that is innocent of `IO` and polymorphic over the
+--   monad, to ensure that the program logic can't do some unexpected missile
+--   launch, or to allow testing our app in a "pure" way. 
+-- 
+-- - What if the repository function needs access to the logger, too? The
+--   repository lives in the environment record, but isn't aware of it. That means
+--   it can't use the `HasLogger` typeclass for easy and convenient dependency
+--   injection. Why privilege the controller in such a way?
+-- 
+--   In a sufficiently complex app, the diverse functions that comprise it will be
+--   organized in a big
+--   [DAG](https://en.wikipedia.org/wiki/Directed_acyclic_graph) of dependencies.
+--   And it would be nice if all the functions taking part in dependency injection
+--   were treated uniformly; if all of them had access to (some view of) the
+--   environment record.
+-- 
+-- To tackle these issues, we begin by giving the controller a more general signature:
+-- 
+-- @
+-- mkControllerIO :: (HasLogger IO e, HasRepository IO e, MonadIO m, MonadReader e m) => Int -> m String
+-- @
+-- 
+-- Now the function can work in other reader-like monads besides 'ReaderT'.
+-- 
+-- Let's go one step further, and abstract away the `IO`, so that functions in the
+-- record can have effects in other monads:
+-- 
+-- @
+-- mkController :: (HasLogger d e, HasRepository d e, LiftDep d m, MonadReader e m) => Int -> m String
+-- mkController x = do
+--   e <- ask
+--   liftD $ logger e "I'm going to insert in the db!"
+--   liftD $ repository e x
+--   return "view"
+-- @
+-- 
+-- Now both the signature and the implementation have changed:
+-- 
+-- - There's a new type variable `d`, the monad in which functions taken from the
+--   environment `e` have their effects.
+-- 
+-- - `MonadIO` has been replaced by `LiftDep` from `Control.Monad.Dep.Class`, a
+--   constraint that says we can lift `d` effects into `m` (though it could still
+--   make sense to require `MonadIO m` for effects not originating in the
+--   environment).
+-- 
+-- - Uses of `liftIO` have been replaced by `liftD`.
+-- 
+-- If all those constraints prove annoying to write, there's a convenient shorthand using the `MonadDep` type family:
+-- 
+-- @
+-- MonadDep [HasLogger, HasRepository] d e m => Int -> m String
+-- @
+-- 
+-- The new, more polymorphic `mkController` function can replace the original `mkControllerIO`:
+-- 
+-- @
+-- mkControllerIO' :: (HasLogger IO e, HasRepository IO e) => Int -> ReaderT e IO String
+-- mkControllerIO' = mkController
+-- @
+-- 
+-- Now let's focus on the environment record. We'll parameterize its type by a
+-- monad: 
+-- 
+-- @
+-- type Env :: (Type -> Type) -> Type
+-- data Env m = Env
+--   { _logger :: String -> m (),
+--     _repository :: Int -> m (),
+--     _controller :: Int -> m String
+--   }
+-- 
+-- instance HasLogger m (Env m) where
+--   logger = _logger
+-- 
+-- instance HasRepository m (Env m) where
+--   repository = _repository
+-- @
+-- 
+-- Notice that the controller function is now part of the environment. No
+-- favorites here!
+-- 
+-- The following implementation of the logger function has no dependencies besides
+-- 'MonadIO':
+-- 
+-- @
+-- mkStdoutLogger :: MonadIO m => String -> m ()
+-- mkStdoutLogger msg = liftIO (putStrLn msg)
+-- @
+-- 
+-- But look at this implementation of the repository function. It gets hold of the
+-- logger through @HasLogger@, just as the controller did:
+-- 
+-- @
+-- mkStdoutRepository :: (MonadDep '[HasLogger] d e m, MonadIO m) => Int -> m ()
+-- mkStdoutRepository entity = do
+--   e <- ask
+--   liftD $ logger e "I'm going to write the entity!"
+--   liftIO $ print entity
+-- @
+-- 
+-- It's about time we choose a concrete monad and assemble an environment record:
+-- 
+-- @
+-- envIO :: Env (DepT Env IO)
+-- envIO =
+--   let _logger = mkStdoutLogger
+--       _repository = mkStdoutRepository
+--       _controller = mkController
+--    in Env {_logger,  _repository, _controller}
+-- @
+-- 
+-- Not very complicated, except... what is that weird `DepT Env IO` doing there in
+-- the signature? 
+-- 
+-- Well, that's the whole reason this library exists. For dependency injection to
+-- work for *all* functions, @Env@ needs to be parameterized with a monad that
+-- provides that same @Env@ environment. And trying to use a @ReaderT (Env
+-- something) IO@ to parameterize @Env@ won't fly; you'll get weird "infinite
+-- type" kind of errors. So I created the 'DepT' newtype over 'ReaderT' to mollify
+-- the compiler.
+-- 
+-- 'DepT' has 'MonadReader' and 'LiftDep' instances, so the effects of
+-- @mkController@ can take place on it.
+--
+-- To invoke the controller from the environment, we can do something like
+-- 
+-- @
+-- runDepT (do e <- ask; _controller e 7) envIO 
+-- @
+-- 
+-- or 
+-- 
+-- @
+-- (do e <- ask; _controller e 7) `runDepT` envIO 
+-- @
+-- 
+-- The companion package
+-- [dep-t-advice](http://hackage.haskell.org/package/dep-t-advice) has some
+-- helper functions for running 'DepT' computations.
+ 
+-- $caveats
+-- The structure of the 'DepT' type might be prone to trigger a [known infelicity
+-- of the GHC
+-- simplifier](https://twitter.com/DiazCarrete/status/1350116413445439493).
+
+
 -- $setup
 --
 -- >>> :set -XTypeApplications
@@ -70,7 +278,7 @@
 
 -- |
 --    A monad transformer which adds a read-only environment to the given monad.
---    The environment type must be parameterized with the transformer's stack.
+--    The environment type must be parameterized with the transformer stack.
 --
 --    The 'return' function ignores the environment, while @>>=@ passes the
 --    inherited environment to both subcomputations.
@@ -129,6 +337,8 @@
 runDepT = runReaderT . toReaderT
 
 -- |
+-- Analogous to 'withReaderT'.
+--
 --    Changes the environment of a 'DepT', for example making the 'DepT' work in
 --    a "bigger" environment than the one in which was defined initially.
 --
diff --git a/lib/Control/Monad/Dep/Class.hs b/lib/Control/Monad/Dep/Class.hs
--- a/lib/Control/Monad/Dep/Class.hs
+++ b/lib/Control/Monad/Dep/Class.hs
@@ -60,7 +60,8 @@
 -- lifted using 'liftD' instead of 'lift' or 'liftIO'. 
 --
 module Control.Monad.Dep.Class
-  ( -- * Reader-like monads carrying dependencies in their environment
+  ( 
+    -- * Reader-like monads carrying dependencies in their environment
     MonadDep,
 
     -- * Lifting effects from dependencies
diff --git a/lib/Dep/Constructor.hs b/lib/Dep/Constructor.hs
new file mode 100644
--- /dev/null
+++ b/lib/Dep/Constructor.hs
@@ -0,0 +1,302 @@
+{-# LANGUAGE AllowAmbiguousTypes #-}
+{-# LANGUAGE ConstraintKinds #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE ImportQualifiedPost #-}
+{-# LANGUAGE DeriveFunctor #-}
+{-# LANGUAGE DerivingStrategies #-}
+{-# LANGUAGE DerivingVia #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE PolyKinds #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE StandaloneDeriving #-}
+{-# LANGUAGE TypeApplications #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE UndecidableInstances #-}
+{-# LANGUAGE BlockArguments #-}
+
+-- | This module provides a method for performing dependency injection in 'Phased'
+-- environments by means of building fixpoints.
+--
+-- To ease the reader into the concept, here's how we can define the
+-- [@factorial@](https://en.wikibooks.org/wiki/Haskell/Fix_and_recursion#Recursion)
+-- function using only 'fix' from @base@:
+-- 
+-- >>> :{
+-- type FactorialDeps = Int -> Int
+-- makeFactorial :: FactorialDeps -> Int -> Int  
+-- makeFactorial deps n = if n == 0 then 1 else n * deps (n-1)
+-- factorial :: Int -> Int
+-- factorial = fix makeFactorial
+-- :}
+--
+-- Looking at it, we can interpret it as a form of dependency injection. In the
+-- example, @makeFactorial@ depends on another function of type @FactorialDeps@
+-- for the @n > 1@ logic. So we build a fixpoint in which the resulting
+-- \"closed\" @factorial@ is passed as the dependency to @makeFactorial@.
+--
+-- Very good, but what does this have to do with dependency injection in a
+-- /real/ application? For real applications, we have a multitude of functions,
+-- not only one. Each component has potentially many functions, and there may be
+-- many components, with a complex directed acyclic graph of dependencies
+-- between components!
+--
+-- This module provides the 'Constructor' applicative. A 'Phased' dependency
+-- injection environment parameterized by 'Constructor' is like the set of all
+-- component constructors taking part in dependency injection, each one still
+-- \"open\" like @makeFactorial@, still waiting for its own dependencies.
+--
+-- And when we use the 'fixEnv' function on this \"open\" environment, we get
+-- back a \"closed\" environment parameterized by 'Identity', were all the
+-- dependencies have been resolved and the components are ready to be used.
+module Dep.Constructor
+  ( -- * Constructor phase
+    Constructor,
+    constructor,
+    lmapConstructor,
+    fixEnv,
+
+    -- * Constructor with accumulator
+    AccumConstructor,
+    accumConstructor,
+    accumConstructor_,
+    _accumConstructor,
+    _accumConstructor_,
+    lmapAccumConstructor,
+    fixEnvAccum,
+    -- * "Control.Arrow" re-exports
+    arr
+  )
+where
+
+import Control.Applicative
+import Data.Bifunctor (second)
+import Data.Coerce
+import Data.Function (fix)
+import Data.Kind
+import Data.Typeable
+import Dep.Env hiding (AccumConstructor, Constructor, accumConstructor, constructor, fixEnv, fixEnvAccum)
+import Control.Category (Category)
+import Control.Category qualified
+import Control.Arrow
+
+-- | A phase with the effect of \"constructing each component by reading its
+-- dependencies from a completed environment\". It should be the final phase.
+-- 
+-- The @deps@ type parameter will typically be the \"closed\" form of the
+-- dependency injection environment. That is, the type of environment produced
+-- by 'fixEnv'. 
+newtype Constructor (deps :: Type) component
+  = Constructor (deps -> component)
+  deriving stock Functor
+
+deriving newtype instance Category Constructor
+-- | Mostly useful for 'arr', which builds a 'Constructor' out of a regular function.
+deriving newtype instance Arrow Constructor
+-- | 'pure' lifts a component that doesn't require any dependencies.
+deriving newtype instance Applicative (Constructor deps)
+
+-- | Turn an environment-consuming function into a 'Constructor' that can be slotted
+-- into some field of a 'Phased' environment.
+--
+-- Equivalent to 'arr'.
+constructor ::
+  forall deps component.
+  (deps -> component) ->
+  Constructor deps component
+-- same order of type parameters as Has
+constructor = Constructor
+
+-- | A generalized 'Constructor' which produces, in addition to the result
+-- value, an @accum@ value which is then aggregated across all components and fed
+-- back along with the completed environment.
+--
+-- Like 'Constructor', 'AccumConstructor' should be the final phase.
+newtype AccumConstructor (accum :: Type) (deps :: Type) component
+  = AccumConstructor ((accum, deps) -> (accum, component))
+  deriving stock Functor
+
+-- | 'pure' lifts a component that doesn't require any dependencies.
+-- The produced accumulator will be 'mempty'.
+instance Monoid accum => Applicative (AccumConstructor accum deps) where
+  pure component = _accumConstructor_ \_ -> component
+  liftA2 f (AccumConstructor u) (AccumConstructor v) = AccumConstructor \accumdeps ->
+    let (acc1, component1) = u accumdeps
+        (acc2, component2) = v accumdeps
+     in (acc1 <> acc2, f component1 component2)
+
+-- |
+instance Monoid accum => Category (AccumConstructor accum) where
+  id = _accumConstructor_ id
+  (.) (AccumConstructor f) (AccumConstructor g) = AccumConstructor \(~(accum0,deps0)) -> 
+      let (accum1, deps1) = g (accum0,deps0)
+          (accum2, deps2) = f (accum0,deps1)
+       in (accum1 <> accum2, deps2)
+
+-- | Mostly useful for 'arr', which builds an 'AccumConstructor' out of a regular function. The produced accumulator will be 'mempty'.
+instance Monoid accum => Arrow (AccumConstructor accum) where
+  arr = _accumConstructor_
+  first (AccumConstructor f) = AccumConstructor \(~(accum,(deps,extra))) -> 
+    let (accum', component) = f (accum,deps)
+     in (accum', (component, extra))
+
+-- | Turn an environment-consuming function into an 'AccumConstructor' that can
+-- be slotted into some field of a 'Phased' environment. The function also
+-- consumes and produces a monoidal accumulator.
+accumConstructor ::
+  forall accum deps component.
+  (accum -> deps -> (accum, component)) ->
+  AccumConstructor accum deps component
+accumConstructor f = AccumConstructor (\(~(accum, deps)) -> f accum deps)
+
+accumConstructor_ ::
+  forall accum deps component.
+  Monoid accum =>
+  -- | Consumes the accumulator but doesn't produce it (returns the 'mempty' accumulator.)
+  (accum -> deps -> component) ->
+  AccumConstructor accum deps component
+accumConstructor_ f = accumConstructor $ \accum deps -> (mempty, f accum deps)
+
+_accumConstructor ::
+  forall accum deps component.
+  -- | Doesn't consume the accumulator but produces it.
+  (deps -> (accum, component)) ->
+  AccumConstructor accum deps component
+_accumConstructor f = accumConstructor $ \_ deps -> f deps
+
+-- | Equivalent to 'arr'.
+_accumConstructor_ ::
+  forall accum deps component.
+  Monoid accum =>
+  -- | Neither consumes nor produces the accumulator, like a 'Constructor'.
+  (deps -> component) ->
+  AccumConstructor accum deps component
+_accumConstructor_ f = accumConstructor $ \_ deps -> (mempty, f deps)
+
+-- | This is a method of performing dependency injection by building fixpoints.
+--
+-- If we have a environment whose fields are functions that construct each
+-- component by searching for its dependencies in a \"fully built\" version of
+-- the environment, we can \"tie the knot\" to obtain the \"fully built\"
+-- environment. This works as long as there aren't any circular dependencies
+-- between components.
+--
+-- Think of it as a version of 'Data.Function.fix' that, instead of \"tying\" a single
+-- function, ties a whole record of them.
+--
+-- We might have arrived as this \"ready-to-wire\" environment by peeling away
+-- successive layers of applicative functor composition using 'pullPhase', until
+-- only the wiring phase remains.
+--
+--  >>> :{
+--  newtype Foo d = Foo {foo :: String -> d ()} deriving Generic
+--  newtype Bar d = Bar {bar :: String -> d ()} deriving Generic
+--  makeIOFoo :: MonadIO m => Foo m
+--  makeIOFoo = Foo (liftIO . putStrLn)
+--  makeBar :: Has Foo m env => env -> Bar m
+--  makeBar (asCall -> call) = Bar (call foo)
+--  type Deps_ = InductiveEnv [Bar,Foo]
+--  type Deps = Deps_ Identity
+--  deps_ :: Deps_ (Constructor (Deps IO)) IO
+--  deps_ = EmptyEnv
+--      & AddDep @Foo (constructor (\_ -> makeIOFoo))
+--      & AddDep @Bar (constructor makeBar)
+--  deps :: Deps IO
+--  deps = fixEnv deps_
+-- :}
+--
+-- >>> :{
+--  bar (dep deps) "this is bar"
+-- :}
+-- this is bar
+fixEnv ::
+  (Phased deps_, Typeable deps_, Typeable m) =>
+  -- | Environment where each field is wrapped in a 'Constructor'
+  deps_ (Constructor (deps_ Identity m)) m ->
+  -- | Fully constructed environment, ready for use.
+  deps_ Identity m
+fixEnv env = fix (pullPhase (liftAH decompose env))
+  where
+    decompose (Constructor f) = coerce f
+
+-- | A generalized 'fixEnv' which threads a monoidal accumulator
+-- along with the environment.
+--
+-- Sometimes, we need constructors to produce a monoidal value along with the
+-- component. Think for example about some kind of composable startup action for
+-- the component.
+--
+-- And on the input side, some constructors need access to the monoidal value
+-- accumulated across all components. Think for example about a component which
+-- publishes diagnostics coming from all other components.
+fixEnvAccum ::
+  (Phased deps_, Typeable deps_, Typeable m, Monoid accum, Typeable accum) =>
+  -- | Environment where each field is wrapped in an 'AccumConstructor'
+  deps_ (AccumConstructor accum (deps_ Identity m)) m ->
+  -- | Fully constructed accumulator and environment, ready for use.
+  (accum, deps_ Identity m)
+fixEnvAccum env =
+  let f = pullPhase <$> pullPhase (liftAH decompose env)
+   in fix f
+  where
+    decompose (AccumConstructor f) = coerce f
+
+-- | Change the dependency environment seen by the component.
+lmapConstructor ::
+  forall deps deps' component.
+  Typeable component =>
+  -- | Modifies the environment, with access to the 'TypeRep' of the component.
+  (TypeRep -> deps -> deps') ->
+  Constructor deps' component ->
+  Constructor deps component
+lmapConstructor tweak (Constructor f) =
+  let tyRep = typeRep (Proxy @component)
+   in Constructor $ f . tweak tyRep
+
+-- | Change the dependency environment seen by the component.
+--
+-- The accumulator remains unchanged.
+lmapAccumConstructor ::
+  forall accum deps deps' component.
+  Typeable component =>
+  -- | Modifies the environment, with access to the 'TypeRep' of the component.
+  (TypeRep -> deps -> deps') ->
+  AccumConstructor accum deps' component ->
+  AccumConstructor accum deps component
+lmapAccumConstructor tweak (AccumConstructor f) =
+  let tyRep = typeRep (Proxy @component)
+   in AccumConstructor (\(~(accum, deps)) -> f (accum, tweak tyRep deps))
+
+-- $setup
+--
+-- >>> :set -XTypeApplications
+-- >>> :set -XMultiParamTypeClasses
+-- >>> :set -XImportQualifiedPost
+-- >>> :set -XTemplateHaskell
+-- >>> :set -XStandaloneKindSignatures
+-- >>> :set -XNamedFieldPuns
+-- >>> :set -XFunctionalDependencies
+-- >>> :set -XFlexibleContexts
+-- >>> :set -XDataKinds
+-- >>> :set -XBlockArguments
+-- >>> :set -XFlexibleInstances
+-- >>> :set -XTypeFamilies
+-- >>> :set -XDeriveGeneric
+-- >>> :set -XViewPatterns
+-- >>> :set -XDerivingStrategies
+-- >>> :set -XDerivingVia
+-- >>> :set -XDeriveAnyClass
+-- >>> :set -XStandaloneDeriving
+-- >>> :set -XUndecidableInstances
+-- >>> :set -XTypeOperators
+-- >>> :set -XScopedTypeVariables
+-- >>> import Data.Kind
+-- >>> import Data.Function ((&))
+-- >>> import Control.Monad.IO.Class
+-- >>> import Dep.Has
+-- >>> import Dep.Env hiding (AccumConstructor, Constructor, accumConstructor, constructor, fixEnv, fixEnvAccum)
+-- >>> import GHC.Generics (Generic)
diff --git a/lib/Dep/Env.hs b/lib/Dep/Env.hs
--- a/lib/Dep/Env.hs
+++ b/lib/Dep/Env.hs
@@ -72,8 +72,14 @@
     Autowired (..),
     Autowireable,
 
+    -- * Inductive environment with anonymous fields
+    InductiveEnv (..),
+    addDep,
+    emptyEnv,
+
     -- * Managing phases
     Phased (..),
+    liftAH,
     pullPhase,
     mapPhase,
     liftA2Phase,
@@ -99,11 +105,6 @@
     fixEnvAccum,
     AccumConstructor,
 
-    -- * Inductive environment with anonymous fields
-    InductiveEnv (..),
-    addDep,
-    emptyEnv,
-
     -- * Re-exports
     Identity (..),
     Constant (..),
@@ -151,11 +152,11 @@
 -- >>> :set -XUndecidableInstances
 -- >>> :set -XTypeOperators
 -- >>> :set -XScopedTypeVariables
+-- >>> :set -fno-warn-deprecations
 -- >>> import Data.Kind
 -- >>> import Data.Function ((&))
 -- >>> import Control.Monad.IO.Class
 -- >>> import Dep.Env
--- >>> import Dep.Env
 -- >>> import GHC.Generics (Generic)
 
 -- via the default field name
@@ -169,7 +170,7 @@
 -- 'Has', so maybe it doesn't make much sense to use it, except for
 -- explicitness.
 newtype TheDefaultFieldName (env :: Type) = TheDefaultFieldName env
-
+{-# DEPRECATED TheDefaultFieldName "more intrusive than useful" #-}
 instance
   (Dep r_, HasField (DefaultFieldName r_) (env_ m) u, Coercible u (r_ m)) =>
   Has r_ m (TheDefaultFieldName (env_ m))
@@ -275,7 +276,10 @@
 -- outermost phase and running it in some way, until we are are left with a
 -- 'Constructor' phase, which we can remove using 'fixEnv'.
 --
--- 'Phased' resembles [FunctorT, TraversableT and ApplicativeT](https://hackage.haskell.org/package/barbies-2.0.3.0/docs/Data-Functor-Transformer.html) from the [barbies](https://hackage.haskell.org/package/barbies) library. 'Phased' instances can be written in terms of them.
+-- 'Phased' resembles [FunctorT, TraversableT and
+-- ApplicativeT](https://hackage.haskell.org/package/barbies-2.0.3.0/docs/Data-Functor-Transformer.html)
+-- from the [barbies](https://hackage.haskell.org/package/barbies) library,
+-- although 'Phased' instances /can't/ be written in terms of them because of the extra 'Typeable' constraints.
 type Phased :: ((Type -> Type) -> (Type -> Type) -> Type) -> Constraint
 class Phased (env_ :: (Type -> Type) -> (Type -> Type) -> Type) where
   -- | Used to implement 'pullPhase' and 'mapPhase',  typically you should use those functions instead.
@@ -348,6 +352,16 @@
     env_ f' m
   liftA2H f enva env = G.to (gLiftA2Phase f (G.from enva) (G.from env))
 
+-- | Slightly less powerful version of 'traverseH'.
+liftAH ::
+  forall deps_ phases phases' m.
+  (Phased deps_, Typeable phases, Typeable phases', Typeable m) =>
+  (forall x. Typeable x => phases x -> phases' x) ->
+  deps_ phases m ->
+  deps_ phases' m
+liftAH tweak =
+  runIdentity . traverseH (Identity . tweak)
+
 -- | Take the outermost phase wrapping each component and \"pull it outwards\",
 -- aggregating the phase's applicative effects.
 --
@@ -632,10 +646,12 @@
 --
 -- The 'Constructor' phase for an environment will typically be parameterized
 -- with the environment itself.
+{-# DEPRECATED Constructor "use the one in Dep.Constructor" #-}
 type Constructor (env :: Type) = ((->) env) `Compose` Identity
 
 -- | Turn an environment-consuming function into a 'Constructor' that can be slotted
 -- into some field of a 'Phased' environment.
+{-# DEPRECATED constructor "use the one in Dep.Constructor" #-}
 constructor :: forall r_ m env. (env -> r_ m) -> Constructor env (r_ m)
 -- same order of type parameters as Has
 constructor = coerce
@@ -645,6 +661,7 @@
 -- back along with the completed environment.
 --
 -- Like 'Constructor', 'AccumConstructor' should be the final phase.
+{-# DEPRECATED AccumConstructor "use the one in Dep.Constructor" #-}
 type AccumConstructor (w :: Type) (env :: Type) = (->) (w, env) `Compose` (,) w `Compose` Identity
 
 -- | This is a method of performing dependency injection that doesn't require
@@ -683,6 +700,7 @@
 --  bar (dep envReady) "this is bar"
 -- :}
 -- this is bar
+{-# DEPRECATED fixEnv "use the one in Dep.Constructor" #-}
 fixEnv ::
   (Phased env_, Typeable env_, Typeable m) =>
   -- | Environment where each field is wrapped in a 'Constructor'
@@ -706,6 +724,7 @@
 -- (accumulator, environment) tuple needs to use a lazy pattern match like
 -- @~(w,env)@. Otherwise 'fixEnvAccum' enters an infinite loop! Such are the
 -- dangers of knot-tying.
+{-# DEPRECATED fixEnvAccum "use the one in Dep.Constructor" #-}
 fixEnvAccum ::
   (Phased env_, Typeable env_, Typeable m, Monoid w, Typeable w) =>
   -- | Environment where each field is wrapped in an 'AccumConstructor'
diff --git a/lib/Dep/Has.hs b/lib/Dep/Has.hs
--- a/lib/Dep/Has.hs
+++ b/lib/Dep/Has.hs
@@ -164,6 +164,7 @@
 -- This allows defining 'Has' instances with empty bodies, thanks to
 -- @DefaultSignatures@.
 type Dep :: ((Type -> Type) -> Type) -> Constraint
+{-# DEPRECATED Dep "more intrusive than useful" #-}
 class Dep r_ where
   -- The Char kind would be useful here, to lowercase the first letter of the
   -- k type and use it as the default preferred field name.
diff --git a/test/doctests.hs b/test/doctests.hs
--- a/test/doctests.hs
+++ b/test/doctests.hs
@@ -7,6 +7,7 @@
     "lib/Control/Monad/Dep/Class.hs", 
     "lib/Dep/Has.hs", 
     "lib/Dep/Env.hs",
+    "lib/Dep/Constructor.hs",
     "lib/Dep/Tagged.hs"
     ]
 
diff --git a/test/tests_env.hs b/test/tests_env.hs
--- a/test/tests_env.hs
+++ b/test/tests_env.hs
@@ -29,7 +29,6 @@
 module Main (main) where
 
 import Dep.Has
-import Dep.Env
 import Control.Monad.Dep.Class
 import Control.Monad.Reader
 import Data.Functor.Constant
@@ -43,6 +42,8 @@
 import Prelude hiding (log)
 import Data.Functor.Identity
 import GHC.TypeLits
+import Dep.Env hiding (AccumConstructor, Constructor, accumConstructor, constructor, fixEnv, fixEnvAccum)
+import Dep.Constructor
 import Control.Monad.Trans.Cont
 import Data.Aeson
 import Data.Aeson.Types
